aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Leidinger <netchild@FreeBSD.org>2026-07-19 07:38:52 +0000
committerAlexander Leidinger <netchild@FreeBSD.org>2026-07-19 15:13:40 +0000
commitd6915bffb7b68d9b55fa3db4e5709463549c379e (patch)
tree1ea1c32fd6f06e99c2476bc4d6cb6775c83de1a6
parent9b21a52495758294e3a50542a59bc47a0c184173 (diff)
-rw-r--r--sys/fs/nullfs/null_vnops.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 50d359c9b909..41823d0c6202 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -200,17 +200,26 @@ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW,
* VOP_INOTIFY.
* - If the lower vnode is watched, then the upper vnode should go through
* VOP_INOTIFY, so copy the flag up.
+ *
+ * The lockless check is only a fast path: the decision to change a flag
+ * is re-made under the upper vnode's interlock, since another thread may
+ * set or clear the flag concurrently.
*/
static void
null_copy_inotify(struct vnode *vp, struct vnode *lvp, short flag)
{
+ if (__predict_true((vn_irflag_read(vp) & flag) ==
+ (vn_irflag_read(lvp) & flag)))
+ return;
+ VI_LOCK(vp);
if ((vn_irflag_read(vp) & flag) != 0) {
- if (__predict_false((vn_irflag_read(lvp) & flag) == 0))
- vn_irflag_unset(vp, flag);
- } else if ((vn_irflag_read(lvp) & flag) != 0) {
- if (__predict_false((vn_irflag_read(vp) & flag) == 0))
- vn_irflag_set(vp, flag);
+ if ((vn_irflag_read(lvp) & flag) == 0)
+ vn_irflag_unset_locked(vp, flag);
+ } else {
+ if ((vn_irflag_read(lvp) & flag) != 0)
+ vn_irflag_set_locked(vp, flag);
}
+ VI_UNLOCK(vp);
}
/*