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

Reply via email to