Module Name:    src
Committed By:   hannken
Date:           Sat Aug 27 15:32:28 UTC 2011

Modified Files:
        src/sys/fs/tmpfs: tmpfs_subr.c tmpfs_vnops.c

Log Message:
Finish and enable whiteout support for tmpfs:

- Enable VOP tmpfs_whiteout().
- Support ISWHITEOUT in tmpfs_alloc_file().
- Support DOWHITEOUT in tmpfs_remove() and tmpfs_rmdir().
- Make rmdir on a directory containing whiteouts working.

Should fix PR #35112 (tmpfs doesn't play well with unionfs).


To generate a diff of this commit:
cvs rdiff -u -r1.76 -r1.77 src/sys/fs/tmpfs/tmpfs_subr.c
cvs rdiff -u -r1.89 -r1.90 src/sys/fs/tmpfs/tmpfs_vnops.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/tmpfs/tmpfs_subr.c
diff -u src/sys/fs/tmpfs/tmpfs_subr.c:1.76 src/sys/fs/tmpfs/tmpfs_subr.c:1.77
--- src/sys/fs/tmpfs/tmpfs_subr.c:1.76	Thu Jun 30 00:37:07 2011
+++ src/sys/fs/tmpfs/tmpfs_subr.c	Sat Aug 27 15:32:28 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: tmpfs_subr.c,v 1.76 2011/06/30 00:37:07 enami Exp $	*/
+/*	$NetBSD: tmpfs_subr.c,v 1.77 2011/08/27 15:32:28 hannken Exp $	*/
 
 /*
  * Copyright (c) 2005-2011 The NetBSD Foundation, Inc.
@@ -74,7 +74,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.76 2011/06/30 00:37:07 enami Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.77 2011/08/27 15:32:28 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -343,7 +343,7 @@
 {
 	tmpfs_mount_t *tmp = VFS_TO_TMPFS(dvp->v_mount);
 	tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp), *node;
-	tmpfs_dirent_t *de;
+	tmpfs_dirent_t *de, *wde;
 	int error;
 
 	KASSERT(VOP_ISLOCKED(dvp));
@@ -381,8 +381,20 @@
 		goto out;
 	}
 
+	/* Remove whiteout before adding the new entry. */
+	if (cnp->cn_flags & ISWHITEOUT) {
+		wde = tmpfs_dir_lookup(dnode, cnp);
+		KASSERT(wde != NULL && wde->td_node == TMPFS_NODE_WHITEOUT);
+		tmpfs_dir_detach(dvp, wde);
+		tmpfs_free_dirent(tmp, wde);
+	}
+
 	/* Associate inode and attach the entry into the directory. */
 	tmpfs_dir_attach(dvp, de, node);
+
+	/* Make node opaque if requested. */
+	if (cnp->cn_flags & ISWHITEOUT)
+		node->tn_flags |= UF_OPAQUE;
 out:
 	vput(dvp);
 	return error;
@@ -444,8 +456,8 @@
 	KASSERT(VOP_ISLOCKED(dvp));
 
 	/* Associate directory entry and the inode. */
+	de->td_node = node;
 	if (node != TMPFS_NODE_WHITEOUT) {
-		de->td_node = node;
 		KASSERT(node->tn_links < LINK_MAX);
 		node->tn_links++;
 

Index: src/sys/fs/tmpfs/tmpfs_vnops.c
diff -u src/sys/fs/tmpfs/tmpfs_vnops.c:1.89 src/sys/fs/tmpfs/tmpfs_vnops.c:1.90
--- src/sys/fs/tmpfs/tmpfs_vnops.c:1.89	Thu Aug 18 21:42:18 2011
+++ src/sys/fs/tmpfs/tmpfs_vnops.c	Sat Aug 27 15:32:28 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: tmpfs_vnops.c,v 1.89 2011/08/18 21:42:18 riastradh Exp $	*/
+/*	$NetBSD: tmpfs_vnops.c,v 1.90 2011/08/27 15:32:28 hannken Exp $	*/
 
 /*
  * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.89 2011/08/18 21:42:18 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.90 2011/08/27 15:32:28 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -103,9 +103,7 @@
 	{ &vop_bwrite_desc,		tmpfs_bwrite },
 	{ &vop_getpages_desc,		tmpfs_getpages },
 	{ &vop_putpages_desc,		tmpfs_putpages },
-#if TMPFS_WHITEOUT
 	{ &vop_whiteout_desc,		tmpfs_whiteout },
-#endif
 	{ NULL, NULL }
 };
 
@@ -713,11 +711,15 @@
 
 	/*
 	 * Remove the entry from the directory (drops the link count) and
-	 * destroy it.  Note: the inode referred by it will not be destroyed
+	 * destroy it or replace it with a whiteout.
+	 * Note: the inode referred by it will not be destroyed
 	 * until the vnode is reclaimed/recycled.
 	 */
 	tmpfs_dir_detach(dvp, de);
-	tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
+	if (ap->a_cnp->cn_flags & DOWHITEOUT)
+		tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
+	else
+		tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
 	error = 0;
 out:
 	/* Drop the references and unlock the vnodes. */
@@ -2103,12 +2105,19 @@
 	KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
 
 	/*
-	 * Directories with more than two entries ('.' and '..') cannot
-	 * be removed.
+	 * Directories with more than two non-whiteout
+	 * entries ('.' and '..') cannot be removed.
 	 */
 	if (node->tn_size > 0) {
-		error = ENOTEMPTY;
-		goto out;
+		KASSERT(error == 0);
+		TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
+			if (de->td_node != TMPFS_NODE_WHITEOUT) {
+				error = ENOTEMPTY;
+				break;
+			}
+		}
+		if (error)
+			goto out;
 	}
 
 	/* Lookup the directory entry (check the cached hint first). */
@@ -2136,10 +2145,22 @@
 	cache_purge(dvp);
 
 	/*
-	 * Destroy the directory entry.  Note: the inode referred by it
-	 * will not be destroyed until the vnode is reclaimed.
+	 * Destroy the directory entry or replace it with a whiteout.
+	 * Note: the inode referred by it will not be destroyed
+	 * until the vnode is reclaimed.
 	 */
-	tmpfs_free_dirent(tmp, de);
+	if (ap->a_cnp->cn_flags & DOWHITEOUT)
+		tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
+	else
+		tmpfs_free_dirent(tmp, de);
+
+	/* Destroy the whiteout entries from the node. */
+	while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {
+		KASSERT(de->td_node == TMPFS_NODE_WHITEOUT);
+		tmpfs_dir_detach(vp, de);
+		tmpfs_free_dirent(tmp, de);
+	}
+
 	KASSERT(node->tn_links == 0);
 out:
 	/* Release the nodes. */
@@ -2507,7 +2528,6 @@
 	return error;
 }
 
-#ifdef TMPFS_WHITEOUT
 int
 tmpfs_whiteout(void *v)
 {
@@ -2544,7 +2564,6 @@
 	}
 	return 0;
 }
-#endif
 
 int
 tmpfs_print(void *v)

Reply via email to