summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2016-07-13 10:16:45 +0000
committeravg <avg@FreeBSD.org>2016-07-13 10:16:45 +0000
commit47ee1070eda527689702b3043dda3ca1d7730c9d (patch)
treeedb21c7532ad172640db91616c5007690f32105b
parentdac107065fcfb1a9a6059d2fc930217f26513ac6 (diff)
downloadFreeBSD-src-47ee1070eda527689702b3043dda3ca1d7730c9d.zip
FreeBSD-src-47ee1070eda527689702b3043dda3ca1d7730c9d.tar.gz
MFC r299947: fix locking in zfsctl_root_lookup
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
index f6f386b..14d39b9 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
@@ -551,9 +551,20 @@ zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
ZFS_ENTER(zfsvfs);
if (strcmp(nm, "..") == 0) {
+#ifdef illumos
err = VFS_ROOT(dvp->v_vfsp, LK_EXCLUSIVE, vpp);
+#else
+ /*
+ * NB: can not use VFS_ROOT here as it would acquire
+ * the vnode lock of the parent (root) vnode while
+ * holding the child's (.zfs) lock.
+ */
+ znode_t *rootzp;
+
+ err = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp);
if (err == 0)
- VOP_UNLOCK(*vpp, 0);
+ *vpp = ZTOV(rootzp);
+#endif
} else {
err = gfs_vop_lookup(dvp, nm, vpp, pnp, flags, rdir,
cr, ct, direntflags, realpnp);
@@ -626,10 +637,10 @@ zfsctl_freebsd_root_lookup(ap)
vnode_t **vpp = ap->a_vpp;
cred_t *cr = ap->a_cnp->cn_cred;
int flags = ap->a_cnp->cn_flags;
+ int lkflags = ap->a_cnp->cn_lkflags;
int nameiop = ap->a_cnp->cn_nameiop;
char nm[NAME_MAX + 1];
int err;
- int ltype;
if ((flags & ISLASTCN) && (nameiop == RENAME || nameiop == CREATE))
return (EOPNOTSUPP);
@@ -638,16 +649,15 @@ zfsctl_freebsd_root_lookup(ap)
strlcpy(nm, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen + 1);
err = zfsctl_root_lookup(dvp, nm, vpp, NULL, 0, NULL, cr, NULL, NULL, NULL);
if (err == 0 && (nm[0] != '.' || nm[1] != '\0')) {
- ltype = VOP_ISLOCKED(dvp);
- if (flags & ISDOTDOT) {
- VN_HOLD(*vpp);
+ if (flags & ISDOTDOT)
VOP_UNLOCK(dvp, 0);
+ err = vn_lock(*vpp, lkflags);
+ if (err != 0) {
+ vrele(*vpp);
+ *vpp = NULL;
}
- vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
- if (flags & ISDOTDOT) {
- VN_RELE(*vpp);
- vn_lock(dvp, ltype| LK_RETRY);
- }
+ if (flags & ISDOTDOT)
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
}
return (err);
OpenPOWER on IntegriCloud