Index: sys/fs/unionfs/union_vfsops.c =================================================================== --- sys/fs/unionfs/union_vfsops.c +++ sys/fs/unionfs/union_vfsops.c @@ -75,10 +75,11 @@ unionfs_domount(struct mount *mp) { int error; + struct mount *lowermp, *uppermp; struct vnode *lowerrootvp; struct vnode *upperrootvp; struct unionfs_mount *ump; - struct thread *td; + struct thread *td; char *target; char *tmp; char *ep; @@ -285,18 +286,29 @@ error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, NULLVP, &(ump->um_rootvp), NULL, td); vrele(upperrootvp); - if (error) { - free(ump, M_UNIONFSMNT); - mp->mnt_data = NULL; - return (error); + if (error != 0) + goto unionfs_domount_cleanup; + + lowermp = vfs_ref_from_vp(ump->um_lowervp); + uppermp = vfs_ref_from_vp(ump->um_uppervp); + if (lowermp == NULL || uppermp == NULL) + error = ENOENT; + else { + MNT_ILOCK(mp); + if ((lowermp->mnt_flag & MNT_LOCAL) && + (uppermp->mnt_flag & MNT_LOCAL)) + mp->mnt_flag |= MNT_LOCAL; + mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS; + MNT_IUNLOCK(mp); } - MNT_ILOCK(mp); - if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && - (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS; - MNT_IUNLOCK(mp); + if (uppermp != NULL) + vfs_rel(uppermp); + if (lowermp != NULL) + vfs_rel(lowermp); + + if (error != 0) + goto unionfs_domount_cleanup; /* * Get new fsid @@ -310,6 +322,12 @@ mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return (0); + +unionfs_domount_cleanup: + + free(ump, M_UNIONFSMNT); + mp->mnt_data = NULL; + return (error); } /* @@ -373,19 +391,30 @@ static int unionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) { + struct mount *uppermp; struct unionfs_mount *ump; + int error; ump = MOUNTTOUNIONFSMOUNT(mp); + uppermp = vfs_ref_from_vp(ump->um_uppervp); /* * Writing is always performed to upper vnode. */ - return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg)); + if (uppermp == NULL) + error = ENOENT; + else { + error = VFS_QUOTACTL(uppermp, cmd, uid, arg); + vfs_rel(uppermp); + } + + return (error); } static int unionfs_statfs(struct mount *mp, struct statfs *sbp) { + struct mount *lowermp, *uppermp; struct unionfs_mount *ump; int error; struct statfs *mstat; @@ -398,7 +427,13 @@ mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO); - error = VFS_STATFS(ump->um_lowervp->v_mount, mstat); + lowermp = vfs_ref_from_vp(ump->um_lowervp); + if (lowermp == NULL) + return (ENOENT); + else + error = VFS_STATFS(lowermp, mstat); + + vfs_rel(lowermp); if (error) { free(mstat, M_STATFS); return (error); @@ -410,7 +445,13 @@ lbsize = mstat->f_bsize; - error = VFS_STATFS(ump->um_uppervp->v_mount, mstat); + uppermp = vfs_ref_from_vp(ump->um_uppervp); + if (uppermp == NULL) + return (ENOENT); + else + error = VFS_STATFS(uppermp, mstat); + + vfs_rel(uppermp); if (error) { free(mstat, M_STATFS); return (error); @@ -470,19 +511,32 @@ unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, int namespace, const char *attrname) { + struct mount *cmp; struct unionfs_mount *ump; struct unionfs_node *unp; + struct vnode *vp, *mvp; + int error; ump = MOUNTTOUNIONFSMOUNT(mp); unp = VTOUNIONFS(filename_vp); if (unp->un_uppervp != NULLVP) { - return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd, - unp->un_uppervp, namespace, attrname)); + vp = unp->un_uppervp; + mvp = ump->um_uppervp; } else { - return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd, - unp->un_lowervp, namespace, attrname)); + vp = unp->un_lowervp; + mvp = ump->um_lowervp; } + cmp = vfs_ref_from_vp(mvp); + + if (cmp == NULL) + error = ENOENT; + else { + error = VFS_EXTATTRCTL(cmp, cmd, vp, namespace, attrname); + vfs_rel(cmp); + } + + return (error); } static struct vfsops unionfs_vfsops = { Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -671,12 +671,14 @@ static int unionfs_access(struct vop_access_args *ap) { + struct mount *uppermp; struct unionfs_mount *ump; struct unionfs_node *unp; struct vnode *uvp; struct vnode *lvp; struct thread *td; struct vattr va; + uint64_t mnt_flag; accmode_t accmode; int error; @@ -714,7 +716,12 @@ if (lvp != NULLVP) { if (accmode & VWRITE) { - if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { + uppermp = vfs_ref_from_vp(ump->um_uppervp); + if (uppermp == NULL) + return (ENOENT); + mnt_flag = uppermp->mnt_flag; + vfs_rel(uppermp); + if (mnt_flag & MNT_RDONLY) { switch (ap->a_vp->v_type) { case VREG: case VDIR: @@ -751,13 +758,14 @@ static int unionfs_getattr(struct vop_getattr_args *ap) { - int error; + struct mount *uppermp; struct unionfs_node *unp; struct unionfs_mount *ump; struct vnode *uvp; struct vnode *lvp; struct thread *td; struct vattr va; + int error; UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); @@ -782,7 +790,10 @@ error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); - if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { + uppermp = vfs_ref_from_vp(ump->um_uppervp); + if (uppermp == NULL) + error = ENOENT; + if (error == 0 && !(uppermp->mnt_flag & MNT_RDONLY)) { /* correct the attr toward shadow file/dir. */ if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); @@ -791,6 +802,8 @@ ap->a_vap->va_gid = va.va_gid; } } + if (uppermp != NULL) + vfs_rel(uppermp); if (error == 0) ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];