git: af0ec3fa29ca - main - inotify: Fix a couple of locking bugs

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Fri, 18 Jul 2025 14:30:44 UTC
The branch main has been updated by markj:

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

commit af0ec3fa29cad823d0196538381f1e832f5974a7
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-07-18 14:25:28 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-07-18 14:25:28 +0000

    inotify: Fix a couple of locking bugs
    
    When hooking vop_rename_post(), the preexisting dst vnode will be
    unlocked.  But, we need to invoke VOP_GETATTR on it in vn_inotify() to
    check its link count.
    
    In inotify_unlink_watch_locked(), the vnode interlock is not held, so
    don't use vn_irflag_unset_locked().
    
    Reviewed by:    kib
    Fixes:          f1f230439fa4 ("vfs: Initial revision of inotify")
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D51401
---
 sys/kern/vfs_inotify.c |  5 +++--
 sys/sys/inotify.h      | 14 +++++++++++---
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c
index 2b42228465a4..d3cd0d1f9832 100644
--- a/sys/kern/vfs_inotify.c
+++ b/sys/kern/vfs_inotify.c
@@ -371,7 +371,7 @@ inotify_unlink_watch_locked(struct inotify_softc *sc, struct inotify_watch *watc
 
 	TAILQ_REMOVE(&vp->v_pollinfo->vpi_inotify, watch, vlink);
 	if (TAILQ_EMPTY(&vp->v_pollinfo->vpi_inotify))
-		vn_irflag_unset_locked(vp, VIRF_INOTIFY);
+		vn_irflag_unset(vp, VIRF_INOTIFY);
 }
 
 /*
@@ -675,7 +675,8 @@ vn_inotify(struct vnode *vp, struct vnode *dvp, struct componentname *cnp,
 					struct vattr va;
 					int error;
 
-					error = VOP_GETATTR(vp, &va, cnp->cn_cred);
+					error = VOP_GETATTR(vp, &va,
+					    cnp->cn_cred);
 					if (error == 0 && va.va_nlink != 0)
 						selfevent = 0;
 				}
diff --git a/sys/sys/inotify.h b/sys/sys/inotify.h
index 65dc5dba43f3..d1f23d5898bb 100644
--- a/sys/sys/inotify.h
+++ b/sys/sys/inotify.h
@@ -107,11 +107,18 @@ void	vn_inotify_revoke(struct vnode *);
 } while (0)
 
 /* Log an inotify event using a specific name for the vnode. */
-#define	INOTIFY_NAME(vp, dvp, cnp, ev) do {				\
+#define	INOTIFY_NAME_LOCK(vp, dvp, cnp, ev, lock) do {			\
 	if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0 ||	\
-	    (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) 		\
+	    (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) {		\
+		if (lock)						\
+			vn_lock((vp), LK_SHARED | LK_RETRY);		\
 		VOP_INOTIFY((vp), (dvp), (cnp), (ev), 0);		\
+		if (lock)						\
+			VOP_UNLOCK(vp);					\
+	}								\
 } while (0)
+#define	INOTIFY_NAME(vp, dvp, cnp, ev)					\
+	INOTIFY_NAME_LOCK((vp), (dvp), (cnp), (ev), false)
 
 extern __uint32_t inotify_rename_cookie;
 
@@ -126,7 +133,8 @@ extern __uint32_t inotify_rename_cookie;
 		VOP_INOTIFY((vp), (tdvp), (tcnp), IN_MOVED_TO, cookie);	\
 	}								\
 	if ((tvp) != NULL)						\
-		INOTIFY_NAME((tvp), (tdvp), (tcnp), _IN_MOVE_DELETE);	\
+		INOTIFY_NAME_LOCK((tvp), (tdvp), (tcnp),		\
+		    _IN_MOVE_DELETE, true);				\
 } while (0)
 
 #define	INOTIFY_REVOKE(vp) do {						\