Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Fix the locking around EVFILT_FS. Previously, the code ...



details:   https://anonhg.NetBSD.org/src/rev/d3cb64b5b5d7
branches:  trunk
changeset: 1023822:d3cb64b5b5d7
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sun Sep 26 21:29:38 2021 +0000

description:
Fix the locking around EVFILT_FS.  Previously, the code would walk the
fs_klist and take the kqueue_misc_lock inside the event callback.
However, that list can be modified by the attach and detach callbacks,
which could result in the walker stepping right off a cliff.

Instead, we give the fs_klist it's own lock, and hold it while we
call knote(), using the NOTE_SUBMIT protocol.  Also, fs_filtops
into vfs_syscalls.c so all of the locking logic is contained in one
file (there is precedence with sig_filtops).  fs_filtops is now marked
MPSAFE.

diffstat:

 sys/kern/kern_event.c   |  56 ++---------------------------------
 sys/kern/vfs_init.c     |   7 +++-
 sys/kern/vfs_syscalls.c |  75 +++++++++++++++++++++++++++++++++++++++++++++---
 sys/sys/event.h         |   6 +--
 4 files changed, 80 insertions(+), 64 deletions(-)

diffs (263 lines):

diff -r 61b83b6461eb -r d3cb64b5b5d7 sys/kern/kern_event.c
--- a/sys/kern/kern_event.c     Sun Sep 26 21:23:31 2021 +0000
+++ b/sys/kern/kern_event.c     Sun Sep 26 21:29:38 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_event.c,v 1.123 2021/09/26 18:13:58 thorpej Exp $ */
+/*     $NetBSD: kern_event.c,v 1.124 2021/09/26 21:29:38 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.123 2021/09/26 18:13:58 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.124 2021/09/26 21:29:38 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -108,9 +108,6 @@
 static int     filt_timerattach(struct knote *);
 static void    filt_timerdetach(struct knote *);
 static int     filt_timer(struct knote *, long hint);
-static int     filt_fsattach(struct knote *kn);
-static void    filt_fsdetach(struct knote *kn);
-static int     filt_fs(struct knote *kn, long hint);
 static int     filt_userattach(struct knote *);
 static void    filt_userdetach(struct knote *);
 static int     filt_user(struct knote *, long hint);
@@ -163,13 +160,6 @@
        .f_event = filt_timer,
 };
 
-static const struct filterops fs_filtops = {
-       .f_flags = 0,
-       .f_attach = filt_fsattach,
-       .f_detach = filt_fsdetach,
-       .f_event = filt_fs,
-};
-
 static const struct filterops user_filtops = {
        .f_flags = FILTEROP_MPSAFE,
        .f_attach = filt_userattach,
@@ -184,7 +174,8 @@
 #define        KN_HASHSIZE             64              /* XXX should be tunable */
 #define        KN_HASH(val, mask)      (((val) ^ (val >> 8)) & (mask))
 
-extern const struct filterops sig_filtops;
+extern const struct filterops fs_filtops;      /* vfs_syscalls.c */
+extern const struct filterops sig_filtops;     /* kern_sig.c */
 
 #define KQ_FLUX_WAKEUP(kq)     cv_broadcast(&kq->kq_cv)
 
@@ -823,45 +814,6 @@
        return rv;
 }
 
-/*
- * Filter event method for EVFILT_FS.
- */
-struct klist fs_klist = SLIST_HEAD_INITIALIZER(&fs_klist);
-
-static int
-filt_fsattach(struct knote *kn)
-{
-
-       mutex_enter(&kqueue_misc_lock);
-       kn->kn_flags |= EV_CLEAR;
-       SLIST_INSERT_HEAD(&fs_klist, kn, kn_selnext);
-       mutex_exit(&kqueue_misc_lock);
-
-       return 0;
-}
-
-static void
-filt_fsdetach(struct knote *kn)
-{
-
-       mutex_enter(&kqueue_misc_lock);
-       SLIST_REMOVE(&fs_klist, kn, knote, kn_selnext);
-       mutex_exit(&kqueue_misc_lock);
-}
-
-static int
-filt_fs(struct knote *kn, long hint)
-{
-       int rv;
-
-       mutex_enter(&kqueue_misc_lock);
-       kn->kn_fflags |= hint;
-       rv = (kn->kn_fflags != 0);
-       mutex_exit(&kqueue_misc_lock);
-
-       return rv;
-}
-
 static int
 filt_userattach(struct knote *kn)
 {
diff -r 61b83b6461eb -r d3cb64b5b5d7 sys/kern/vfs_init.c
--- a/sys/kern/vfs_init.c       Sun Sep 26 21:23:31 2021 +0000
+++ b/sys/kern/vfs_init.c       Sun Sep 26 21:29:38 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_init.c,v 1.52 2021/02/04 21:07:06 jdolecek Exp $   */
+/*     $NetBSD: vfs_init.c,v 1.53 2021/09/26 21:29:38 thorpej Exp $    */
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.52 2021/02/04 21:07:06 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.53 2021/09/26 21:29:38 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/mount.h>
@@ -455,6 +455,9 @@
         * included in the kernel.
         */
        module_init_class(MODULE_CLASS_VFS);
+
+       extern kmutex_t fs_klist_lock;
+       mutex_init(&fs_klist_lock, MUTEX_DEFAULT, IPL_NONE);
 }
 
 /*
diff -r 61b83b6461eb -r d3cb64b5b5d7 sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c   Sun Sep 26 21:23:31 2021 +0000
+++ b/sys/kern/vfs_syscalls.c   Sun Sep 26 21:29:38 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_syscalls.c,v 1.552 2021/09/11 10:08:55 riastradh Exp $     */
+/*     $NetBSD: vfs_syscalls.c,v 1.553 2021/09/26 21:29:38 thorpej Exp $       */
 
 /*-
  * Copyright (c) 2008, 2009, 2019, 2020 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.552 2021/09/11 10:08:55 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.553 2021/09/26 21:29:38 thorpej Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_fileassoc.h"
@@ -165,6 +165,63 @@
 
 const u_int nmountcompatnames = __arraycount(mountcompatnames);
 
+/*
+ * Filter event method for EVFILT_FS.
+ */
+static struct klist fs_klist = SLIST_HEAD_INITIALIZER(&fs_klist);
+kmutex_t fs_klist_lock;
+
+CTASSERT((NOTE_SUBMIT & VQ_MOUNT) == 0);
+CTASSERT((NOTE_SUBMIT & VQ_UNMOUNT) == 0);
+
+static int
+filt_fsattach(struct knote *kn)
+{
+       mutex_enter(&fs_klist_lock);
+       kn->kn_flags |= EV_CLEAR;
+       SLIST_INSERT_HEAD(&fs_klist, kn, kn_selnext);
+       mutex_exit(&fs_klist_lock);
+
+       return 0;
+}
+
+static void
+filt_fsdetach(struct knote *kn)
+{
+       mutex_enter(&fs_klist_lock);
+       SLIST_REMOVE(&fs_klist, kn, knote, kn_selnext);
+       mutex_exit(&fs_klist_lock);
+}
+
+static int
+filt_fs(struct knote *kn, long hint)
+{
+       int rv;
+
+       if (hint & NOTE_SUBMIT) {
+               KASSERT(mutex_owned(&fs_klist_lock));
+               kn->kn_fflags |= hint & ~NOTE_SUBMIT;
+       } else {
+               mutex_enter(&fs_klist_lock);
+       }
+
+       rv = (kn->kn_fflags != 0);
+
+       if ((hint & NOTE_SUBMIT) == 0) {
+               mutex_exit(&fs_klist_lock);
+       }
+
+       return rv;
+}
+
+/* referenced in kern_event.c */
+const struct filterops fs_filtops = {
+       .f_flags = FILTEROP_MPSAFE,
+       .f_attach = filt_fsattach,
+       .f_detach = filt_fsdetach,
+       .f_event = filt_fs,
+};
+
 static int 
 fd_nameiat(struct lwp *l, int fdat, struct nameidata *ndp)
 {
@@ -553,8 +610,11 @@
                    &data_len);
                vfsopsrele = false;
        }
-       if (!error)
-               KNOTE(&fs_klist, VQ_MOUNT);
+       if (!error) {
+               mutex_enter(&fs_klist_lock);
+               KNOTE(&fs_klist, NOTE_SUBMIT | VQ_MOUNT);
+               mutex_exit(&fs_klist_lock);
+       }
 
     done:
        if (vfsopsrele)
@@ -633,8 +693,11 @@
        vrele(vp);
        error = dounmount(mp, SCARG(uap, flags), l);
        vfs_rele(mp);
-       if (!error)
-               KNOTE(&fs_klist, VQ_UNMOUNT);
+       if (!error) {
+               mutex_enter(&fs_klist_lock);
+               KNOTE(&fs_klist, NOTE_SUBMIT | VQ_UNMOUNT);
+               mutex_exit(&fs_klist_lock);
+       }
        return error;
 }
 
diff -r 61b83b6461eb -r d3cb64b5b5d7 sys/sys/event.h
--- a/sys/sys/event.h   Sun Sep 26 21:23:31 2021 +0000
+++ b/sys/sys/event.h   Sun Sep 26 21:29:38 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: event.h,v 1.42 2021/09/26 03:12:50 thorpej Exp $       */
+/*     $NetBSD: event.h,v 1.43 2021/09/26 21:29:39 thorpej Exp $       */
 
 /*-
  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon%FreeBSD.org@localhost>
@@ -271,7 +271,7 @@
 #define        kn_data         kn_kevent.data
 };
 
-#include <sys/systm.h> /* for copyin_t */
+#include <sys/systm.h> /* for copyin_t */
 
 struct lwp;
 struct timespec;
@@ -307,8 +307,6 @@
 int    filt_seltrue(struct knote *, long);
 extern const struct filterops seltrue_filtops;
 
-extern struct klist fs_klist;  /* EVFILT_FS */
-
 #else  /* !_KERNEL */
 
 #include <sys/cdefs.h>



Home | Main Index | Thread Index | Old Index