Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Change union rmdir semantics to fail directory removal for



details:   https://anonhg.NetBSD.org/src/rev/e9ae32822a12
branches:  trunk
changeset: 768046:e9ae32822a12
user:      hannken <hannken%NetBSD.org@localhost>
date:      Sun Aug 07 06:01:51 2011 +0000

description:
Change union rmdir semantics to fail directory removal for
non-empty directories like all other file systems do.

Change test accordingly.

diffstat:

 sys/fs/union/union.h       |   3 +-
 sys/fs/union/union_subr.c  |  95 +++++++++++++++++++++++++++++++++++++++++++++-
 sys/fs/union/union_vnops.c |  11 ++++-
 tests/fs/vfs/t_union.c     |   5 +-
 4 files changed, 107 insertions(+), 7 deletions(-)

diffs (192 lines):

diff -r 19fe505bf0ed -r e9ae32822a12 sys/fs/union/union.h
--- a/sys/fs/union/union.h      Sun Aug 07 05:56:32 2011 +0000
+++ b/sys/fs/union/union.h      Sun Aug 07 06:01:51 2011 +0000
@@ -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,
diff -r 19fe505bf0ed -r e9ae32822a12 sys/fs/union/union_subr.c
--- a/sys/fs/union/union_subr.c Sun Aug 07 05:56:32 2011 +0000
+++ b/sys/fs/union/union_subr.c Sun Aug 07 06:01:51 2011 +0000
@@ -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.
  */
diff -r 19fe505bf0ed -r e9ae32822a12 sys/fs/union/union_vnops.c
--- a/sys/fs/union/union_vnops.c        Sun Aug 07 05:56:32 2011 +0000
+++ b/sys/fs/union/union_vnops.c        Sun Aug 07 06:01:51 2011 +0000
@@ -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;
diff -r 19fe505bf0ed -r e9ae32822a12 tests/fs/vfs/t_union.c
--- a/tests/fs/vfs/t_union.c    Sun Aug 07 05:56:32 2011 +0000
+++ b/tests/fs/vfs/t_union.c    Sun Aug 07 06:01:51 2011 +0000
@@ -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);



Home | Main Index | Thread Index | Old Index