Module Name: src Committed By: christos Date: Sat Jul 1 20:08:56 UTC 2017
Modified Files: src/sys/kern: kern_event.c src/sys/sys: event.h Log Message: fix file descriptor locking (from joerg). fixes kernel crashes by running go XXX: pullup-7 To generate a diff of this commit: cvs rdiff -u -r1.91 -r1.92 src/sys/kern/kern_event.c cvs rdiff -u -r1.29 -r1.30 src/sys/sys/event.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_event.c diff -u src/sys/kern/kern_event.c:1.91 src/sys/kern/kern_event.c:1.92 --- src/sys/kern/kern_event.c:1.91 Thu May 11 19:50:17 2017 +++ src/sys/kern/kern_event.c Sat Jul 1 16:08:56 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_event.c,v 1.91 2017/05/11 23:50:17 christos Exp $ */ +/* $NetBSD: kern_event.c,v 1.92 2017/07/01 20:08:56 christos Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.91 2017/05/11 23:50:17 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.92 2017/07/01 20:08:56 christos Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1021,8 +1021,9 @@ kqueue_register(struct kqueue *kq, struc if (error != 0) { #ifdef DIAGNOSTIC - printf("%s: event not supported for file type" - " %d (error %d)\n", __func__, kn->kn_obj ? + printf("%s: event type %d not supported for " + "file type %d (error %d)\n", __func__, + kn->kn_filter, kn->kn_obj ? ((file_t *)kn->kn_obj)->f_type : -1, error); #endif /* knote_detach() drops fdp->fd_lock */ @@ -1204,10 +1205,19 @@ kqueue_scan(file_t *fp, size_t maxevents error = 0; } } + mutex_spin_exit(&kq->kq_lock); } else { /* mark end of knote list */ TAILQ_INSERT_TAIL(&kq->kq_head, marker, kn_tqe); + /* + * Acquire the fdp->fd_lock interlock to avoid races with + * file creation/destruction from other threads. + */ + mutex_spin_exit(&kq->kq_lock); + mutex_enter(&fdp->fd_lock); + mutex_spin_enter(&kq->kq_lock); + while (count != 0) { kn = TAILQ_FIRST(&kq->kq_head); /* get next knote */ while ((kn->kn_status & KN_MARKER) != 0) { @@ -1218,6 +1228,7 @@ kqueue_scan(file_t *fp, size_t maxevents (timeout = gettimeleft(&ats, &sleepts)) <= 0)) goto done; + mutex_exit(&fdp->fd_lock); goto retry; } /* someone else's marker. */ @@ -1239,6 +1250,7 @@ kqueue_scan(file_t *fp, size_t maxevents KASSERT(kn->kn_fop != NULL); KASSERT(kn->kn_fop->f_event != NULL); KERNEL_LOCK(1, NULL); /* XXXSMP */ + KASSERT(mutex_owned(&fdp->fd_lock)); rv = (*kn->kn_fop->f_event)(kn, 0); KERNEL_UNLOCK_ONE(NULL); /* XXXSMP */ mutex_spin_enter(&kq->kq_lock); @@ -1261,10 +1273,10 @@ kqueue_scan(file_t *fp, size_t maxevents nkev++; if (kn->kn_flags & EV_ONESHOT) { /* delete ONESHOT events after retrieval */ - mutex_spin_exit(&kq->kq_lock); - mutex_enter(&fdp->fd_lock); kn->kn_status &= ~KN_BUSY; + mutex_spin_exit(&kq->kq_lock); knote_detach(kn, fdp, true); + mutex_enter(&fdp->fd_lock); mutex_spin_enter(&kq->kq_lock); } else if (kn->kn_flags & EV_CLEAR) { /* clear state after retrieval */ @@ -1286,9 +1298,11 @@ kqueue_scan(file_t *fp, size_t maxevents if (nkev == kevcnt) { /* do copyouts in kevcnt chunks */ mutex_spin_exit(&kq->kq_lock); + mutex_exit(&fdp->fd_lock); error = (*keops->keo_put_events) (keops->keo_private, kevbuf, ulistp, nevents, nkev); + mutex_enter(&fdp->fd_lock); mutex_spin_enter(&kq->kq_lock); nevents += nkev; nkev = 0; @@ -1301,9 +1315,10 @@ kqueue_scan(file_t *fp, size_t maxevents break; } } - } done: - mutex_spin_exit(&kq->kq_lock); + mutex_spin_exit(&kq->kq_lock); + mutex_exit(&fdp->fd_lock); + } if (nkev != 0) { /* copyout remaining events */ error = (*keops->keo_put_events)(keops->keo_private, Index: src/sys/sys/event.h diff -u src/sys/sys/event.h:1.29 src/sys/sys/event.h:1.30 --- src/sys/sys/event.h:1.29 Wed Jun 14 12:37:05 2017 +++ src/sys/sys/event.h Sat Jul 1 16:08:56 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: event.h,v 1.29 2017/06/14 16:37:05 christos Exp $ */ +/* $NetBSD: event.h,v 1.30 2017/07/01 20:08:56 christos Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon <jle...@freebsd.org> @@ -188,10 +188,10 @@ struct knote { TAILQ_ENTRY(knote) kn_tqe; /* q: for struct kqueue */ struct kqueue *kn_kq; /* q: which queue we are on */ struct kevent kn_kevent; - uint32_t kn_status; - uint32_t kn_sfflags; /* saved filter flags */ - uintptr_t kn_sdata; /* saved data field */ - void *kn_obj; /* pointer to monitored obj */ + uint32_t kn_status; /* q: flags below */ + uint32_t kn_sfflags; /* saved filter flags */ + uintptr_t kn_sdata; /* saved data field */ + void *kn_obj; /* monitored obj */ const struct filterops *kn_fop; struct kfilter *kn_kfilter; void *kn_hook; @@ -201,7 +201,8 @@ struct knote { #define KN_DISABLED 0x04U /* event is disabled */ #define KN_DETACHED 0x08U /* knote is detached */ #define KN_MARKER 0x10U /* is a marker */ -#define KN_BUSY 0x20U /* is being scanned */ +#define KN_BUSY 0x20U /* is being scanned */ +/* Toggling KN_BUSY also requires kn_kq->kq_fdp->fd_lock. */ #define kn_id kn_kevent.ident #define kn_filter kn_kevent.filter