fix a vnode reference leak caused by illumos compat traverse()

This commit partially reverts r273641 which introduced the leak.
It did so to accomodate for some consumers of traverse() that expected
the starting vnode to stay as-is.  But that introduced the leak in the
case when a mounted filesystem was found and its root vnode was
returned.

r299914 removed the troublesome consumers and now there is no reason to
keep the starting vnode.  So, now the new rules are:
- if there is no mounted filesystem, then nothing is changed
- otherwise the starting vnode is always released
- the root vnode of the mounted filesystem is returned locked and
  referenced in the case of success

MFC after:	5 weeks
X-MFC after:	r299914
This commit is contained in:
avg 2016-05-16 12:15:19 +00:00
parent 04f04889ae
commit 88211e07b7
2 changed files with 8 additions and 9 deletions

View File

@ -89,13 +89,14 @@ traverse(vnode_t **cvpp, int lktype)
if (vfsp == NULL)
break;
error = vfs_busy(vfsp, 0);
/*
* tvp is NULL for *cvpp vnode, which we can't unlock.
* At least some callers expect the reference to be
* maintained to the original *cvpp
*/
if (tvp != NULL)
vput(cvp);
else
vrele(cvp);
if (error)
return (error);

View File

@ -1018,7 +1018,6 @@ zfsctl_snapdir_lookup(ap)
VN_HOLD(*vpp);
err = traverse(vpp, LK_EXCLUSIVE | LK_RETRY);
if (err != 0) {
VN_RELE(*vpp);
*vpp = NULL;
} else if (*vpp == sep->se_root) {
/*
@ -1613,16 +1612,15 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
*/
error = traverse(&vp, LK_SHARED | LK_RETRY);
if (error == 0) {
if (vp == sep->se_root)
if (vp == sep->se_root) {
VN_RELE(vp); /* release covered vp */
error = SET_ERROR(EINVAL);
else
} else {
*zfsvfsp = VTOZ(vp)->z_zfsvfs;
VN_URELE(vp); /* put snapshot's root vp */
}
}
mutex_exit(&sdp->sd_lock);
if (error == 0)
VN_URELE(vp);
else
VN_RELE(vp);
} else {
error = SET_ERROR(EINVAL);
mutex_exit(&sdp->sd_lock);