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);