git: e60f608eb9cf - main - Add sysctl kern.proc.kqueue
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 13 Mar 2025 16:10:06 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=e60f608eb9cf3b38099948545934d699de9bbcea
commit e60f608eb9cf3b38099948545934d699de9bbcea
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-02-23 20:25:25 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-03-13 16:09:35 +0000
Add sysctl kern.proc.kqueue
reporting registered events in the specified kqueue.
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D49163
---
sys/kern/kern_event.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++-
sys/kern/sys_pipe.c | 20 ++++++-
sys/kern/vfs_subr.c | 50 ++++++++++++++++--
sys/sys/event.h | 5 ++
sys/sys/sysctl.h | 1 +
sys/sys/user.h | 28 ++++++++++
sys/vm/sg_pager.c | 1 +
7 files changed, 238 insertions(+), 8 deletions(-)
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index dcb2c10ee1f5..14aa3abd1901 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -64,6 +64,7 @@
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/syscallsubr.h>
#include <sys/taskqueue.h>
@@ -2730,8 +2731,15 @@ knote_drop_detached(struct knote *kn, struct thread *td)
KQ_NOTOWNED(kq);
KQ_LOCK(kq);
- KASSERT(kn->kn_influx == 1,
- ("knote_drop called on %p with influx %d", kn, kn->kn_influx));
+ for (;;) {
+ KASSERT(kn->kn_influx >= 1,
+ ("knote_drop called on %p with influx %d",
+ kn, kn->kn_influx));
+ if (kn->kn_influx == 1)
+ break;
+ kq->kq_state |= KQ_FLUXWAIT;
+ msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0);
+ }
if (kn->kn_fop->f_isfd)
list = &kq->kq_knlist[kn->kn_id];
@@ -2829,3 +2837,132 @@ noacquire:
fdrop(fp, td);
return (error);
}
+
+struct knote_status_export_bit {
+ int kn_status_bit;
+ int knt_status_bit;
+};
+
+#define ST(name) \
+ { .kn_status_bit = KN_##name, .knt_status_bit = KNOTE_STATUS_##name }
+static const struct knote_status_export_bit knote_status_export_bits[] = {
+ ST(ACTIVE),
+ ST(QUEUED),
+ ST(DISABLED),
+ ST(DETACHED),
+ ST(KQUEUE),
+};
+#undef ST
+
+static int
+knote_status_export(int kn_status)
+{
+ const struct knote_status_export_bit *b;
+ unsigned i;
+ int res;
+
+ res = 0;
+ for (i = 0; i < nitems(knote_status_export_bits); i++) {
+ b = &knote_status_export_bits[i];
+ if ((kn_status & b->kn_status_bit) != 0)
+ res |= b->knt_status_bit;
+ }
+ return (res);
+}
+
+static int
+sysctl_kern_proc_kqueue_report_one(struct proc *p, struct sysctl_req *req,
+ struct kqueue *kq, struct knote *kn)
+{
+ struct kinfo_knote kin;
+ int error;
+
+ if (kn->kn_status == KN_MARKER)
+ return (0);
+
+ memset(&kin, 0, sizeof(kin));
+ memcpy(&kin.knt_event, &kn->kn_kevent, sizeof(struct kevent));
+ kin.knt_status = knote_status_export(kn->kn_status);
+ kn_enter_flux(kn);
+ KQ_UNLOCK_FLUX(kq);
+ if (kn->kn_fop->f_userdump != NULL)
+ (void)kn->kn_fop->f_userdump(p, kn, &kin);
+ error = SYSCTL_OUT(req, &kin, sizeof(kin));
+ maybe_yield();
+ KQ_LOCK(kq);
+ kn_leave_flux(kn);
+ return (error);
+}
+
+static int
+sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS)
+{
+ struct thread *td;
+ struct proc *p;
+ struct file *fp;
+ struct kqueue *kq;
+ struct knote *kn;
+ int error, i, *name;
+
+ name = (int *)arg1;
+ if ((u_int)arg2 != 2)
+ return (EINVAL);
+
+ error = pget((pid_t)name[0], PGET_HOLD | PGET_CANDEBUG, &p);
+ if (error != 0)
+ return (error);
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32)) {
+ /* XXXKIB */
+ error = EOPNOTSUPP;
+ goto out1;
+ }
+#endif
+
+ td = curthread;
+ error = fget_remote(td, p, name[1] /* kqfd */, &fp);
+ if (error != 0)
+ goto out1;
+ if (fp->f_type != DTYPE_KQUEUE) {
+ error = EINVAL;
+ goto out2;
+ }
+
+ kq = fp->f_data;
+ if (req->oldptr == NULL) {
+ error = SYSCTL_OUT(req, NULL, sizeof(struct kinfo_knote) *
+ kq->kq_knlistsize * 11 / 10);
+ goto out2;
+ }
+
+ KQ_LOCK(kq);
+ for (i = 0; i < kq->kq_knlistsize; i++) {
+ SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) {
+ error = sysctl_kern_proc_kqueue_report_one(p, req,
+ kq, kn);
+ if (error != 0)
+ goto out3;
+ }
+ }
+ if (kq->kq_knhashmask == 0)
+ goto out3;
+ for (i = 0; i <= kq->kq_knhashmask; i++) {
+ SLIST_FOREACH(kn, &kq->kq_knhash[i], kn_link) {
+ error = sysctl_kern_proc_kqueue_report_one(p, req,
+ kq, kn);
+ if (error != 0)
+ goto out3;
+ }
+ }
+out3:
+ KQ_UNLOCK_FLUX(kq);
+out2:
+ fdrop(fp, td);
+out1:
+ PRELE(p);
+ return (error);
+}
+
+static SYSCTL_NODE(_kern_proc, KERN_PROC_KQUEUE, kq,
+ CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sysctl_kern_proc_kqueue, "KQueue events");
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index b842db44e7f1..9340779918a2 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -175,21 +175,26 @@ static void filt_pipedetach_notsup(struct knote *kn);
static int filt_pipenotsup(struct knote *kn, long hint);
static int filt_piperead(struct knote *kn, long hint);
static int filt_pipewrite(struct knote *kn, long hint);
+static int filt_pipedump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
static const struct filterops pipe_nfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach_notsup,
.f_event = filt_pipenotsup
+ /* no userdump */
};
static const struct filterops pipe_rfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
- .f_event = filt_piperead
+ .f_event = filt_piperead,
+ .f_userdump = filt_pipedump,
};
static const struct filterops pipe_wfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
- .f_event = filt_pipewrite
+ .f_event = filt_pipewrite,
+ .f_userdump = filt_pipedump,
};
/*
@@ -1900,3 +1905,14 @@ filt_pipenotsup(struct knote *kn, long hint)
return (0);
}
+
+static int
+filt_pipedump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin)
+{
+ struct pipe *pipe = kn->kn_hook;
+
+ kin->knt_extdata = KNOTE_EXTDATA_PIPE;
+ kin->knt_pipe.knt_pipe_ino = pipe->pipe_ino;
+ return (0);
+}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9e9b56064ecf..95ed98d3217d 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -79,6 +79,7 @@
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
+#include <sys/user.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
#include <sys/watchdog.h>
@@ -6483,7 +6484,7 @@ const struct filterops fs_filtops = {
.f_isfd = 0,
.f_attach = filt_fsattach,
.f_detach = filt_fsdetach,
- .f_event = filt_fsevent
+ .f_event = filt_fsevent,
};
static int
@@ -6559,20 +6560,26 @@ static int filt_vfsread(struct knote *kn, long hint);
static int filt_vfswrite(struct knote *kn, long hint);
static int filt_vfsvnode(struct knote *kn, long hint);
static void filt_vfsdetach(struct knote *kn);
+static int filt_vfsdump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
+
static const struct filterops vfsread_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfsread
+ .f_event = filt_vfsread,
+ .f_userdump = filt_vfsdump,
};
static const struct filterops vfswrite_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfswrite
+ .f_event = filt_vfswrite,
+ .f_userdump = filt_vfsdump,
};
static const struct filterops vfsvnode_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfsvnode
+ .f_event = filt_vfsvnode,
+ .f_userdump = filt_vfsdump,
};
static void
@@ -6721,6 +6728,41 @@ filt_vfsvnode(struct knote *kn, long hint)
return (res);
}
+static int
+filt_vfsdump(struct proc *p, struct knote *kn, struct kinfo_knote *kin)
+{
+ struct vattr va;
+ struct vnode *vp;
+ char *fullpath, *freepath;
+ int error;
+
+ kin->knt_extdata = KNOTE_EXTDATA_VNODE;
+
+ vp = kn->kn_fp->f_vnode;
+ kin->knt_vnode.knt_vnode_type = vntype_to_kinfo(vp->v_type);
+
+ va.va_fsid = VNOVAL;
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_GETATTR(vp, &va, curthread->td_ucred);
+ VOP_UNLOCK(vp);
+ if (error != 0)
+ return (error);
+ kin->knt_vnode.knt_vnode_fsid = va.va_fsid;
+ kin->knt_vnode.knt_vnode_fileid = va.va_fileid;
+
+ freepath = NULL;
+ fullpath = "-";
+ error = vn_fullpath(vp, &fullpath, &freepath);
+ if (error == 0) {
+ strlcpy(kin->knt_vnode.knt_vnode_fullpath, fullpath,
+ sizeof(kin->knt_vnode.knt_vnode_fullpath));
+ }
+ if (freepath != NULL)
+ free(freepath, M_TEMP);
+
+ return (0);
+}
+
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 1c640c86703d..dee3365ba7b6 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -262,12 +262,17 @@ struct knlist {
#define EVENT_REGISTER 1
#define EVENT_PROCESS 2
+struct kinfo_knote;
+struct proc;
+
struct filterops {
int f_isfd; /* true if ident == filedescriptor */
int (*f_attach)(struct knote *kn);
void (*f_detach)(struct knote *kn);
int (*f_event)(struct knote *kn, long hint);
void (*f_touch)(struct knote *kn, struct kevent *kev, u_long type);
+ int (*f_userdump)(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
};
/*
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index f7abc27083aa..916c91da3d53 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -1041,6 +1041,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
#define KERN_PROC_SIGFASTBLK 44 /* address of fastsigblk magic word */
#define KERN_PROC_VM_LAYOUT 45 /* virtual address space layout info */
#define KERN_PROC_RLIMIT_USAGE 46 /* array of rlim_t */
+#define KERN_PROC_KQUEUE 47 /* array of struct kinfo_knote */
/*
* KERN_IPC identifiers
diff --git a/sys/sys/user.h b/sys/sys/user.h
index 02ca69968541..cf42412af66f 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -38,6 +38,7 @@
#ifndef _KERNEL
/* stuff that *used* to be included by user.h, or is now needed */
#include <sys/errno.h>
+#include <sys/event.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ucred.h>
@@ -665,6 +666,33 @@ struct kinfo_vm_layout {
uintptr_t kvm_spare[12];
};
+#define KNOTE_STATUS_ACTIVE 0x00000001
+#define KNOTE_STATUS_QUEUED 0x00000002
+#define KNOTE_STATUS_DISABLED 0x00000004
+#define KNOTE_STATUS_DETACHED 0x00000008
+#define KNOTE_STATUS_KQUEUE 0x00000010
+
+#define KNOTE_EXTDATA_NONE 0
+#define KNOTE_EXTDATA_VNODE 1
+#define KNOTE_EXTDATA_PIPE 2
+
+struct kinfo_knote {
+ struct kevent knt_event;
+ int knt_status;
+ int knt_extdata;
+ union {
+ struct {
+ int knt_vnode_type;
+ uint64_t knt_vnode_fsid;
+ uint64_t knt_vnode_fileid;
+ char knt_vnode_fullpath[PATH_MAX];
+ } knt_vnode;
+ struct {
+ ino_t knt_pipe_ino;
+ } knt_pipe;
+ };
+};
+
#ifdef _KERNEL
/* Flags for kern_proc_out function. */
#define KERN_PROC_NOTHREADS 0x1
diff --git a/sys/vm/sg_pager.c b/sys/vm/sg_pager.c
index f1f4a3763bb0..64f226dd9c58 100644
--- a/sys/vm/sg_pager.c
+++ b/sys/vm/sg_pager.c
@@ -34,6 +34,7 @@
*/
#include <sys/param.h>
+#include <sys/event.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>