linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups
@ 2008-07-30  2:43 Erez Zadok
  2008-07-30  2:43 ` [PATCH 01/19] LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a Erez Zadok
                   ` (18 more replies)
  0 siblings, 19 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos


The following is a series of patchsets related to Unionfs, and one for
fsstack.  This series includes four types of changes:

1. Fold in Hugh Dickins's fsstack_copy_inode_size fix.  Since it depends on
   code in unionfs, I'm temporarily folding this patch into my tree.  I'll
   extract it into a separate patch which can be applied cleanly against
   2.6.27-rc in the next few days.

2. Assorted fixes to adderess VFS API changes in 2.6.26/2.6.27-rc1:
   ->symlink, ->permission, nameidata intent flags changed, and
   kmem_cache_create prototype changed.

3. Extracted all whiteout related code into a separate file, and cleaned it
   up a lot.  Now the main unionfs code calls somewhat generic functions
   such as "check if there's a whiteout" or "create a whiteout" and the
   like.  Once Bharata whiteout code makes it in, it would be easy to make
   unionfs use filesystem-native whiteout support.

4. Reworked much of the lookup code in unionfs to ensure that we have a
   vfsmount at every lookup stage, esp. when crossing directories.  In
   particular, started using vfs_path_lookup instead of lookup_one_len.
   These changes are a first but important step towards getting rid of all
   vfs_* calls within unionfs in preparation for having Miklos's path_*
   calls.

There were also a few smaller bug fixes: memleak (also from Hugh Dickins),
some cache coherency fixes, and a fix to an LTP/rename13 regression.

These patches were tested (where appropriate) on v2.6.27-rc1, MM, as well as
the backports to 2.6.{26,25,24,23,22,21,20,19,18,9} on ext2/3/4, xfs,
reiserfs, nfs2/3/4, jffs2, ramfs, tmpfs, cramfs, and squashfs (where
available).  Also tested with LTP-full-20080630 and with a continuous
parallel kernel compile (while forcing cache flushing, manipulating lower
branches, etc.).  See http://unionfs.filesystems.org/ to download
back-ported unionfs code.

Please pull from the 'master' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/ezk/unionfs.git

to receive the following:

Erez Zadok (18):
      Unionfs: simplify the macros used to get/set the dentry start/end branches
      Unionfs: move a rename helper closer to rename code
      Unionfs: create and consolidate helpers to iput lower objects
      Unionfs: create and consolidate helpers to path-put lower objects
      Unionfs: simplify stale-inode detection code
      Unionfs: overhaul whiteout code
      Unionfs: lookup overhaul using vfs_path_lookup
      Unionfs: free lower paths array when destroying dentry's private data
      Unionfs: cache coherency fixes
      Unionfs: remove old lookup code
      Unionfs: update maintainers
      Unionfs: update copyrights
      Unionfs: minor checkpatch fixes
      Unionfs: properly hash newly created inodes
      Unionfs: symlink no longer takes a mode parameter
      Unionfs: permission no longer takes a nameidata parameter
      Unionfs: LOOKUP_ACCESS intent no longer exists
      Unionfs: use new kmem_cache_create constructor prototype

Hugh Dickins (1):
      LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a

 MAINTAINERS              |    3 
 fs/stack.c               |   58 ++-
 fs/unionfs/Makefile      |    2 
 fs/unionfs/commonfops.c  |   32 -
 fs/unionfs/copyup.c      |   45 +-
 fs/unionfs/debug.c       |    8 
 fs/unionfs/dentry.c      |  123 +++----
 fs/unionfs/dirfops.c     |   28 -
 fs/unionfs/dirhelper.c   |  130 -------
 fs/unionfs/fanout.h      |  158 ++++++---
 fs/unionfs/file.c        |    6 
 fs/unionfs/inode.c       |  225 ++-----------
 fs/unionfs/lookup.c      |  769 ++++++++++++++++++++---------------------------
 fs/unionfs/main.c        |   40 --
 fs/unionfs/mmap.c        |    6 
 fs/unionfs/rdstate.c     |    6 
 fs/unionfs/rename.c      |  206 ++++--------
 fs/unionfs/sioq.c        |   26 -
 fs/unionfs/sioq.h        |    7 
 fs/unionfs/subr.c        |  209 ------------
 fs/unionfs/super.c       |   22 -
 fs/unionfs/union.h       |   58 +--
 fs/unionfs/unlink.c      |   28 -
 fs/unionfs/whiteout.c    |  577 +++++++++++++++++++++++++++++++++++
 fs/unionfs/xattr.c       |    6 
 include/linux/fs_stack.h |    3 
 include/linux/union_fs.h |    6 
 27 files changed, 1384 insertions(+), 1403 deletions(-)

Thanks.
---
Erez Zadok
ezk@cs.sunysb.edu

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/19] LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 02/19] Unionfs: simplify the macros used to get/set the dentry start/end branches Erez Zadok
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Hugh Dickins,
	Erez Zadok, Michael Halcrow, hooanon05, Christoph Hellwig,
	Andrew Morton

From: Hugh Dickins <hugh@veritas.com>

But akpm was dissatisfied with the resulting patch: its lack of
commentary, the #ifs, the nesting around i_size_read, the lack of
attention to i_blocks.  I promised to redo it with the general
spin_lock_32bit() he proposed; but disliked the result, partly because
"32bit" obscures the real constraints, which are best commented within
fsstack_copy_inode_size itself.

This version adds those comments, and uses sizeof comparisons which the
compiler can optimize out, instead of CONFIG_SMP, CONFIG_LSF.
BITS_PER_LONG.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: Erez Zadok <ezk@cs.sunysb.edu>
Cc: Michael Halcrow <mhalcrow@us.ibm.com>
Cc: <hooanon05@yahoo.co.jp>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/stack.c               |   58 ++++++++++++++++++++++++++++++++++++++-------
 include/linux/fs_stack.h |    3 +-
 2 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/fs/stack.c b/fs/stack.c
index 4336f2b..a66ff6c 100644
--- a/fs/stack.c
+++ b/fs/stack.c
@@ -19,16 +19,56 @@
  * This function cannot be inlined since i_size_{read,write} is rather
  * heavy-weight on 32-bit systems
  */
-void fsstack_copy_inode_size(struct inode *dst, const struct inode *src)
+void fsstack_copy_inode_size(struct inode *dst, struct inode *src)
 {
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	spin_lock(&dst->i_lock);
-#endif
-	i_size_write(dst, i_size_read(src));
-	dst->i_blocks = src->i_blocks;
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	spin_unlock(&dst->i_lock);
-#endif
+	loff_t i_size;
+	blkcnt_t i_blocks;
+
+	/*
+	 * i_size_read() includes its own seqlocking and protection from
+	 * preemption (see include/linux/fs.h): we need nothing extra for
+	 * that here, and prefer to avoid nesting locks than attempt to
+	 * keep i_size and i_blocks in synch together.
+	 */
+	i_size = i_size_read(src);
+
+	/*
+	 * But if CONFIG_LSF (on 32-bit), we ought to make an effort to keep
+	 * the two halves of i_blocks in synch despite SMP or PREEMPT - though
+	 * stat's generic_fillattr() doesn't bother, and we won't be applying
+	 * quotas (where i_blocks does become important) at the upper level.
+	 *
+	 * We don't actually know what locking is used at the lower level; but
+	 * if it's a filesystem that supports quotas, it will be using i_lock
+	 * as in inode_add_bytes().  tmpfs uses other locking, and its 32-bit
+	 * is (just) able to exceed 2TB i_size with the aid of holes; but its
+	 * i_blocks cannot carry into the upper long without almost 2TB swap -
+	 * let's ignore that case.
+	 */
+	if (sizeof(i_blocks) > sizeof(long))
+		spin_lock(&src->i_lock);
+	i_blocks = src->i_blocks;
+	if (sizeof(i_blocks) > sizeof(long))
+		spin_unlock(&src->i_lock);
+
+	/*
+	 * If CONFIG_SMP on 32-bit, it's vital for fsstack_copy_inode_size()
+	 * to hold some lock around i_size_write(), otherwise i_size_read()
+	 * may spin forever (see include/linux/fs.h).  We don't necessarily
+	 * hold i_mutex when this is called, so take i_lock for that case.
+	 *
+	 * And if CONFIG_LSF (on 32-bit), continue our effort to keep the
+	 * two halves of i_blocks in synch despite SMP or PREEMPT: use i_lock
+	 * for that case too, and do both at once by combining the tests.
+	 *
+	 * There is none of this locking overhead in the 64-bit case.
+	 */
+	if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
+		spin_lock(&dst->i_lock);
+	i_size_write(dst, i_size);
+	dst->i_blocks = i_blocks;
+	if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long))
+		spin_unlock(&dst->i_lock);
 }
 EXPORT_SYMBOL_GPL(fsstack_copy_inode_size);
 
diff --git a/include/linux/fs_stack.h b/include/linux/fs_stack.h
index 6b52faf..6615a52 100644
--- a/include/linux/fs_stack.h
+++ b/include/linux/fs_stack.h
@@ -21,8 +21,7 @@
 
 /* externs for fs/stack.c */
 extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src);
-extern void fsstack_copy_inode_size(struct inode *dst,
-				    const struct inode *src);
+extern void fsstack_copy_inode_size(struct inode *dst, struct inode *src);
 
 /* inlines */
 static inline void fsstack_copy_attr_atime(struct inode *dest,
-- 
1.5.2.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/19] Unionfs: simplify the macros used to get/set the dentry start/end branches
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
  2008-07-30  2:43 ` [PATCH 01/19] LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 03/19] Unionfs: move a rename helper closer to rename code Erez Zadok
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c |    6 ++--
 fs/unionfs/copyup.c     |   14 ++++++------
 fs/unionfs/dentry.c     |    6 +---
 fs/unionfs/fanout.h     |   48 +++++-----------------------------------------
 fs/unionfs/inode.c      |    2 +-
 fs/unionfs/lookup.c     |   18 ++++++----------
 fs/unionfs/main.c       |    4 +-
 fs/unionfs/rename.c     |   10 ++++----
 fs/unionfs/subr.c       |    4 +-
 fs/unionfs/super.c      |    2 +-
 10 files changed, 36 insertions(+), 78 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 631e081..6f61fb0 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -290,7 +290,7 @@ static int do_delayed_copyup(struct file *file)
 	}
 	/* for reg file, we only open it "once" */
 	fbend(file) = fbstart(file);
-	set_dbend(dentry, dbstart(dentry));
+	dbend(dentry) = dbstart(dentry);
 	ibend(dentry->d_inode) = ibstart(dentry->d_inode);
 
 out:
@@ -823,8 +823,8 @@ static int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd,
 		}
 	}
 	/* restore original dentry's offsets */
-	set_dbstart(dentry, orig_bstart);
-	set_dbend(dentry, orig_bend);
+	dbstart(dentry) = orig_bstart;
+	dbend(dentry) = orig_bend;
 	ibstart(dentry->d_inode) = orig_bstart;
 	ibend(dentry->d_inode) = orig_bend;
 
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 6d1e461..b918897 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -354,8 +354,8 @@ static void __clear(struct dentry *dentry, struct dentry *old_lower_dentry,
 {
 	/* get rid of the lower dentry and all its traces */
 	unionfs_set_lower_dentry_idx(dentry, new_bindex, NULL);
-	set_dbstart(dentry, old_bstart);
-	set_dbend(dentry, old_bend);
+	dbstart(dentry) = old_bstart;
+	dbend(dentry) = old_bend;
 
 	dput(new_lower_dentry);
 	dput(old_lower_dentry);
@@ -633,8 +633,8 @@ static void __cleanup_dentry(struct dentry *dentry, int bindex,
 		new_bstart = bindex;
 	if (new_bend < 0)
 		new_bend = bindex;
-	set_dbstart(dentry, new_bstart);
-	set_dbend(dentry, new_bend);
+	dbstart(dentry) = new_bstart;
+	dbend(dentry) = new_bend;
 
 }
 
@@ -657,9 +657,9 @@ static void __set_dentry(struct dentry *upper, struct dentry *lower,
 {
 	unionfs_set_lower_dentry_idx(upper, bindex, lower);
 	if (likely(dbstart(upper) > bindex))
-		set_dbstart(upper, bindex);
+		dbstart(upper) = bindex;
 	if (likely(dbend(upper) < bindex))
-		set_dbend(upper, bindex);
+		dbend(upper) = bindex;
 }
 
 /*
@@ -883,6 +883,6 @@ void unionfs_postcopyup_release(struct dentry *dentry)
 		}
 	}
 	bindex = dbstart(dentry);
-	set_dbend(dentry, bindex);
+	dbend(dentry) = bindex;
 	ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bindex;
 }
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index e5f894c..44b17ce 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -106,8 +106,7 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 		bstart = dbstart(dentry);
 		bend = dbend(dentry);
 		__dput_lowers(dentry, bstart, bend);
-		set_dbstart(dentry, -1);
-		set_dbend(dentry, -1);
+		dbstart(dentry) = dbend(dentry) = -1;
 
 		interpose_flag = INTERPOSE_REVAL_NEG;
 		if (positive) {
@@ -542,8 +541,7 @@ static void unionfs_d_iput(struct dentry *dentry, struct inode *inode)
 			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
 		}
 	}
-	set_dbstart(dentry, -1);
-	set_dbend(dentry, -1);
+	dbstart(dentry) = dbend(dentry) = -1;
 
 drop_lower_inodes:
 	rc = atomic_read(&inode->i_count);
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index 29d42fb..69a8e8f 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -33,6 +33,12 @@ static inline struct unionfs_inode_info *UNIONFS_I(const struct inode *inode)
 #define ibstart(ino) (UNIONFS_I(ino)->bstart)
 #define ibend(ino) (UNIONFS_I(ino)->bend)
 
+/* Dentry to private data */
+#define UNIONFS_D(dent) ((struct unionfs_dentry_info *)(dent)->d_fsdata)
+#define dbstart(dent) (UNIONFS_D(dent)->bstart)
+#define dbend(dent) (UNIONFS_D(dent)->bend)
+#define dbopaque(dent) (UNIONFS_D(dent)->bopaque)
+
 /* Superblock to private data */
 #define UNIONFS_SB(super) ((struct unionfs_sb_info *)(super)->s_fs_info)
 #define sbstart(sb) 0
@@ -199,48 +205,6 @@ static inline void branchput(struct super_block *sb, int index)
 }
 
 /* Dentry macros */
-static inline struct unionfs_dentry_info *UNIONFS_D(const struct dentry *dent)
-{
-	BUG_ON(!dent);
-	return dent->d_fsdata;
-}
-
-static inline int dbstart(const struct dentry *dent)
-{
-	BUG_ON(!dent);
-	return UNIONFS_D(dent)->bstart;
-}
-
-static inline void set_dbstart(struct dentry *dent, int val)
-{
-	BUG_ON(!dent);
-	UNIONFS_D(dent)->bstart = val;
-}
-
-static inline int dbend(const struct dentry *dent)
-{
-	BUG_ON(!dent);
-	return UNIONFS_D(dent)->bend;
-}
-
-static inline void set_dbend(struct dentry *dent, int val)
-{
-	BUG_ON(!dent);
-	UNIONFS_D(dent)->bend = val;
-}
-
-static inline int dbopaque(const struct dentry *dent)
-{
-	BUG_ON(!dent);
-	return UNIONFS_D(dent)->bopaque;
-}
-
-static inline void set_dbopaque(struct dentry *dent, int val)
-{
-	BUG_ON(!dent);
-	UNIONFS_D(dent)->bopaque = val;
-}
-
 static inline void unionfs_set_lower_dentry_idx(struct dentry *dent, int index,
 						struct dentry *val)
 {
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index a1d7aaf..8b4da54 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -644,7 +644,7 @@ static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode)
 				unionfs_set_lower_dentry_idx(dentry, i, NULL);
 			}
 		}
-		set_dbend(dentry, bindex);
+		dbend(dentry) = bindex;
 
 		/*
 		 * Only INTERPOSE_LOOKUP can return a value other than 0 on
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 7f512c2..33be53c 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -206,8 +206,7 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 		if (wh_lower_dentry->d_inode) {
 			/* We found a whiteout so let's give up. */
 			if (S_ISREG(wh_lower_dentry->d_inode->i_mode)) {
-				set_dbend(dentry, bindex);
-				set_dbopaque(dentry, bindex);
+				dbend(dentry) = dbopaque(dentry) = bindex;
 				dput(wh_lower_dentry);
 				break;
 			}
@@ -276,7 +275,7 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 
 		/* store underlying dentry */
 		if (dbstart(dentry) == -1)
-			set_dbstart(dentry, bindex);
+			dbstart(dentry) = bindex;
 		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
 		/*
 		 * FIXME: the following line needs to get fixed to allow
@@ -285,7 +284,7 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 		unionfs_set_lower_mnt_idx(dentry, bindex,
 					  unionfs_mntget(parent_dentry,
 							 bindex));
-		set_dbend(dentry, bindex);
+		dbend(dentry) = bindex;
 
 		/* update parent directory's atime with the bindex */
 		fsstack_copy_attr_atime(parent_dentry->d_inode,
@@ -306,8 +305,7 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 			err = opaque;
 			goto out_free;
 		} else if (opaque) {
-			set_dbend(dentry, bindex);
-			set_dbopaque(dentry, bindex);
+			dbend(dentry) = dbopaque(dentry) = bindex;
 			break;
 		}
 	}
@@ -353,8 +351,7 @@ out_negative:
 				     first_lower_dentry);
 	unionfs_set_lower_mnt_idx(dentry, first_dentry_offset,
 				  first_lower_mnt);
-	set_dbstart(dentry, first_dentry_offset);
-	set_dbend(dentry, first_dentry_offset);
+	dbstart(dentry) = dbend(dentry) = first_dentry_offset;
 
 	if (lookupmode == INTERPOSE_REVAL_NEG)
 		BUG_ON(dentry->d_inode != NULL);
@@ -421,8 +418,7 @@ out_free:
 	}
 	kfree(UNIONFS_D(dentry)->lower_paths);
 	UNIONFS_D(dentry)->lower_paths = NULL;
-	set_dbstart(dentry, -1);
-	set_dbend(dentry, -1);
+	dbstart(dentry) = dbend(dentry) = -1;
 
 out:
 	if (!err && UNIONFS_D(dentry)) {
@@ -582,7 +578,7 @@ void update_bstart(struct dentry *dentry)
 		if (!lower_dentry)
 			continue;
 		if (lower_dentry->d_inode) {
-			set_dbstart(dentry, bindex);
+			dbstart(dentry) = bindex;
 			break;
 		}
 		dput(lower_dentry);
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index b76264a..b8f84bb 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -675,8 +675,8 @@ static int unionfs_read_super(struct super_block *sb, void *raw_data,
 		unionfs_set_lower_dentry_idx(sb->s_root, bindex, d);
 		unionfs_set_lower_mnt_idx(sb->s_root, bindex, m);
 	}
-	set_dbstart(sb->s_root, bstart);
-	set_dbend(sb->s_root, bend);
+	dbstart(sb->s_root) = bstart;
+	dbend(sb->s_root) = bend;
 
 	/* Set the generation number to one, since this is for the mount. */
 	atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index cc16eb2..fe8d877 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -156,9 +156,9 @@ out:
 	if (!err) {
 		/* Fixup the new_dentry. */
 		if (bindex < dbstart(new_dentry))
-			set_dbstart(new_dentry, bindex);
+			dbstart(new_dentry) = bindex;
 		else if (bindex > dbend(new_dentry))
-			set_dbend(new_dentry, bindex);
+			dbend(new_dentry) = bindex;
 	}
 
 	kfree(wh_name);
@@ -298,7 +298,7 @@ static int do_unionfs_rename(struct inode *old_dir,
 				       &nd);
 		unlock_dir(lower_parent);
 		if (!local_err) {
-			set_dbopaque(old_dentry, bwh_old);
+			dbopaque(old_dentry) = bwh_old;
 		} else {
 			/*
 			 * we can't fix anything now, so we cop-out and use
@@ -426,9 +426,9 @@ static int may_rename_dir(struct dentry *dentry)
 	if (dbend(dentry) == bstart || dbopaque(dentry) == bstart)
 		return 0;
 
-	set_dbstart(dentry, bstart + 1);
+	dbstart(dentry) = bstart + 1;
 	err = check_empty(dentry, NULL);
-	set_dbstart(dentry, bstart);
+	dbstart(dentry) = bstart;
 	if (err == -ENOTEMPTY)
 		err = -EXDEV;
 	return err;
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index 1a40f63..b76fa7a 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -107,7 +107,7 @@ int create_whiteout(struct dentry *dentry, int start)
 
 	/* set dbopaque so that lookup will not proceed after this branch */
 	if (!err)
-		set_dbopaque(dentry, bindex);
+		dbopaque(dentry) = bindex;
 
 out:
 	kfree(name);
@@ -195,7 +195,7 @@ int make_dir_opaque(struct dentry *dentry, int bindex)
 	if (!diropq->d_inode)
 		err = vfs_create(lower_dir, diropq, S_IRUGO, &nd);
 	if (!err)
-		set_dbopaque(dentry, bindex);
+		dbopaque(dentry) = bindex;
 	release_lower_nd(&nd, err);
 
 	dput(diropq);
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index b110760..1a172af 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -771,7 +771,7 @@ out_no_change:
 	/* update our unionfs_sb_info and root dentry index of last branch */
 	i = sbmax(sb);		/* save no. of branches to release at end */
 	sbend(sb) = new_branches - 1;
-	set_dbend(sb->s_root, new_branches - 1);
+	dbend(sb->s_root) = new_branches - 1;
 	old_ibstart = ibstart(sb->s_root->d_inode);
 	old_ibend = ibend(sb->s_root->d_inode);
 	ibend(sb->s_root->d_inode) = new_branches - 1;
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/19] Unionfs: move a rename helper closer to rename code
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
  2008-07-30  2:43 ` [PATCH 01/19] LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a Erez Zadok
  2008-07-30  2:43 ` [PATCH 02/19] Unionfs: simplify the macros used to get/set the dentry start/end branches Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 04/19] Unionfs: create and consolidate helpers to iput lower objects Erez Zadok
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/rename.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 fs/unionfs/subr.c   |   42 ------------------------------------------
 fs/unionfs/union.h  |    3 ---
 3 files changed, 42 insertions(+), 45 deletions(-)

diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index fe8d877..5b3f1a3 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -18,6 +18,48 @@
 
 #include "union.h"
 
+/*
+ * This is a helper function for rename, used when rename ends up with hosed
+ * over dentries and we need to revert.
+ */
+static int unionfs_refresh_lower_dentry(struct dentry *dentry, int bindex)
+{
+	struct dentry *lower_dentry;
+	struct dentry *lower_parent;
+	int err = 0;
+
+	verify_locked(dentry);
+
+	unionfs_lock_dentry(dentry->d_parent, UNIONFS_DMUTEX_CHILD);
+	lower_parent = unionfs_lower_dentry_idx(dentry->d_parent, bindex);
+	unionfs_unlock_dentry(dentry->d_parent);
+
+	BUG_ON(!S_ISDIR(lower_parent->d_inode->i_mode));
+
+	lower_dentry = lookup_one_len(dentry->d_name.name, lower_parent,
+				      dentry->d_name.len);
+	if (IS_ERR(lower_dentry)) {
+		err = PTR_ERR(lower_dentry);
+		goto out;
+	}
+
+	dput(unionfs_lower_dentry_idx(dentry, bindex));
+	iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
+	unionfs_set_lower_inode_idx(dentry->d_inode, bindex, NULL);
+
+	if (!lower_dentry->d_inode) {
+		dput(lower_dentry);
+		unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+	} else {
+		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
+		unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
+					    igrab(lower_dentry->d_inode));
+	}
+
+out:
+	return err;
+}
+
 static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			    struct inode *new_dir, struct dentry *new_dentry,
 			    int bindex, struct dentry **wh_old)
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index b76fa7a..1f1db3d 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -114,48 +114,6 @@ out:
 	return err;
 }
 
-/*
- * This is a helper function for rename, which ends up with hosed over
- * dentries when it needs to revert.
- */
-int unionfs_refresh_lower_dentry(struct dentry *dentry, int bindex)
-{
-	struct dentry *lower_dentry;
-	struct dentry *lower_parent;
-	int err = 0;
-
-	verify_locked(dentry);
-
-	unionfs_lock_dentry(dentry->d_parent, UNIONFS_DMUTEX_CHILD);
-	lower_parent = unionfs_lower_dentry_idx(dentry->d_parent, bindex);
-	unionfs_unlock_dentry(dentry->d_parent);
-
-	BUG_ON(!S_ISDIR(lower_parent->d_inode->i_mode));
-
-	lower_dentry = lookup_one_len(dentry->d_name.name, lower_parent,
-				      dentry->d_name.len);
-	if (IS_ERR(lower_dentry)) {
-		err = PTR_ERR(lower_dentry);
-		goto out;
-	}
-
-	dput(unionfs_lower_dentry_idx(dentry, bindex));
-	iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
-	unionfs_set_lower_inode_idx(dentry->d_inode, bindex, NULL);
-
-	if (!lower_dentry->d_inode) {
-		dput(lower_dentry);
-		unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-	} else {
-		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
-		unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
-					    igrab(lower_dentry->d_inode));
-	}
-
-out:
-	return err;
-}
-
 int make_dir_opaque(struct dentry *dentry, int bindex)
 {
 	int err = 0;
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index edd5685..7ddbad1 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -346,9 +346,6 @@ extern int check_empty(struct dentry *dentry,
 extern int delete_whiteouts(struct dentry *dentry, int bindex,
 			    struct unionfs_dir_state *namelist);
 
-/* Re-lookup a lower dentry. */
-extern int unionfs_refresh_lower_dentry(struct dentry *dentry, int bindex);
-
 extern void unionfs_reinterpose(struct dentry *this_dentry);
 extern struct super_block *unionfs_duplicate_super(struct super_block *sb);
 
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/19] Unionfs: create and consolidate helpers to iput lower objects
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (2 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 03/19] Unionfs: move a rename helper closer to rename code Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 05/19] Unionfs: create and consolidate helpers to path-put " Erez Zadok
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c |    5 +---
 fs/unionfs/copyup.c     |    5 +--
 fs/unionfs/dentry.c     |   25 +-----------------------
 fs/unionfs/fanout.h     |   49 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/unionfs/super.c      |    6 +----
 fs/unionfs/unlink.c     |   22 ++------------------
 6 files changed, 57 insertions(+), 55 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 6f61fb0..585c5c9 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -280,14 +280,11 @@ static int do_delayed_copyup(struct file *file)
 			unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
 		}
 		if (unionfs_lower_dentry_idx(dentry, bindex)) {
-			BUG_ON(!dentry->d_inode);
-			iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
-			unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
-						    NULL);
 			dput(unionfs_lower_dentry_idx(dentry, bindex));
 			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
 		}
 	}
+	iput_lowers(dentry->d_inode, bstart, bend, false);
 	/* for reg file, we only open it "once" */
 	fbend(file) = fbstart(file);
 	dbend(dentry) = dbstart(dentry);
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index b918897..f20b984 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -877,11 +877,10 @@ void unionfs_postcopyup_release(struct dentry *dentry)
 		if (unionfs_lower_dentry_idx(dentry, bindex)) {
 			dput(unionfs_lower_dentry_idx(dentry, bindex));
 			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-			iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
-			unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
-						    NULL);
 		}
 	}
+	iput_lowers(dentry->d_inode, dbstart(dentry)+1, dbend(dentry), false);
+
 	bindex = dbstart(dentry);
 	dbend(dentry) = bindex;
 	ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bindex;
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index 44b17ce..a7960ac 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -35,22 +35,6 @@ static inline void __dput_lowers(struct dentry *dentry, int start, int end)
 	}
 }
 
-static inline void __iput_lowers(struct inode *inode, int start, int end)
-{
-	struct inode *lower_inode;
-	int bindex;
-
-	if (start < 0)
-		return;
-	for (bindex = start; bindex <= end; bindex++) {
-		lower_inode = unionfs_lower_inode_idx(inode, bindex);
-		if (!lower_inode)
-			continue;
-		unionfs_set_lower_inode_idx(inode, bindex, NULL);
-		iput(lower_inode);
-	}
-}
-
 /*
  * Revalidate a single dentry.
  * Assume that dentry's info node is locked.
@@ -111,14 +95,7 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 		interpose_flag = INTERPOSE_REVAL_NEG;
 		if (positive) {
 			interpose_flag = INTERPOSE_REVAL;
-
-			bstart = ibstart(dentry->d_inode);
-			bend = ibend(dentry->d_inode);
-			__iput_lowers(dentry->d_inode, bstart, bend);
-			kfree(UNIONFS_I(dentry->d_inode)->lower_inodes);
-			UNIONFS_I(dentry->d_inode)->lower_inodes = NULL;
-			ibstart(dentry->d_inode) = -1;
-			ibend(dentry->d_inode) = -1;
+			iput_lowers_all(dentry->d_inode, true);
 		}
 
 		result = unionfs_lookup_backend(dentry, &lowernd,
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index 69a8e8f..94421f8 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -277,4 +277,53 @@ static inline void verify_locked(struct dentry *d)
 	BUG_ON(!mutex_is_locked(&UNIONFS_D(d)->lock));
 }
 
+/* macros to put lower objects */
+
+/*
+ * iput lower inodes of an unionfs dentry, from bstart to bend.  If
+ * @free_lower is true, then also kfree the memory used to hold the lower
+ * object pointers.
+ */
+static inline void iput_lowers(struct inode *inode,
+			       int bstart, int bend, bool free_lower)
+{
+	struct inode *lower_inode;
+	int bindex;
+
+	BUG_ON(!inode);
+	BUG_ON(!UNIONFS_I(inode));
+	BUG_ON(bstart < 0);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		lower_inode = unionfs_lower_inode_idx(inode, bindex);
+		if (lower_inode) {
+			unionfs_set_lower_inode_idx(inode, bindex, NULL);
+			/* see Documentation/filesystems/unionfs/issues.txt */
+			lockdep_off();
+			iput(lower_inode);
+			lockdep_on();
+		}
+	}
+
+	if (free_lower) {
+		kfree(UNIONFS_I(inode)->lower_inodes);
+		UNIONFS_I(inode)->lower_inodes = NULL;
+	}
+}
+
+/* iput all lower inodes, and reset start/end branch indices to -1 */
+static inline void iput_lowers_all(struct inode *inode, bool free_lower)
+{
+	int bstart, bend;
+
+	BUG_ON(!inode);
+	BUG_ON(!UNIONFS_I(inode));
+	bstart = ibstart(inode);
+	bend = ibend(inode);
+	BUG_ON(bstart < 0);
+
+	iput_lowers(inode, bstart, bend, free_lower);
+	ibstart(inode) = ibend(inode) = -1;
+}
+
 #endif	/* not _FANOUT_H */
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 1a172af..9715529 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -789,11 +789,7 @@ out_no_change:
 		new_lower_inodes[i] = lower_dentry->d_inode;
 	}
 	/* 2. release reference on all older lower inodes */
-	for (i = old_ibstart; i <= old_ibend; i++) {
-		iput(unionfs_lower_inode_idx(sb->s_root->d_inode, i));
-		unionfs_set_lower_inode_idx(sb->s_root->d_inode, i, NULL);
-	}
-	kfree(UNIONFS_I(sb->s_root->d_inode)->lower_inodes);
+	iput_lowers(sb->s_root->d_inode, old_ibstart, old_ibend, true);
 	/* 3. update root dentry's inode to new lower_inodes array */
 	UNIONFS_I(sb->s_root->d_inode)->lower_inodes = new_lower_inodes;
 	new_lower_inodes = NULL;
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index cad0386..3d6ca5f 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -146,12 +146,8 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
 	/* call d_drop so the system "forgets" about us */
 	if (!err) {
 		unionfs_postcopyup_release(dentry);
-		if (inode->i_nlink == 0) {
-			/* drop lower inodes */
-			iput(unionfs_lower_inode(inode));
-			unionfs_set_lower_inode(inode, NULL);
-			ibstart(inode) = ibend(inode) = -1;
-		}
+		if (inode->i_nlink == 0) /* drop lower inodes */
+			iput_lowers_all(inode, false);
 		d_drop(dentry);
 		/*
 		 * if unlink/whiteout succeeded, parent dir mtime has
@@ -264,21 +260,9 @@ out:
 	 * about us.
 	 */
 	if (!err) {
-		struct inode *inode = dentry->d_inode;
-		BUG_ON(!inode);
-		iput(unionfs_lower_inode_idx(inode, dstart));
-		unionfs_set_lower_inode_idx(inode, dstart, NULL);
+		iput_lowers_all(dentry->d_inode, false);
 		dput(unionfs_lower_dentry_idx(dentry, dstart));
 		unionfs_set_lower_dentry_idx(dentry, dstart, NULL);
-		/*
-		 * If the last directory is unlinked, then mark istart/end
-		 * as -1, (to maintain the invariant that if there are no
-		 * lower objects, then branch index start and end are set to
-		 * -1).
-		 */
-		if (!unionfs_lower_inode_idx(inode, dstart) &&
-		    !unionfs_lower_inode_idx(inode, dend))
-			ibstart(inode) = ibend(inode) = -1;
 		d_drop(dentry);
 		/* update our lower vfsmnts, in case a copyup took place */
 		unionfs_postcopyup_setmnt(dentry);
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/19] Unionfs: create and consolidate helpers to path-put lower objects
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (3 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 04/19] Unionfs: create and consolidate helpers to iput lower objects Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 06/19] Unionfs: simplify stale-inode detection code Erez Zadok
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c |    9 +------
 fs/unionfs/copyup.c     |   23 ++++++------------
 fs/unionfs/dentry.c     |   31 ++------------------------
 fs/unionfs/fanout.h     |   55 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/unionfs/lookup.c     |   14 +++--------
 5 files changed, 71 insertions(+), 61 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 585c5c9..5816d41 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -275,15 +275,8 @@ static int do_delayed_copyup(struct file *file)
 			fput(unionfs_lower_file_idx(file, bindex));
 			unionfs_set_lower_file_idx(file, bindex, NULL);
 		}
-		if (unionfs_lower_mnt_idx(dentry, bindex)) {
-			unionfs_mntput(dentry, bindex);
-			unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
-		}
-		if (unionfs_lower_dentry_idx(dentry, bindex)) {
-			dput(unionfs_lower_dentry_idx(dentry, bindex));
-			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-		}
 	}
+	path_put_lowers(dentry, bstart, bend, false);
 	iput_lowers(dentry->d_inode, bstart, bend, false);
 	/* for reg file, we only open it "once" */
 	fbend(file) = fbstart(file);
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index f20b984..55d48aa 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -866,22 +866,15 @@ void unionfs_postcopyup_setmnt(struct dentry *dentry)
  */
 void unionfs_postcopyup_release(struct dentry *dentry)
 {
-	int bindex;
+	int bstart, bend;
 
 	BUG_ON(S_ISDIR(dentry->d_inode->i_mode));
-	for (bindex = dbstart(dentry)+1; bindex <= dbend(dentry); bindex++) {
-		if (unionfs_lower_mnt_idx(dentry, bindex)) {
-			unionfs_mntput(dentry, bindex);
-			unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
-		}
-		if (unionfs_lower_dentry_idx(dentry, bindex)) {
-			dput(unionfs_lower_dentry_idx(dentry, bindex));
-			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-		}
-	}
-	iput_lowers(dentry->d_inode, dbstart(dentry)+1, dbend(dentry), false);
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+
+	path_put_lowers(dentry, bstart + 1, bend, false);
+	iput_lowers(dentry->d_inode, bstart + 1, bend, false);
 
-	bindex = dbstart(dentry);
-	dbend(dentry) = bindex;
-	ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bindex;
+	dbend(dentry) = bstart;
+	ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bstart;
 }
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index a7960ac..51c0baf 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -455,8 +455,6 @@ static int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 
 static void unionfs_d_release(struct dentry *dentry)
 {
-	int bindex, bstart, bend;
-
 	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
 	if (unlikely(!UNIONFS_D(dentry)))
 		goto out;	/* skip if no lower branches */
@@ -471,20 +469,7 @@ static void unionfs_d_release(struct dentry *dentry)
 	}
 
 	/* Release all the lower dentries */
-	bstart = dbstart(dentry);
-	bend = dbend(dentry);
-	for (bindex = bstart; bindex <= bend; bindex++) {
-		dput(unionfs_lower_dentry_idx(dentry, bindex));
-		unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-		/* NULL lower mnt is ok if this is a negative dentry */
-		if (!dentry->d_inode && !unionfs_lower_mnt_idx(dentry, bindex))
-			continue;
-		unionfs_mntput(dentry, bindex);
-		unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
-	}
-	/* free private data (unionfs_dentry_info) here */
-	kfree(UNIONFS_D(dentry)->lower_paths);
-	UNIONFS_D(dentry)->lower_paths = NULL;
+	path_put_lowers_all(dentry, true);
 
 	unionfs_unlock_dentry(dentry);
 
@@ -500,7 +485,7 @@ out:
  */
 static void unionfs_d_iput(struct dentry *dentry, struct inode *inode)
 {
-	int bindex, rc;
+	int rc;
 
 	BUG_ON(!dentry);
 	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
@@ -508,17 +493,7 @@ static void unionfs_d_iput(struct dentry *dentry, struct inode *inode)
 
 	if (!UNIONFS_D(dentry) || dbstart(dentry) < 0)
 		goto drop_lower_inodes;
-	for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
-		if (unionfs_lower_mnt_idx(dentry, bindex)) {
-			unionfs_mntput(dentry, bindex);
-			unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
-		}
-		if (unionfs_lower_dentry_idx(dentry, bindex)) {
-			dput(unionfs_lower_dentry_idx(dentry, bindex));
-			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
-		}
-	}
-	dbstart(dentry) = dbend(dentry) = -1;
+	path_put_lowers_all(dentry, false);
 
 drop_lower_inodes:
 	rc = atomic_read(&inode->i_count);
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index 94421f8..d8977bd 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -326,4 +326,59 @@ static inline void iput_lowers_all(struct inode *inode, bool free_lower)
 	ibstart(inode) = ibend(inode) = -1;
 }
 
+/*
+ * dput/mntput all lower dentries and vfsmounts of an unionfs dentry, from
+ * bstart to bend.  If @free_lower is true, then also kfree the memory used
+ * to hold the lower object pointers.
+ *
+ * XXX: implement using path_put VFS macros
+ */
+static inline void path_put_lowers(struct dentry *dentry,
+				   int bstart, int bend, bool free_lower)
+{
+	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
+	int bindex;
+
+	BUG_ON(!dentry);
+	BUG_ON(!UNIONFS_D(dentry));
+	BUG_ON(bstart < 0);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+		if (lower_dentry) {
+			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+			dput(lower_dentry);
+		}
+		lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
+		if (lower_mnt) {
+			unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
+			mntput(lower_mnt);
+		}
+	}
+
+	if (free_lower) {
+		kfree(UNIONFS_D(dentry)->lower_paths);
+		UNIONFS_D(dentry)->lower_paths = NULL;
+	}
+}
+
+/*
+ * dput/mntput all lower dentries and vfsmounts, and reset start/end branch
+ * indices to -1.
+ */
+static inline void path_put_lowers_all(struct dentry *dentry, bool free_lower)
+{
+	int bstart, bend;
+
+	BUG_ON(!dentry);
+	BUG_ON(!UNIONFS_D(dentry));
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+	BUG_ON(bstart < 0);
+
+	path_put_lowers(dentry, bstart, bend, free_lower);
+	dbstart(dentry) = dbend(dentry) = -1;
+}
+
 #endif	/* not _FANOUT_H */
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 33be53c..f6bb748 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -407,18 +407,12 @@ out_drop:
 	d_drop(dentry);
 
 out_free:
-	/* should dput all the underlying dentries on error condition */
-	bstart = dbstart(dentry);
-	if (bstart >= 0) {
-		bend = dbend(dentry);
-		for (bindex = bstart; bindex <= bend; bindex++) {
-			dput(unionfs_lower_dentry_idx(dentry, bindex));
-			unionfs_mntput(dentry, bindex);
-		}
-	}
+	/* should dput/mntput all the underlying dentries on error condition */
+	if (dbstart(dentry) >= 0)
+		path_put_lowers_all(dentry, false);
+	/* free lower_paths unconditionally */
 	kfree(UNIONFS_D(dentry)->lower_paths);
 	UNIONFS_D(dentry)->lower_paths = NULL;
-	dbstart(dentry) = dbend(dentry) = -1;
 
 out:
 	if (!err && UNIONFS_D(dentry)) {
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/19] Unionfs: simplify stale-inode detection code
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (4 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 05/19] Unionfs: create and consolidate helpers to path-put " Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 07/19] Unionfs: overhaul whiteout code Erez Zadok
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/dentry.c |   16 +++++++++++++++-
 fs/unionfs/lookup.c |   10 ++--------
 fs/unionfs/main.c   |   14 +-------------
 fs/unionfs/union.h  |    2 +-
 4 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index 51c0baf..cd4611b 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -18,6 +18,20 @@
 
 #include "union.h"
 
+bool is_negative_lower(const struct dentry *dentry)
+{
+	int bindex;
+	struct dentry *lower_dentry;
+
+	BUG_ON(!dentry || dbstart(dentry) < 0);
+	for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
+		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+		/* XXX: what if lower_dentry is NULL? */
+		if (lower_dentry && lower_dentry->d_inode)
+			return false;
+	}
+	return true;
+}
 
 static inline void __dput_lowers(struct dentry *dentry, int start, int end)
 {
@@ -113,7 +127,7 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 			dentry = result;
 		}
 
-		if (unlikely(positive && UNIONFS_I(dentry->d_inode)->stale)) {
+		if (unlikely(positive && is_negative_lower(dentry))) {
 			make_bad_inode(dentry->d_inode);
 			d_drop(dentry);
 			valid = false;
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index f6bb748..1ba7103 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -320,11 +320,9 @@ out_negative:
 		goto out;
 
 	/* If we've only got negative dentries, then use the leftmost one. */
-	if (lookupmode == INTERPOSE_REVAL) {
-		if (dentry->d_inode)
-			UNIONFS_I(dentry->d_inode)->stale = 1;
+	if (lookupmode == INTERPOSE_REVAL)
 		goto out;
-	}
+
 	if (!lower_dir_dentry) {
 		err = -ENOENT;
 		goto out;
@@ -424,7 +422,6 @@ out:
 		     !UNIONFS_I(dentry->d_inode)->lower_inodes)) {
 			unionfs_mntput(dentry->d_sb->s_root, bstart);
 			dput(first_lower_dentry);
-			UNIONFS_I(dentry->d_inode)->stale = 1;
 		}
 	}
 	kfree(whname);
@@ -433,9 +430,6 @@ out:
 		unionfs_unlock_dentry(dentry);
 	if (!err && d_interposed)
 		return d_interposed;
-	if (dentry->d_inode && UNIONFS_I(dentry->d_inode)->stale &&
-	    first_dentry_offset >= 0)
-		unionfs_mntput(dentry->d_sb->s_root, first_dentry_offset);
 	return ERR_PTR(err);
 }
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index b8f84bb..a9d2cb6 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -83,25 +83,13 @@ struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block *sb,
 {
 	int err = 0;
 	struct inode *inode;
-	int is_negative_dentry = 1;
-	int bindex, bstart, bend;
 	int need_fill_inode = 1;
 	struct dentry *spliced = NULL;
 
 	verify_locked(dentry);
 
-	bstart = dbstart(dentry);
-	bend = dbend(dentry);
-
 	/* Make sure that we didn't get a negative dentry. */
-	for (bindex = bstart; bindex <= bend; bindex++) {
-		if (unionfs_lower_dentry_idx(dentry, bindex) &&
-		    unionfs_lower_dentry_idx(dentry, bindex)->d_inode) {
-			is_negative_dentry = 0;
-			break;
-		}
-	}
-	BUG_ON(is_negative_dentry);
+	BUG_ON(is_negative_lower(dentry));
 
 	/*
 	 * We allocate our new inode below by calling unionfs_iget,
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 7ddbad1..f5cf09b 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -99,7 +99,6 @@ struct unionfs_inode_info {
 	int bstart;
 	int bend;
 	atomic_t generation;
-	int stale;
 	/* Stuff for readdir over NFS. */
 	spinlock_t rdlock;
 	struct list_head readdircache;
@@ -377,6 +376,7 @@ extern bool __unionfs_d_revalidate_one_locked(struct dentry *dentry,
 					      bool willwrite);
 extern bool __unionfs_d_revalidate_chain(struct dentry *dentry,
 					 struct nameidata *nd, bool willwrite);
+extern bool is_negative_lower(const struct dentry *dentry);
 extern bool is_newer_lower(const struct dentry *dentry);
 extern void purge_sb_data(struct super_block *sb);
 
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/19] Unionfs: overhaul whiteout code
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (5 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 06/19] Unionfs: simplify stale-inode detection code Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 08/19] Unionfs: lookup overhaul using vfs_path_lookup Erez Zadok
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Move all whiteout functions and helpers into a separate file, replace all
embedded whiteout code with calls to helpers.  Cleanup and consolidate the
code.  This will make it easier to replace the whiteout code with a
Linux-native whiteout implementation (once available).

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/Makefile    |    2 +-
 fs/unionfs/dirfops.c   |   22 +-
 fs/unionfs/dirhelper.c |  124 +----------
 fs/unionfs/inode.c     |  183 ++-------------
 fs/unionfs/lookup.c    |   85 +-------
 fs/unionfs/rename.c    |  149 ++-----------
 fs/unionfs/sioq.c      |   18 --
 fs/unionfs/subr.c      |  161 --------------
 fs/unionfs/super.c     |    2 +-
 fs/unionfs/union.h     |   40 ++---
 fs/unionfs/whiteout.c  |  577 ++++++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 655 insertions(+), 708 deletions(-)
 create mode 100644 fs/unionfs/whiteout.c

diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
index 17ca4a7..0dc28c1 100644
--- a/fs/unionfs/Makefile
+++ b/fs/unionfs/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_UNION_FS) += unionfs.o
 
 unionfs-y := subr.o dentry.o file.o inode.o main.o super.o \
 	rdstate.o copyup.o dirhelper.o rename.o unlink.o \
-	lookup.o commonfops.o dirfops.o sioq.o mmap.o
+	lookup.o commonfops.o dirfops.o sioq.o mmap.o whiteout.o
 
 unionfs-$(CONFIG_UNION_FS_XATTR) += xattr.o
 
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 8272fb6..e35afa4 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -36,37 +36,33 @@ struct unionfs_getdents_callback {
 };
 
 /* based on generic filldir in fs/readir.c */
-static int unionfs_filldir(void *dirent, const char *name, int namelen,
+static int unionfs_filldir(void *dirent, const char *oname, int namelen,
 			   loff_t offset, u64 ino, unsigned int d_type)
 {
 	struct unionfs_getdents_callback *buf = dirent;
 	struct filldir_node *found = NULL;
 	int err = 0;
-	int is_wh_entry = 0;
+	int is_whiteout;
+	char *name = (char *) oname;
 
 	buf->filldir_called++;
 
-	if ((namelen > UNIONFS_WHLEN) &&
-	    !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
-		name += UNIONFS_WHLEN;
-		namelen -= UNIONFS_WHLEN;
-		is_wh_entry = 1;
-	}
+	is_whiteout = is_whiteout_name(&name, &namelen);
 
-	found = find_filldir_node(buf->rdstate, name, namelen, is_wh_entry);
+	found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout);
 
 	if (found) {
 		/*
 		 * If we had non-whiteout entry in dir cache, then mark it
 		 * as a whiteout and but leave it in the dir cache.
 		 */
-		if (is_wh_entry && !found->whiteout)
-			found->whiteout = is_wh_entry;
+		if (is_whiteout && !found->whiteout)
+			found->whiteout = is_whiteout;
 		goto out;
 	}
 
 	/* if 'name' isn't a whiteout, filldir it. */
-	if (!is_wh_entry) {
+	if (!is_whiteout) {
 		off_t pos = rdstate2offset(buf->rdstate);
 		u64 unionfs_ino = ino;
 
@@ -85,7 +81,7 @@ static int unionfs_filldir(void *dirent, const char *name, int namelen,
 	}
 	buf->entries_written++;
 	err = add_filldir_node(buf->rdstate, name, namelen,
-			       buf->rdstate->bindex, is_wh_entry);
+			       buf->rdstate->bindex, is_whiteout);
 	if (err)
 		buf->filldir_error = err;
 
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 4b73bb6..302a4a1 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -18,112 +18,6 @@
 
 #include "union.h"
 
-/*
- * Delete all of the whiteouts in a given directory for rmdir.
- *
- * lower directory inode should be locked
- */
-int do_delete_whiteouts(struct dentry *dentry, int bindex,
-			struct unionfs_dir_state *namelist)
-{
-	int err = 0;
-	struct dentry *lower_dir_dentry = NULL;
-	struct dentry *lower_dentry;
-	char *name = NULL, *p;
-	struct inode *lower_dir;
-	int i;
-	struct list_head *pos;
-	struct filldir_node *cursor;
-
-	/* Find out lower parent dentry */
-	lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-	BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
-	lower_dir = lower_dir_dentry->d_inode;
-	BUG_ON(!S_ISDIR(lower_dir->i_mode));
-
-	err = -ENOMEM;
-	name = __getname();
-	if (unlikely(!name))
-		goto out;
-	strcpy(name, UNIONFS_WHPFX);
-	p = name + UNIONFS_WHLEN;
-
-	err = 0;
-	for (i = 0; !err && i < namelist->size; i++) {
-		list_for_each(pos, &namelist->list[i]) {
-			cursor =
-				list_entry(pos, struct filldir_node,
-					   file_list);
-			/* Only operate on whiteouts in this branch. */
-			if (cursor->bindex != bindex)
-				continue;
-			if (!cursor->whiteout)
-				continue;
-
-			strcpy(p, cursor->name);
-			lower_dentry =
-				lookup_one_len(name, lower_dir_dentry,
-					       cursor->namelen +
-					       UNIONFS_WHLEN);
-			if (IS_ERR(lower_dentry)) {
-				err = PTR_ERR(lower_dentry);
-				break;
-			}
-			if (lower_dentry->d_inode)
-				err = vfs_unlink(lower_dir, lower_dentry);
-			dput(lower_dentry);
-			if (err)
-				break;
-		}
-	}
-
-	__putname(name);
-
-	/* After all of the removals, we should copy the attributes once. */
-	fsstack_copy_attr_times(dentry->d_inode, lower_dir_dentry->d_inode);
-
-out:
-	return err;
-}
-
-/* delete whiteouts in a dir (for rmdir operation) using sioq if necessary */
-int delete_whiteouts(struct dentry *dentry, int bindex,
-		     struct unionfs_dir_state *namelist)
-{
-	int err;
-	struct super_block *sb;
-	struct dentry *lower_dir_dentry;
-	struct inode *lower_dir;
-	struct sioq_args args;
-
-	sb = dentry->d_sb;
-
-	BUG_ON(!S_ISDIR(dentry->d_inode->i_mode));
-	BUG_ON(bindex < dbstart(dentry));
-	BUG_ON(bindex > dbend(dentry));
-	err = is_robranch_super(sb, bindex);
-	if (err)
-		goto out;
-
-	lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-	BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
-	lower_dir = lower_dir_dentry->d_inode;
-	BUG_ON(!S_ISDIR(lower_dir->i_mode));
-
-	if (!permission(lower_dir, MAY_WRITE | MAY_EXEC, NULL)) {
-		err = do_delete_whiteouts(dentry, bindex, namelist);
-	} else {
-		args.deletewh.namelist = namelist;
-		args.deletewh.dentry = dentry;
-		args.deletewh.bindex = bindex;
-		run_sioq(__delete_whiteouts, &args);
-		err = args.err;
-	}
-
-out:
-	return err;
-}
-
 #define RD_NONE 0
 #define RD_CHECK_EMPTY 1
 /* The callback structure for check_empty. */
@@ -135,13 +29,14 @@ struct unionfs_rdutil_callback {
 };
 
 /* This filldir function makes sure only whiteouts exist within a directory. */
-static int readdir_util_callback(void *dirent, const char *name, int namelen,
+static int readdir_util_callback(void *dirent, const char *oname, int namelen,
 				 loff_t offset, u64 ino, unsigned int d_type)
 {
 	int err = 0;
 	struct unionfs_rdutil_callback *buf = dirent;
-	int whiteout = 0;
+	int is_whiteout;
 	struct filldir_node *found;
+	char *name = (char *) oname;
 
 	buf->filldir_called = 1;
 
@@ -149,14 +44,9 @@ static int readdir_util_callback(void *dirent, const char *name, int namelen,
 			       (name[1] == '.' && namelen == 2)))
 		goto out;
 
-	if (namelen > UNIONFS_WHLEN &&
-	    !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
-		namelen -= UNIONFS_WHLEN;
-		name += UNIONFS_WHLEN;
-		whiteout = 1;
-	}
+	is_whiteout = is_whiteout_name(&name, &namelen);
 
-	found = find_filldir_node(buf->rdstate, name, namelen, whiteout);
+	found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout);
 	/* If it was found in the table there was a previous whiteout. */
 	if (found)
 		goto out;
@@ -166,11 +56,11 @@ static int readdir_util_callback(void *dirent, const char *name, int namelen,
 	 * empty.
 	 */
 	err = -ENOTEMPTY;
-	if ((buf->mode == RD_CHECK_EMPTY) && !whiteout)
+	if ((buf->mode == RD_CHECK_EMPTY) && !is_whiteout)
 		goto out;
 
 	err = add_filldir_node(buf->rdstate, name, namelen,
-			       buf->rdstate->bindex, whiteout);
+			       buf->rdstate->bindex, is_whiteout);
 
 out:
 	buf->err = err;
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index 8b4da54..bfebc0c 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -19,79 +19,6 @@
 #include "union.h"
 
 /*
- * Helper function when creating new objects (create, symlink, and mknod).
- * Checks to see if there's a whiteout in @lower_dentry's parent directory,
- * whose name is taken from @dentry.  Then tries to remove that whiteout, if
- * found.
- *
- * Return 0 if no whiteout was found, or if one was found and successfully
- * removed (a zero tells the caller that @lower_dentry belongs to a good
- * branch to create the new object in).  Return -ERRNO if an error occurred
- * during whiteout lookup or in trying to unlink the whiteout.
- */
-static int check_for_whiteout(struct dentry *dentry,
-			      struct dentry *lower_dentry)
-{
-	int err = 0;
-	struct dentry *wh_dentry = NULL;
-	struct dentry *lower_dir_dentry;
-	char *name = NULL;
-
-	/*
-	 * check if whiteout exists in this branch, i.e. lookup .wh.foo
-	 * first.
-	 */
-	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
-	if (unlikely(IS_ERR(name))) {
-		err = PTR_ERR(name);
-		goto out;
-	}
-
-	wh_dentry = lookup_one_len(name, lower_dentry->d_parent,
-				   dentry->d_name.len + UNIONFS_WHLEN);
-	if (IS_ERR(wh_dentry)) {
-		err = PTR_ERR(wh_dentry);
-		wh_dentry = NULL;
-		goto out;
-	}
-
-	if (!wh_dentry->d_inode) /* no whiteout exists */
-		goto out;
-
-	/* .wh.foo has been found, so let's unlink it */
-	lower_dir_dentry = lock_parent_wh(wh_dentry);
-	/* see Documentation/filesystems/unionfs/issues.txt */
-	lockdep_off();
-	err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry);
-	lockdep_on();
-	unlock_dir(lower_dir_dentry);
-
-	/*
-	 * Whiteouts are special files and should be deleted no matter what
-	 * (as if they never existed), in order to allow this create
-	 * operation to succeed.  This is especially important in sticky
-	 * directories: a whiteout may have been created by one user, but
-	 * the newly created file may be created by another user.
-	 * Therefore, in order to maintain Unix semantics, if the vfs_unlink
-	 * above failed, then we have to try to directly unlink the
-	 * whiteout.  Note: in the ODF version of unionfs, whiteout are
-	 * handled much more cleanly.
-	 */
-	if (err == -EPERM) {
-		struct inode *inode = lower_dir_dentry->d_inode;
-		err = inode->i_op->unlink(inode, wh_dentry);
-	}
-	if (err)
-		printk(KERN_ERR "unionfs: could not "
-		       "unlink whiteout, err = %d\n", err);
-
-out:
-	dput(wh_dentry);
-	kfree(name);
-	return err;
-}
-
-/*
  * Find a writeable branch to create new object in.  Checks all writeble
  * branches of the parent inode, from istart to iend order; if none are
  * suitable, also tries branch 0 (which may require a copyup).
@@ -125,7 +52,9 @@ begin:
 		 * check for whiteouts in writeable branch, and remove them
 		 * if necessary.
 		 */
-		err = check_for_whiteout(dentry, lower_dentry);
+		err = check_unlink_whiteout(dentry, lower_dentry, bindex);
+		if (err > 0)	/* ignore if whiteout found and removed */
+			err = 0;
 		if (err)
 			continue;
 		/* if get here, we can write to the branch */
@@ -302,7 +231,6 @@ static int unionfs_link(struct dentry *old_dentry, struct inode *dir,
 	struct dentry *lower_old_dentry = NULL;
 	struct dentry *lower_new_dentry = NULL;
 	struct dentry *lower_dir_dentry = NULL;
-	struct dentry *whiteout_dentry;
 	char *name = NULL;
 
 	unionfs_read_lock(old_dentry->d_sb, UNIONFS_SMUTEX_CHILD);
@@ -320,48 +248,20 @@ static int unionfs_link(struct dentry *old_dentry, struct inode *dir,
 
 	lower_new_dentry = unionfs_lower_dentry(new_dentry);
 
-	/*
-	 * check if whiteout exists in the branch of new dentry, i.e. lookup
-	 * .wh.foo first. If present, delete it
-	 */
-	name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len);
-	if (unlikely(IS_ERR(name))) {
-		err = PTR_ERR(name);
-		goto out;
-	}
-
-	whiteout_dentry = lookup_one_len(name, lower_new_dentry->d_parent,
-					 new_dentry->d_name.len +
-					 UNIONFS_WHLEN);
-	if (IS_ERR(whiteout_dentry)) {
-		err = PTR_ERR(whiteout_dentry);
-		goto out;
-	}
-
-	if (!whiteout_dentry->d_inode) {
-		dput(whiteout_dentry);
-		whiteout_dentry = NULL;
-	} else {
-		/* found a .wh.foo entry, unlink it and then call vfs_link() */
-		lower_dir_dentry = lock_parent_wh(whiteout_dentry);
-		err = is_robranch_super(new_dentry->d_sb, dbstart(new_dentry));
-		if (!err) {
-			/* see Documentation/filesystems/unionfs/issues.txt */
-			lockdep_off();
-			err = vfs_unlink(lower_dir_dentry->d_inode,
-					 whiteout_dentry);
-			lockdep_on();
-		}
-
+	/* check for a whiteout in new dentry branch, and delete it */
+	err = check_unlink_whiteout(new_dentry, lower_new_dentry,
+				    dbstart(new_dentry));
+	if (err > 0) {	       /* whiteout found and removed successfully */
+		lower_dir_dentry = dget_parent(lower_new_dentry);
 		fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+		dput(lower_dir_dentry);
 		dir->i_nlink = unionfs_get_nlinks(dir);
-		unlock_dir(lower_dir_dentry);
-		lower_dir_dentry = NULL;
-		dput(whiteout_dentry);
-		if (err)
-			goto out;
+		err = 0;
 	}
+	if (err)
+		goto out;
 
+	/* check if parent hierachy is needed, then link in same branch */
 	if (dbstart(old_dentry) != dbstart(new_dentry)) {
 		lower_new_dentry = create_parents(dir, new_dentry,
 						  new_dentry->d_name.name,
@@ -531,12 +431,10 @@ out:
 static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode)
 {
 	int err = 0;
-	struct dentry *lower_dentry = NULL, *whiteout_dentry = NULL;
+	struct dentry *lower_dentry = NULL;
 	struct dentry *lower_parent_dentry = NULL;
 	int bindex = 0, bstart;
 	char *name = NULL;
-	int whiteout_unlinked = 0;
-	struct sioq_args args;
 	int valid;
 
 	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
@@ -558,51 +456,18 @@ static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode)
 
 	lower_dentry = unionfs_lower_dentry(dentry);
 
-	/*
-	 * check if whiteout exists in this branch, i.e. lookup .wh.foo
-	 * first.
-	 */
-	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
-	if (unlikely(IS_ERR(name))) {
-		err = PTR_ERR(name);
-		goto out;
-	}
-
-	whiteout_dentry = lookup_one_len(name, lower_dentry->d_parent,
-					 dentry->d_name.len + UNIONFS_WHLEN);
-	if (IS_ERR(whiteout_dentry)) {
-		err = PTR_ERR(whiteout_dentry);
-		goto out;
-	}
-
-	if (!whiteout_dentry->d_inode) {
-		dput(whiteout_dentry);
-		whiteout_dentry = NULL;
-	} else {
-		lower_parent_dentry = lock_parent_wh(whiteout_dentry);
-
-		/* found a.wh.foo entry, remove it then do vfs_mkdir */
-		err = is_robranch_super(dentry->d_sb, bstart);
-		if (!err) {
-			args.unlink.parent = lower_parent_dentry->d_inode;
-			args.unlink.dentry = whiteout_dentry;
-			run_sioq(__unionfs_unlink, &args);
-			err = args.err;
-		}
-		dput(whiteout_dentry);
-
-		unlock_dir(lower_parent_dentry);
-
-		if (err) {
-			/* exit if the error returned was NOT -EROFS */
-			if (!IS_COPYUP_ERR(err))
-				goto out;
-			bstart--;
-		} else {
-			whiteout_unlinked = 1;
-		}
+	/* check for a whiteout in new dentry branch, and delete it */
+	err = check_unlink_whiteout(dentry, lower_dentry, bstart);
+	if (err > 0)	       /* whiteout found and removed successfully */
+		err = 0;
+	if (err) {
+		/* exit if the error returned was NOT -EROFS */
+		if (!IS_COPYUP_ERR(err))
+			goto out;
+		bstart--;
 	}
 
+	/* check if copyup's needed, and mkdir */
 	for (bindex = bstart; bindex >= 0; bindex--) {
 		int i;
 		int bend = dbend(dentry);
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 1ba7103..0f62087 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -20,58 +20,6 @@
 
 static int realloc_dentry_private_data(struct dentry *dentry);
 
-/* is the filename valid == !(whiteout for a file or opaque dir marker) */
-static int is_validname(const char *name)
-{
-	if (!strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN))
-		return 0;
-	if (!strncmp(name, UNIONFS_DIR_OPAQUE_NAME,
-		     sizeof(UNIONFS_DIR_OPAQUE_NAME) - 1))
-		return 0;
-	return 1;
-}
-
-/* The rest of these are utility functions for lookup. */
-static noinline_for_stack int is_opaque_dir(struct dentry *dentry, int bindex)
-{
-	int err = 0;
-	struct dentry *lower_dentry;
-	struct dentry *wh_lower_dentry;
-	struct inode *lower_inode;
-	struct sioq_args args;
-
-	lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-	lower_inode = lower_dentry->d_inode;
-
-	BUG_ON(!S_ISDIR(lower_inode->i_mode));
-
-	mutex_lock(&lower_inode->i_mutex);
-
-	if (!permission(lower_inode, MAY_EXEC, NULL)) {
-		wh_lower_dentry =
-			lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
-				       sizeof(UNIONFS_DIR_OPAQUE) - 1);
-	} else {
-		args.is_opaque.dentry = lower_dentry;
-		run_sioq(__is_opaque_dir, &args);
-		wh_lower_dentry = args.ret;
-	}
-
-	mutex_unlock(&lower_inode->i_mutex);
-
-	if (IS_ERR(wh_lower_dentry)) {
-		err = PTR_ERR(wh_lower_dentry);
-		goto out;
-	}
-
-	/* This is an opaque dir iff wh_lower_dentry is positive */
-	err = !!wh_lower_dentry->d_inode;
-
-	dput(wh_lower_dentry);
-out:
-	return err;
-}
-
 /*
  * Main (and complex) driver function for Unionfs's lookup
  *
@@ -99,7 +47,6 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 	struct dentry *first_lower_dentry = NULL;
 	struct vfsmount *first_lower_mnt = NULL;
 	int opaque;
-	char *whname = NULL;
 	const char *name;
 	int namelen;
 
@@ -184,42 +131,19 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
 		if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
 			continue;
 
-		/* Reuse the whiteout name because its value doesn't change. */
-		if (!whname) {
-			whname = alloc_whname(name, namelen);
-			if (unlikely(IS_ERR(whname))) {
-				err = PTR_ERR(whname);
-				goto out_free;
-			}
-		}
-
-		/* check if whiteout exists in this branch: lookup .wh.foo */
-		wh_lower_dentry = lookup_one_len(whname, lower_dir_dentry,
-						 namelen + UNIONFS_WHLEN);
+		/* check for whiteouts: stop lookup if found */
+		wh_lower_dentry = lookup_whiteout(name, lower_dir_dentry);
 		if (IS_ERR(wh_lower_dentry)) {
 			dput(first_lower_dentry);
 			unionfs_mntput(first_dentry, first_dentry_offset);
 			err = PTR_ERR(wh_lower_dentry);
 			goto out_free;
 		}
-
 		if (wh_lower_dentry->d_inode) {
-			/* We found a whiteout so let's give up. */
-			if (S_ISREG(wh_lower_dentry->d_inode->i_mode)) {
-				dbend(dentry) = dbopaque(dentry) = bindex;
-				dput(wh_lower_dentry);
-				break;
-			}
-			err = -EIO;
-			printk(KERN_ERR "unionfs: EIO: invalid whiteout "
-			       "entry type %d\n",
-			       wh_lower_dentry->d_inode->i_mode);
+			dbend(dentry) = dbopaque(dentry) = bindex;
 			dput(wh_lower_dentry);
-			dput(first_lower_dentry);
-			unionfs_mntput(first_dentry, first_dentry_offset);
-			goto out_free;
+			break;
 		}
-
 		dput(wh_lower_dentry);
 		wh_lower_dentry = NULL;
 
@@ -424,7 +348,6 @@ out:
 			dput(first_lower_dentry);
 		}
 	}
-	kfree(whname);
 	dput(parent_dentry);
 	if (err && (lookupmode == INTERPOSE_LOOKUP))
 		unionfs_unlock_dentry(dentry);
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index 5b3f1a3..85f96ee 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -62,17 +62,14 @@ out:
 
 static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			    struct inode *new_dir, struct dentry *new_dentry,
-			    int bindex, struct dentry **wh_old)
+			    int bindex)
 {
 	int err = 0;
 	struct dentry *lower_old_dentry;
 	struct dentry *lower_new_dentry;
 	struct dentry *lower_old_dir_dentry;
 	struct dentry *lower_new_dir_dentry;
-	struct dentry *lower_wh_dentry;
-	struct dentry *lower_wh_dir_dentry;
 	struct dentry *trap;
-	char *wh_name = NULL;
 
 	lower_new_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
 	lower_old_dentry = unionfs_lower_dentry_idx(old_dentry, bindex);
@@ -93,46 +90,14 @@ static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		}
 	}
 
-	wh_name = alloc_whname(new_dentry->d_name.name,
-			       new_dentry->d_name.len);
-	if (unlikely(IS_ERR(wh_name))) {
-		err = PTR_ERR(wh_name);
-		goto out;
-	}
-
-	lower_wh_dentry = lookup_one_len(wh_name, lower_new_dentry->d_parent,
-					 new_dentry->d_name.len +
-					 UNIONFS_WHLEN);
-	if (IS_ERR(lower_wh_dentry)) {
-		err = PTR_ERR(lower_wh_dentry);
+	/* check for and remove whiteout, if any */
+	err = check_unlink_whiteout(new_dentry, lower_new_dentry, bindex);
+	if (err > 0) /* ignore if whiteout found and successfully removed */
+		err = 0;
+	if (err)
 		goto out;
-	}
-
-	if (lower_wh_dentry->d_inode) {
-		/* get rid of the whiteout that is existing */
-		if (lower_new_dentry->d_inode) {
-			printk(KERN_ERR "unionfs: both a whiteout and a "
-			       "dentry exist when doing a rename!\n");
-			err = -EIO;
-
-			dput(lower_wh_dentry);
-			goto out;
-		}
-
-		lower_wh_dir_dentry = lock_parent_wh(lower_wh_dentry);
-		err = is_robranch_super(old_dentry->d_sb, bindex);
-		if (!err)
-			err = vfs_unlink(lower_wh_dir_dentry->d_inode,
-					 lower_wh_dentry);
-
-		dput(lower_wh_dentry);
-		unlock_dir(lower_wh_dir_dentry);
-		if (err)
-			goto out;
-	} else {
-		dput(lower_wh_dentry);
-	}
 
+	/* check of old_dentry branch is writable */
 	err = is_robranch_super(old_dentry->d_sb, bindex);
 	if (err)
 		goto out;
@@ -142,28 +107,6 @@ static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	lower_old_dir_dentry = dget_parent(lower_old_dentry);
 	lower_new_dir_dentry = dget_parent(lower_new_dentry);
 
-	/*
-	 * ready to whiteout for old_dentry. caller will create the actual
-	 * whiteout, and must dput(*wh_old)
-	 */
-	if (wh_old) {
-		char *whname;
-		whname = alloc_whname(old_dentry->d_name.name,
-				      old_dentry->d_name.len);
-		err = PTR_ERR(whname);
-		if (unlikely(IS_ERR(whname)))
-			goto out_dput;
-		*wh_old = lookup_one_len(whname, lower_old_dir_dentry,
-					 old_dentry->d_name.len +
-					 UNIONFS_WHLEN);
-		kfree(whname);
-		err = PTR_ERR(*wh_old);
-		if (IS_ERR(*wh_old)) {
-			*wh_old = NULL;
-			goto out_dput;
-		}
-	}
-
 	/* see Documentation/filesystems/unionfs/issues.txt */
 	lockdep_off();
 	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
@@ -188,7 +131,6 @@ out_err_unlock:
 	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
 	lockdep_on();
 
-out_dput:
 	dput(lower_old_dir_dentry);
 	dput(lower_new_dir_dentry);
 	dput(lower_old_dentry);
@@ -203,8 +145,6 @@ out:
 			dbend(new_dentry) = bindex;
 	}
 
-	kfree(wh_name);
-
 	return err;
 }
 
@@ -227,7 +167,6 @@ static int do_unionfs_rename(struct inode *old_dir,
 	int local_err = 0;
 	int eio = 0;
 	int revert = 0;
-	struct dentry *wh_old = NULL;
 
 	old_bstart = dbstart(old_dentry);
 	bwh_old = old_bstart;
@@ -239,7 +178,7 @@ static int do_unionfs_rename(struct inode *old_dir,
 
 	/* Rename source to destination. */
 	err = __unionfs_rename(old_dir, old_dentry, new_dir, new_dentry,
-			       old_bstart, &wh_old);
+			       old_bstart);
 	if (err) {
 		if (!IS_COPYUP_ERR(err))
 			goto out;
@@ -282,7 +221,6 @@ static int do_unionfs_rename(struct inode *old_dir,
 		} else if (IS_COPYUP_ERR(err)) {
 			do_copyup = bindex - 1;
 		} else if (revert) {
-			dput(wh_old);
 			goto revert;
 		}
 	}
@@ -301,11 +239,10 @@ static int do_unionfs_rename(struct inode *old_dir,
 			/* if copyup failed, try next branch to the left */
 			if (err)
 				continue;
-			dput(wh_old);
 			bwh_old = bindex;
 			err = __unionfs_rename(old_dir, old_dentry,
 					       new_dir, new_dentry,
-					       bindex, &wh_old);
+					       bindex);
 			break;
 		}
 	}
@@ -323,38 +260,22 @@ static int do_unionfs_rename(struct inode *old_dir,
 	 * (2) We did a copy_up
 	 */
 	if ((old_bstart != old_bend) || (do_copyup != -1)) {
-		struct dentry *lower_parent;
-		struct nameidata nd;
-		if (!wh_old || wh_old->d_inode || bwh_old < 0) {
-			printk(KERN_ERR "unionfs: rename error "
-			       "(wh_old=%p/%p bwh_old=%d)\n", wh_old,
-			       (wh_old ? wh_old->d_inode : NULL), bwh_old);
+		if (bwh_old < 0) {
+			printk(KERN_ERR "unionfs: rename error (bwh_old=%d)\n",
+			       bwh_old);
 			err = -EIO;
 			goto out;
 		}
-		err = init_lower_nd(&nd, LOOKUP_CREATE);
-		if (unlikely(err < 0))
-			goto out;
-		lower_parent = lock_parent_wh(wh_old);
-		local_err = vfs_create(lower_parent->d_inode, wh_old, S_IRUGO,
-				       &nd);
-		unlock_dir(lower_parent);
-		if (!local_err) {
-			dbopaque(old_dentry) = bwh_old;
-		} else {
-			/*
-			 * we can't fix anything now, so we cop-out and use
-			 * -EIO.
-			 */
+		err = create_whiteout(old_dentry, bwh_old);
+		if (err) {
+			/* can't fix anything now, so we exit with -EIO */
 			printk(KERN_ERR "unionfs: can't create a whiteout for "
-			       "the source in rename!\n");
+			       "%s in rename!\n", old_dentry->d_name.name);
 			err = -EIO;
 		}
-		release_lower_nd(&nd, local_err);
 	}
 
 out:
-	dput(wh_old);
 	return err;
 
 revert:
@@ -391,7 +312,7 @@ revert:
 	}
 
 	local_err = __unionfs_rename(new_dir, new_dentry,
-				     old_dir, old_dentry, old_bstart, NULL);
+				     old_dir, old_dentry, old_bstart);
 
 	/* If we can't fix it, then we cop-out with -EIO. */
 	if (local_err) {
@@ -412,40 +333,6 @@ revert_out:
 	return err;
 }
 
-static struct dentry *lookup_whiteout(struct dentry *dentry)
-{
-	char *whname;
-	int bindex = -1, bstart = -1, bend = -1;
-	struct dentry *parent, *lower_parent, *wh_dentry;
-
-	whname = alloc_whname(dentry->d_name.name, dentry->d_name.len);
-	if (unlikely(IS_ERR(whname)))
-		return (void *)whname;
-
-	parent = dget_parent(dentry);
-	unionfs_lock_dentry(parent, UNIONFS_DMUTEX_WHITEOUT);
-	bstart = dbstart(parent);
-	bend = dbend(parent);
-	wh_dentry = ERR_PTR(-ENOENT);
-	for (bindex = bstart; bindex <= bend; bindex++) {
-		lower_parent = unionfs_lower_dentry_idx(parent, bindex);
-		if (!lower_parent)
-			continue;
-		wh_dentry = lookup_one_len(whname, lower_parent,
-					   dentry->d_name.len + UNIONFS_WHLEN);
-		if (IS_ERR(wh_dentry))
-			continue;
-		if (wh_dentry->d_inode)
-			break;
-		dput(wh_dentry);
-		wh_dentry = ERR_PTR(-ENOENT);
-	}
-	unionfs_unlock_dentry(parent);
-	dput(parent);
-	kfree(whname);
-	return wh_dentry;
-}
-
 /*
  * We can't copyup a directory, because it may involve huge numbers of
  * children, etc.  Doing that in the kernel would be bad, so instead we
@@ -511,7 +398,7 @@ int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	 * if new_dentry is already lower because of whiteout,
 	 * simply override it even if the whited-out dir is not empty.
 	 */
-	wh_dentry = lookup_whiteout(new_dentry);
+	wh_dentry = find_first_whiteout(new_dentry);
 	if (!IS_ERR(wh_dentry)) {
 		dput(wh_dentry);
 	} else if (new_dentry->d_inode) {
diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
index 2a8c88e..0ea8436 100644
--- a/fs/unionfs/sioq.c
+++ b/fs/unionfs/sioq.c
@@ -99,21 +99,3 @@ void __unionfs_unlink(struct work_struct *work)
 	args->err = vfs_unlink(u->parent, u->dentry);
 	complete(&args->comp);
 }
-
-void __delete_whiteouts(struct work_struct *work)
-{
-	struct sioq_args *args = container_of(work, struct sioq_args, work);
-	struct deletewh_args *d = &args->deletewh;
-
-	args->err = do_delete_whiteouts(d->dentry, d->bindex, d->namelist);
-	complete(&args->comp);
-}
-
-void __is_opaque_dir(struct work_struct *work)
-{
-	struct sioq_args *args = container_of(work, struct sioq_args, work);
-
-	args->ret = lookup_one_len(UNIONFS_DIR_OPAQUE, args->is_opaque.dentry,
-				   sizeof(UNIONFS_DIR_OPAQUE) - 1);
-	complete(&args->comp);
-}
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index 1f1db3d..dda2745 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -19,152 +19,6 @@
 #include "union.h"
 
 /*
- * Pass an unionfs dentry and an index.  It will try to create a whiteout
- * for the filename in dentry, and will try in branch 'index'.  On error,
- * it will proceed to a branch to the left.
- */
-int create_whiteout(struct dentry *dentry, int start)
-{
-	int bstart, bend, bindex;
-	struct dentry *lower_dir_dentry;
-	struct dentry *lower_dentry;
-	struct dentry *lower_wh_dentry;
-	struct nameidata nd;
-	char *name = NULL;
-	int err = -EINVAL;
-
-	verify_locked(dentry);
-
-	bstart = dbstart(dentry);
-	bend = dbend(dentry);
-
-	/* create dentry's whiteout equivalent */
-	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
-	if (unlikely(IS_ERR(name))) {
-		err = PTR_ERR(name);
-		goto out;
-	}
-
-	for (bindex = start; bindex >= 0; bindex--) {
-		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-
-		if (!lower_dentry) {
-			/*
-			 * if lower dentry is not present, create the
-			 * entire lower dentry directory structure and go
-			 * ahead.  Since we want to just create whiteout, we
-			 * only want the parent dentry, and hence get rid of
-			 * this dentry.
-			 */
-			lower_dentry = create_parents(dentry->d_inode,
-						      dentry,
-						      dentry->d_name.name,
-						      bindex);
-			if (!lower_dentry || IS_ERR(lower_dentry)) {
-				int ret = PTR_ERR(lower_dentry);
-				if (!IS_COPYUP_ERR(ret))
-					printk(KERN_ERR
-					       "unionfs: create_parents for "
-					       "whiteout failed: bindex=%d "
-					       "err=%d\n", bindex, ret);
-				continue;
-			}
-		}
-
-		lower_wh_dentry =
-			lookup_one_len(name, lower_dentry->d_parent,
-				       dentry->d_name.len + UNIONFS_WHLEN);
-		if (IS_ERR(lower_wh_dentry))
-			continue;
-
-		/*
-		 * The whiteout already exists. This used to be impossible,
-		 * but now is possible because of opaqueness.
-		 */
-		if (lower_wh_dentry->d_inode) {
-			dput(lower_wh_dentry);
-			err = 0;
-			goto out;
-		}
-
-		err = init_lower_nd(&nd, LOOKUP_CREATE);
-		if (unlikely(err < 0))
-			goto out;
-		lower_dir_dentry = lock_parent_wh(lower_wh_dentry);
-		err = is_robranch_super(dentry->d_sb, bindex);
-		if (!err)
-			err = vfs_create(lower_dir_dentry->d_inode,
-					 lower_wh_dentry,
-					 ~current->fs->umask & S_IRWXUGO,
-					 &nd);
-		unlock_dir(lower_dir_dentry);
-		dput(lower_wh_dentry);
-		release_lower_nd(&nd, err);
-
-		if (!err || !IS_COPYUP_ERR(err))
-			break;
-	}
-
-	/* set dbopaque so that lookup will not proceed after this branch */
-	if (!err)
-		dbopaque(dentry) = bindex;
-
-out:
-	kfree(name);
-	return err;
-}
-
-int make_dir_opaque(struct dentry *dentry, int bindex)
-{
-	int err = 0;
-	struct dentry *lower_dentry, *diropq;
-	struct inode *lower_dir;
-	struct nameidata nd;
-	kernel_cap_t orig_cap;
-
-	/*
-	 * Opaque directory whiteout markers are special files (like regular
-	 * whiteouts), and should appear to the users as if they don't
-	 * exist.  They should be created/deleted regardless of directory
-	 * search/create permissions, but only for the duration of this
-	 * creation of the .wh.__dir_opaque: file.  Note, this does not
-	 * circumvent normal ->permission).
-	 */
-	orig_cap = current->cap_effective;
-	cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
-	cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
-
-	lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-	lower_dir = lower_dentry->d_inode;
-	BUG_ON(!S_ISDIR(dentry->d_inode->i_mode) ||
-	       !S_ISDIR(lower_dir->i_mode));
-
-	mutex_lock(&lower_dir->i_mutex);
-	diropq = lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
-				sizeof(UNIONFS_DIR_OPAQUE) - 1);
-	if (IS_ERR(diropq)) {
-		err = PTR_ERR(diropq);
-		goto out;
-	}
-
-	err = init_lower_nd(&nd, LOOKUP_CREATE);
-	if (unlikely(err < 0))
-		goto out;
-	if (!diropq->d_inode)
-		err = vfs_create(lower_dir, diropq, S_IRUGO, &nd);
-	if (!err)
-		dbopaque(dentry) = bindex;
-	release_lower_nd(&nd, err);
-
-	dput(diropq);
-
-out:
-	mutex_unlock(&lower_dir->i_mutex);
-	current->cap_effective = orig_cap;
-	return err;
-}
-
-/*
  * returns the right n_link value based on the inode type
  */
 int unionfs_get_nlinks(const struct inode *inode)
@@ -184,21 +38,6 @@ int unionfs_get_nlinks(const struct inode *inode)
 	return 1;
 }
 
-/* construct whiteout filename */
-char *alloc_whname(const char *name, int len)
-{
-	char *buf;
-
-	buf = kmalloc(len + UNIONFS_WHLEN + 1, GFP_KERNEL);
-	if (unlikely(!buf))
-		return ERR_PTR(-ENOMEM);
-
-	strcpy(buf, UNIONFS_WHPFX);
-	strlcat(buf, name, len + UNIONFS_WHLEN + 1);
-
-	return buf;
-}
-
 /* copy a/m/ctime from the lower branch with the newest times */
 void unionfs_copy_attr_times(struct inode *upper)
 {
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 9715529..3b6b65a 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -173,7 +173,7 @@ static int unionfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	 *
 	 * XXX: this restriction goes away with ODF.
 	 */
-	buf->f_namelen -= UNIONFS_WHLEN;
+	unionfs_set_max_namelen(&buf->f_namelen);
 
 	/*
 	 * reset two fields to avoid confusing user-land.
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index f5cf09b..9271b3b 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -306,18 +306,10 @@ extern void release_lower_nd(struct nameidata *nd, int err);
 /* replicates the directory structure up to given dentry in given branch */
 extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
 				     const char *name, int bindex);
-extern int make_dir_opaque(struct dentry *dir, int bindex);
 
 /* partial lookup */
 extern int unionfs_partial_lookup(struct dentry *dentry);
 
-/*
- * Pass an unionfs dentry and an index and it will try to create a whiteout
- * in branch 'index'.
- *
- * On error, it will proceed to a branch to the left
- */
-extern int create_whiteout(struct dentry *dentry, int start);
 /* copies a file from dbstart to newbindex branch */
 extern int copyup_file(struct inode *dir, struct file *file, int bstart,
 		       int newbindex, loff_t size);
@@ -332,18 +324,25 @@ extern int copyup_dentry(struct inode *dir, struct dentry *dentry,
 extern void unionfs_postcopyup_setmnt(struct dentry *dentry);
 extern void unionfs_postcopyup_release(struct dentry *dentry);
 
-extern int remove_whiteouts(struct dentry *dentry,
-			    struct dentry *lower_dentry, int bindex);
-
-extern int do_delete_whiteouts(struct dentry *dentry, int bindex,
-			       struct unionfs_dir_state *namelist);
-
 /* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */
 extern int check_empty(struct dentry *dentry,
 		       struct unionfs_dir_state **namelist);
-/* Delete whiteouts from this directory in branch bindex. */
+/* whiteout and opaque directory helpers */
+extern char *alloc_whname(const char *name, int len);
+extern bool is_whiteout_name(char **namep, int *namelenp);
+extern bool is_validname(const char *name);
+extern struct dentry *lookup_whiteout(const char *name,
+				      struct dentry *lower_parent);
+extern struct dentry *find_first_whiteout(struct dentry *dentry);
+extern int unlink_whiteout(struct dentry *wh_dentry);
+extern int check_unlink_whiteout(struct dentry *dentry,
+				 struct dentry *lower_dentry, int bindex);
+extern int create_whiteout(struct dentry *dentry, int start);
 extern int delete_whiteouts(struct dentry *dentry, int bindex,
 			    struct unionfs_dir_state *namelist);
+extern int is_opaque_dir(struct dentry *dentry, int bindex);
+extern int make_dir_opaque(struct dentry *dir, int bindex);
+extern void unionfs_set_max_namelen(long *namelen);
 
 extern void unionfs_reinterpose(struct dentry *this_dentry);
 extern struct super_block *unionfs_duplicate_super(struct super_block *sb);
@@ -476,20 +475,9 @@ static inline int is_robranch(const struct dentry *dentry)
 	return is_robranch_idx(dentry, index);
 }
 
-/* What do we use for whiteouts. */
-#define UNIONFS_WHPFX ".wh."
-#define UNIONFS_WHLEN 4
-/*
- * If a directory contains this file, then it is opaque.  We start with the
- * .wh. flag so that it is blocked by lookup.
- */
-#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque"
-#define UNIONFS_DIR_OPAQUE UNIONFS_WHPFX UNIONFS_DIR_OPAQUE_NAME
-
 /*
  * EXTERNALS:
  */
-extern char *alloc_whname(const char *name, int len);
 extern int check_branch(struct nameidata *nd);
 extern int parse_branch_mode(const char *name, int *perms);
 
diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
new file mode 100644
index 0000000..b1768ed
--- /dev/null
+++ b/fs/unionfs/whiteout.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2006 Charles P. Wright
+ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
+ * Copyright (c) 2005-2006 Junjiro Okajima
+ * Copyright (c) 2005      Arun M. Krishnakumar
+ * Copyright (c) 2004-2006 David P. Quigley
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003      Puja Gupta
+ * Copyright (c) 2003      Harikesavan Krishnan
+ * Copyright (c) 2003-2007 Stony Brook University
+ * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "union.h"
+
+/*
+ * whiteout and opaque directory helpers
+ */
+
+/* What do we use for whiteouts. */
+#define UNIONFS_WHPFX ".wh."
+#define UNIONFS_WHLEN 4
+/*
+ * If a directory contains this file, then it is opaque.  We start with the
+ * .wh. flag so that it is blocked by lookup.
+ */
+#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque"
+#define UNIONFS_DIR_OPAQUE UNIONFS_WHPFX UNIONFS_DIR_OPAQUE_NAME
+
+/* construct whiteout filename */
+char *alloc_whname(const char *name, int len)
+{
+	char *buf;
+
+	buf = kmalloc(len + UNIONFS_WHLEN + 1, GFP_KERNEL);
+	if (unlikely(!buf))
+		return ERR_PTR(-ENOMEM);
+
+	strcpy(buf, UNIONFS_WHPFX);
+	strlcat(buf, name, len + UNIONFS_WHLEN + 1);
+
+	return buf;
+}
+
+/*
+ * XXX: this can be inline or CPP macro, but is here to keep all whiteout
+ * code in one place.
+ */
+void unionfs_set_max_namelen(long *namelen)
+{
+	*namelen -= UNIONFS_WHLEN;
+}
+
+/* check if @namep is a whiteout, update @namep and @namelenp accordingly */
+bool is_whiteout_name(char **namep, int *namelenp)
+{
+	if (*namelenp > UNIONFS_WHLEN &&
+	    !strncmp(*namep, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
+		*namep += UNIONFS_WHLEN;
+		*namelenp -= UNIONFS_WHLEN;
+		return true;
+	}
+	return false;
+}
+
+/* is the filename valid == !(whiteout for a file or opaque dir marker) */
+bool is_validname(const char *name)
+{
+	if (!strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN))
+		return false;
+	if (!strncmp(name, UNIONFS_DIR_OPAQUE_NAME,
+		     sizeof(UNIONFS_DIR_OPAQUE_NAME) - 1))
+		return false;
+	return true;
+}
+
+/*
+ * Look for a whiteout @name in @lower_parent directory.  If error, return
+ * ERR_PTR.  Caller must dput() the returned dentry if not an error.
+ *
+ * XXX: some callers can reuse the whname allocated buffer to avoid repeated
+ * free then re-malloc calls.  Need to provide a different API for those
+ * callers.
+ */
+struct dentry *lookup_whiteout(const char *name, struct dentry *lower_parent)
+{
+	char *whname = NULL;
+	int err = 0, namelen;
+	struct dentry *wh_dentry = NULL;
+
+	namelen = strlen(name);
+	whname = alloc_whname(name, namelen);
+	if (unlikely(IS_ERR(whname))) {
+		err = PTR_ERR(whname);
+		goto out;
+	}
+
+	/* check if whiteout exists in this branch: lookup .wh.foo */
+	wh_dentry = lookup_one_len(whname, lower_parent, strlen(whname));
+	if (IS_ERR(wh_dentry)) {
+		err = PTR_ERR(wh_dentry);
+		goto out;
+	}
+
+	/* check if negative dentry (ENOENT) */
+	if (!wh_dentry->d_inode)
+		goto out;
+
+	/* whiteout found: check if valid type */
+	if (!S_ISREG(wh_dentry->d_inode->i_mode)) {
+		printk(KERN_ERR "unionfs: invalid whiteout %s entry type %d\n",
+		       whname, wh_dentry->d_inode->i_mode);
+		dput(wh_dentry);
+		err = -EIO;
+		goto out;
+	}
+
+out:
+	kfree(whname);
+	if (err)
+		wh_dentry = ERR_PTR(err);
+	return wh_dentry;
+}
+
+/* find and return first whiteout in parent directory, else ENOENT */
+struct dentry *find_first_whiteout(struct dentry *dentry)
+{
+	int bindex, bstart, bend;
+	struct dentry *parent, *lower_parent, *wh_dentry;
+
+	parent = dget_parent(dentry);
+	unionfs_lock_dentry(parent, UNIONFS_DMUTEX_WHITEOUT);
+	bstart = dbstart(parent);
+	bend = dbend(parent);
+	wh_dentry = ERR_PTR(-ENOENT);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		lower_parent = unionfs_lower_dentry_idx(parent, bindex);
+		if (!lower_parent)
+			continue;
+		wh_dentry = lookup_whiteout(dentry->d_name.name, lower_parent);
+		if (IS_ERR(wh_dentry))
+			continue;
+		if (wh_dentry->d_inode)
+			break;
+		dput(wh_dentry);
+		wh_dentry = ERR_PTR(-ENOENT);
+	}
+	unionfs_unlock_dentry(parent);
+	dput(parent);
+
+	return wh_dentry;
+}
+
+/*
+ * Unlink a whiteout dentry.  Returns 0 or -errno.  Caller must hold and
+ * release dentry reference.
+ */
+int unlink_whiteout(struct dentry *wh_dentry)
+{
+	int err;
+	struct dentry *lower_dir_dentry;
+
+	/* dget and lock parent dentry */
+	lower_dir_dentry = lock_parent_wh(wh_dentry);
+
+	/* see Documentation/filesystems/unionfs/issues.txt */
+	lockdep_off();
+	err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry);
+	lockdep_on();
+	unlock_dir(lower_dir_dentry);
+
+	/*
+	 * Whiteouts are special files and should be deleted no matter what
+	 * (as if they never existed), in order to allow this create
+	 * operation to succeed.  This is especially important in sticky
+	 * directories: a whiteout may have been created by one user, but
+	 * the newly created file may be created by another user.
+	 * Therefore, in order to maintain Unix semantics, if the vfs_unlink
+	 * above failed, then we have to try to directly unlink the
+	 * whiteout.  Note: in the ODF version of unionfs, whiteout are
+	 * handled much more cleanly.
+	 */
+	if (err == -EPERM) {
+		struct inode *inode = lower_dir_dentry->d_inode;
+		err = inode->i_op->unlink(inode, wh_dentry);
+	}
+	if (err)
+		printk(KERN_ERR "unionfs: could not unlink whiteout %s, "
+		       "err = %d\n", wh_dentry->d_name.name, err);
+
+	return err;
+
+}
+
+/*
+ * Helper function when creating new objects (create, symlink, mknod, etc.).
+ * Checks to see if there's a whiteout in @lower_dentry's parent directory,
+ * whose name is taken from @dentry.  Then tries to remove that whiteout, if
+ * found.  If <dentry,bindex> is a branch marked readonly, return -EROFS.
+ * If it finds both a regular file and a whiteout, return -EIO (this should
+ * never happen).
+ *
+ * Return 0 if no whiteout was found.  Return 1 if one was found and
+ * successfully removed.  Therefore a value >= 0 tells the caller that
+ * @lower_dentry belongs to a good branch to create the new object in).
+ * Return -ERRNO if an error occurred during whiteout lookup or in trying to
+ * unlink the whiteout.
+ */
+int check_unlink_whiteout(struct dentry *dentry, struct dentry *lower_dentry,
+			  int bindex)
+{
+	int err;
+	struct dentry *wh_dentry = NULL;
+	struct dentry *lower_dir_dentry = NULL;
+
+	/* look for whiteout dentry first */
+	lower_dir_dentry = dget_parent(lower_dentry);
+	wh_dentry = lookup_whiteout(dentry->d_name.name, lower_dir_dentry);
+	dput(lower_dir_dentry);
+	if (IS_ERR(wh_dentry)) {
+		err = PTR_ERR(wh_dentry);
+		goto out;
+	}
+
+	if (!wh_dentry->d_inode) { /* no whiteout exists*/
+		err = 0;
+		goto out_dput;
+	}
+
+	/* check if regular file and whiteout were both found */
+	if (unlikely(lower_dentry->d_inode)) {
+		err = -EIO;
+		printk(KERN_ERR "unionfs: found both whiteout and regular "
+		       "file in directory %s (branch %d)\n",
+		       lower_dentry->d_parent->d_name.name, bindex);
+		goto out_dput;
+	}
+
+	/* check if branch is writeable */
+	err = is_robranch_super(dentry->d_sb, bindex);
+	if (err)
+		goto out_dput;
+
+	/* .wh.foo has been found, so let's unlink it */
+	err = unlink_whiteout(wh_dentry);
+	if (!err)
+		err = 1; /* a whiteout was found and successfully removed */
+out_dput:
+	dput(wh_dentry);
+out:
+	return err;
+}
+
+/*
+ * Pass an unionfs dentry and an index.  It will try to create a whiteout
+ * for the filename in dentry, and will try in branch 'index'.  On error,
+ * it will proceed to a branch to the left.
+ */
+int create_whiteout(struct dentry *dentry, int start)
+{
+	int bstart, bend, bindex;
+	struct dentry *lower_dir_dentry;
+	struct dentry *lower_dentry;
+	struct dentry *lower_wh_dentry;
+	struct nameidata nd;
+	char *name = NULL;
+	int err = -EINVAL;
+
+	verify_locked(dentry);
+
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+
+	/* create dentry's whiteout equivalent */
+	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
+	if (unlikely(IS_ERR(name))) {
+		err = PTR_ERR(name);
+		goto out;
+	}
+
+	for (bindex = start; bindex >= 0; bindex--) {
+		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+
+		if (!lower_dentry) {
+			/*
+			 * if lower dentry is not present, create the
+			 * entire lower dentry directory structure and go
+			 * ahead.  Since we want to just create whiteout, we
+			 * only want the parent dentry, and hence get rid of
+			 * this dentry.
+			 */
+			lower_dentry = create_parents(dentry->d_inode,
+						      dentry,
+						      dentry->d_name.name,
+						      bindex);
+			if (!lower_dentry || IS_ERR(lower_dentry)) {
+				int ret = PTR_ERR(lower_dentry);
+				if (!IS_COPYUP_ERR(ret))
+					printk(KERN_ERR
+					       "unionfs: create_parents for "
+					       "whiteout failed: bindex=%d "
+					       "err=%d\n", bindex, ret);
+				continue;
+			}
+		}
+
+		lower_wh_dentry =
+			lookup_one_len(name, lower_dentry->d_parent,
+				       dentry->d_name.len + UNIONFS_WHLEN);
+		if (IS_ERR(lower_wh_dentry))
+			continue;
+
+		/*
+		 * The whiteout already exists. This used to be impossible,
+		 * but now is possible because of opaqueness.
+		 */
+		if (lower_wh_dentry->d_inode) {
+			dput(lower_wh_dentry);
+			err = 0;
+			goto out;
+		}
+
+		err = init_lower_nd(&nd, LOOKUP_CREATE);
+		if (unlikely(err < 0))
+			goto out;
+		lower_dir_dentry = lock_parent_wh(lower_wh_dentry);
+		err = is_robranch_super(dentry->d_sb, bindex);
+		if (!err)
+			err = vfs_create(lower_dir_dentry->d_inode,
+					 lower_wh_dentry,
+					 ~current->fs->umask & S_IRUGO,
+					 &nd);
+		unlock_dir(lower_dir_dentry);
+		dput(lower_wh_dentry);
+		release_lower_nd(&nd, err);
+
+		if (!err || !IS_COPYUP_ERR(err))
+			break;
+	}
+
+	/* set dbopaque so that lookup will not proceed after this branch */
+	if (!err)
+		dbopaque(dentry) = bindex;
+
+out:
+	kfree(name);
+	return err;
+}
+
+/*
+ * Delete all of the whiteouts in a given directory for rmdir.
+ *
+ * lower directory inode should be locked
+ */
+static int do_delete_whiteouts(struct dentry *dentry, int bindex,
+			       struct unionfs_dir_state *namelist)
+{
+	int err = 0;
+	struct dentry *lower_dir_dentry = NULL;
+	struct dentry *lower_dentry;
+	char *name = NULL, *p;
+	struct inode *lower_dir;
+	int i;
+	struct list_head *pos;
+	struct filldir_node *cursor;
+
+	/* Find out lower parent dentry */
+	lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+	BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
+	lower_dir = lower_dir_dentry->d_inode;
+	BUG_ON(!S_ISDIR(lower_dir->i_mode));
+
+	err = -ENOMEM;
+	name = __getname();
+	if (unlikely(!name))
+		goto out;
+	strcpy(name, UNIONFS_WHPFX);
+	p = name + UNIONFS_WHLEN;
+
+	err = 0;
+	for (i = 0; !err && i < namelist->size; i++) {
+		list_for_each(pos, &namelist->list[i]) {
+			cursor =
+				list_entry(pos, struct filldir_node,
+					   file_list);
+			/* Only operate on whiteouts in this branch. */
+			if (cursor->bindex != bindex)
+				continue;
+			if (!cursor->whiteout)
+				continue;
+
+			strlcpy(p, cursor->name, PATH_MAX - UNIONFS_WHLEN);
+			lower_dentry =
+				lookup_one_len(name, lower_dir_dentry,
+					       cursor->namelen +
+					       UNIONFS_WHLEN);
+			if (IS_ERR(lower_dentry)) {
+				err = PTR_ERR(lower_dentry);
+				break;
+			}
+			if (lower_dentry->d_inode)
+				err = vfs_unlink(lower_dir, lower_dentry);
+			dput(lower_dentry);
+			if (err)
+				break;
+		}
+	}
+
+	__putname(name);
+
+	/* After all of the removals, we should copy the attributes once. */
+	fsstack_copy_attr_times(dentry->d_inode, lower_dir_dentry->d_inode);
+
+out:
+	return err;
+}
+
+
+void __delete_whiteouts(struct work_struct *work)
+{
+	struct sioq_args *args = container_of(work, struct sioq_args, work);
+	struct deletewh_args *d = &args->deletewh;
+
+	args->err = do_delete_whiteouts(d->dentry, d->bindex, d->namelist);
+	complete(&args->comp);
+}
+
+/* delete whiteouts in a dir (for rmdir operation) using sioq if necessary */
+int delete_whiteouts(struct dentry *dentry, int bindex,
+		     struct unionfs_dir_state *namelist)
+{
+	int err;
+	struct super_block *sb;
+	struct dentry *lower_dir_dentry;
+	struct inode *lower_dir;
+	struct sioq_args args;
+
+	sb = dentry->d_sb;
+
+	BUG_ON(!S_ISDIR(dentry->d_inode->i_mode));
+	BUG_ON(bindex < dbstart(dentry));
+	BUG_ON(bindex > dbend(dentry));
+	err = is_robranch_super(sb, bindex);
+	if (err)
+		goto out;
+
+	lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+	BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
+	lower_dir = lower_dir_dentry->d_inode;
+	BUG_ON(!S_ISDIR(lower_dir->i_mode));
+
+	if (!permission(lower_dir, MAY_WRITE | MAY_EXEC, NULL)) {
+		err = do_delete_whiteouts(dentry, bindex, namelist);
+	} else {
+		args.deletewh.namelist = namelist;
+		args.deletewh.dentry = dentry;
+		args.deletewh.bindex = bindex;
+		run_sioq(__delete_whiteouts, &args);
+		err = args.err;
+	}
+
+out:
+	return err;
+}
+
+/****************************************************************************
+ * Opaque directory helpers                                                 *
+ ****************************************************************************/
+
+/*
+ * is_opaque_dir: returns 0 if it is NOT an opaque dir, 1 if it is, and
+ * -errno if an error occurred trying to figure this out.
+ */
+int is_opaque_dir(struct dentry *dentry, int bindex)
+{
+	int err = 0;
+	struct dentry *lower_dentry;
+	struct dentry *wh_lower_dentry;
+	struct inode *lower_inode;
+	struct sioq_args args;
+
+	lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+	lower_inode = lower_dentry->d_inode;
+
+	BUG_ON(!S_ISDIR(lower_inode->i_mode));
+
+	mutex_lock(&lower_inode->i_mutex);
+
+	if (!permission(lower_inode, MAY_EXEC, NULL)) {
+		wh_lower_dentry =
+			lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
+				       sizeof(UNIONFS_DIR_OPAQUE) - 1);
+	} else {
+		args.is_opaque.dentry = lower_dentry;
+		run_sioq(__is_opaque_dir, &args);
+		wh_lower_dentry = args.ret;
+	}
+
+	mutex_unlock(&lower_inode->i_mutex);
+
+	if (IS_ERR(wh_lower_dentry)) {
+		err = PTR_ERR(wh_lower_dentry);
+		goto out;
+	}
+
+	/* This is an opaque dir iff wh_lower_dentry is positive */
+	err = !!wh_lower_dentry->d_inode;
+
+	dput(wh_lower_dentry);
+out:
+	return err;
+}
+
+void __is_opaque_dir(struct work_struct *work)
+{
+	struct sioq_args *args = container_of(work, struct sioq_args, work);
+
+	args->ret = lookup_one_len(UNIONFS_DIR_OPAQUE, args->is_opaque.dentry,
+				   sizeof(UNIONFS_DIR_OPAQUE) - 1);
+	complete(&args->comp);
+}
+
+int make_dir_opaque(struct dentry *dentry, int bindex)
+{
+	int err = 0;
+	struct dentry *lower_dentry, *diropq;
+	struct inode *lower_dir;
+	struct nameidata nd;
+	kernel_cap_t orig_cap;
+
+	/*
+	 * Opaque directory whiteout markers are special files (like regular
+	 * whiteouts), and should appear to the users as if they don't
+	 * exist.  They should be created/deleted regardless of directory
+	 * search/create permissions, but only for the duration of this
+	 * creation of the .wh.__dir_opaque: file.  Note, this does not
+	 * circumvent normal ->permission).
+	 */
+	orig_cap = current->cap_effective;
+	cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+	cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+
+	lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+	lower_dir = lower_dentry->d_inode;
+	BUG_ON(!S_ISDIR(dentry->d_inode->i_mode) ||
+	       !S_ISDIR(lower_dir->i_mode));
+
+	mutex_lock(&lower_dir->i_mutex);
+	diropq = lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
+				sizeof(UNIONFS_DIR_OPAQUE) - 1);
+	if (IS_ERR(diropq)) {
+		err = PTR_ERR(diropq);
+		goto out;
+	}
+
+	err = init_lower_nd(&nd, LOOKUP_CREATE);
+	if (unlikely(err < 0))
+		goto out;
+	if (!diropq->d_inode)
+		err = vfs_create(lower_dir, diropq, S_IRUGO, &nd);
+	if (!err)
+		dbopaque(dentry) = bindex;
+	release_lower_nd(&nd, err);
+
+	dput(diropq);
+
+out:
+	mutex_unlock(&lower_dir->i_mutex);
+	current->cap_effective = orig_cap;
+	return err;
+}
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/19] Unionfs: lookup overhaul using vfs_path_lookup
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (6 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 07/19] Unionfs: overhaul whiteout code Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 09/19] Unionfs: free lower paths array when destroying dentry's private data Erez Zadok
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Rework the lookup code to use vfs_path_lookup as much as possible, to ensure
that we have a vfsmount at this critical stage.  This is necessary for the
upcoming VFS API change from vfs_* to path_* methods.  This change also
allows unionfs to cross bind mounts and other mounts on lower branches.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c |    3 +-
 fs/unionfs/inode.c      |   18 ++-
 fs/unionfs/lookup.c     |  348 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/unionfs/rename.c     |    1 +
 fs/unionfs/union.h      |    4 +
 5 files changed, 366 insertions(+), 8 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 5816d41..df002d5 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -422,7 +422,8 @@ reval_dentry:
 	dgen = atomic_read(&UNIONFS_D(dentry)->generation);
 
 	if (unlikely(sbgen > dgen)) {
-		pr_debug("unionfs: retry dentry revalidation\n");
+		pr_debug("unionfs: retry dentry %s revalidation\n",
+			 dentry->d_name.name);
 		schedule();
 		goto reval_dentry;
 	}
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index bfebc0c..f81ebb6 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -178,6 +178,7 @@ static struct dentry *unionfs_lookup(struct inode *parent,
 {
 	struct path path_save = {NULL, NULL};
 	struct dentry *ret;
+	int err = 0;
 
 	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
 	if (dentry != dentry->d_parent)
@@ -193,7 +194,14 @@ static struct dentry *unionfs_lookup(struct inode *parent,
 	 * unionfs_lookup_backend returns a locked dentry upon success,
 	 * so we'll have to unlock it below.
 	 */
-	ret = unionfs_lookup_backend(dentry, nd, INTERPOSE_LOOKUP);
+
+	/* allocate dentry private data.  We free it in ->d_release */
+	err = new_dentry_private_data(dentry, UNIONFS_DMUTEX_CHILD);
+	if (unlikely(err)) {
+		ret = ERR_PTR(err);
+		goto out;
+	}
+	ret = unionfs_lookup_full(dentry, nd, INTERPOSE_LOOKUP);
 
 	/* restore the dentry & vfsmnt in namei */
 	if (nd) {
@@ -203,6 +211,11 @@ static struct dentry *unionfs_lookup(struct inode *parent,
 	if (!IS_ERR(ret)) {
 		if (ret)
 			dentry = ret;
+		/* lookup_full can return multiple positive dentries */
+		if (dentry->d_inode && !S_ISDIR(dentry->d_inode->i_mode)) {
+			BUG_ON(dbstart(dentry) < 0);
+			unionfs_postcopyup_release(dentry);
+		}
 		unionfs_copy_attr_times(dentry->d_inode);
 		/* parent times may have changed */
 		unionfs_copy_attr_times(dentry->d_parent->d_inode);
@@ -212,9 +225,10 @@ static struct dentry *unionfs_lookup(struct inode *parent,
 	if (!IS_ERR(ret)) {
 		unionfs_check_dentry(dentry);
 		unionfs_check_nd(nd);
-		unionfs_unlock_dentry(dentry);
 	}
+	unionfs_unlock_dentry(dentry);
 
+out:
 	if (dentry != dentry->d_parent) {
 		unionfs_check_dentry(dentry->d_parent);
 		unionfs_unlock_dentry(dentry->d_parent);
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 0f62087..37adf66 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -18,7 +18,49 @@
 
 #include "union.h"
 
-static int realloc_dentry_private_data(struct dentry *dentry);
+/*
+ * Lookup one path component @name relative to a <base,mnt> path pair.
+ * Behaves nearly the same as lookup_one_len (i.e., return negative dentry
+ * on ENOENT), but uses the @mnt passed, so it can cross bind mounts and
+ * other lower mounts properly.  If @new_mnt is non-null, will fill in the
+ * new mnt there.  Caller is responsible to dput/mntput/path_put returned
+ * @dentry and @new_mnt.
+ */
+struct dentry *__lookup_one(struct dentry *base, struct vfsmount *mnt,
+			    const char *name, struct vfsmount **new_mnt)
+{
+	struct dentry *dentry = NULL;
+	struct nameidata lower_nd;
+	int err;
+
+	/* we use flags=0 to get basic lookup */
+	err = vfs_path_lookup(base, mnt, name, 0, &lower_nd);
+
+	switch (err) {
+	case 0: /* no error */
+		dentry = lower_nd.path.dentry;
+		if (new_mnt)
+			*new_mnt = lower_nd.path.mnt; /* rc already inc'ed */
+		break;
+	case -ENOENT:
+		 /*
+		  * We don't consider ENOENT an error, and we want to return
+		  * a negative dentry (ala lookup_one_len).  As we know
+		  * there was no inode for this name before (-ENOENT), then
+		  * it's safe to call lookup_one_len (which doesn't take a
+		  * vfsmount).
+		  */
+		dentry = lookup_one_len(name, base, strlen(name));
+		if (new_mnt)
+			*new_mnt = mntget(lower_nd.path.mnt);
+		break;
+	default: /* all other real errors */
+		dentry = ERR_PTR(err);
+		break;
+	}
+
+	return dentry;
+}
 
 /*
  * Main (and complex) driver function for Unionfs's lookup
@@ -32,7 +74,8 @@ static int realloc_dentry_private_data(struct dentry *dentry);
  * dentry's info, which the caller must unlock.
  */
 struct dentry *unionfs_lookup_backend(struct dentry *dentry,
-				      struct nameidata *nd, int lookupmode)
+				      struct nameidata *nd_unused,
+				      int lookupmode)
 {
 	int err = 0;
 	struct dentry *lower_dentry = NULL;
@@ -361,6 +404,7 @@ out:
  * Caller must lock this dentry with unionfs_lock_dentry.
  *
  * Returns: 0 (ok), or -ERRNO if an error occurred.
+ * XXX: get rid of _partial_lookup and make callers call _lookup_full directly
  */
 int unionfs_partial_lookup(struct dentry *dentry)
 {
@@ -368,7 +412,8 @@ int unionfs_partial_lookup(struct dentry *dentry)
 	struct nameidata nd = { .flags = 0 };
 	int err = -ENOSYS;
 
-	tmp = unionfs_lookup_backend(dentry, &nd, INTERPOSE_PARTIAL);
+	tmp = unionfs_lookup_full(dentry, &nd, INTERPOSE_PARTIAL);
+
 	if (!tmp) {
 		err = 0;
 		goto out;
@@ -377,7 +422,7 @@ int unionfs_partial_lookup(struct dentry *dentry)
 		err = PTR_ERR(tmp);
 		goto out;
 	}
-	/* need to change the interface */
+	/* XXX: need to change the interface */
 	BUG_ON(tmp != dentry);
 out:
 	return err;
@@ -437,7 +482,7 @@ static inline int __realloc_dentry_private_data(struct dentry *dentry)
 }
 
 /* UNIONFS_D(dentry)->lock must be locked */
-static int realloc_dentry_private_data(struct dentry *dentry)
+int realloc_dentry_private_data(struct dentry *dentry)
 {
 	if (!__realloc_dentry_private_data(dentry))
 		return 0;
@@ -568,3 +613,296 @@ void release_lower_nd(struct nameidata *nd, int err)
 	kfree(nd->intent.open.file);
 #endif /* ALLOC_LOWER_ND_FILE */
 }
+
+/*
+ * Main (and complex) driver function for Unionfs's lookup
+ *
+ * Returns: NULL (ok), ERR_PTR if an error occurred, or a non-null non-error
+ * PTR if d_splice returned a different dentry.
+ *
+ * If lookupmode is INTERPOSE_PARTIAL/REVAL/REVAL_NEG, the passed dentry's
+ * inode info must be locked.  If lookupmode is INTERPOSE_LOOKUP (i.e., a
+ * newly looked-up dentry), then unionfs_lookup_backend will return a locked
+ * dentry's info, which the caller must unlock.
+ */
+struct dentry *unionfs_lookup_full(struct dentry *dentry,
+				   struct nameidata *nd_unused, int lookupmode)
+{
+	int err = 0;
+	struct dentry *lower_dentry = NULL;
+	struct vfsmount *lower_mnt;
+	struct vfsmount *lower_dir_mnt;
+	struct dentry *wh_lower_dentry = NULL;
+	struct dentry *lower_dir_dentry = NULL;
+	struct dentry *parent_dentry = NULL;
+	struct dentry *d_interposed = NULL;
+	int bindex, bstart, bend, bopaque;
+	int opaque, num_positive = 0;
+	const char *name;
+	int namelen;
+	int pos_start, pos_end;
+
+	/*
+	 * We should already have a lock on this dentry in the case of a
+	 * partial lookup, or a revalidation.  Otherwise it is returned from
+	 * new_dentry_private_data already locked.
+	 */
+	verify_locked(dentry);
+
+	/* must initialize dentry operations */
+	dentry->d_op = &unionfs_dops;
+
+	/* We never partial lookup the root directory. */
+	if (IS_ROOT(dentry))
+		goto out;
+	parent_dentry = dget_parent(dentry);
+
+	name = dentry->d_name.name;
+	namelen = dentry->d_name.len;
+
+	/* No dentries should get created for possible whiteout names. */
+	if (!is_validname(name)) {
+		err = -EPERM;
+		goto out_free;
+	}
+
+	/* Now start the actual lookup procedure. */
+	bstart = dbstart(parent_dentry);
+	bend = dbend(parent_dentry);
+	bopaque = dbopaque(parent_dentry);
+	BUG_ON(bstart < 0);
+
+	/* adjust bend to bopaque if needed */
+	if ((bopaque >= 0) && (bopaque < bend))
+		bend = bopaque;
+
+	/* lookup all possible dentries */
+	for (bindex = bstart; bindex <= bend; bindex++) {
+
+		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+		lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
+
+		/* skip if we already have a positive lower dentry */
+		if (lower_dentry) {
+			if (dbstart(dentry) < 0)
+				dbstart(dentry) = bindex;
+			if (bindex > dbend(dentry))
+				dbend(dentry) = bindex;
+			if (lower_dentry->d_inode)
+				num_positive++;
+			continue;
+		}
+
+		lower_dir_dentry =
+			unionfs_lower_dentry_idx(parent_dentry, bindex);
+		/* if the lower dentry's parent does not exist, skip this */
+		if (!lower_dir_dentry || !lower_dir_dentry->d_inode)
+			continue;
+
+		/* also skip it if the parent isn't a directory. */
+		if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
+			continue; /* XXX: should be BUG_ON */
+
+		/* check for whiteouts: stop lookup if found */
+		wh_lower_dentry = lookup_whiteout(name, lower_dir_dentry);
+		if (IS_ERR(wh_lower_dentry)) {
+			err = PTR_ERR(wh_lower_dentry);
+			goto out_free;
+		}
+		if (wh_lower_dentry->d_inode) {
+			dbend(dentry) = dbopaque(dentry) = bindex;
+			if (dbstart(dentry) < 0)
+				dbstart(dentry) = bindex;
+			dput(wh_lower_dentry);
+			break;
+		}
+		dput(wh_lower_dentry);
+
+		/* Now do regular lookup; lookup @name */
+		lower_dir_mnt = unionfs_lower_mnt_idx(parent_dentry, bindex);
+		lower_mnt = NULL; /* XXX: needed? */
+
+		lower_dentry = __lookup_one(lower_dir_dentry, lower_dir_mnt,
+					    name, &lower_mnt);
+
+		if (IS_ERR(lower_dentry)) {
+			err = PTR_ERR(lower_dentry);
+			goto out_free;
+		}
+		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
+		BUG_ON(!lower_mnt);
+		unionfs_set_lower_mnt_idx(dentry, bindex, lower_mnt);
+
+		/* adjust dbstart/end */
+		if (dbstart(dentry) < 0)
+			dbstart(dentry) = bindex;
+		if (bindex > dbend(dentry))
+			dbend(dentry) = bindex;
+		/*
+		 * We always store the lower dentries above, and update
+		 * dbstart/dbend, even if the whole unionfs dentry is
+		 * negative (i.e., no lower inodes).
+		 */
+		if (!lower_dentry->d_inode)
+			continue;
+		num_positive++;
+
+		/*
+		 * check if we just found an opaque directory, if so, stop
+		 * lookups here.
+		 */
+		if (!S_ISDIR(lower_dentry->d_inode->i_mode))
+			continue;
+		opaque = is_opaque_dir(dentry, bindex);
+		if (opaque < 0) {
+			err = opaque;
+			goto out_free;
+		} else if (opaque) {
+			dbend(dentry) = dbopaque(dentry) = bindex;
+			break;
+		}
+		dbend(dentry) = bindex;
+
+		/* update parent directory's atime with the bindex */
+		fsstack_copy_attr_atime(parent_dentry->d_inode,
+					lower_dir_dentry->d_inode);
+	}
+
+	/* sanity checks, then decide if to process a negative dentry */
+	BUG_ON(dbstart(dentry) < 0 && dbend(dentry) >= 0);
+	BUG_ON(dbstart(dentry) >= 0 && dbend(dentry) < 0);
+
+	if (num_positive > 0)
+		goto out_positive;
+
+	/*** handle NEGATIVE dentries ***/
+
+	/*
+	 * If negative, keep only first lower negative dentry, to save on
+	 * memory.
+	 */
+	if (dbstart(dentry) < dbend(dentry)) {
+		path_put_lowers(dentry, dbstart(dentry) + 1,
+				dbend(dentry), false);
+		dbend(dentry) = dbstart(dentry);
+	}
+	if (lookupmode == INTERPOSE_PARTIAL)
+		goto out;
+	if (lookupmode == INTERPOSE_LOOKUP) {
+		/*
+		 * If all we found was a whiteout in the first available
+		 * branch, then create a negative dentry for a possibly new
+		 * file to be created.
+		 */
+		if (dbopaque(dentry) < 0)
+			goto out;
+		/* XXX: need to get mnt here */
+		bindex = dbstart(dentry);
+		if (unionfs_lower_dentry_idx(dentry, bindex))
+			goto out;
+		lower_dir_dentry =
+			unionfs_lower_dentry_idx(parent_dentry, bindex);
+		if (!lower_dir_dentry || !lower_dir_dentry->d_inode)
+			goto out;
+		if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
+			goto out; /* XXX: should be BUG_ON */
+		/* XXX: do we need to cross bind mounts here? */
+		lower_dentry = lookup_one_len(name, lower_dir_dentry, namelen);
+		if (IS_ERR(lower_dentry)) {
+			err = PTR_ERR(lower_dentry);
+			goto out;
+		}
+		/* XXX: need to mntget/mntput as needed too! */
+		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
+		/* XXX: wrong mnt for crossing bind mounts! */
+		lower_mnt = unionfs_mntget(dentry->d_sb->s_root, bindex);
+		unionfs_set_lower_mnt_idx(dentry, bindex, lower_mnt);
+
+		goto out;
+	}
+
+	/* if we're revalidating a positive dentry, don't make it negative */
+	if (lookupmode != INTERPOSE_REVAL)
+		d_add(dentry, NULL);
+
+	goto out;
+
+out_positive:
+	/*** handle POSITIVE dentries ***/
+
+	/*
+	 * This unionfs dentry is positive (at least one lower inode
+	 * exists), so scan entire dentry from beginning to end, and remove
+	 * any negative lower dentries, if any.  Then, update dbstart/dbend
+	 * to reflect the start/end of positive dentries.
+	 */
+	pos_start = pos_end = -1;
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		lower_dentry = unionfs_lower_dentry_idx(dentry,
+							bindex);
+		if (lower_dentry && lower_dentry->d_inode) {
+			if (pos_start < 0)
+				pos_start = bindex;
+			if (bindex > pos_end)
+				pos_end = bindex;
+			continue;
+		}
+		path_put_lowers(dentry, bindex, bindex, false);
+	}
+	if (pos_start >= 0)
+		dbstart(dentry) = pos_start;
+	if (pos_end >= 0)
+		dbend(dentry) = pos_end;
+
+	/* Partial lookups need to re-interpose, or throw away older negs. */
+	if (lookupmode == INTERPOSE_PARTIAL) {
+		if (dentry->d_inode) {
+			unionfs_reinterpose(dentry);
+			goto out;
+		}
+
+		/*
+		 * This dentry was positive, so it is as if we had a
+		 * negative revalidation.
+		 */
+		lookupmode = INTERPOSE_REVAL_NEG;
+		update_bstart(dentry);
+	}
+
+	/*
+	 * Interpose can return a dentry if d_splice returned a different
+	 * dentry.
+	 */
+	d_interposed = unionfs_interpose(dentry, dentry->d_sb, lookupmode);
+	if (IS_ERR(d_interposed))
+		err = PTR_ERR(d_interposed);
+	else if (d_interposed)
+		dentry = d_interposed;
+
+	if (!err)
+		goto out;
+	d_drop(dentry);
+
+out_free:
+	/* should dput/mntput all the underlying dentries on error condition */
+	if (dbstart(dentry) >= 0)
+		path_put_lowers_all(dentry, false);
+	/* free lower_paths unconditionally */
+	kfree(UNIONFS_D(dentry)->lower_paths);
+	UNIONFS_D(dentry)->lower_paths = NULL;
+
+out:
+	if (dentry && UNIONFS_D(dentry)) {
+		BUG_ON(dbstart(dentry) < 0 && dbend(dentry) >= 0);
+		BUG_ON(dbstart(dentry) >= 0 && dbend(dentry) < 0);
+	}
+	if (d_interposed && UNIONFS_D(d_interposed)) {
+		BUG_ON(dbstart(d_interposed) < 0 && dbend(d_interposed) >= 0);
+		BUG_ON(dbstart(d_interposed) >= 0 && dbend(d_interposed) < 0);
+	}
+
+	dput(parent_dentry);
+	if (!err && d_interposed)
+		return d_interposed;
+	return ERR_PTR(err);
+}
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index 85f96ee..ecce9da 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -195,6 +195,7 @@ static int do_unionfs_rename(struct inode *old_dir,
 		struct dentry *unlink_dentry;
 		struct dentry *unlink_dir_dentry;
 
+		BUG_ON(bindex < 0);
 		unlink_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
 		if (!unlink_dentry)
 			continue;
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 9271b3b..81f34c4 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -294,6 +294,7 @@ static inline void unionfs_double_lock_dentry(struct dentry *d1,
 }
 
 extern int new_dentry_private_data(struct dentry *dentry, int subclass);
+extern int realloc_dentry_private_data(struct dentry *dentry);
 extern void free_dentry_private_data(struct dentry *dentry);
 extern void update_bstart(struct dentry *dentry);
 extern int init_lower_nd(struct nameidata *nd, unsigned int flags);
@@ -309,6 +310,9 @@ extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
 
 /* partial lookup */
 extern int unionfs_partial_lookup(struct dentry *dentry);
+extern struct dentry *unionfs_lookup_full(struct dentry *dentry,
+					  struct nameidata *nd_unused,
+					  int lookupmode);
 
 /* copies a file from dbstart to newbindex branch */
 extern int copyup_file(struct inode *dir, struct file *file, int bstart,
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/19] Unionfs: free lower paths array when destroying dentry's private data
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (7 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 08/19] Unionfs: lookup overhaul using vfs_path_lookup Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 10/19] Unionfs: cache coherency fixes Erez Zadok
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm
  Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok,
	Hugh Dickins

CC: Hugh Dickins <hugh@veritas.com>

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/lookup.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 37adf66..b5f64c9 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -450,6 +450,8 @@ void free_dentry_private_data(struct dentry *dentry)
 {
 	if (!dentry || !dentry->d_fsdata)
 		return;
+	kfree(UNIONFS_D(dentry)->lower_paths);
+	UNIONFS_D(dentry)->lower_paths = NULL;
 	kmem_cache_free(unionfs_dentry_cachep, dentry->d_fsdata);
 	dentry->d_fsdata = NULL;
 }
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/19] Unionfs: cache coherency fixes
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (8 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 09/19] Unionfs: free lower paths array when destroying dentry's private data Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 11/19] Unionfs: remove old lookup code Erez Zadok
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Handle unhashed or silly-renamed lower dentries properly.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c |    3 +-
 fs/unionfs/debug.c      |    2 +-
 fs/unionfs/dentry.c     |   49 +++++++++++++++++++++++++++++++++++++++++-----
 fs/unionfs/main.c       |    3 --
 4 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index df002d5..d64272b 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -466,7 +466,8 @@ reval_dentry:
 	dgen = atomic_read(&UNIONFS_D(dentry)->generation);
 
 	if (unlikely(sbgen > dgen)) {
-		pr_debug("unionfs: retry (locked) dentry revalidation\n");
+		pr_debug("unionfs: retry (locked) dentry %s revalidation\n",
+			 dentry->d_name.name);
 		schedule();
 		goto reval_dentry;
 	}
diff --git a/fs/unionfs/debug.c b/fs/unionfs/debug.c
index d154c32..4da4f0b 100644
--- a/fs/unionfs/debug.c
+++ b/fs/unionfs/debug.c
@@ -313,7 +313,7 @@ check_inode:
 			}
 		}
 	/* check if lower inode is newer than upper one (it shouldn't) */
-	if (unlikely(is_newer_lower(dentry))) {
+	if (unlikely(is_newer_lower(dentry) && !is_negative_lower(dentry))) {
 		PRINT_CALLER(fname, fxn, line);
 		for (bindex = ibstart(inode); bindex <= ibend(inode);
 		     bindex++) {
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index cd4611b..dfa4755 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -23,11 +23,16 @@ bool is_negative_lower(const struct dentry *dentry)
 	int bindex;
 	struct dentry *lower_dentry;
 
-	BUG_ON(!dentry || dbstart(dentry) < 0);
+	BUG_ON(!dentry);
+	/* cache coherency: check if file was deleted on lower branch */
+	if (dbstart(dentry) < 0)
+		return true;
 	for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
 		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-		/* XXX: what if lower_dentry is NULL? */
-		if (lower_dentry && lower_dentry->d_inode)
+		/* unhashed (i.e., unlinked) lower dentries don't count */
+		if (lower_dentry && lower_dentry->d_inode &&
+		    !d_deleted(lower_dentry) &&
+		    !(lower_dentry->d_flags & DCACHE_NFSFS_RENAMED))
 			return false;
 	}
 	return true;
@@ -75,6 +80,7 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 	verify_locked(dentry);
 	verify_locked(dentry->d_parent);
 
+	sbgen = atomic_read(&UNIONFS_SB(dentry->d_sb)->generation);
 	/* if the dentry is unhashed, do NOT revalidate */
 	if (d_deleted(dentry))
 		goto out;
@@ -83,7 +89,6 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 	if (dentry->d_inode)
 		positive = 1;
 	dgen = atomic_read(&UNIONFS_D(dentry)->generation);
-	sbgen = atomic_read(&UNIONFS_SB(dentry->d_sb)->generation);
 	/*
 	 * If we are working on an unconnected dentry, then there is no
 	 * revalidation to be done, because this file does not exist within
@@ -103,6 +108,21 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 		/* Free the pointers for our inodes and this dentry. */
 		bstart = dbstart(dentry);
 		bend = dbend(dentry);
+
+		/*
+		 * mntput unhashed lower dentries, because those files got
+		 * deleted or rmdir'ed.
+		 */
+		for (bindex = bstart; bindex <= bend; bindex++) {
+			lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+			if (!lower_dentry)
+				continue;
+			if (!d_deleted(lower_dentry) &&
+			    !(lower_dentry->d_flags & DCACHE_NFSFS_RENAMED))
+			    continue;
+			unionfs_mntput(dentry, bindex);
+		}
+
 		__dput_lowers(dentry, bstart, bend);
 		dbstart(dentry) = dbend(dentry) = -1;
 
@@ -112,8 +132,12 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 			iput_lowers_all(dentry->d_inode, true);
 		}
 
-		result = unionfs_lookup_backend(dentry, &lowernd,
-						interpose_flag);
+		if (realloc_dentry_private_data(dentry) != 0) {
+			valid = false;
+			goto out;
+		}
+
+		result = unionfs_lookup_full(dentry, &lowernd, interpose_flag);
 		if (result) {
 			if (IS_ERR(result)) {
 				valid = false;
@@ -179,6 +203,9 @@ static bool __unionfs_d_revalidate_one(struct dentry *dentry,
 	}
 
 out:
+	if (valid)
+		atomic_set(&UNIONFS_D(dentry)->generation, sbgen);
+
 	return valid;
 }
 
@@ -241,6 +268,16 @@ bool is_newer_lower(const struct dentry *dentry)
 			return true;
 		}
 	}
+
+	/*
+	 * Last check: if this is a positive dentry, but somehow all lower
+	 * dentries are negative or unhashed, then this dentry needs to be
+	 * revalidated, because someone probably deleted the objects from
+	 * the lower branches directly.
+	 */
+	if (is_negative_lower(dentry))
+		return true;
+
 	return false;		/* default: lower is not newer */
 }
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index a9d2cb6..1fd67c6 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -88,9 +88,6 @@ struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block *sb,
 
 	verify_locked(dentry);
 
-	/* Make sure that we didn't get a negative dentry. */
-	BUG_ON(is_negative_lower(dentry));
-
 	/*
 	 * We allocate our new inode below by calling unionfs_iget,
 	 * which will initialize some of the new inode's fields
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/19] Unionfs: remove old lookup code
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (9 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 10/19] Unionfs: cache coherency fixes Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 12/19] Unionfs: update maintainers Erez Zadok
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/lookup.c |  337 ---------------------------------------------------
 fs/unionfs/union.h  |    3 -
 2 files changed, 0 insertions(+), 340 deletions(-)

diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index b5f64c9..93c3a14 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -63,343 +63,6 @@ struct dentry *__lookup_one(struct dentry *base, struct vfsmount *mnt,
 }
 
 /*
- * Main (and complex) driver function for Unionfs's lookup
- *
- * Returns: NULL (ok), ERR_PTR if an error occurred, or a non-null non-error
- * PTR if d_splice returned a different dentry.
- *
- * If lookupmode is INTERPOSE_PARTIAL/REVAL/REVAL_NEG, the passed dentry's
- * inode info must be locked.  If lookupmode is INTERPOSE_LOOKUP (i.e., a
- * newly looked-up dentry), then unionfs_lookup_backend will return a locked
- * dentry's info, which the caller must unlock.
- */
-struct dentry *unionfs_lookup_backend(struct dentry *dentry,
-				      struct nameidata *nd_unused,
-				      int lookupmode)
-{
-	int err = 0;
-	struct dentry *lower_dentry = NULL;
-	struct dentry *wh_lower_dentry = NULL;
-	struct dentry *lower_dir_dentry = NULL;
-	struct dentry *parent_dentry = NULL;
-	struct dentry *d_interposed = NULL;
-	int bindex, bstart = -1, bend, bopaque;
-	int dentry_count = 0;	/* Number of positive dentries. */
-	int first_dentry_offset = -1; /* -1 is uninitialized */
-	struct dentry *first_dentry = NULL;
-	struct dentry *first_lower_dentry = NULL;
-	struct vfsmount *first_lower_mnt = NULL;
-	int opaque;
-	const char *name;
-	int namelen;
-
-	/*
-	 * We should already have a lock on this dentry in the case of a
-	 * partial lookup, or a revalidation. Otherwise it is returned from
-	 * new_dentry_private_data already locked.
-	 */
-	if (lookupmode == INTERPOSE_PARTIAL || lookupmode == INTERPOSE_REVAL ||
-	    lookupmode == INTERPOSE_REVAL_NEG)
-		verify_locked(dentry);
-	else			/* this could only be INTERPOSE_LOOKUP */
-		BUG_ON(UNIONFS_D(dentry) != NULL);
-
-	switch (lookupmode) {
-	case INTERPOSE_PARTIAL:
-		break;
-	case INTERPOSE_LOOKUP:
-		err = new_dentry_private_data(dentry, UNIONFS_DMUTEX_CHILD);
-		if (unlikely(err))
-			goto out;
-		break;
-	default:
-		/* default: can only be INTERPOSE_REVAL/REVAL_NEG */
-		err = realloc_dentry_private_data(dentry);
-		if (unlikely(err))
-			goto out;
-		break;
-	}
-
-	/* must initialize dentry operations */
-	dentry->d_op = &unionfs_dops;
-
-	parent_dentry = dget_parent(dentry);
-	/* We never partial lookup the root directory. */
-	if (parent_dentry == dentry) {
-		dput(parent_dentry);
-		parent_dentry = NULL;
-		goto out;
-	}
-
-	name = dentry->d_name.name;
-	namelen = dentry->d_name.len;
-
-	/* No dentries should get created for possible whiteout names. */
-	if (!is_validname(name)) {
-		err = -EPERM;
-		goto out_free;
-	}
-
-	/* Now start the actual lookup procedure. */
-	bstart = dbstart(parent_dentry);
-	bend = dbend(parent_dentry);
-	bopaque = dbopaque(parent_dentry);
-	BUG_ON(bstart < 0);
-
-	/*
-	 * It would be ideal if we could convert partial lookups to only have
-	 * to do this work when they really need to.  It could probably improve
-	 * performance quite a bit, and maybe simplify the rest of the code.
-	 */
-	if (lookupmode == INTERPOSE_PARTIAL) {
-		bstart++;
-		if ((bopaque != -1) && (bopaque < bend))
-			bend = bopaque;
-	}
-
-	for (bindex = bstart; bindex <= bend; bindex++) {
-		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-		if (lookupmode == INTERPOSE_PARTIAL && lower_dentry)
-			continue;
-		BUG_ON(lower_dentry != NULL);
-
-		lower_dir_dentry =
-			unionfs_lower_dentry_idx(parent_dentry, bindex);
-
-		/* if the parent lower dentry does not exist skip this */
-		if (!(lower_dir_dentry && lower_dir_dentry->d_inode))
-			continue;
-
-		/* also skip it if the parent isn't a directory. */
-		if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
-			continue;
-
-		/* check for whiteouts: stop lookup if found */
-		wh_lower_dentry = lookup_whiteout(name, lower_dir_dentry);
-		if (IS_ERR(wh_lower_dentry)) {
-			dput(first_lower_dentry);
-			unionfs_mntput(first_dentry, first_dentry_offset);
-			err = PTR_ERR(wh_lower_dentry);
-			goto out_free;
-		}
-		if (wh_lower_dentry->d_inode) {
-			dbend(dentry) = dbopaque(dentry) = bindex;
-			dput(wh_lower_dentry);
-			break;
-		}
-		dput(wh_lower_dentry);
-		wh_lower_dentry = NULL;
-
-		/* Now do regular lookup; lookup foo */
-		BUG_ON(!lower_dir_dentry);
-		lower_dentry = lookup_one_len(name, lower_dir_dentry, namelen);
-		if (IS_ERR(lower_dentry)) {
-			dput(first_lower_dentry);
-			unionfs_mntput(first_dentry, first_dentry_offset);
-			err = PTR_ERR(lower_dentry);
-			goto out_free;
-		}
-
-		/*
-		 * Store the first negative dentry specially, because if they
-		 * are all negative we need this for future creates.
-		 */
-		if (!lower_dentry->d_inode) {
-			if (!first_lower_dentry && (dbstart(dentry) == -1)) {
-				first_lower_dentry = lower_dentry;
-				/*
-				 * FIXME: following line needs to be changed
-				 * to allow mount-point crossing
-				 */
-				first_dentry = parent_dentry;
-				first_lower_mnt =
-					unionfs_mntget(parent_dentry, bindex);
-				first_dentry_offset = bindex;
-			} else {
-				dput(lower_dentry);
-			}
-
-			continue;
-		}
-
-		/*
-		 * If we already found at least one positive dentry
-		 * (dentry_count is non-zero), then we skip all remaining
-		 * positive dentries if their type is a non-dir.  This is
-		 * because only directories are allowed to stack on multiple
-		 * branches, but we have to skip non-dirs (to avoid, say,
-		 * calling readdir on a regular file).
-		 */
-		if ((lookupmode != INTERPOSE_PARTIAL) &&
-		    !S_ISDIR(lower_dentry->d_inode->i_mode) &&
-		    dentry_count) {
-			dput(lower_dentry);
-			continue;
-		}
-
-		/* number of positive dentries */
-		dentry_count++;
-
-		/* store underlying dentry */
-		if (dbstart(dentry) == -1)
-			dbstart(dentry) = bindex;
-		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
-		/*
-		 * FIXME: the following line needs to get fixed to allow
-		 * mount-point crossing
-		 */
-		unionfs_set_lower_mnt_idx(dentry, bindex,
-					  unionfs_mntget(parent_dentry,
-							 bindex));
-		dbend(dentry) = bindex;
-
-		/* update parent directory's atime with the bindex */
-		fsstack_copy_attr_atime(parent_dentry->d_inode,
-					lower_dir_dentry->d_inode);
-
-		/* We terminate file lookups here. */
-		if (!S_ISDIR(lower_dentry->d_inode->i_mode)) {
-			if (lookupmode == INTERPOSE_PARTIAL)
-				continue;
-			if (dentry_count == 1)
-				goto out_positive;
-		}
-
-		opaque = is_opaque_dir(dentry, bindex);
-		if (opaque < 0) {
-			dput(first_lower_dentry);
-			unionfs_mntput(first_dentry, first_dentry_offset);
-			err = opaque;
-			goto out_free;
-		} else if (opaque) {
-			dbend(dentry) = dbopaque(dentry) = bindex;
-			break;
-		}
-	}
-
-	if (dentry_count)
-		goto out_positive;
-	else
-		goto out_negative;
-
-out_negative:
-	if (lookupmode == INTERPOSE_PARTIAL)
-		goto out;
-
-	/* If we've only got negative dentries, then use the leftmost one. */
-	if (lookupmode == INTERPOSE_REVAL)
-		goto out;
-
-	if (!lower_dir_dentry) {
-		err = -ENOENT;
-		goto out;
-	}
-	/* This should only happen if we found a whiteout. */
-	if (first_dentry_offset == -1) {
-		first_lower_dentry = lookup_one_len(name, lower_dir_dentry,
-						    namelen);
-		first_dentry_offset = bindex;
-		if (IS_ERR(first_lower_dentry)) {
-			err = PTR_ERR(first_lower_dentry);
-			goto out;
-		}
-
-		/*
-		 * FIXME: the following line needs to be changed to allow
-		 * mount-point crossing
-		 */
-		first_dentry = dentry;
-		first_lower_mnt = unionfs_mntget(dentry->d_sb->s_root,
-						 bindex);
-	}
-	unionfs_set_lower_dentry_idx(dentry, first_dentry_offset,
-				     first_lower_dentry);
-	unionfs_set_lower_mnt_idx(dentry, first_dentry_offset,
-				  first_lower_mnt);
-	dbstart(dentry) = dbend(dentry) = first_dentry_offset;
-
-	if (lookupmode == INTERPOSE_REVAL_NEG)
-		BUG_ON(dentry->d_inode != NULL);
-	else
-		d_add(dentry, NULL);
-	goto out;
-
-/* This part of the code is for positive dentries. */
-out_positive:
-	BUG_ON(dentry_count <= 0);
-
-	/*
-	 * If we're holding onto the first negative dentry & corresponding
-	 * vfsmount - throw it out.
-	 */
-	dput(first_lower_dentry);
-	unionfs_mntput(first_dentry, first_dentry_offset);
-
-	/* Partial lookups need to re-interpose, or throw away older negs. */
-	if (lookupmode == INTERPOSE_PARTIAL) {
-		if (dentry->d_inode) {
-			unionfs_reinterpose(dentry);
-			goto out;
-		}
-
-		/*
-		 * This somehow turned positive, so it is as if we had a
-		 * negative revalidation.
-		 */
-		lookupmode = INTERPOSE_REVAL_NEG;
-
-		update_bstart(dentry);
-		bstart = dbstart(dentry);
-		bend = dbend(dentry);
-	}
-
-	/*
-	 * Interpose can return a dentry if d_splice returned a different
-	 * dentry.
-	 */
-	d_interposed = unionfs_interpose(dentry, dentry->d_sb, lookupmode);
-	if (IS_ERR(d_interposed))
-		err = PTR_ERR(d_interposed);
-	else if (d_interposed)
-		dentry = d_interposed;
-
-	if (err)
-		goto out_drop;
-
-	goto out;
-
-out_drop:
-	d_drop(dentry);
-
-out_free:
-	/* should dput/mntput all the underlying dentries on error condition */
-	if (dbstart(dentry) >= 0)
-		path_put_lowers_all(dentry, false);
-	/* free lower_paths unconditionally */
-	kfree(UNIONFS_D(dentry)->lower_paths);
-	UNIONFS_D(dentry)->lower_paths = NULL;
-
-out:
-	if (!err && UNIONFS_D(dentry)) {
-		BUG_ON(dbend(dentry) > UNIONFS_D(dentry)->bcount);
-		BUG_ON(dbend(dentry) > sbmax(dentry->d_sb));
-		if (dbstart(dentry) < 0 &&
-		    dentry->d_inode && bstart >= 0 &&
-		    (!UNIONFS_I(dentry->d_inode) ||
-		     !UNIONFS_I(dentry->d_inode)->lower_inodes)) {
-			unionfs_mntput(dentry->d_sb->s_root, bstart);
-			dput(first_lower_dentry);
-		}
-	}
-	dput(parent_dentry);
-	if (err && (lookupmode == INTERPOSE_LOOKUP))
-		unionfs_unlock_dentry(dentry);
-	if (!err && d_interposed)
-		return d_interposed;
-	return ERR_PTR(err);
-}
-
-/*
  * This is a utility function that fills in a unionfs dentry.
  * Caller must lock this dentry with unionfs_lock_dentry.
  *
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 81f34c4..356a146 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -415,9 +415,6 @@ static inline int d_deleted(struct dentry *d)
 	return d_unhashed(d) && (d != d->d_sb->s_root);
 }
 
-struct dentry *unionfs_lookup_backend(struct dentry *dentry,
-				      struct nameidata *nd, int lookupmode);
-
 /* unionfs_permission, check if we should bypass error to facilitate copyup */
 #define IS_COPYUP_ERR(err) ((err) == -EROFS)
 
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 12/19] Unionfs: update maintainers
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (10 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 11/19] Unionfs: remove old lookup code Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 13/19] Unionfs: update copyrights Erez Zadok
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 MAINTAINERS |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 797e7b9..c722f8e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4176,10 +4176,9 @@ S:	Maintained
 UNIONFS
 P:	Erez Zadok
 M:	ezk@cs.sunysb.edu
-P:	Josef "Jeff" Sipek
-M:	jsipek@cs.sunysb.edu
 L:	unionfs@filesystems.org
 W:	http://unionfs.filesystems.org
+T:	git git.kernel.org/pub/scm/linux/kernel/git/ezk/unionfs.git
 S:	Maintained
 
 USB ACM DRIVER
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 13/19] Unionfs: update copyrights
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (11 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 12/19] Unionfs: update maintainers Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 14/19] Unionfs: minor checkpatch fixes Erez Zadok
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/commonfops.c  |    6 +++---
 fs/unionfs/copyup.c      |    6 +++---
 fs/unionfs/debug.c       |    6 +++---
 fs/unionfs/dentry.c      |    6 +++---
 fs/unionfs/dirfops.c     |    6 +++---
 fs/unionfs/dirhelper.c   |    6 +++---
 fs/unionfs/fanout.h      |    6 +++---
 fs/unionfs/file.c        |    6 +++---
 fs/unionfs/inode.c       |    6 +++---
 fs/unionfs/lookup.c      |    6 +++---
 fs/unionfs/main.c        |    6 +++---
 fs/unionfs/mmap.c        |    6 +++---
 fs/unionfs/rdstate.c     |    6 +++---
 fs/unionfs/rename.c      |    6 +++---
 fs/unionfs/sioq.c        |    6 +++---
 fs/unionfs/sioq.h        |    6 +++---
 fs/unionfs/subr.c        |    6 +++---
 fs/unionfs/super.c       |    6 +++---
 fs/unionfs/union.h       |    6 +++---
 fs/unionfs/unlink.c      |    6 +++---
 fs/unionfs/whiteout.c    |    6 +++---
 fs/unionfs/xattr.c       |    6 +++---
 include/linux/union_fs.h |    6 +++---
 23 files changed, 69 insertions(+), 69 deletions(-)

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index d64272b..5861970 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 55d48aa..bbd49c8 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/debug.c b/fs/unionfs/debug.c
index 4da4f0b..db62d22 100644
--- a/fs/unionfs/debug.c
+++ b/fs/unionfs/debug.c
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index dfa4755..7f0c7f7 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index e35afa4..14ca7d3 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 302a4a1..d936f03 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index d8977bd..4f264de 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005      Arun M. Krishnakumar
@@ -7,8 +7,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c
index 9b5fc58..965d071 100644
--- a/fs/unionfs/file.c
+++ b/fs/unionfs/file.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index f81ebb6..fa3c518 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 93c3a14..0ae7f3a 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 1fd67c6..6484e2b 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
index febde7c..b7d4713 100644
--- a/fs/unionfs/mmap.c
+++ b/fs/unionfs/mmap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -9,8 +9,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/rdstate.c b/fs/unionfs/rdstate.c
index 7ba1e1a..06d5374 100644
--- a/fs/unionfs/rdstate.c
+++ b/fs/unionfs/rdstate.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index ecce9da..da7d589 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
index 0ea8436..e6f15a0 100644
--- a/fs/unionfs/sioq.c
+++ b/fs/unionfs/sioq.c
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2006-2007 Erez Zadok
+ * Copyright (c) 2006-2008 Erez Zadok
  * Copyright (c) 2006      Charles P. Wright
  * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2006      Junjiro Okajima
  * Copyright (c) 2006      David P. Quigley
- * Copyright (c) 2006-2007 Stony Brook University
- * Copyright (c) 2006-2007 The Research Foundation of SUNY
+ * Copyright (c) 2006-2008 Stony Brook University
+ * Copyright (c) 2006-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
index afb71ee..e072bf7 100644
--- a/fs/unionfs/sioq.h
+++ b/fs/unionfs/sioq.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2006-2007 Erez Zadok
+ * Copyright (c) 2006-2008 Erez Zadok
  * Copyright (c) 2006      Charles P. Wright
  * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2006      Junjiro Okajima
  * Copyright (c) 2006      David P. Quigley
- * Copyright (c) 2006-2007 Stony Brook University
- * Copyright (c) 2006-2007 The Research Foundation of SUNY
+ * Copyright (c) 2006-2008 Stony Brook University
+ * Copyright (c) 2006-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index dda2745..8747d20 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 3b6b65a..f163c08 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 356a146..4c7b213 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005      Arun M. Krishnakumar
@@ -7,8 +7,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index 3d6ca5f..623f68d 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
index b1768ed..94b5241 100644
--- a/fs/unionfs/whiteout.c
+++ b/fs/unionfs/whiteout.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
index 8001c65..93a8fce 100644
--- a/fs/unionfs/xattr.c
+++ b/fs/unionfs/xattr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2003-2006 Charles P. Wright
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
  * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8,8 +8,8 @@
  * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
  * Copyright (c) 2003      Puja Gupta
  * Copyright (c) 2003      Harikesavan Krishnan
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/include/linux/union_fs.h b/include/linux/union_fs.h
index 9d601d2..7199458 100644
--- a/include/linux/union_fs.h
+++ b/include/linux/union_fs.h
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2008 Erez Zadok
  * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
- * Copyright (c) 2003-2007 Stony Brook University
- * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ * Copyright (c) 2003-2008 Stony Brook University
+ * Copyright (c) 2003-2008 The Research Foundation of SUNY
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 14/19] Unionfs: minor checkpatch fixes
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (12 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 13/19] Unionfs: update copyrights Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 15/19] Unionfs: properly hash newly created inodes Erez Zadok
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/main.c  |   12 ------------
 fs/unionfs/super.c |    4 ++--
 2 files changed, 2 insertions(+), 14 deletions(-)

diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 6484e2b..0cdd50b 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -459,8 +459,6 @@ static struct unionfs_dentry_info *unionfs_parse_options(
 
 	while ((optname = strsep(&options, ",")) != NULL) {
 		char *optarg;
-		char *endptr;
-		int intval;
 
 		if (!optname || !*optname)
 			continue;
@@ -493,16 +491,6 @@ static struct unionfs_dentry_info *unionfs_parse_options(
 			continue;
 		}
 
-		/* All of these options require an integer argument. */
-		intval = simple_strtoul(optarg, &endptr, 0);
-		if (*endptr) {
-			printk(KERN_ERR
-			       "unionfs: invalid %s option '%s'\n",
-			       optname, optarg);
-			err = -EINVAL;
-			goto out_error;
-		}
-
 		err = -EINVAL;
 		printk(KERN_ERR
 		       "unionfs: unrecognized option '%s'\n", optname);
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index f163c08..1f4b3f4 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -33,8 +33,8 @@ struct inode *unionfs_iget(struct super_block *sb, unsigned long ino)
 	inode = iget_locked(sb, ino);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
- 	if (!(inode->i_state & I_NEW))
- 		return inode;
+	if (!(inode->i_state & I_NEW))
+		return inode;
 
 	info = UNIONFS_I(inode);
 	memset(info, 0, offsetof(struct unionfs_inode_info, vfs_inode));
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 15/19] Unionfs: properly hash newly created inodes
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (13 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 14/19] Unionfs: minor checkpatch fixes Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 16/19] Unionfs: symlink no longer takes a mode parameter Erez Zadok
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

This fixes LTP's syscalls/rename13 test.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/inode.c |    2 +-
 fs/unionfs/main.c  |    3 +++
 2 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index fa3c518..a05b412 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -339,7 +339,7 @@ check_link:
 
 	/* Its a hard link, so use the same inode */
 	new_dentry->d_inode = igrab(old_dentry->d_inode);
-	d_instantiate(new_dentry, new_dentry->d_inode);
+	d_add(new_dentry, new_dentry->d_inode);
 	unionfs_copy_attr_all(dir, lower_new_dentry->d_parent->d_inode);
 	fsstack_copy_inode_size(dir, lower_new_dentry->d_parent->d_inode);
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 0cdd50b..fea670b 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -128,6 +128,9 @@ skip:
 	/* only (our) lookup wants to do a d_add */
 	switch (flag) {
 	case INTERPOSE_DEFAULT:
+		/* for operations which create new inodes */
+		d_add(dentry, inode);
+		break;
 	case INTERPOSE_REVAL_NEG:
 		d_instantiate(dentry, inode);
 		break;
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 16/19] Unionfs: symlink no longer takes a mode parameter
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (14 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 15/19] Unionfs: properly hash newly created inodes Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 17/19] Unionfs: permission no longer takes a nameidata parameter Erez Zadok
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/copyup.c |    1 -
 fs/unionfs/inode.c  |    3 +--
 fs/unionfs/sioq.c   |    2 +-
 fs/unionfs/sioq.h   |    1 -
 4 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index bbd49c8..ae6ea2b 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -184,7 +184,6 @@ static int __copyup_ndentry(struct dentry *old_lower_dentry,
 		args.symlink.parent = new_lower_parent_dentry->d_inode;
 		args.symlink.dentry = new_lower_dentry;
 		args.symlink.symbuf = symbuf;
-		args.symlink.mode = old_mode;
 
 		run_sioq(__unionfs_symlink, &args);
 		err = args.err;
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index a05b412..1a95e3b 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -412,8 +412,7 @@ static int unionfs_symlink(struct inode *parent, struct dentry *dentry,
 	}
 
 	mode = S_IALLUGO;
-	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry,
-			  symname, mode);
+	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
 	if (!err) {
 		err = PTR_ERR(unionfs_interpose(dentry, parent->i_sb, 0));
 		if (!err) {
diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
index e6f15a0..dd45e39 100644
--- a/fs/unionfs/sioq.c
+++ b/fs/unionfs/sioq.c
@@ -87,7 +87,7 @@ void __unionfs_symlink(struct work_struct *work)
 	struct sioq_args *args = container_of(work, struct sioq_args, work);
 	struct symlink_args *s = &args->symlink;
 
-	args->err = vfs_symlink(s->parent, s->dentry, s->symbuf, s->mode);
+	args->err = vfs_symlink(s->parent, s->dentry, s->symbuf);
 	complete(&args->comp);
 }
 
diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
index e072bf7..679a0df 100644
--- a/fs/unionfs/sioq.h
+++ b/fs/unionfs/sioq.h
@@ -49,7 +49,6 @@ struct symlink_args {
 	struct inode *parent;
 	struct dentry *dentry;
 	char *symbuf;
-	umode_t mode;
 };
 
 struct unlink_args {
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 17/19] Unionfs: permission no longer takes a nameidata parameter
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (15 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 16/19] Unionfs: symlink no longer takes a mode parameter Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 18/19] Unionfs: LOOKUP_ACCESS intent no longer exists Erez Zadok
  2008-07-30  2:43 ` [PATCH 19/19] Unionfs: use new kmem_cache_create constructor prototype Erez Zadok
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/inode.c    |   11 ++---------
 fs/unionfs/whiteout.c |    4 ++--
 2 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index 1a95e3b..0bd9fab 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -750,8 +750,7 @@ static void unionfs_put_link(struct dentry *dentry, struct nameidata *nd,
  * unionfs_permission, or anything it calls, will use stale branch
  * information.
  */
-static int unionfs_permission(struct inode *inode, int mask,
-			      struct nameidata *nd)
+static int unionfs_permission(struct inode *inode, int mask)
 {
 	struct inode *lower_inode = NULL;
 	int err = 0;
@@ -759,9 +758,6 @@ static int unionfs_permission(struct inode *inode, int mask,
 	const int is_file = !S_ISDIR(inode->i_mode);
 	const int write_mask = (mask & MAY_WRITE) && !(mask & MAY_READ);
 
-	if (nd)
-		unionfs_lock_dentry(nd->path.dentry, UNIONFS_DMUTEX_CHILD);
-
 	if (!UNIONFS_I(inode)->lower_inodes) {
 		if (is_file)	/* dirs can be unlinked but chdir'ed to */
 			err = -ESTALE;	/* force revalidate */
@@ -801,7 +797,7 @@ static int unionfs_permission(struct inode *inode, int mask,
 		 * readonly, because those conditions should lead to a
 		 * copyup taking place later on.
 		 */
-		err = permission(lower_inode, mask, nd);
+		err = inode_permission(lower_inode, mask);
 		if (err && bindex > 0) {
 			umode_t mode = lower_inode->i_mode;
 			if (is_robranch_super(inode->i_sb, bindex) &&
@@ -833,9 +829,6 @@ static int unionfs_permission(struct inode *inode, int mask,
 
 out:
 	unionfs_check_inode(inode);
-	unionfs_check_nd(nd);
-	if (nd)
-		unionfs_unlock_dentry(nd->path.dentry);
 	return err;
 }
 
diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
index 94b5241..db7a21e 100644
--- a/fs/unionfs/whiteout.c
+++ b/fs/unionfs/whiteout.c
@@ -455,7 +455,7 @@ int delete_whiteouts(struct dentry *dentry, int bindex,
 	lower_dir = lower_dir_dentry->d_inode;
 	BUG_ON(!S_ISDIR(lower_dir->i_mode));
 
-	if (!permission(lower_dir, MAY_WRITE | MAY_EXEC, NULL)) {
+	if (!inode_permission(lower_dir, MAY_WRITE | MAY_EXEC)) {
 		err = do_delete_whiteouts(dentry, bindex, namelist);
 	} else {
 		args.deletewh.namelist = namelist;
@@ -492,7 +492,7 @@ int is_opaque_dir(struct dentry *dentry, int bindex)
 
 	mutex_lock(&lower_inode->i_mutex);
 
-	if (!permission(lower_inode, MAY_EXEC, NULL)) {
+	if (!inode_permission(lower_inode, MAY_EXEC)) {
 		wh_lower_dentry =
 			lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
 				       sizeof(UNIONFS_DIR_OPAQUE) - 1);
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 18/19] Unionfs: LOOKUP_ACCESS intent no longer exists
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (16 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 17/19] Unionfs: permission no longer takes a nameidata parameter Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  2008-07-30  2:43 ` [PATCH 19/19] Unionfs: use new kmem_cache_create constructor prototype Erez Zadok
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/lookup.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 0ae7f3a..0a9602a 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -252,9 +252,6 @@ int init_lower_nd(struct nameidata *nd, unsigned int flags)
 		nd->intent.open.file = file;
 #endif /* ALLOC_LOWER_ND_FILE */
 		break;
-	case LOOKUP_ACCESS:
-		nd->flags = flags;
-		break;
 	default:
 		/*
 		 * We should never get here, for now.
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 19/19] Unionfs: use new kmem_cache_create constructor prototype
  2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
                   ` (17 preceding siblings ...)
  2008-07-30  2:43 ` [PATCH 18/19] Unionfs: LOOKUP_ACCESS intent no longer exists Erez Zadok
@ 2008-07-30  2:43 ` Erez Zadok
  18 siblings, 0 replies; 20+ messages in thread
From: Erez Zadok @ 2008-07-30  2:43 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, linux-fsdevel, viro, hch, miklos, Erez Zadok

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/super.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 1f4b3f4..e774ef3 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -900,7 +900,7 @@ static void unionfs_destroy_inode(struct inode *inode)
 }
 
 /* unionfs inode cache constructor */
-static void init_once(struct kmem_cache *cachep, void *obj)
+static void init_once(void *obj)
 {
 	struct unionfs_inode_info *i = obj;
 
-- 
1.5.2.2


^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2008-07-30  2:44 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-30  2:43 [GIT PULL -mm] 00/19 fsstack+Unionfs updates/fixes/cleanups Erez Zadok
2008-07-30  2:43 ` [PATCH 01/19] LTP's iogen01 doio tests used to hang nicely on 32-bit SMP when /tmp was a Erez Zadok
2008-07-30  2:43 ` [PATCH 02/19] Unionfs: simplify the macros used to get/set the dentry start/end branches Erez Zadok
2008-07-30  2:43 ` [PATCH 03/19] Unionfs: move a rename helper closer to rename code Erez Zadok
2008-07-30  2:43 ` [PATCH 04/19] Unionfs: create and consolidate helpers to iput lower objects Erez Zadok
2008-07-30  2:43 ` [PATCH 05/19] Unionfs: create and consolidate helpers to path-put " Erez Zadok
2008-07-30  2:43 ` [PATCH 06/19] Unionfs: simplify stale-inode detection code Erez Zadok
2008-07-30  2:43 ` [PATCH 07/19] Unionfs: overhaul whiteout code Erez Zadok
2008-07-30  2:43 ` [PATCH 08/19] Unionfs: lookup overhaul using vfs_path_lookup Erez Zadok
2008-07-30  2:43 ` [PATCH 09/19] Unionfs: free lower paths array when destroying dentry's private data Erez Zadok
2008-07-30  2:43 ` [PATCH 10/19] Unionfs: cache coherency fixes Erez Zadok
2008-07-30  2:43 ` [PATCH 11/19] Unionfs: remove old lookup code Erez Zadok
2008-07-30  2:43 ` [PATCH 12/19] Unionfs: update maintainers Erez Zadok
2008-07-30  2:43 ` [PATCH 13/19] Unionfs: update copyrights Erez Zadok
2008-07-30  2:43 ` [PATCH 14/19] Unionfs: minor checkpatch fixes Erez Zadok
2008-07-30  2:43 ` [PATCH 15/19] Unionfs: properly hash newly created inodes Erez Zadok
2008-07-30  2:43 ` [PATCH 16/19] Unionfs: symlink no longer takes a mode parameter Erez Zadok
2008-07-30  2:43 ` [PATCH 17/19] Unionfs: permission no longer takes a nameidata parameter Erez Zadok
2008-07-30  2:43 ` [PATCH 18/19] Unionfs: LOOKUP_ACCESS intent no longer exists Erez Zadok
2008-07-30  2:43 ` [PATCH 19/19] Unionfs: use new kmem_cache_create constructor prototype Erez Zadok

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).