Module Name:    src
Committed By:   thorpej
Date:           Sun Sep 26 03:12:50 UTC 2021

Modified Files:
        src/sys/kern: kern_event.c
        src/sys/sys: event.h

Log Message:
- Define a new filterops flag FILTEROP_MPSAFE, which states that the
  kqueue filter does not require the KERNEL_LOCK to be held.
- Add wrappers around the calls into the filterops that take care of
  the locking requirements.

No functional change, since no filterops yet define FILTEROP_MPSAFE.


To generate a diff of this commit:
cvs rdiff -u -r1.121 -r1.122 src/sys/kern/kern_event.c
cvs rdiff -u -r1.41 -r1.42 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.121 src/sys/kern/kern_event.c:1.122
--- src/sys/kern/kern_event.c:1.121	Sun Sep 26 01:16:10 2021
+++ src/sys/kern/kern_event.c	Sun Sep 26 03:12:50 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_event.c,v 1.121 2021/09/26 01:16:10 thorpej Exp $	*/
+/*	$NetBSD: kern_event.c,v 1.122 2021/09/26 03:12:50 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.121 2021/09/26 01:16:10 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.122 2021/09/26 03:12:50 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -143,6 +143,12 @@ static const struct filterops proc_filto
 	.f_event = filt_proc,
 };
 
+/*
+ * file_filtops is not marked MPSAFE because it's going to call
+ * fileops::fo_kqfilter(), which might not be.  That function,
+ * however, will override the knote's filterops, and thus will
+ * inherit the MPSAFE-ness of the back-end at that time.
+ */
 static const struct filterops file_filtops = {
 	.f_flags = FILTEROP_ISFD,
 	.f_attach = filt_fileattach,
@@ -241,6 +247,69 @@ static size_t		user_kfiltersz;		/* size 
 static krwlock_t	kqueue_filter_lock;	/* lock on filter lists */
 static kmutex_t		kqueue_misc_lock;	/* miscellaneous */
 
+static int
+filter_attach(struct knote *kn)
+{
+	int rv;
+
+	KASSERT(kn->kn_fop != NULL);
+	KASSERT(kn->kn_fop->f_attach != NULL);
+
+	/*
+	 * N.B. that kn->kn_fop may change as the result of calling
+	 * f_attach().
+	 */
+	if (kn->kn_fop->f_flags & FILTEROP_MPSAFE) {
+		rv = kn->kn_fop->f_attach(kn);
+	} else {
+		KERNEL_LOCK(1, NULL);
+		rv = kn->kn_fop->f_attach(kn);
+		KERNEL_UNLOCK_ONE(NULL);
+	}
+
+	return rv;
+}
+
+static void
+filter_detach(struct knote *kn)
+{
+	KASSERT(kn->kn_fop != NULL);
+	KASSERT(kn->kn_fop->f_detach != NULL);
+
+	if (kn->kn_fop->f_flags & FILTEROP_MPSAFE) {
+		kn->kn_fop->f_detach(kn);
+	} else {
+		KERNEL_LOCK(1, NULL);
+		kn->kn_fop->f_detach(kn);
+		KERNEL_UNLOCK_ONE(NULL);
+	}
+}
+
+static int
+filter_event(struct knote *kn, long hint)
+{
+	int rv;
+
+	KASSERT(kn->kn_fop != NULL);
+	KASSERT(kn->kn_fop->f_event != NULL);
+
+	if (kn->kn_fop->f_flags & FILTEROP_MPSAFE) {
+		rv = kn->kn_fop->f_event(kn, hint);
+	} else {
+		KERNEL_LOCK(1, NULL);
+		rv = kn->kn_fop->f_event(kn, hint);
+		KERNEL_UNLOCK_ONE(NULL);
+	}
+
+	return rv;
+}
+
+static void
+filter_touch(struct knote *kn, struct kevent *kev, long type)
+{
+	kn->kn_fop->f_touch(kn, kev, type);
+}
+
 static kauth_listener_t	kqueue_listener;
 
 static int
@@ -1233,9 +1302,11 @@ kqueue_register(struct kqueue *kq, struc
 			}
 			SLIST_INSERT_HEAD(list, kn, kn_link);
 
-			KERNEL_LOCK(1, NULL);		/* XXXSMP */
-			error = (*kfilter->filtops->f_attach)(kn);
-			KERNEL_UNLOCK_ONE(NULL);	/* XXXSMP */
+			/*
+			 * N.B. kn->kn_fop may change as the result
+			 * of filter_attach()!
+			 */
+			error = filter_attach(kn);
 			if (error != 0) {
 #ifdef DEBUG
 				struct proc *p = curlwp->l_proc;
@@ -1277,7 +1348,7 @@ kqueue_register(struct kqueue *kq, struc
 	if (!(kn->kn_fop->f_flags & FILTEROP_ISFD) &&
 	    kn->kn_fop->f_touch != NULL) {
 		mutex_spin_enter(&kq->kq_lock);
-		(*kn->kn_fop->f_touch)(kn, kev, EVENT_REGISTER);
+		filter_touch(kn, kev, EVENT_REGISTER);
 		mutex_spin_exit(&kq->kq_lock);
 	} else {
 		kn->kn_sfflags = kev->fflags;
@@ -1291,11 +1362,7 @@ kqueue_register(struct kqueue *kq, struc
 	 * broken and does not return an error.
 	 */
 done_ev_add:
-	KASSERT(kn->kn_fop != NULL);
-	KASSERT(kn->kn_fop->f_event != NULL);
-	KERNEL_LOCK(1, NULL);			/* XXXSMP */
-	rv = (*kn->kn_fop->f_event)(kn, 0);
-	KERNEL_UNLOCK_ONE(NULL);		/* XXXSMP */
+	rv = filter_event(kn, 0);
 	if (rv)
 		knote_activate(kn);
 
@@ -1507,12 +1574,8 @@ relock:
 		}
 		if ((kn->kn_flags & EV_ONESHOT) == 0) {
 			mutex_spin_exit(&kq->kq_lock);
-			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 */
+			rv = filter_event(kn, 0);
 			mutex_spin_enter(&kq->kq_lock);
 			/* Re-poll if note was re-enqueued. */
 			if ((kn->kn_status & KN_QUEUED) != 0) {
@@ -1538,7 +1601,7 @@ relock:
 				kn->kn_fop->f_touch != NULL);
 		/* XXXAD should be got from f_event if !oneshot. */
 		if (touch) {
-			(*kn->kn_fop->f_touch)(kn, kevp, EVENT_PROCESS);
+			filter_touch(kn, kevp, EVENT_PROCESS);
 		} else {
 			*kevp = kn->kn_kevent;
 		}
@@ -1872,10 +1935,7 @@ knote_detach(struct knote *kn, filedesc_
 	KASSERT(kn->kn_fop != NULL);
 	/* Remove from monitored object. */
 	if (dofop) {
-		KASSERT(kn->kn_fop->f_detach != NULL);
-		KERNEL_LOCK(1, NULL);		/* XXXSMP */
-		(*kn->kn_fop->f_detach)(kn);
-		KERNEL_UNLOCK_ONE(NULL);	/* XXXSMP */
+		filter_detach(kn);
 	}
 
 	/* Remove from descriptor table. */

Index: src/sys/sys/event.h
diff -u src/sys/sys/event.h:1.41 src/sys/sys/event.h:1.42
--- src/sys/sys/event.h:1.41	Sun Sep 26 01:16:10 2021
+++ src/sys/sys/event.h	Sun Sep 26 03:12:50 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: event.h,v 1.41 2021/09/26 01:16:10 thorpej Exp $	*/
+/*	$NetBSD: event.h,v 1.42 2021/09/26 03:12:50 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jle...@freebsd.org>
@@ -221,6 +221,7 @@ struct filterops {
 
 /* filterops flags */
 #define	FILTEROP_ISFD	__BIT(0)	/* ident == file descriptor */
+#define	FILTEROP_MPSAFE	__BIT(1)	/* does not require KERNEL_LOCK */
 
 /*
  * Field locking:

Reply via email to