diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -31,7 +31,7 @@ #define _CORE_H enum psc_type { - PSC_TYPE_PROC, + PSC_TYPE_PROC = 0, PSC_TYPE_FILES, PSC_TYPE_VMMAP, PSC_TYPE_GROUPS, @@ -43,6 +43,7 @@ PSC_TYPE_ENVV, PSC_TYPE_AUXV, PSC_TYPE_PTLWPINFO, + PSC_TYPE_KQUEUES, PSC_TYPE_MAX }; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -57,22 +57,62 @@ GElf_Phdr pc_phdr; }; -static struct psc_type_info { +static const struct psc_type_info { unsigned int n_type; int structsize; } psc_type_info[PSC_TYPE_MAX] = { - { .n_type = NT_PROCSTAT_PROC, .structsize = sizeof(struct kinfo_proc) }, - { .n_type = NT_PROCSTAT_FILES, .structsize = sizeof(struct kinfo_file) }, - { .n_type = NT_PROCSTAT_VMMAP, .structsize = sizeof(struct kinfo_vmentry) }, - { .n_type = NT_PROCSTAT_GROUPS, .structsize = sizeof(gid_t) }, - { .n_type = NT_PROCSTAT_UMASK, .structsize = sizeof(u_short) }, - { .n_type = NT_PROCSTAT_RLIMIT, .structsize = sizeof(struct rlimit) * RLIM_NLIMITS }, - { .n_type = NT_PROCSTAT_OSREL, .structsize = sizeof(int) }, - { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, - { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, - { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, - { .n_type = NT_PROCSTAT_AUXV, .structsize = sizeof(Elf_Auxinfo) }, - { .n_type = NT_PTLWPINFO, .structsize = sizeof(struct ptrace_lwpinfo) }, + [PSC_TYPE_PROC] = { + .n_type = NT_PROCSTAT_PROC, + .structsize = sizeof(struct kinfo_proc) + }, + [PSC_TYPE_FILES] = { + .n_type = NT_PROCSTAT_FILES, + .structsize = sizeof(struct kinfo_file) + }, + [PSC_TYPE_VMMAP] = { + .n_type = NT_PROCSTAT_VMMAP, + .structsize = sizeof(struct kinfo_vmentry) + }, + [PSC_TYPE_GROUPS] = { + .n_type = NT_PROCSTAT_GROUPS, + .structsize = sizeof(gid_t) + }, + [PSC_TYPE_UMASK] = { + .n_type = NT_PROCSTAT_UMASK, + .structsize = sizeof(u_short) + }, + [PSC_TYPE_RLIMIT] = { + .n_type = NT_PROCSTAT_RLIMIT, + .structsize = sizeof(struct rlimit) * RLIM_NLIMITS + }, + [PSC_TYPE_OSREL] = { + .n_type = NT_PROCSTAT_OSREL, + .structsize = sizeof(int) + }, + [PSC_TYPE_PSSTRINGS] = { + .n_type = NT_PROCSTAT_PSSTRINGS, + .structsize = sizeof(vm_offset_t) + }, + [PSC_TYPE_ARGV] = { + .n_type = NT_PROCSTAT_PSSTRINGS, + .structsize = sizeof(vm_offset_t) + }, + [PSC_TYPE_ENVV] = { + .n_type = NT_PROCSTAT_PSSTRINGS, + .structsize = sizeof(vm_offset_t) + }, + [PSC_TYPE_AUXV] = { + .n_type = NT_PROCSTAT_AUXV, + .structsize = sizeof(Elf_Auxinfo) + }, + [PSC_TYPE_PTLWPINFO] = { + .n_type = NT_PTLWPINFO, + .structsize = sizeof(struct ptrace_lwpinfo) + }, + [PSC_TYPE_KQUEUES] = { + .n_type = NT_PROCSTAT_KQUEUES, + .structsize = sizeof(struct kinfo_knote) + }, }; static bool core_offset(struct procstat_core *core, off_t offset); diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -2862,6 +2862,9 @@ procstat_get_kqueue_info(struct procstat *procstat, struct kinfo_proc *kp, int kqfd, unsigned int *count, char *errbuf) { + struct kinfo_knote *kn, *k, *res, *rn; + size_t len, kqn; + switch (procstat->type) { case PROCSTAT_KVM: warnx("kvm method is not supported"); @@ -2870,8 +2873,34 @@ return (procstat_get_kqueue_info_sysctl(kp->ki_pid, kqfd, count, errbuf)); case PROCSTAT_CORE: - warnx("core method is not supported"); - return (NULL); + k = procstat_core_get(procstat->core, PSC_TYPE_KQUEUES, + NULL, &len); + if (k == NULL) { + snprintf(errbuf, _POSIX2_LINE_MAX, + "getting NT_PROCSTAT_KQUEUES note failed"); + *count = 0; + return (NULL); + } + for (kqn = 0, kn = k; kn < k + len / sizeof(*kn); kn++) { + if (kn->knt_kq_fd == kqfd) + kqn++; + } + res = calloc(kqn, sizeof(*res)); + if (res == NULL) { + free(k); + snprintf(errbuf, _POSIX2_LINE_MAX, + "no memory"); + return (NULL); + } + for (kn = k, rn = res; kn < k + len / sizeof(*kn); kn++) { + if (kn->knt_kq_fd != kqfd) + continue; + *rn = *kn; + rn++; + } + *count = kqn; + free(k); + return (res); default: warnx("unknown access method: %d", procstat->type); return (NULL); diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -446,6 +446,25 @@ uint32_t kvm_spare[12]; }; +struct kinfo_knote32 { + int knt_kq_fd; + struct kevent32 knt_event; + int knt_status; + int knt_extdata; + uint32_t knt_spare0[8]; + union { + struct { + int knt_vnode_type; + uint32_t knt_vnode_fsid[2]; + uint32_t knt_vnode_fileid[2]; + char knt_vnode_fullpath[PATH_MAX]; + } knt_vnode; + struct { + uint32_t knt_pipe_ino[2]; + } knt_pipe; + }; +}; + struct kld_file_stat_1_32 { int version; /* set to sizeof(struct kld_file_stat_1) */ char name[MAXPATHLEN]; diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -679,6 +679,86 @@ return (error); } +static void +freebsd32_kevent_to_kevent32(const struct kevent *kevp, struct kevent32 *ks32) +{ + uint64_t e; + int j; + + CP(*kevp, *ks32, ident); + CP(*kevp, *ks32, filter); + CP(*kevp, *ks32, flags); + CP(*kevp, *ks32, fflags); +#if BYTE_ORDER == LITTLE_ENDIAN + ks32->data1 = kevp->data; + ks32->data2 = kevp->data >> 32; +#else + ks32->data1 = kevp->data >> 32; + ks32->data2 = kevp->data; +#endif + PTROUT_CP(*kevp, *ks32, udata); + for (j = 0; j < nitems(kevp->ext); j++) { + e = kevp->ext[j]; +#if BYTE_ORDER == LITTLE_ENDIAN + ks32->ext64[2 * j] = e; + ks32->ext64[2 * j + 1] = e >> 32; +#else + ks32->ext64[2 * j] = e >> 32; + ks32->ext64[2 * j + 1] = e; +#endif + } +} + +void +freebsd32_kinfo_knote_to_32(const struct kinfo_knote *kin, + struct kinfo_knote32 *kin32) +{ + memset(kin32, 0, sizeof(*kin32)); + CP(*kin, *kin32, knt_kq_fd); + freebsd32_kevent_to_kevent32(&kin->knt_event, &kin32->knt_event); + CP(*kin, *kin32, knt_status); + CP(*kin, *kin32, knt_extdata); + switch (kin->knt_extdata) { + case KNOTE_EXTDATA_NONE: + break; + case KNOTE_EXTDATA_VNODE: + CP(*kin, *kin32, knt_vnode.knt_vnode_type); +#if BYTE_ORDER == LITTLE_ENDIAN + kin32->knt_vnode.knt_vnode_fsid[0] = kin->knt_vnode. + knt_vnode_fsid; + kin32->knt_vnode.knt_vnode_fsid[1] = kin->knt_vnode. + knt_vnode_fsid >> 32; + kin32->knt_vnode.knt_vnode_fileid[0] = kin->knt_vnode. + knt_vnode_fileid; + kin32->knt_vnode.knt_vnode_fileid[1] = kin->knt_vnode. + knt_vnode_fileid >> 32; +#else + kin32->knt_vnode.knt_vnode_fsid[1] = kin->knt_vnode. + knt_vnode_fsid; + kin32->knt_vnode.knt_vnode_fsid[0] = kin->knt_vnode. + knt_vnode_fsid >> 32; + kin32->knt_vnode.knt_vnode_fileid[1] = kin->knt_vnode. + knt_vnode_fileid; + kin32->knt_vnode.knt_vnode_fileid[0] = kin->knt_vnode. + knt_vnode_fileid >> 32; +#endif + memcpy(kin32->knt_vnode.knt_vnode_fullpath, + kin->knt_vnode.knt_vnode_fullpath, PATH_MAX); + break; + case KNOTE_EXTDATA_PIPE: +#if BYTE_ORDER == LITTLE_ENDIAN + kin32->knt_pipe.knt_pipe_ino[0] = kin->knt_pipe.knt_pipe_ino; + kin32->knt_pipe.knt_pipe_ino[1] = kin->knt_pipe. + knt_pipe_ino >> 32; +#else + kin32->knt_pipe.knt_pipe_ino[1] = kin->knt_pipe.knt_pipe_ino; + kin32->knt_pipe.knt_pipe_ino[0] = kin->knt_pipe. + knt_pipe_ino >> 32; +#endif + break; + } +} + /* * Copy 'count' items into the destination list pointed to by uap->eventlist. */ @@ -687,36 +767,13 @@ { struct freebsd32_kevent_args *uap; struct kevent32 ks32[KQ_NEVENTS]; - uint64_t e; - int i, j, error; + int i, error; KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); uap = (struct freebsd32_kevent_args *)arg; - for (i = 0; i < count; i++) { - CP(kevp[i], ks32[i], ident); - CP(kevp[i], ks32[i], filter); - CP(kevp[i], ks32[i], flags); - CP(kevp[i], ks32[i], fflags); -#if BYTE_ORDER == LITTLE_ENDIAN - ks32[i].data1 = kevp[i].data; - ks32[i].data2 = kevp[i].data >> 32; -#else - ks32[i].data1 = kevp[i].data >> 32; - ks32[i].data2 = kevp[i].data; -#endif - PTROUT_CP(kevp[i], ks32[i], udata); - for (j = 0; j < nitems(kevp->ext); j++) { - e = kevp[i].ext[j]; -#if BYTE_ORDER == LITTLE_ENDIAN - ks32[i].ext64[2 * j] = e; - ks32[i].ext64[2 * j + 1] = e >> 32; -#else - ks32[i].ext64[2 * j] = e >> 32; - ks32[i].ext64[2 * j + 1] = e; -#endif - } - } + for (i = 0; i < count; i++) + freebsd32_kevent_to_kevent32(&kevp[i], &ks32[i]); error = copyout(ks32, uap->eventlist, count * sizeof *ks32); if (error == 0) uap->eventlist += count; diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h --- a/sys/compat/freebsd32/freebsd32_util.h +++ b/sys/compat/freebsd32/freebsd32_util.h @@ -122,6 +122,11 @@ int freebsd32_exec_copyin_args(struct image_args *args, const char *fname, enum uio_seg segflg, uint32_t *argv, uint32_t *envv); +struct kinfo_knote; +struct kinfo_knote32; +void freebsd32_kinfo_knote_to_32(const struct kinfo_knote *kin, + struct kinfo_knote32 *kin32); + extern int compat_freebsd_32bit; #endif /* !_COMPAT_FREEBSD32_FREEBSD32_UTIL_H_ */ diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1574,6 +1574,7 @@ static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *); static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *); +static void __elfN(note_procstat_kqueues)(void *, struct sbuf *, size_t *); static void note_procstat_files(void *, struct sbuf *, size_t *); static void note_procstat_groups(void *, struct sbuf *, size_t *); static void note_procstat_osrel(void *, struct sbuf *, size_t *); @@ -1899,6 +1900,8 @@ __elfN(note_procstat_psstrings), p); size += __elfN(register_note)(td, list, NT_PROCSTAT_AUXV, __elfN(note_procstat_auxv), p); + size += __elfN(register_note)(td, list, NT_PROCSTAT_KQUEUES, + __elfN(note_procstat_kqueues), p); *sizep = size; } @@ -2719,6 +2722,54 @@ } } +static void +__elfN(note_procstat_kqueues)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size, sect_sz, i; + ssize_t start_len, sect_len; + int structsize; + bool compat32; + +#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 + compat32 = true; + structsize = sizeof(struct kinfo_knote32); +#else + compat32 = false; + structsize = sizeof(struct kinfo_knote); +#endif + p = arg; + if (sb == NULL) { + size = 0; + sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); + sbuf_set_drain(sb, sbuf_count_drain, &size); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + kern_proc_kqueues_out(p, sb, -1, compat32); + sbuf_finish(sb); + sbuf_delete(sb); + *sizep = size; + } else { + sbuf_start_section(sb, &start_len); + + sbuf_bcat(sb, &structsize, sizeof(structsize)); + kern_proc_kqueues_out(p, sb, *sizep - sizeof(structsize), + compat32); + + sect_len = sbuf_end_section(sb, start_len, 0, 0); + if (sect_len < 0) + return; + sect_sz = sect_len; + + KASSERT(sect_sz <= *sizep, + ("kern_proc_kqueue_out did not respect maxlen; " + "requested %zu, got %zu", *sizep - sizeof(structsize), + sect_sz - sizeof(structsize))); + + for (i = 0; i < *sizep - sect_sz && sb->s_error == 0; i++) + sbuf_putc(sb, 0); + } +} + #define MAX_NOTES_LOOP 4096 bool __elfN(parse_notes)(const struct image_params *imgp, const Elf_Note *checknote, diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -34,14 +34,11 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> #include "opt_capsicum.h" #include "opt_ddb.h" #include "opt_ktrace.h" -#include <sys/param.h> #include <sys/systm.h> - #include <sys/capsicum.h> #include <sys/conf.h> #include <sys/fcntl.h> @@ -2996,6 +2993,47 @@ return (error); } +int +fget_remote_foreach(struct thread *td, struct proc *p, + int (*fn)(struct proc *, int, struct file *, void *), void *arg) +{ + struct filedesc *fdp; + struct fdescenttbl *fdt; + struct file *fp; + int error, error1, fd, highfd; + + error = 0; + PROC_LOCK(p); + fdp = fdhold(p); + PROC_UNLOCK(p); + if (fdp == NULL) + return (ENOENT); + + FILEDESC_SLOCK(fdp); + if (refcount_load(&fdp->fd_refcnt) != 0) { + fdt = atomic_load_ptr(&fdp->fd_files); + highfd = fdt->fdt_nfiles - 1; + FILEDESC_SUNLOCK(fdp); + } else { + error = ENOENT; + FILEDESC_SUNLOCK(fdp); + goto out; + } + + for (fd = 0; fd <= highfd; fd++) { + error1 = fget_remote(td, p, fd, &fp); + if (error1 != 0) + continue; + error = fn(p, fd, fp, arg); + fdrop(fp, td); + if (error != 0) + break; + } +out: + fddrop(fdp); + return (error); +} + #ifdef CAPABILITIES int fgetvp_lookup_smr(struct nameidata *ndp, struct vnode **vpp, bool *fsearch) diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -58,6 +58,7 @@ #include <sys/poll.h> #include <sys/protosw.h> #include <sys/resourcevar.h> +#include <sys/sbuf.h> #include <sys/sigio.h> #include <sys/signalvar.h> #include <sys/socket.h> @@ -74,6 +75,10 @@ #include <sys/ktrace.h> #endif #include <machine/atomic.h> +#ifdef COMPAT_FREEBSD32 +#include <compat/freebsd32/freebsd32.h> +#include <compat/freebsd32/freebsd32_util.h> +#endif #include <vm/uma.h> @@ -2871,94 +2876,181 @@ } static int -sysctl_kern_proc_kqueue_report_one(struct proc *p, struct sysctl_req *req, - struct kqueue *kq, struct knote *kn) +kern_proc_kqueue_report_one(struct sbuf *s, struct proc *p, + int kq_fd, struct kqueue *kq, struct knote *kn, bool compat32 __unused) { struct kinfo_knote kin; +#ifdef COMPAT_FREEBSD32 + struct kinfo_knote32 kin32; +#endif int error; if (kn->kn_status == KN_MARKER) return (0); memset(&kin, 0, sizeof(kin)); + kin.knt_kq_fd = kq_fd; 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(); +#ifdef COMPAT_FREEBSD32 + if (compat32) { + freebsd32_kinfo_knote_to_32(&kin, &kin32); + error = sbuf_bcat(s, &kin32, sizeof(kin32)); + } else +#endif + error = sbuf_bcat(s, &kin, sizeof(kin)); KQ_LOCK(kq); kn_leave_flux(kn); return (error); } +static int +kern_proc_kqueue_report(struct sbuf *s, struct proc *p, int kq_fd, + struct kqueue *kq, bool compat32) +{ + struct knote *kn; + int error, i; + + error = 0; + KQ_LOCK(kq); + for (i = 0; i < kq->kq_knlistsize; i++) { + SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) { + error = kern_proc_kqueue_report_one(s, p, kq_fd, + kq, kn, compat32); + if (error != 0) + goto out; + } + } + if (kq->kq_knhashmask == 0) + goto out; + for (i = 0; i <= kq->kq_knhashmask; i++) { + SLIST_FOREACH(kn, &kq->kq_knhash[i], kn_link) { + error = kern_proc_kqueue_report_one(s, p, kq_fd, + kq, kn, compat32); + if (error != 0) + goto out; + } + } +out: + KQ_UNLOCK_FLUX(kq); + return (error); +} + +struct kern_proc_kqueues_out1_cb_args { + struct sbuf *s; + bool compat32; +}; + +static int +kern_proc_kqueues_out1_cb(struct proc *p, int fd, struct file *fp, void *arg) +{ + struct kqueue *kq; + struct kern_proc_kqueues_out1_cb_args *a; + + if (fp->f_type != DTYPE_KQUEUE) + return (0); + a = arg; + kq = fp->f_data; + return (kern_proc_kqueue_report(a->s, p, fd, kq, a->compat32)); +} + +static int +kern_proc_kqueues_out1(struct thread *td, struct proc *p, struct sbuf *s, + bool compat32) +{ + struct kern_proc_kqueues_out1_cb_args a; + + a.s = s; + a.compat32 = compat32; + return (fget_remote_foreach(td, p, kern_proc_kqueues_out1_cb, &a)); +} + +int +kern_proc_kqueues_out(struct proc *p, struct sbuf *sb, size_t maxlen, + bool compat32) +{ + struct sbuf *s, sm; + int error; + + s = sbuf_new(&sm, NULL, maxlen, SBUF_FIXEDLEN); + error = kern_proc_kqueues_out1(curthread, p, s, compat32); + sbuf_finish(s); + if (error == 0) + sbuf_bcat(sb, sbuf_data(s), MIN(sbuf_len(s), maxlen)); + sbuf_delete(s); + return (error); +} + +static int +sysctl_kern_proc_kqueue_one(struct thread *td, struct sbuf *s, struct proc *p, + int kq_fd, bool compat32) +{ + struct file *fp; + struct kqueue *kq; + int error; + + error = fget_remote(td, p, kq_fd, &fp); + if (error == 0) { + if (fp->f_type != DTYPE_KQUEUE) { + error = EINVAL; + } else { + kq = fp->f_data; + error = kern_proc_kqueue_report(s, p, kq_fd, kq, + compat32); + } + fdrop(fp, td); + } + 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; + struct sbuf *s, sm; + int error, error1, *name; + bool compat32; name = (int *)arg1; - if ((u_int)arg2 != 2) + if ((u_int)arg2 > 2 || (u_int)arg2 == 0) 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; +#ifdef FREEBSD_COMPAT32 + compat32 = SV_CURPROC_FLAG(SV_ILP32); +#else + compat32 = false; +#endif + + s = sbuf_new_for_sysctl(&sm, NULL, 0, req); + if (s == NULL) { + error = ENOMEM; + goto out; + } + sbuf_clear_flags(s, SBUF_INCLUDENUL); + + if ((u_int)arg2 == 1) { + error = kern_proc_kqueues_out1(td, p, s, compat32); + } else { + error = sysctl_kern_proc_kqueue_one(td, s, p, + name[1] /* kq_fd */, compat32); } - kq = fp->f_data; - if (req->oldptr == NULL) { - error = SYSCTL_OUT(req, NULL, sizeof(struct kinfo_knote) * - kq->kq_knlistsize * 11 / 10); - goto out2; - } + error1 = sbuf_finish(s); + if (error == 0) + error = error1; + sbuf_delete(s); - 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: +out: PRELE(p); return (error); } diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -840,6 +840,7 @@ #define NT_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ #define NT_PROCSTAT_AUXV 16 /* Procstat auxv data. */ #define NT_PTLWPINFO 17 /* Thread ptrace miscellaneous info. */ +#define NT_PROCSTAT_KQUEUES 18 /* Procstat kqueues events. */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_X86_SEGBASES 0x200 /* x86 FS/GS base addresses. */ diff --git a/sys/sys/file.h b/sys/sys/file.h --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -267,6 +267,8 @@ int needfcntl, struct file **fpp); int _fdrop(struct file *fp, struct thread *td); int fget_remote(struct thread *td, struct proc *p, int fd, struct file **fpp); +int fget_remote_foreach(struct thread *td, struct proc *p, + int (*fn)(struct proc *, int, struct file *, void *), void *arg); fo_rdwr_t invfo_rdwr; fo_truncate_t invfo_truncate; diff --git a/sys/sys/user.h b/sys/sys/user.h --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -677,9 +677,11 @@ #define KNOTE_EXTDATA_PIPE 2 struct kinfo_knote { + int knt_kq_fd; struct kevent knt_event; int knt_status; int knt_extdata; + uint64_t knt_spare0[4]; union { struct { int knt_vnode_type; @@ -720,6 +722,8 @@ int kern_proc_out(struct proc *p, struct sbuf *sb, int flags); int kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags); +int kern_proc_kqueues_out(struct proc *p, struct sbuf *s, size_t maxlen, + bool compat32); int vntype_to_kinfo(int vtype); void pack_kinfo(struct kinfo_file *kif); diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c --- a/usr.bin/gcore/elfcore.c +++ b/usr.bin/gcore/elfcore.c @@ -105,6 +105,7 @@ static void *elf_note_procstat_auxv(void *, size_t *); static void *elf_note_procstat_files(void *, size_t *); static void *elf_note_procstat_groups(void *, size_t *); +static void *elf_note_procstat_kqueues(void *, size_t *); static void *elf_note_procstat_osrel(void *, size_t *); static void *elf_note_procstat_proc(void *, size_t *); static void *elf_note_procstat_psstrings(void *, size_t *); @@ -388,6 +389,7 @@ elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid, sb); elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb); + elf_putnote(NT_PROCSTAT_KQUEUES, elf_note_procstat_kqueues, &pid, sb); #endif size = sbuf_end_section(sb, old_len, 1, 0); @@ -756,7 +758,7 @@ { size_t len; pid_t pid; - int name[4], structsize; + int name[5], structsize; void *buf, *p; pid = *(pid_t *)arg; @@ -841,6 +843,14 @@ sizeof(Elf_Auxinfo), sizep)); } +static void * +elf_note_procstat_kqueues(void *arg, size_t *sizep) +{ + + return (procstat_sysctl(arg, KERN_PROC_KQUEUE, + sizeof(struct kinfo_knote), sizep)); +} + static void * elf_note_procstat_rlimit(void *arg, size_t *sizep) {