svn commit: r270319 - stable/10/sys/fs/nullfs
Konstantin Belousov
kib at FreeBSD.org
Fri Aug 22 07:09:55 UTC 2014
Author: kib
Date: Fri Aug 22 07:09:54 2014
New Revision: 270319
URL: http://svnweb.freebsd.org/changeset/base/270319
Log:
MFC r269708:
Unlock ldvp and lock dvp to compensate for possible ldvp unlock in lower
VOP_LOOKUP() and dvp reclamation. Use cached value of dvp->v_mount.
Modified:
stable/10/sys/fs/nullfs/null_vnops.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/fs/nullfs/null_vnops.c
==============================================================================
--- stable/10/sys/fs/nullfs/null_vnops.c Fri Aug 22 05:03:30 2014 (r270318)
+++ stable/10/sys/fs/nullfs/null_vnops.c Fri Aug 22 07:09:54 2014 (r270319)
@@ -361,9 +361,11 @@ null_lookup(struct vop_lookup_args *ap)
struct vnode *dvp = ap->a_dvp;
int flags = cnp->cn_flags;
struct vnode *vp, *ldvp, *lvp;
+ struct mount *mp;
int error;
- if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ mp = dvp->v_mount;
+ if ((flags & ISLASTCN) != 0 && (mp->mnt_flag & MNT_RDONLY) != 0 &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
return (EROFS);
/*
@@ -376,9 +378,43 @@ null_lookup(struct vop_lookup_args *ap)
((dvp->v_vflag & VV_ROOT) != 0 && (flags & ISDOTDOT) == 0),
("ldvp %p fl %#x dvp %p fl %#x flags %#x", ldvp, ldvp->v_vflag,
dvp, dvp->v_vflag, flags));
+
+ /*
+ * Hold ldvp. The reference on it, owned by dvp, is lost in
+ * case of dvp reclamation, and we need ldvp to move our lock
+ * from ldvp to dvp.
+ */
+ vhold(ldvp);
+
error = VOP_LOOKUP(ldvp, &lvp, cnp);
- if (error == EJUSTRETURN && (flags & ISLASTCN) &&
- (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+
+ /*
+ * VOP_LOOKUP() on lower vnode may unlock ldvp, which allows
+ * dvp to be reclaimed due to shared v_vnlock. Check for the
+ * doomed state and return error.
+ */
+ if ((error == 0 || error == EJUSTRETURN) &&
+ (dvp->v_iflag & VI_DOOMED) != 0) {
+ error = ENOENT;
+ if (lvp != NULL)
+ vput(lvp);
+
+ /*
+ * If vgone() did reclaimed dvp before curthread
+ * relocked ldvp, the locks of dvp and ldpv are no
+ * longer shared. In this case, relock of ldvp in
+ * lower fs VOP_LOOKUP() does not restore the locking
+ * state of dvp. Compensate for this by unlocking
+ * ldvp and locking dvp, which is also correct if the
+ * locks are still shared.
+ */
+ VOP_UNLOCK(ldvp, 0);
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
+ }
+ vdrop(ldvp);
+
+ if (error == EJUSTRETURN && (flags & ISLASTCN) != 0 &&
+ (mp->mnt_flag & MNT_RDONLY) != 0 &&
(cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
error = EROFS;
@@ -388,7 +424,7 @@ null_lookup(struct vop_lookup_args *ap)
VREF(dvp);
vrele(lvp);
} else {
- error = null_nodeget(dvp->v_mount, lvp, &vp);
+ error = null_nodeget(mp, lvp, &vp);
if (error == 0)
*ap->a_vpp = vp;
}
More information about the svn-src-stable
mailing list