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

Reply via email to