Module Name: src Committed By: thorpej Date: Sun Sep 26 21:29:39 UTC 2021
Modified Files: src/sys/kern: kern_event.c vfs_init.c vfs_syscalls.c src/sys/sys: event.h Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.123 -r1.124 src/sys/kern/kern_event.c cvs rdiff -u -r1.52 -r1.53 src/sys/kern/vfs_init.c cvs rdiff -u -r1.552 -r1.553 src/sys/kern/vfs_syscalls.c cvs rdiff -u -r1.42 -r1.43 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.123 src/sys/kern/kern_event.c:1.124 --- src/sys/kern/kern_event.c:1.123 Sun Sep 26 18:13:58 2021 +++ src/sys/kern/kern_event.c Sun Sep 26 21:29:38 2021 @@ -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 void filt_timerexpire(void *x); 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 @@ static const struct filterops timer_filt .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 @@ static int kq_calloutmax = (4 * 1024); #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 @@ filt_timer(struct knote *kn, long hint) 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) { Index: src/sys/kern/vfs_init.c diff -u src/sys/kern/vfs_init.c:1.52 src/sys/kern/vfs_init.c:1.53 --- src/sys/kern/vfs_init.c:1.52 Thu Feb 4 21:07:06 2021 +++ src/sys/kern/vfs_init.c Sun Sep 26 21:29:38 2021 @@ -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 @@ vfsinit(void) * 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); } /* Index: src/sys/kern/vfs_syscalls.c diff -u src/sys/kern/vfs_syscalls.c:1.552 src/sys/kern/vfs_syscalls.c:1.553 --- src/sys/kern/vfs_syscalls.c:1.552 Sat Sep 11 10:08:55 2021 +++ src/sys/kern/vfs_syscalls.c Sun Sep 26 21:29:38 2021 @@ -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 char * const mountcompatnames[] = 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 @@ do_sys_mount(struct lwp *l, const char * &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 @@ sys_unmount(struct lwp *l, const struct 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; } Index: src/sys/sys/event.h diff -u src/sys/sys/event.h:1.42 src/sys/sys/event.h:1.43 --- src/sys/sys/event.h:1.42 Sun Sep 26 03:12:50 2021 +++ src/sys/sys/event.h Sun Sep 26 21:29:39 2021 @@ -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 <jle...@freebsd.org> @@ -271,7 +271,7 @@ struct knote { #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 kfilter_unregister(const char *); 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>