summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/kern_event.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-12-20 11:12:40 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-12-20 13:36:34 +0100
commit2b2563da953978f63e3e707f758fd600dcd19a32 (patch)
treea207b096c10788192b56025e8187f14d1b5a978d /freebsd/sys/kern/kern_event.c
parentfreebsd/if_cpsw: Port. (diff)
downloadrtems-libbsd-2b2563da953978f63e3e707f758fd600dcd19a32.tar.bz2
Update to FreeBSD head 2018-12-20
Git mirror commit 19a6ceb89dbacf74697d493e48c388767126d418. It includes an update of wpa_supplicant to version 2.7. It includes an update of the OpenSSL baseline to version 1.1.1a. Update #3472.
Diffstat (limited to 'freebsd/sys/kern/kern_event.c')
-rw-r--r--freebsd/sys/kern/kern_event.c110
1 files changed, 58 insertions, 52 deletions
diff --git a/freebsd/sys/kern/kern_event.c b/freebsd/sys/kern/kern_event.c
index 2fae2d89..5c75c657 100644
--- a/freebsd/sys/kern/kern_event.c
+++ b/freebsd/sys/kern/kern_event.c
@@ -110,13 +110,13 @@ TASKQUEUE_DEFINE_THREAD(kqueue_ctx);
static int kevent_copyout(void *arg, struct kevent *kevp, int count);
static int kevent_copyin(void *arg, struct kevent *kevp, int count);
static int kqueue_register(struct kqueue *kq, struct kevent *kev,
- struct thread *td, int waitok);
+ struct thread *td, int mflag);
static int kqueue_acquire(struct file *fp, struct kqueue **kqp);
static void kqueue_release(struct kqueue *kq, int locked);
static void kqueue_destroy(struct kqueue *kq);
static void kqueue_drain(struct kqueue *kq, struct thread *td);
static int kqueue_expand(struct kqueue *kq, struct filterops *fops,
- uintptr_t ident, int waitok);
+ uintptr_t ident, int mflag);
static void kqueue_task(void *arg, int pending);
static int kqueue_scan(struct kqueue *kq, int maxevents,
struct kevent_copyops *k_ops,
@@ -165,7 +165,7 @@ static void knote_drop_detached(struct knote *kn, struct thread *td);
static void knote_enqueue(struct knote *kn);
static void knote_dequeue(struct knote *kn);
static void knote_init(void);
-static struct knote *knote_alloc(int waitok);
+static struct knote *knote_alloc(int mflag);
static void knote_free(struct knote *kn);
static void filt_kqdetach(struct knote *kn);
@@ -571,10 +571,12 @@ knote_fork(struct knlist *list, int pid)
struct kevent kev;
int error;
- if (list == NULL)
+ MPASS(list != NULL);
+ KNL_ASSERT_LOCKED(list);
+ if (SLIST_EMPTY(&list->kl_list))
return;
- list->kl_lock(list->kl_lockarg);
+ memset(&kev, 0, sizeof(kev));
SLIST_FOREACH(kn, &list->kl_list, kn_selnext) {
kq = kn->kn_kq;
KQ_LOCK(kq);
@@ -587,10 +589,8 @@ knote_fork(struct knlist *list, int pid)
* The same as knote(), activate the event.
*/
if ((kn->kn_sfflags & NOTE_TRACK) == 0) {
- kn->kn_status |= KN_HASKQLOCK;
if (kn->kn_fop->f_event(kn, NOTE_FORK))
KNOTE_ACTIVATE(kn, 1);
- kn->kn_status &= ~KN_HASKQLOCK;
KQ_UNLOCK(kq);
continue;
}
@@ -621,7 +621,7 @@ knote_fork(struct knlist *list, int pid)
kev.fflags = kn->kn_sfflags;
kev.data = kn->kn_id; /* parent */
kev.udata = kn->kn_kevent.udata;/* preserve udata */
- error = kqueue_register(kq, &kev, NULL, 0);
+ error = kqueue_register(kq, &kev, NULL, M_NOWAIT);
if (error)
kn->kn_fflags |= NOTE_TRACKERR;
@@ -635,17 +635,16 @@ knote_fork(struct knlist *list, int pid)
kev.fflags = kn->kn_sfflags;
kev.data = kn->kn_id; /* parent */
kev.udata = kn->kn_kevent.udata;/* preserve udata */
- error = kqueue_register(kq, &kev, NULL, 0);
+ error = kqueue_register(kq, &kev, NULL, M_NOWAIT);
if (error)
kn->kn_fflags |= NOTE_TRACKERR;
if (kn->kn_fop->f_event(kn, NOTE_FORK))
KNOTE_ACTIVATE(kn, 0);
+ list->kl_lock(list->kl_lockarg);
KQ_LOCK(kq);
kn_leave_flux(kn);
KQ_UNLOCK_FLUX(kq);
- list->kl_lock(list->kl_lockarg);
}
- list->kl_unlock(list->kl_lockarg);
}
#endif /* __rtems__ */
@@ -1352,7 +1351,7 @@ kqueue_kevent(struct kqueue *kq, struct thread *td, int nchanges, int nevents,
if (!kevp->filter)
continue;
kevp->flags &= ~EV_SYSFLAGS;
- error = kqueue_register(kq, kevp, td, 1);
+ error = kqueue_register(kq, kevp, td, M_WAITOK);
if (error || (kevp->flags & EV_RECEIPT)) {
if (nevents == 0)
return (error);
@@ -1495,12 +1494,11 @@ kqueue_fo_release(int filt)
}
/*
- * A ref to kq (obtained via kqueue_acquire) must be held. waitok will
- * influence if memory allocation should wait. Make sure it is 0 if you
- * hold any mutexes.
+ * A ref to kq (obtained via kqueue_acquire) must be held.
*/
static int
-kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int waitok)
+kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td,
+ int mflag)
{
struct filterops *fops;
struct file *fp;
@@ -1530,7 +1528,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa
* allocation failures are handled in the loop, only
* if the spare knote appears to be actually required.
*/
- tkn = knote_alloc(waitok);
+ tkn = knote_alloc(mflag);
} else {
tkn = NULL;
}
@@ -1546,11 +1544,11 @@ findkn:
goto done;
if ((kev->flags & EV_ADD) == EV_ADD && kqueue_expand(kq, fops,
- kev->ident, 0) != 0) {
+ kev->ident, M_NOWAIT) != 0) {
/* try again */
fdrop(fp, td);
fp = NULL;
- error = kqueue_expand(kq, fops, kev->ident, waitok);
+ error = kqueue_expand(kq, fops, kev->ident, mflag);
if (error)
goto done;
goto findkn;
@@ -1590,8 +1588,11 @@ findkn:
break;
}
} else {
- if ((kev->flags & EV_ADD) == EV_ADD)
- kqueue_expand(kq, fops, kev->ident, waitok);
+ if ((kev->flags & EV_ADD) == EV_ADD) {
+ error = kqueue_expand(kq, fops, kev->ident, mflag);
+ if (error != 0)
+ goto done;
+ }
KQ_LOCK(kq);
@@ -1663,6 +1664,8 @@ findkn:
kn->kn_kevent.flags &= ~(EV_ADD | EV_DELETE |
EV_ENABLE | EV_DISABLE | EV_FORCEONESHOT);
kn->kn_status = KN_DETACHED;
+ if ((kev->flags & EV_DISABLE) != 0)
+ kn->kn_status |= KN_DISABLED;
kn_enter_flux(kn);
error = knote_attach(kn, kq);
@@ -1698,6 +1701,11 @@ findkn:
KNOTE_ACTIVATE(kn, 1);
}
+ if ((kev->flags & EV_ENABLE) != 0)
+ kn->kn_status &= ~KN_DISABLED;
+ else if ((kev->flags & EV_DISABLE) != 0)
+ kn->kn_status |= KN_DISABLED;
+
/*
* The user may change some filter values after the initial EV_ADD,
* but doing so will not reset any filter which has already been
@@ -1715,19 +1723,17 @@ findkn:
kn->kn_sdata = kev->data;
}
+done_ev_add:
/*
* We can get here with kn->kn_knlist == NULL. This can happen when
* the initial attach event decides that the event is "completed"
- * already. i.e. filt_procattach is called on a zombie process. It
- * will call filt_proc which will remove it from the list, and NULL
+ * already, e.g., filt_procattach() is called on a zombie process. It
+ * will call filt_proc() which will remove it from the list, and NULL
* kn_knlist.
+ *
+ * KN_DISABLED will be stable while the knote is in flux, so the
+ * unlocked read will not race with an update.
*/
-done_ev_add:
- if ((kev->flags & EV_ENABLE) != 0)
- kn->kn_status &= ~KN_DISABLED;
- else if ((kev->flags & EV_DISABLE) != 0)
- kn->kn_status |= KN_DISABLED;
-
if ((kn->kn_status & KN_DISABLED) == 0)
event = kn->kn_fop->f_event(kn, 0);
else
@@ -1815,23 +1821,18 @@ kqueue_schedtask(struct kqueue *kq)
* Expand the kq to make sure we have storage for fops/ident pair.
*
* Return 0 on success (or no work necessary), return errno on failure.
- *
- * Not calling hashinit w/ waitok (proper malloc flag) should be safe.
- * If kqueue_register is called from a non-fd context, there usually/should
- * be no locks held.
*/
static int
kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
- int waitok)
+ int mflag)
{
struct klist *list, *tmp_knhash, *to_free;
u_long tmp_knhashmask;
- int size;
- int fd;
- int mflag = waitok ? M_WAITOK : M_NOWAIT;
+ int error, fd, size;
KQ_NOTOWNED(kq);
+ error = 0;
to_free = NULL;
if (fops->f_isfd) {
fd = ident;
@@ -1843,9 +1844,11 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
if (list == NULL)
return ENOMEM;
KQ_LOCK(kq);
- if (kq->kq_knlistsize > fd) {
+ if ((kq->kq_state & KQ_CLOSING) != 0) {
+ to_free = list;
+ error = EBADF;
+ } else if (kq->kq_knlistsize > fd) {
to_free = list;
- list = NULL;
} else {
if (kq->kq_knlist != NULL) {
bcopy(kq->kq_knlist, list,
@@ -1863,12 +1866,16 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
}
} else {
if (kq->kq_knhashmask == 0) {
- tmp_knhash = hashinit(KN_HASHSIZE, M_KQUEUE,
- &tmp_knhashmask);
+ tmp_knhash = hashinit_flags(KN_HASHSIZE, M_KQUEUE,
+ &tmp_knhashmask, (mflag & M_WAITOK) != 0 ?
+ HASH_WAITOK : HASH_NOWAIT);
if (tmp_knhash == NULL)
- return ENOMEM;
+ return (ENOMEM);
KQ_LOCK(kq);
- if (kq->kq_knhashmask == 0) {
+ if ((kq->kq_state & KQ_CLOSING) != 0) {
+ to_free = tmp_knhash;
+ error = EBADF;
+ } else if (kq->kq_knhashmask == 0) {
kq->kq_knhash = tmp_knhash;
kq->kq_knhashmask = tmp_knhashmask;
} else {
@@ -1880,7 +1887,7 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
free(to_free, M_KQUEUE);
KQ_NOTOWNED(kq);
- return 0;
+ return (error);
}
static void
@@ -1950,7 +1957,7 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops,
asbt = -1;
} else
asbt = 0;
- marker = knote_alloc(1);
+ marker = knote_alloc(M_WAITOK);
marker->kn_status = KN_MARKER;
KQ_LOCK(kq);
@@ -2463,10 +2470,8 @@ knote(struct knlist *list, long hint, int lockflags)
KNOTE_ACTIVATE(kn, 1);
KQ_UNLOCK_FLUX(kq);
} else {
- kn->kn_status |= KN_HASKQLOCK;
if (kn->kn_fop->f_event(kn, hint))
KNOTE_ACTIVATE(kn, 1);
- kn->kn_status &= ~KN_HASKQLOCK;
KQ_UNLOCK(kq);
}
}
@@ -2807,6 +2812,8 @@ knote_attach(struct knote *kn, struct kqueue *kq)
KASSERT(kn_in_flux(kn), ("knote %p not marked influx", kn));
KQ_OWNED(kq);
+ if ((kq->kq_state & KQ_CLOSING) != 0)
+ return (EBADF);
if (kn->kn_fop->f_isfd) {
if (kn->kn_id >= kq->kq_knlistsize)
return (ENOMEM);
@@ -2902,11 +2909,10 @@ knote_init(void)
SYSINIT(knote, SI_SUB_PSEUDO, SI_ORDER_ANY, knote_init, NULL);
static struct knote *
-knote_alloc(int waitok)
+knote_alloc(int mflag)
{
- return (uma_zalloc(knote_zone, (waitok ? M_WAITOK : M_NOWAIT) |
- M_ZERO));
+ return (uma_zalloc(knote_zone, mflag | M_ZERO));
}
static void
@@ -2920,7 +2926,7 @@ knote_free(struct knote *kn)
* Register the kev w/ the kq specified by fd.
*/
int
-kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok)
+kqfd_register(int fd, struct kevent *kev, struct thread *td, int mflag)
{
struct kqueue *kq;
struct file *fp;
@@ -2933,7 +2939,7 @@ kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok)
if ((error = kqueue_acquire(fp, &kq)) != 0)
goto noacquire;
- error = kqueue_register(kq, kev, td, waitok);
+ error = kqueue_register(kq, kev, td, mflag);
kqueue_release(kq, 0);
noacquire: