git: 1d5e4020e36e - main - vnode: add VIRF_KNOTE flag

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 10 May 2026 18:11:14 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=1d5e4020e36e1cc9e906200c9c3c784ef43d977e

commit 1d5e4020e36e1cc9e906200c9c3c784ef43d977e
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-04-24 01:31:27 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-05-10 17:43:46 +0000

    vnode: add VIRF_KNOTE flag
    
    to indicate non-empty vnode knote list.  Use it instead of
    VN_KNLIST_EMPTY() and guard note activations with it.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D56611
---
 sys/kern/vfs_subr.c | 14 ++++++++++----
 sys/sys/mount.h     | 12 ++++++++++--
 sys/sys/vnode.h     | 29 ++++++++++++-----------------
 3 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 48bfea2f5bf9..f46c666b115c 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -6090,7 +6090,7 @@ vop_create_post(void *ap, int rc)
 	a = ap;
 	dvp = a->a_dvp;
 	vn_seqc_write_end(dvp);
-	if (!rc) {
+	if (rc == 0) {
 		VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
 		INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
 	}
@@ -6244,7 +6244,7 @@ vop_mknod_post(void *ap, int rc)
 	a = ap;
 	dvp = a->a_dvp;
 	vn_seqc_write_end(dvp);
-	if (!rc) {
+	if (rc == 0) {
 		VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
 		INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
 	}
@@ -6512,7 +6512,7 @@ vop_read_pgcache_post(void *ap, int rc)
 {
 	struct vop_read_pgcache_args *a = ap;
 
-	if (!rc)
+	if (rc == 0)
 		VFS_KNOTE_UNLOCKED(a->a_vp, NOTE_READ);
 }
 
@@ -6659,6 +6659,8 @@ vfs_knlunlock(void *arg)
 {
 	struct vnode *vp = arg;
 
+	if (KNLIST_EMPTY(&vp->v_pollinfo->vpi_selinfo.si_note))
+		vn_irflag_unset(vp, VIRF_KNOTE);
 	VOP_UNLOCK(vp);
 }
 
@@ -6706,7 +6708,11 @@ vfs_kqfilter(struct vop_kqfilter_args *ap)
 		return (ENOMEM);
 	knl = &vp->v_pollinfo->vpi_selinfo.si_note;
 	vhold(vp);
-	knlist_add(knl, kn, 0);
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+	knlist_add(knl, kn, 1);
+	if ((vn_irflag_read(vp) & VIRF_KNOTE) == 0)
+		vn_irflag_set(vp, VIRF_KNOTE);
+	VOP_UNLOCK(vp);
 
 	return (0);
 }
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index f99d0856f16e..480a6c16badf 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -952,14 +952,22 @@ vfs_statfs_t	__vfs_statfs;
 	}								\
 } while (0)
 
+#include <sys/vnode.h>
+
 #define VFS_KNOTE_LOCKED(vp, hint) do					\
 {									\
-	VN_KNOTE((vp), (hint), KNF_LISTLOCKED);				\
+	if ((vn_irflag_read(vp) & VIRF_KNOTE) != 0) {			\
+		KNOTE_LOCKED(&vp->v_pollinfo->vpi_selinfo.si_note,	\
+		    hint);						\
+	}								\
 } while (0)
 
 #define VFS_KNOTE_UNLOCKED(vp, hint) do					\
 {									\
-	VN_KNOTE((vp), (hint), 0);					\
+	if ((vn_irflag_read(vp) & VIRF_KNOTE) != 0) {			\
+		KNOTE_UNLOCKED(&vp->v_pollinfo->vpi_selinfo.si_note,	\
+		    hint);						\
+	}								\
 } while (0)
 
 #include <sys/module.h>
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 3fd2c770cda1..d1d20778a8ec 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -224,18 +224,14 @@ _Static_assert(sizeof(struct vnode) <= 448, "vnode size crosses 448 bytes");
 /* XXX: These are temporary to avoid a source sweep at this time */
 #define v_object	v_bufobj.bo_object
 
-/* We don't need to lock the knlist */
-#define	VN_KNLIST_EMPTY(vp) ((vp)->v_pollinfo == NULL ||	\
-	    KNLIST_EMPTY(&(vp)->v_pollinfo->vpi_selinfo.si_note))
-
-#define VN_KNOTE(vp, b, a)					\
-	do {							\
-		if (!VN_KNLIST_EMPTY(vp))			\
-			KNOTE(&vp->v_pollinfo->vpi_selinfo.si_note, (b), \
-			    (a) | KNF_NOKQLOCK);		\
-	} while (0)
-#define	VN_KNOTE_LOCKED(vp, b)		VN_KNOTE(vp, b, KNF_LISTLOCKED)
-#define	VN_KNOTE_UNLOCKED(vp, b)	VN_KNOTE(vp, b, 0)
+#define VN_KNOTE(vp, b, a) do {                    			\
+	if ((vn_irflag_read(vp) & VIRF_KNOTE) != 0) {			\
+		KNOTE(&vp->v_pollinfo->vpi_selinfo.si_note, (b),	\
+		    (a) | KNF_NOKQLOCK);				\
+	}								\
+} while (0)
+#define   VN_KNOTE_LOCKED(vp, b)     VN_KNOTE(vp, b, KNF_LISTLOCKED)
+#define   VN_KNOTE_UNLOCKED(vp, b)   VN_KNOTE(vp, b, 0)
 
 /*
  * Vnode flags.
@@ -260,6 +256,7 @@ _Static_assert(sizeof(struct vnode) <= 448, "vnode size crosses 448 bytes");
 #define	VIRF_INOTIFY	0x0080	/* This vnode is being watched */
 #define	VIRF_INOTIFY_PARENT 0x0100 /* A parent of this vnode may be being
 				      watched */
+#define	VIRF_KNOTE	0x0200	/* Has knlist */
 
 #define	VI_UNUSED0	0x0001	/* unused */
 #define	VI_MOUNT	0x0002	/* Mount in progress */
@@ -1052,7 +1049,7 @@ void	vop_rename_fail(struct vop_rename_args *ap);
 	off_t osize, ooffset, noffset;					\
 									\
 	osize = ooffset = noffset = 0;					\
-	if (!VN_KNLIST_EMPTY((ap)->a_vp)) {				\
+	if ((vn_irflag_read((ap)->a_vp) & VIRF_KNOTE) != 0) {		\
 		error = VOP_GETATTR((ap)->a_vp, &va, (ap)->a_cred);	\
 		if (error)						\
 			return (error);					\
@@ -1063,10 +1060,8 @@ void	vop_rename_fail(struct vop_rename_args *ap);
 #define vop_write_post(ap, ret)						\
 	noffset = (ap)->a_uio->uio_offset;				\
 	if (noffset > ooffset) {					\
-		if (!VN_KNLIST_EMPTY((ap)->a_vp)) {			\
-			VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE |	\
-			    (noffset > osize ? NOTE_EXTEND : 0));	\
-		}							\
+		VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE |		\
+		    (noffset > osize ? NOTE_EXTEND : 0));		\
 		INOTIFY((ap)->a_vp, IN_MODIFY);				\
 	}