Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_event.c
Show All 27 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_compat.h" | #include "opt_compat.h" | ||||
#include "opt_ktrace.h" | #include "opt_ktrace.h" | ||||
#include "opt_kqueue.h" | #include "opt_kqueue.h" | ||||
#ifdef COMPAT_FREEBSD11 | |||||
#define _WANT_FREEBSD11_KEVENT | |||||
#endif | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | static int kqueue_scan(struct kqueue *kq, int maxevents, | ||||
const struct timespec *timeout, | const struct timespec *timeout, | ||||
struct kevent *keva, struct thread *td); | struct kevent *keva, struct thread *td); | ||||
static void kqueue_wakeup(struct kqueue *kq); | static void kqueue_wakeup(struct kqueue *kq); | ||||
static struct filterops *kqueue_fo_find(int filt); | static struct filterops *kqueue_fo_find(int filt); | ||||
static void kqueue_fo_release(int filt); | static void kqueue_fo_release(int filt); | ||||
struct g_kevent_args; | struct g_kevent_args; | ||||
static int kern_kevent_generic(struct thread *td, | static int kern_kevent_generic(struct thread *td, | ||||
struct g_kevent_args *uap, | struct g_kevent_args *uap, | ||||
struct kevent_copyops *k_ops); | struct kevent_copyops *k_ops, const char *struct_name); | ||||
static fo_ioctl_t kqueue_ioctl; | static fo_ioctl_t kqueue_ioctl; | ||||
static fo_poll_t kqueue_poll; | static fo_poll_t kqueue_poll; | ||||
static fo_kqfilter_t kqueue_kqfilter; | static fo_kqfilter_t kqueue_kqfilter; | ||||
static fo_stat_t kqueue_stat; | static fo_stat_t kqueue_stat; | ||||
static fo_close_t kqueue_close; | static fo_close_t kqueue_close; | ||||
static fo_fill_kinfo_t kqueue_fill_kinfo; | static fo_fill_kinfo_t kqueue_fill_kinfo; | ||||
▲ Show 20 Lines • Show All 773 Lines • ▼ Show 20 Lines | kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps) | ||||
finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops); | finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
td->td_retval[0] = fd; | td->td_retval[0] = fd; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef KTRACE | |||||
static size_t | |||||
kev_iovlen(int n, u_int kgio, size_t kevent_size) | |||||
{ | |||||
if (n < 0 || n >= kgio / kevent_size) | |||||
return (kgio); | |||||
return (n * kevent_size); | |||||
} | |||||
#endif | |||||
struct g_kevent_args { | struct g_kevent_args { | ||||
int fd; | int fd; | ||||
void *changelist; | void *changelist; | ||||
int nchanges; | int nchanges; | ||||
void *eventlist; | void *eventlist; | ||||
int nevents; | int nevents; | ||||
const struct timespec *timeout; | const struct timespec *timeout; | ||||
}; | }; | ||||
Show All 11 Lines | struct g_kevent_args gk_args = { | ||||
.fd = uap->fd, | .fd = uap->fd, | ||||
.changelist = uap->changelist, | .changelist = uap->changelist, | ||||
.nchanges = uap->nchanges, | .nchanges = uap->nchanges, | ||||
.eventlist = uap->eventlist, | .eventlist = uap->eventlist, | ||||
.nevents = uap->nevents, | .nevents = uap->nevents, | ||||
.timeout = uap->timeout, | .timeout = uap->timeout, | ||||
}; | }; | ||||
return (kern_kevent_generic(td, &gk_args, &k_ops)); | return (kern_kevent_generic(td, &gk_args, &k_ops, "kevent")); | ||||
} | } | ||||
static int | static int | ||||
kern_kevent_generic(struct thread *td, struct g_kevent_args *uap, | kern_kevent_generic(struct thread *td, struct g_kevent_args *uap, | ||||
struct kevent_copyops *k_ops) | struct kevent_copyops *k_ops, const char *struct_name) | ||||
{ | { | ||||
struct timespec ts, *tsp; | struct timespec ts, *tsp; | ||||
int error; | |||||
#ifdef KTRACE | #ifdef KTRACE | ||||
struct uio ktruio; | struct kevent *eventlist = uap->eventlist; | ||||
struct iovec ktriov; | |||||
struct uio *ktruioin = NULL; | |||||
struct uio *ktruioout = NULL; | |||||
u_int kgio; | |||||
#endif | #endif | ||||
int error; | |||||
if (uap->timeout != NULL) { | if (uap->timeout != NULL) { | ||||
error = copyin(uap->timeout, &ts, sizeof(ts)); | error = copyin(uap->timeout, &ts, sizeof(ts)); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
tsp = &ts; | tsp = &ts; | ||||
} else | } else | ||||
tsp = NULL; | tsp = NULL; | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (KTRPOINT(td, KTR_GENIO)) { | if (KTRPOINT(td, KTR_STRUCT_ARRAY)) | ||||
kgio = ktr_geniosize; | ktrstructarray(struct_name, UIO_USERSPACE, uap->changelist, | ||||
kib: There is one issue there, note the kevent_size argument. The kern_kevent_generic() is called… | |||||
Not Done Inline ActionsI can actually switch on the structure size in kdump to handle these without requiring a separate name. I do agree that we could add dumping of kevent32 structures, but would probably do that as a separate change. jhb: I can actually switch on the structure size in kdump to handle these without requiring a… | |||||
Not Done Inline ActionsRelying on size is messy, it assumes that there is no collisions and never will be. It is mostly fine when we extend a single structure like lwpinfo, but there we have at least four different definitions of kevent{native,32}{12,11} and might be more in future. I would be not suprised if something goes wrong and some sizes appear same. kib: Relying on size is messy, it assumes that there is no collisions and never will be. It is… | |||||
ktriov.iov_base = uap->changelist; | uap->nchanges, k_ops->kevent_size); | ||||
ktriov.iov_len = kev_iovlen(uap->nchanges, kgio, | |||||
k_ops->kevent_size); | |||||
ktruio = (struct uio){ .uio_iov = &ktriov, .uio_iovcnt = 1, | |||||
.uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ, | |||||
.uio_td = td }; | |||||
ktruioin = cloneuio(&ktruio); | |||||
ktriov.iov_base = uap->eventlist; | |||||
ktriov.iov_len = kev_iovlen(uap->nevents, kgio, | |||||
k_ops->kevent_size); | |||||
ktriov.iov_len = uap->nevents * k_ops->kevent_size; | |||||
ktruioout = cloneuio(&ktruio); | |||||
} | |||||
#endif | #endif | ||||
error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents, | error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents, | ||||
k_ops, tsp); | k_ops, tsp); | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (ktruioin != NULL) { | if (error == 0 && KTRPOINT(td, KTR_STRUCT_ARRAY)) | ||||
ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio, | ktrstructarray(struct_name, UIO_USERSPACE, eventlist, | ||||
k_ops->kevent_size); | td->td_retval[0], k_ops->kevent_size); | ||||
ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0); | |||||
ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio, | |||||
k_ops->kevent_size); | |||||
ktrgenio(uap->fd, UIO_READ, ktruioout, error); | |||||
} | |||||
#endif | #endif | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Copy 'count' items into the destination list pointed to by uap->eventlist. | * Copy 'count' items into the destination list pointed to by uap->eventlist. | ||||
*/ | */ | ||||
Show All 26 Lines | kevent_copyin(void *arg, struct kevent *kevp, int count) | ||||
error = copyin(uap->changelist, kevp, count * sizeof *kevp); | error = copyin(uap->changelist, kevp, count * sizeof *kevp); | ||||
if (error == 0) | if (error == 0) | ||||
uap->changelist += count; | uap->changelist += count; | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef COMPAT_FREEBSD11 | #ifdef COMPAT_FREEBSD11 | ||||
struct kevent_freebsd11 { | |||||
__uintptr_t ident; /* identifier for this event */ | |||||
short filter; /* filter for event */ | |||||
unsigned short flags; | |||||
unsigned int fflags; | |||||
__intptr_t data; | |||||
void *udata; /* opaque user data identifier */ | |||||
}; | |||||
static int | static int | ||||
kevent11_copyout(void *arg, struct kevent *kevp, int count) | kevent11_copyout(void *arg, struct kevent *kevp, int count) | ||||
{ | { | ||||
struct freebsd11_kevent_args *uap; | struct freebsd11_kevent_args *uap; | ||||
struct kevent_freebsd11 kev11; | struct kevent_freebsd11 kev11; | ||||
int error, i; | int error, i; | ||||
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); | KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count)); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | struct g_kevent_args gk_args = { | ||||
.fd = uap->fd, | .fd = uap->fd, | ||||
.changelist = uap->changelist, | .changelist = uap->changelist, | ||||
.nchanges = uap->nchanges, | .nchanges = uap->nchanges, | ||||
.eventlist = uap->eventlist, | .eventlist = uap->eventlist, | ||||
.nevents = uap->nevents, | .nevents = uap->nevents, | ||||
.timeout = uap->timeout, | .timeout = uap->timeout, | ||||
}; | }; | ||||
return (kern_kevent_generic(td, &gk_args, &k_ops)); | return (kern_kevent_generic(td, &gk_args, &k_ops, "kevent_freebsd11")); | ||||
} | } | ||||
#endif | #endif | ||||
int | int | ||||
kern_kevent(struct thread *td, int fd, int nchanges, int nevents, | kern_kevent(struct thread *td, int fd, int nchanges, int nevents, | ||||
struct kevent_copyops *k_ops, const struct timespec *timeout) | struct kevent_copyops *k_ops, const struct timespec *timeout) | ||||
{ | { | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
▲ Show 20 Lines • Show All 1,542 Lines • Show Last 20 Lines |
There is one issue there, note the kevent_size argument. The kern_kevent_generic() is called for native and for native compat11 kevents. I think it would be useful to utilize the kstructarray name and e.g. use "event-11" for compat case.
Also, it might be possible now to dump kevent32 and kevent32-11 from the compat32 layer.