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
This commit is contained in:
parent
705e6b8170
commit
0ab1aa90fa
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user