Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -1764,33 +1764,47 @@ static int unionfs_getwritemount(struct vop_getwritemount_args *ap) { + struct unionfs_node *unp; struct vnode *uvp; - struct vnode *vp; + struct vnode *vp, *ovp; int error; UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); error = 0; vp = ap->a_vp; + uvp = NULLVP; - if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) + VI_LOCK(vp); + + if (vp->v_mount != NULL && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) { + VI_UNLOCK(vp); return (EACCES); + } - KASSERT_UNIONFS_VNODE(vp); + unp = VTOUNIONFS(vp); - uvp = UNIONFSVPTOUPPERVP(vp); - if (uvp == NULLVP && VREG == vp->v_type) - uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); + if (unp != NULL) + uvp = unp->un_uppervp; - if (uvp != NULLVP) - error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); - else { + if (uvp == NULLVP && unp != NULL && unp->un_dvp != NULL) { + ovp = vp; + vp = unp->un_dvp; + VI_UNLOCK(ovp); VI_LOCK(vp); - if (vp->v_holdcnt == 0) - error = EOPNOTSUPP; - else - error = EACCES; + unp = VTOUNIONFS(vp); + if (unp != NULL) + uvp = unp->un_uppervp; + } + + if (uvp != NULLVP) { + vholdnz(uvp); + VI_UNLOCK(vp); + error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); + vdrop(uvp); + } else { VI_UNLOCK(vp); + *(ap->a_mpp) = NULL; } UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);