aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nullfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nullfs')
-rw-r--r--sys/fs/nullfs/null_subr.c4
-rw-r--r--sys/fs/nullfs/null_vfsops.c5
-rw-r--r--sys/fs/nullfs/null_vnops.c69
3 files changed, 56 insertions, 22 deletions
diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c
index 0356877eaf05..7dcc83880bb9 100644
--- a/sys/fs/nullfs/null_subr.c
+++ b/sys/fs/nullfs/null_subr.c
@@ -245,6 +245,10 @@ null_nodeget(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
vp->v_object = lowervp->v_object;
vn_irflag_set(vp, VIRF_PGREAD);
}
+ if ((vn_irflag_read(lowervp) & VIRF_INOTIFY) != 0)
+ vn_irflag_set(vp, VIRF_INOTIFY);
+ if ((vn_irflag_read(lowervp) & VIRF_INOTIFY_PARENT) != 0)
+ vn_irflag_set(vp, VIRF_INOTIFY_PARENT);
if (lowervp == MOUNTTONULLMOUNT(mp)->nullm_lowerrootvp)
vp->v_vflag |= VV_ROOT;
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
index 7ab1fb6c1a25..4cddf24a5745 100644
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -365,12 +365,7 @@ nullfs_statfs(struct mount *mp, struct statfs *sbp)
return (error);
}
- /* now copy across the "interesting" information and fake the rest */
sbp->f_type = mstat->f_type;
- sbp->f_flags &= MNT_RDONLY | MNT_NOEXEC | MNT_NOSUID | MNT_UNION |
- MNT_NOSYMFOLLOW | MNT_AUTOMOUNTED | MNT_EXPORTED | MNT_IGNORE;
- mstat->f_flags &= ~(MNT_ROOTFS | MNT_AUTOMOUNTED | MNT_EXPORTED);
- sbp->f_flags |= mstat->f_flags;
sbp->f_bsize = mstat->f_bsize;
sbp->f_iosize = mstat->f_iosize;
sbp->f_blocks = mstat->f_blocks;
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 4747b1dd5b82..74c1a8f3acb6 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -190,6 +190,26 @@ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW,
&null_bug_bypass, 0, "");
/*
+ * Synchronize inotify flags with the lower vnode:
+ * - If the upper vnode has the flag set and the lower does not, then the lower
+ * vnode is unwatched and the upper vnode does not need to go through
+ * VOP_INOTIFY.
+ * - If the lower vnode is watched, then the upper vnode should go through
+ * VOP_INOTIFY, so copy the flag up.
+ */
+static void
+null_copy_inotify(struct vnode *vp, struct vnode *lvp, short flag)
+{
+ 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);
+ }
+}
+
+/*
* This is the 10-Apr-92 bypass routine.
* This version has been optimized for speed, throwing away some
* safety checks. It should still always work, but it's not as
@@ -305,7 +325,10 @@ null_bypass(struct vop_generic_args *ap)
lvp = *(vps_p[i]);
/*
- * Get rid of the transient hold on lvp.
+ * Get rid of the transient hold on lvp. Copy inotify
+ * flags up in case something is watching the lower
+ * layer.
+ *
* If lowervp was unlocked during VOP
* operation, nullfs upper vnode could have
* been reclaimed, which changes its v_vnlock
@@ -314,6 +337,10 @@ null_bypass(struct vop_generic_args *ap)
* upper (reclaimed) vnode.
*/
if (lvp != NULLVP) {
+ null_copy_inotify(old_vps[i], lvp,
+ VIRF_INOTIFY);
+ null_copy_inotify(old_vps[i], lvp,
+ VIRF_INOTIFY_PARENT);
if (VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
old_vps[i]->v_vnlock != lvp->v_vnlock) {
VOP_UNLOCK(lvp);
@@ -385,7 +412,7 @@ null_lookup(struct vop_lookup_args *ap)
{
struct componentname *cnp = ap->a_cnp;
struct vnode *dvp = ap->a_dvp;
- int flags = cnp->cn_flags;
+ uint64_t flags = cnp->cn_flags;
struct vnode *vp, *ldvp, *lvp;
struct mount *mp;
int error;
@@ -403,17 +430,25 @@ null_lookup(struct vop_lookup_args *ap)
/*
* Renames in the lower mounts might create an inconsistent
- * configuration where lower vnode is moved out of the
- * directory tree remounted by our null mount. Do not try to
- * handle it fancy, just avoid VOP_LOOKUP() with DOTDOT name
- * which cannot be handled by VOP, at least passing over lower
- * root.
+ * configuration where lower vnode is moved out of the directory tree
+ * remounted by our null mount.
+ *
+ * Do not try to handle it fancy, just avoid VOP_LOOKUP() with DOTDOT
+ * name which cannot be handled by the VOP.
*/
- if ((ldvp->v_vflag & VV_ROOT) != 0 && (flags & ISDOTDOT) != 0) {
- KASSERT((dvp->v_vflag & VV_ROOT) == 0,
- ("ldvp %p fl %#x dvp %p fl %#x flags %#x",
- ldvp, ldvp->v_vflag, dvp, dvp->v_vflag, flags));
- return (ENOENT);
+ if ((flags & ISDOTDOT) != 0) {
+ struct nameidata *ndp;
+
+ if ((ldvp->v_vflag & VV_ROOT) != 0) {
+ KASSERT((dvp->v_vflag & VV_ROOT) == 0,
+ ("ldvp %p fl %#x dvp %p fl %#x flags %#jx",
+ ldvp, ldvp->v_vflag, dvp, dvp->v_vflag,
+ (uintmax_t)flags));
+ return (ENOENT);
+ }
+ ndp = vfs_lookup_nameidata(cnp);
+ if (ndp != NULL && vfs_lookup_isroot(ndp, ldvp))
+ return (ENOENT);
}
/*
@@ -528,7 +563,7 @@ null_setattr(struct vop_setattr_args *ap)
}
}
- return (null_bypass((struct vop_generic_args *)ap));
+ return (null_bypass(&ap->a_gen));
}
/*
@@ -539,7 +574,7 @@ null_stat(struct vop_stat_args *ap)
{
int error;
- if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
+ if ((error = null_bypass(&ap->a_gen)) != 0)
return (error);
ap->a_sb->st_dev = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
@@ -551,7 +586,7 @@ null_getattr(struct vop_getattr_args *ap)
{
int error;
- if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
+ if ((error = null_bypass(&ap->a_gen)) != 0)
return (error);
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
@@ -584,7 +619,7 @@ null_access(struct vop_access_args *ap)
break;
}
}
- return (null_bypass((struct vop_generic_args *)ap));
+ return (null_bypass(&ap->a_gen));
}
static int
@@ -610,7 +645,7 @@ null_accessx(struct vop_accessx_args *ap)
break;
}
}
- return (null_bypass((struct vop_generic_args *)ap));
+ return (null_bypass(&ap->a_gen));
}
/*