unionfs: fix up VOP_UNLOCK use after flags stopped being supported

For the most part the code was passing the LK_RELEASE flag.
The 2 cases which did not use the VOP_UNLOCK_FLAGS macro.

This fixes a panic when stacking unionfs on top of e.g., tmpfs when
debug is enabled.

Note there are latent bugs which prevent unionfs from working with debug
regardless of this change.

PR:		243064
Reported by:	Mason Loring Bliss
This commit is contained in:
Mateusz Guzik 2020-01-03 22:12:25 +00:00
parent 3d59b89c7a
commit 4a20fe31c3
3 changed files with 39 additions and 41 deletions

View File

@ -361,9 +361,9 @@ unionfs_noderem(struct vnode *vp, struct thread *td)
VI_UNLOCK(vp);
if (lvp != NULLVP)
VOP_UNLOCK(lvp, LK_RELEASE);
VOP_UNLOCK(lvp, 0);
if (uvp != NULLVP)
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
if (dvp != NULLVP && unp->un_hash.le_prev != NULL)
unionfs_rem_cached_vnode(unp, dvp);
@ -551,7 +551,7 @@ unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
cn->cn_flags |= NOCACHE;
vref(dvp);
VOP_UNLOCK(dvp, LK_RELEASE);
VOP_UNLOCK(dvp, 0);
if ((error = relookup(dvp, vpp, cn))) {
uma_zfree(namei_zone, cn->cn_pnbuf);
@ -961,7 +961,7 @@ unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
}
unionfs_vn_create_on_upper_free_out1:
VOP_UNLOCK(udvp, LK_RELEASE);
VOP_UNLOCK(udvp, 0);
unionfs_vn_create_on_upper_free_out2:
if (cn.cn_flags & HASBUF) {

View File

@ -167,7 +167,7 @@ unionfs_domount(struct mount *mp)
uid = va.va_uid;
gid = va.va_gid;
}
VOP_UNLOCK(mp->mnt_vnodecovered, LK_RELEASE);
VOP_UNLOCK(mp->mnt_vnodecovered, 0);
if (error)
return (error);
@ -252,7 +252,7 @@ unionfs_domount(struct mount *mp)
* Save reference
*/
if (below) {
VOP_UNLOCK(upperrootvp, LK_RELEASE);
VOP_UNLOCK(upperrootvp, 0);
vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY);
ump->um_lowervp = upperrootvp;
ump->um_uppervp = lowerrootvp;
@ -278,7 +278,7 @@ unionfs_domount(struct mount *mp)
/*
* Unlock the node
*/
VOP_UNLOCK(ump->um_uppervp, LK_RELEASE);
VOP_UNLOCK(ump->um_uppervp, 0);
/*
* Get the unionfs root vnode.

View File

@ -128,7 +128,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
if (udvp != NULLVP) {
dtmpvp = udvp;
if (ldvp != NULLVP)
VOP_UNLOCK(ldvp, LK_RELEASE);
VOP_UNLOCK(ldvp, 0);
}
else
dtmpvp = ldvp;
@ -136,7 +136,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
error = VOP_LOOKUP(dtmpvp, &vp, cnp);
if (dtmpvp == udvp && ldvp != NULLVP) {
VOP_UNLOCK(udvp, LK_RELEASE);
VOP_UNLOCK(udvp, 0);
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
}
@ -148,10 +148,10 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
*/
if (nameiop == DELETE || nameiop == RENAME ||
(cnp->cn_lkflags & LK_TYPE_MASK))
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
vrele(vp);
VOP_UNLOCK(dvp, LK_RELEASE);
VOP_UNLOCK(dvp, 0);
*(ap->a_vpp) = dunp->un_dvp;
vref(dunp->un_dvp);
@ -188,7 +188,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
}
if (nameiop == DELETE || nameiop == RENAME ||
(cnp->cn_lkflags & LK_TYPE_MASK))
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
}
/* check whiteout */
@ -232,7 +232,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
return (lerror);
}
if (cnp->cn_lkflags & LK_TYPE_MASK)
VOP_UNLOCK(lvp, LK_RELEASE);
VOP_UNLOCK(lvp, 0);
}
}
@ -267,7 +267,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
goto unionfs_lookup_out;
if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
lockflag = 1;
@ -275,7 +275,7 @@ unionfs_lookup(struct vop_cachedlookup_args *ap)
error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
udvp, VTOUNIONFS(vp), cnp, td);
if (lockflag != 0)
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
if (error != 0) {
UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
@ -372,7 +372,7 @@ unionfs_create(struct vop_create_args *ap)
if (vp->v_type == VSOCK)
*(ap->a_vpp) = vp;
else {
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
ap->a_dvp, ap->a_vpp, cnp, curthread);
vrele(vp);
@ -446,7 +446,7 @@ unionfs_mknod(struct vop_mknod_args *ap)
if (vp->v_type == VSOCK)
*(ap->a_vpp) = vp;
else {
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
ap->a_dvp, ap->a_vpp, cnp, curthread);
vrele(vp);
@ -903,7 +903,7 @@ unionfs_ioctl(struct vop_ioctl_args *ap)
unionfs_get_node_status(unp, ap->a_td, &unsp);
ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
unionfs_tryrem_node_status(unp, unsp);
VOP_UNLOCK(ap->a_vp, LK_RELEASE);
VOP_UNLOCK(ap->a_vp, 0);
if (ovp == NULLVP)
return (EBADF);
@ -930,7 +930,7 @@ unionfs_poll(struct vop_poll_args *ap)
unionfs_get_node_status(unp, ap->a_td, &unsp);
ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
unionfs_tryrem_node_status(unp, unsp);
VOP_UNLOCK(ap->a_vp, LK_RELEASE);
VOP_UNLOCK(ap->a_vp, 0);
if (ovp == NULLVP)
return (EBADF);
@ -990,7 +990,7 @@ unionfs_remove(struct vop_remove_args *ap)
ump = NULL;
vp = uvp = lvp = NULLVP;
/* search vnode */
VOP_UNLOCK(ap->a_vp, LK_RELEASE);
VOP_UNLOCK(ap->a_vp, 0);
error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE);
if (error != 0 && error != ENOENT) {
@ -1193,7 +1193,7 @@ unionfs_rename(struct vop_rename_args *ap)
if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
goto unionfs_rename_abort;
error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
VOP_UNLOCK(fvp, LK_RELEASE);
VOP_UNLOCK(fvp, 0);
if (error != 0)
goto unionfs_rename_abort;
break;
@ -1201,7 +1201,7 @@ unionfs_rename(struct vop_rename_args *ap)
if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
goto unionfs_rename_abort;
error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
VOP_UNLOCK(fvp, LK_RELEASE);
VOP_UNLOCK(fvp, 0);
if (error != 0)
goto unionfs_rename_abort;
break;
@ -1258,13 +1258,13 @@ unionfs_rename(struct vop_rename_args *ap)
if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
goto unionfs_rename_abort;
error = unionfs_relookup_for_delete(fdvp, fcnp, td);
VOP_UNLOCK(fdvp, LK_RELEASE);
VOP_UNLOCK(fdvp, 0);
if (error != 0)
goto unionfs_rename_abort;
/* Locke of tvp is canceled in order to avoid recursive lock. */
if (tvp != NULLVP && tvp != tdvp)
VOP_UNLOCK(tvp, LK_RELEASE);
VOP_UNLOCK(tvp, 0);
error = unionfs_relookup_for_rename(tdvp, tcnp, td);
if (tvp != NULLVP && tvp != tdvp)
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
@ -1282,11 +1282,11 @@ unionfs_rename(struct vop_rename_args *ap)
}
if (ltdvp != NULLVP)
VOP_UNLOCK(ltdvp, LK_RELEASE);
VOP_UNLOCK(ltdvp, 0);
if (tdvp != rtdvp)
vrele(tdvp);
if (ltvp != NULLVP)
VOP_UNLOCK(ltvp, LK_RELEASE);
VOP_UNLOCK(ltvp, 0);
if (tvp != rtvp && tvp != NULLVP) {
if (rtvp == NULLVP)
vput(tvp);
@ -1360,7 +1360,7 @@ unionfs_mkdir(struct vop_mkdir_args *ap)
}
if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
cnp->cn_lkflags = LK_EXCLUSIVE;
error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
ap->a_dvp, ap->a_vpp, cnp, td);
@ -1458,7 +1458,7 @@ unionfs_symlink(struct vop_symlink_args *ap)
if (udvp != NULLVP) {
error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
if (error == 0) {
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
cnp->cn_lkflags = LK_EXCLUSIVE;
error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
ap->a_dvp, ap->a_vpp, cnp, td);
@ -1817,7 +1817,7 @@ static void
unionfs_revlock(struct vnode *vp, int flags)
{
if (flags & LK_RELEASE)
VOP_UNLOCK(vp, flags);
VOP_UNLOCK_FLAGS(vp, flags);
else {
/* UPGRADE */
if (vn_lock(vp, flags) != 0)
@ -1849,7 +1849,7 @@ unionfs_lock(struct vop_lock1_args *ap)
vp = ap->a_vp;
if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
return (VOP_UNLOCK(vp, flags | LK_RELEASE));
return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
if ((flags & LK_INTERLOCK) == 0)
VI_LOCK(vp);
@ -1884,12 +1884,12 @@ unionfs_lock(struct vop_lock1_args *ap)
/* Share Lock is once released and a deadlock is avoided. */
vholdnz(uvp);
uhold = 1;
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
unp = VTOUNIONFS(vp);
if (unp == NULL) {
/* vnode is released. */
VI_UNLOCK(vp);
VOP_UNLOCK(lvp, LK_RELEASE);
VOP_UNLOCK(lvp, 0);
vdrop(uvp);
return (EBUSY);
}
@ -1909,7 +1909,7 @@ unionfs_lock(struct vop_lock1_args *ap)
/* vnode is released. */
VI_UNLOCK(vp);
if (error == 0)
VOP_UNLOCK(lvp, LK_RELEASE);
VOP_UNLOCK(lvp, 0);
vdrop(lvp);
if (uhold != 0)
vdrop(uvp);
@ -1940,10 +1940,10 @@ unionfs_lock(struct vop_lock1_args *ap)
/* vnode is released. */
VI_UNLOCK(vp);
if (error == 0)
VOP_UNLOCK(uvp, LK_RELEASE);
VOP_UNLOCK(uvp, 0);
vdrop(uvp);
if (lvp != NULLVP) {
VOP_UNLOCK(lvp, LK_RELEASE);
VOP_UNLOCK(lvp, 0);
vdrop(lvp);
}
return (vop_stdlock(ap));
@ -1974,7 +1974,6 @@ static int
unionfs_unlock(struct vop_unlock_args *ap)
{
int error;
int flags;
int uhold;
struct vnode *vp;
struct vnode *lvp;
@ -1985,7 +1984,6 @@ unionfs_unlock(struct vop_unlock_args *ap)
error = 0;
uhold = 0;
flags = ap->a_flags | LK_RELEASE;
vp = ap->a_vp;
unp = VTOUNIONFS(vp);
@ -1996,13 +1994,13 @@ unionfs_unlock(struct vop_unlock_args *ap)
if (lvp != NULLVP) {
vholdnz(lvp);
error = VOP_UNLOCK(lvp, flags);
error = VOP_UNLOCK(lvp, 0);
}
if (error == 0 && uvp != NULLVP) {
vholdnz(uvp);
uhold = 1;
error = VOP_UNLOCK(uvp, flags);
error = VOP_UNLOCK(uvp, 0);
}
if (lvp != NULLVP)
@ -2072,7 +2070,7 @@ unionfs_advlock(struct vop_advlock_args *ap)
unionfs_tryrem_node_status(unp, unsp);
}
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
@ -2081,7 +2079,7 @@ unionfs_advlock(struct vop_advlock_args *ap)
return error;
unionfs_advlock_abort:
VOP_UNLOCK(vp, LK_RELEASE);
VOP_UNLOCK(vp, 0);
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);