diff -urBN /usr/src.orig/sys/fs/unionfs/union_subr.c /usr/src/sys/fs/unionfs/union_subr.c --- /usr/src.orig/sys/fs/unionfs/union_subr.c Tue Feb 13 15:40:19 2007 +++ /usr/src/sys/fs/unionfs/union_subr.c Tue Feb 13 18:05:59 2007 @@ -1105,6 +1105,12 @@ return (0); /* open vnode */ +#ifdef MAC + if ((error = mac_check_vnode_open(cred, vp, VEXEC|VREAD)) != 0) + return (error); +#endif + if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0) + return (error); if ((error = VOP_OPEN(vp, FREAD, cred, td, -1)) != 0) return (error); diff -urBN /usr/src.orig/sys/fs/unionfs/union_vfsops.c /usr/src/sys/fs/unionfs/union_vfsops.c --- /usr/src.orig/sys/fs/unionfs/union_vfsops.c Tue Feb 13 15:40:19 2007 +++ /usr/src/sys/fs/unionfs/union_vfsops.c Tue Feb 13 18:05:59 2007 @@ -288,6 +288,11 @@ ump->um_ufile = ufile; ump->um_copymode = copymode; + MNT_ILOCK(mp); + if ((lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE) && + (upperrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE)) + mp->mnt_kern_flag |= MNTK_MPSAFE; + MNT_IUNLOCK(mp); mp->mnt_data = (qaddr_t)ump; /* diff -urBN /usr/src.orig/sys/fs/unionfs/union_vnops.c /usr/src/sys/fs/unionfs/union_vnops.c --- /usr/src.orig/sys/fs/unionfs/union_vnops.c Tue Feb 13 15:40:20 2007 +++ /usr/src/sys/fs/unionfs/union_vnops.c Tue Feb 13 18:05:59 2007 @@ -874,6 +874,7 @@ unp = VTOUNIONFS(ap->a_vp); 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, ap->a_td, unsp); VOP_UNLOCK(ap->a_vp, 0, ap->a_td); if (ovp == NULLVP) @@ -898,6 +899,7 @@ unp = VTOUNIONFS(ap->a_vp); 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, ap->a_td, unsp); VOP_UNLOCK(ap->a_vp, 0, ap->a_td); if (ovp == NULLVP) @@ -916,6 +918,7 @@ unp = VTOUNIONFS(ap->a_vp); 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, ap->a_td, unsp); if (ovp == NULLVP) return (EBADF); @@ -1386,41 +1389,41 @@ /* check opaque */ if (uvp != NULLVP && lvp != NULLVP) { if ((error = VOP_GETATTR(uvp, &va, ap->a_cred, td)) != 0) - return (error); + goto unionfs_readdir_exit; if (va.va_flags & OPAQUE) lvp = NULLVP; } + /* check the open count. unionfs needs to open before readdir. */ if (VOP_ISLOCKED(ap->a_vp, td) != LK_EXCLUSIVE) { vn_lock(ap->a_vp, LK_UPGRADE | LK_RETRY, td); locked = 1; } - unionfs_get_node_status(unp, curthread, &unsp); + unionfs_get_node_status(unp, td, &unsp); + if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || + (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { + unionfs_tryrem_node_status(unp, td, unsp); + error = EBADF; + } if (locked == 1) vn_lock(ap->a_vp, LK_DOWNGRADE | LK_RETRY, td); + if (error != 0) + goto unionfs_readdir_exit; /* upper only */ if (uvp != NULLVP && lvp == NULLVP) { - if (unsp->uns_upper_opencnt <= 0) - error = EBADF; - else { - error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, - ap->a_ncookies, ap->a_cookies); - unsp->uns_readdir_status = 0; - } + error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, + ap->a_ncookies, ap->a_cookies); + unsp->uns_readdir_status = 0; goto unionfs_readdir_exit; } /* lower only */ if (uvp == NULLVP && lvp != NULLVP) { - if (unsp->uns_lower_opencnt <= 0) - error = EBADF; - else { - error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, - ap->a_ncookies, ap->a_cookies); - unsp->uns_readdir_status = 2; - } + error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, + ap->a_ncookies, ap->a_cookies); + unsp->uns_readdir_status = 2; goto unionfs_readdir_exit; } @@ -1428,11 +1431,6 @@ /* * readdir upper and lower */ - if (unsp->uns_lower_opencnt <= 0 || unsp->uns_upper_opencnt <= 0) { - error = EBADF; - goto unionfs_readdir_exit; - } - if (uio->uio_offset == 0) unsp->uns_readdir_status = 0; @@ -1441,10 +1439,8 @@ error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, ap->a_ncookies, ap->a_cookies); - if (error != 0 || eofflag == 0) { - UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); - return (error); - } + if (error != 0 || eofflag == 0) + goto unionfs_readdir_exit; unsp->uns_readdir_status = 1; /* @@ -1453,10 +1449,8 @@ * size of DIRBLKSIZ equals DEV_BSIZE. * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) */ - if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) { - UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); - return (0); - } + if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) + goto unionfs_readdir_exit; /* * backup cookies @@ -1506,6 +1500,9 @@ } unionfs_readdir_exit: + if (error != 0 && ap->a_eofflag != NULL) + *(ap->a_eofflag) = 1; + UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); return (error); @@ -1858,7 +1855,8 @@ unsp->uns_upper_opencnt++; VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td); unsp->uns_lower_opencnt--; - } + } else + unionfs_tryrem_node_status(unp, td, unsp); } VOP_UNLOCK(vp, 0, td);