summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2016-05-16 15:28:39 +0000
committeravg <avg@FreeBSD.org>2016-05-16 15:28:39 +0000
commit77ee692358b84d49d81b84c705673d8fb2939f74 (patch)
tree7f493cd017d27b533f72ce53dc4bf7f5e1aa09e5 /sys/cddl
parentfd1f834a75d4b8bf74209551230c614be7c9f20b (diff)
downloadFreeBSD-src-77ee692358b84d49d81b84c705673d8fb2939f74.zip
FreeBSD-src-77ee692358b84d49d81b84c705673d8fb2939f74.tar.gz
fix locking in zfsctl_root_lookup
Dropping the root vnode's lock after VFS_ROOT() didn't really help the fact that we acquired the lock while holding its child's, .zfs, lock while performing the operaiton. So, directly use zfs_zget() to get the root vnode. While there simplify the code in zfsctl_freebsd_root_lookup. We know that .zfs is always exclusively locked. We know that there is already a reference on *vpp, so no need for an extra one. Account for the fact that .. lookup may ask for a different lock type, not necessarily LK_EXCLUSIVE. And handle a possible failure to acquire the lock given the lock flags. MFC after: 5 weeks
Diffstat (limited to 'sys/cddl')
-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 ec4518d..743e1f8 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
@@ -537,9 +537,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);
@@ -601,10 +612,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);
@@ -613,16 +624,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