Module Name: src Committed By: hannken Date: Sun Aug 7 06:01:51 UTC 2011
Modified Files: src/sys/fs/union: union.h union_subr.c union_vnops.c src/tests/fs/vfs: t_union.c Log Message: Change union rmdir semantics to fail directory removal for non-empty directories like all other file systems do. Change test accordingly. To generate a diff of this commit: cvs rdiff -u -r1.18 -r1.19 src/sys/fs/union/union.h cvs rdiff -u -r1.43 -r1.44 src/sys/fs/union/union_subr.c cvs rdiff -u -r1.41 -r1.42 src/sys/fs/union/union_vnops.c cvs rdiff -u -r1.7 -r1.8 src/tests/fs/vfs/t_union.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/union/union.h diff -u src/sys/fs/union/union.h:1.18 src/sys/fs/union/union.h:1.19 --- src/sys/fs/union/union.h:1.18 Sat Jun 28 01:34:05 2008 +++ src/sys/fs/union/union.h Sun Aug 7 06:01:51 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: union.h,v 1.18 2008/06/28 01:34:05 rumble Exp $ */ +/* $NetBSD: union.h,v 1.19 2011/08/07 06:01:51 hannken Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -134,6 +134,7 @@ struct vnode *, struct vnode *, struct componentname *, struct vnode *, struct vnode *, int); +extern int union_check_rmdir(struct union_node *, kauth_cred_t); extern int union_copyfile(struct vnode *, struct vnode *, kauth_cred_t, struct lwp *); extern int union_copyup(struct union_node *, int, kauth_cred_t, Index: src/sys/fs/union/union_subr.c diff -u src/sys/fs/union/union_subr.c:1.43 src/sys/fs/union/union_subr.c:1.44 --- src/sys/fs/union/union_subr.c:1.43 Sun Jun 12 03:35:55 2011 +++ src/sys/fs/union/union_subr.c Sun Aug 7 06:01:51 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: union_subr.c,v 1.43 2011/06/12 03:35:55 rmind Exp $ */ +/* $NetBSD: union_subr.c,v 1.44 2011/08/07 06:01:51 hannken Exp $ */ /* * Copyright (c) 1994 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.43 2011/06/12 03:35:55 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.44 2011/08/07 06:01:51 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -82,6 +82,7 @@ #include <sys/vnode.h> #include <sys/namei.h> #include <sys/malloc.h> +#include <sys/dirent.h> #include <sys/file.h> #include <sys/filedesc.h> #include <sys/queue.h> @@ -1194,6 +1195,96 @@ } /* + * Check whether node can rmdir (check empty). + */ +int +union_check_rmdir(struct union_node *un, kauth_cred_t cred) +{ + int dirlen, eofflag, error; + char *dirbuf; + struct vattr va; + struct vnode *tvp; + struct dirent *dp, *edp; + struct componentname cn; + struct iovec aiov; + struct uio auio; + + KASSERT(un->un_uppervp != NULL); + + /* Check upper for being opaque. */ + KASSERT(VOP_ISLOCKED(un->un_uppervp)); + error = VOP_GETATTR(un->un_uppervp, &va, cred); + if (error || (va.va_flags & OPAQUE)) + return error; + + if (un->un_lowervp == NULL) + return 0; + + /* Check lower for being empty. */ + vn_lock(un->un_lowervp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_GETATTR(un->un_lowervp, &va, cred); + if (error) { + VOP_UNLOCK(un->un_lowervp); + return error; + } + dirlen = va.va_blocksize; + dirbuf = kmem_alloc(dirlen, KM_SLEEP); + if (dirbuf == NULL) { + VOP_UNLOCK(un->un_lowervp); + return ENOMEM; + } + /* error = 0; */ + eofflag = 0; + auio.uio_offset = 0; + do { + aiov.iov_len = dirlen; + aiov.iov_base = dirbuf; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = aiov.iov_len; + auio.uio_rw = UIO_READ; + UIO_SETUP_SYSSPACE(&auio); + error = VOP_READDIR(un->un_lowervp, &auio, cred, &eofflag, + NULL, NULL); + if (error) + break; + edp = (struct dirent *)&dirbuf[dirlen - auio.uio_resid]; + for (dp = (struct dirent *)dirbuf; + error == 0 && dp < edp; + dp = (struct dirent *)((char *)dp + dp->d_reclen)) { + if (dp->d_reclen == 0) { + error = ENOTEMPTY; + break; + } + if (dp->d_type == DT_WHT || + (dp->d_namlen == 1 && dp->d_name[0] == '.') || + (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2))) + continue; + /* Check for presence in the upper layer. */ + cn.cn_nameiop = LOOKUP; + cn.cn_flags = ISLASTCN | RDONLY; + cn.cn_cred = cred; + cn.cn_nameptr = dp->d_name; + cn.cn_namelen = dp->d_namlen; + cn.cn_hash = 0; + cn.cn_consume = 0; + error = VOP_LOOKUP(un->un_uppervp, &tvp, &cn); + if (error == ENOENT && (cn.cn_flags & ISWHITEOUT)) { + error = 0; + continue; + } + if (error == 0) + vput(tvp); + error = ENOTEMPTY; + } + } while (error == 0 && !eofflag); + kmem_free(dirbuf, dirlen); + VOP_UNLOCK(un->un_lowervp); + + return error; +} + +/* * This hook is called from vn_readdir() to switch to lower directory * entry after the upper directory is read. */ Index: src/sys/fs/union/union_vnops.c diff -u src/sys/fs/union/union_vnops.c:1.41 src/sys/fs/union/union_vnops.c:1.42 --- src/sys/fs/union/union_vnops.c:1.41 Fri Aug 5 08:17:47 2011 +++ src/sys/fs/union/union_vnops.c Sun Aug 7 06:01:51 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: union_vnops.c,v 1.41 2011/08/05 08:17:47 hannken Exp $ */ +/* $NetBSD: union_vnops.c,v 1.42 2011/08/07 06:01:51 hannken Exp $ */ /* * Copyright (c) 1992, 1993, 1994, 1995 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.41 2011/08/05 08:17:47 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.42 2011/08/07 06:01:51 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1432,6 +1432,13 @@ if (dun->un_uppervp == NULLVP) panic("union rmdir: null upper vnode"); + error = union_check_rmdir(un, cnp->cn_cred); + if (error) { + vput(ap->a_dvp); + vput(ap->a_vp); + return error; + } + if (un->un_uppervp != NULLVP) { struct vnode *dvp = dun->un_uppervp; struct vnode *vp = un->un_uppervp; Index: src/tests/fs/vfs/t_union.c diff -u src/tests/fs/vfs/t_union.c:1.7 src/tests/fs/vfs/t_union.c:1.8 --- src/tests/fs/vfs/t_union.c:1.7 Fri Aug 5 08:17:47 2011 +++ src/tests/fs/vfs/t_union.c Sun Aug 7 06:01:51 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: t_union.c,v 1.7 2011/08/05 08:17:47 hannken Exp $ */ +/* $NetBSD: t_union.c,v 1.8 2011/08/07 06:01:51 hannken Exp $ */ #include <sys/types.h> #include <sys/mount.h> @@ -176,8 +176,9 @@ mountunion(mp, lower); - /* all file systems fail sooner or later */ FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(ENOTEMPTY, rump_sys_rmdir(TDIR) == -1); + RL(rump_sys_rmdir(TDFILE)); RL(rump_sys_rmdir(TDIR)); ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1); ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDIR, &sb) == -1);