]> git.pld-linux.org Git - packages/kernel.git/blobdiff - kernel-unionfs.patch
- rel 3
[packages/kernel.git] / kernel-unionfs.patch
index c6b37b7d9bb8ef84ec1cc55e25161823a71aefa3..3cdb4769d8d9219333705749432f073d66478a4f 100644 (file)
@@ -1,8 +1,8 @@
 diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
-index f15621e..55e2f07 100644
+index 8c624a1..4aa288b 100644
 --- a/Documentation/filesystems/00-INDEX
 +++ b/Documentation/filesystems/00-INDEX
-@@ -112,6 +112,8 @@ udf.txt
+@@ -110,6 +110,8 @@ udf.txt
        - info and mount options for the UDF filesystem.
  ufs.txt
        - info on the ufs filesystem.
@@ -532,10 +532,10 @@ index 0000000..1adde69
 +
 +For more information, see <http://unionfs.filesystems.org/>.
 diff --git a/MAINTAINERS b/MAINTAINERS
-index 8dca9d8..4421543 100644
+index 9a648eb..81b24a8 100644
 --- a/MAINTAINERS
 +++ b/MAINTAINERS
-@@ -5095,6 +5095,14 @@ F:      Documentation/cdrom/
+@@ -6765,6 +6765,14 @@ F:      Documentation/cdrom/
  F:    drivers/cdrom/cdrom.c
  F:    include/linux/cdrom.h
  
@@ -548,13 +548,13 @@ index 8dca9d8..4421543 100644
 +S:    Maintained
 +
  UNSORTED BLOCK IMAGES (UBI)
- M:    Artem Bityutskiy <dedekind@infradead.org>
+ M:    Artem Bityutskiy <dedekind1@gmail.com>
  W:    http://www.linux-mtd.infradead.org/
 diff --git a/fs/Kconfig b/fs/Kconfig
-index 0e7da7b..b69b6bd 100644
+index d621f02..c12677d 100644
 --- a/fs/Kconfig
 +++ b/fs/Kconfig
-@@ -167,6 +167,7 @@ if MISC_FILESYSTEMS
+@@ -194,6 +194,7 @@ if MISC_FILESYSTEMS
  source "fs/adfs/Kconfig"
  source "fs/affs/Kconfig"
  source "fs/ecryptfs/Kconfig"
@@ -563,10 +563,10 @@ index 0e7da7b..b69b6bd 100644
  source "fs/hfsplus/Kconfig"
  source "fs/befs/Kconfig"
 diff --git a/fs/Makefile b/fs/Makefile
-index af6d047..6c254d5 100644
+index 93804d4..3ff10bb 100644
 --- a/fs/Makefile
 +++ b/fs/Makefile
-@@ -84,6 +84,7 @@ obj-$(CONFIG_ISO9660_FS)     += isofs/
+@@ -83,6 +83,7 @@ obj-$(CONFIG_ISO9660_FS)     += isofs/
  obj-$(CONFIG_HFSPLUS_FS)      += hfsplus/ # Before hfs to find wrapped HFS+
  obj-$(CONFIG_HFS_FS)          += hfs/
  obj-$(CONFIG_ECRYPT_FS)               += ecryptfs/
@@ -574,74 +574,74 @@ index af6d047..6c254d5 100644
  obj-$(CONFIG_VXFS_FS)         += freevxfs/
  obj-$(CONFIG_NFS_FS)          += nfs/
  obj-$(CONFIG_EXPORTFS)                += exportfs/
-diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
-index 2dda5ad..8f006a0 100644
---- a/fs/ecryptfs/dentry.c
-+++ b/fs/ecryptfs/dentry.c
-@@ -62,7 +62,7 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
-               struct inode *lower_inode =
-                       ecryptfs_inode_to_lower(dentry->d_inode);
--              fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
-+              fsstack_copy_attr_all(dentry->d_inode, lower_inode);
-       }
- out:
-       return rc;
-diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
-index 2f0945d..e884c3b 100644
---- a/fs/ecryptfs/inode.c
-+++ b/fs/ecryptfs/inode.c
-@@ -624,9 +624,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
-                       lower_new_dir_dentry->d_inode, lower_new_dentry);
-       if (rc)
-               goto out_lock;
--      fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
-+      fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
-       if (new_dir != old_dir)
--              fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL);
-+              fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
- out_lock:
-       unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
-       dput(lower_new_dentry->d_parent);
-@@ -965,7 +965,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
-       rc = notify_change(lower_dentry, ia);
-       mutex_unlock(&lower_dentry->d_inode->i_mutex);
- out:
--      fsstack_copy_attr_all(inode, lower_inode, NULL);
-+      fsstack_copy_attr_all(inode, lower_inode);
-       return rc;
- }
-diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
-index 9f0aa98..3d94155 100644
---- a/fs/ecryptfs/main.c
-+++ b/fs/ecryptfs/main.c
-@@ -190,7 +190,7 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
-               init_special_inode(inode, lower_inode->i_mode,
-                                  lower_inode->i_rdev);
-       dentry->d_op = &ecryptfs_dops;
--      fsstack_copy_attr_all(inode, lower_inode, NULL);
-+      fsstack_copy_attr_all(inode, lower_inode);
-       /* This size will be overwritten for real files w/ headers and
-        * other metadata */
-       fsstack_copy_inode_size(inode, lower_inode);
 diff --git a/fs/namei.c b/fs/namei.c
-index 1f13751..88584c4 100644
+index 208c6aa..050eded 100644
 --- a/fs/namei.c
 +++ b/fs/namei.c
-@@ -375,6 +375,7 @@ void release_open_intent(struct nameidata *nd)
-       else
-               fput(nd->intent.open.file);
+@@ -491,6 +491,7 @@ void release_open_intent(struct nameidata *nd)
+                       fput(file);
+       }
  }
 +EXPORT_SYMBOL_GPL(release_open_intent);
  
- static inline struct dentry *
- do_revalidate(struct dentry *dentry, struct nameidata *nd)
+ static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
+ {
+@@ -1804,6 +1805,42 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+       return __lookup_hash(&this, base, NULL);
+ }
++/* pass nameidata from caller (useful for NFS) */
++struct dentry *lookup_one_len_nd(const char *name, struct dentry *base,
++                               int len, struct nameidata *nd)
++{
++      struct qstr this;
++      unsigned long hash;
++      unsigned int c;
++
++      WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
++
++      this.name = name;
++      this.len = len;
++      if (!len)
++              return ERR_PTR(-EACCES);
++
++      hash = init_name_hash();
++      while (len--) {
++              c = *(const unsigned char *)name++;
++              if (c == '/' || c == '\0')
++                      return ERR_PTR(-EACCES);
++              hash = partial_name_hash(c, hash);
++      }
++      this.hash = end_name_hash(hash);
++      /*
++       * See if the low-level filesystem might want
++       * to use its own hash..
++       */
++      if (base->d_flags & DCACHE_OP_HASH) {
++              int err = base->d_op->d_hash(base, base->d_inode, &this);
++              if (err < 0)
++                      return ERR_PTR(err);
++      }
++
++      return __lookup_hash(&this, base, nd);
++}
++
+ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
+                struct path *path, int *empty)
+ {
+@@ -3384,6 +3421,7 @@ EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
+ EXPORT_SYMBOL(getname);
+ EXPORT_SYMBOL(lock_rename);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_nd);
+ EXPORT_SYMBOL(page_follow_link_light);
+ EXPORT_SYMBOL(page_put_link);
+ EXPORT_SYMBOL(page_readlink);
 diff --git a/fs/splice.c b/fs/splice.c
-index 73766d2..3753029 100644
+index 1ec0493..3215728 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
-@@ -1057,8 +1057,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
+@@ -1084,8 +1084,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
  /*
   * Attempt to initiate a splice from pipe to file.
   */
@@ -652,7 +652,7 @@ index 73766d2..3753029 100644
  {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
                                loff_t *, size_t, unsigned int);
-@@ -1080,13 +1080,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+@@ -1108,13 +1108,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
  
        return splice_write(pipe, out, ppos, len, flags);
  }
@@ -670,7 +670,7 @@ index 73766d2..3753029 100644
  {
        ssize_t (*splice_read)(struct file *, loff_t *,
                               struct pipe_inode_info *, size_t, unsigned int);
-@@ -1105,6 +1106,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
+@@ -1134,6 +1135,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
  
        return splice_read(in, ppos, pipe, len, flags);
  }
@@ -678,7 +678,7 @@ index 73766d2..3753029 100644
  
  /**
   * splice_direct_to_actor - splices data directly between two non-pipes
-@@ -1174,7 +1176,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+@@ -1203,7 +1205,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
                size_t read_len;
                loff_t pos = sd->pos, prev_pos = pos;
  
@@ -687,16 +687,18 @@ index 73766d2..3753029 100644
                if (unlikely(ret <= 0))
                        goto out_release;
  
-@@ -1233,7 +1235,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
+@@ -1262,8 +1264,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
  {
        struct file *file = sd->u.file;
  
--      return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags);
-+      return vfs_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags);
+-      return do_splice_from(pipe, file, &file->f_pos, sd->total_len,
+-                            sd->flags);
++      return vfs_splice_from(pipe, file, &file->f_pos, sd->total_len,
++                             sd->flags);
  }
  
  /**
-@@ -1330,7 +1332,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+@@ -1348,7 +1350,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                } else
                        off = &out->f_pos;
  
@@ -705,7 +707,7 @@ index 73766d2..3753029 100644
  
                if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
                        ret = -EFAULT;
-@@ -1350,7 +1352,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+@@ -1368,7 +1370,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                } else
                        off = &in->f_pos;
  
@@ -714,116 +716,6 @@ index 73766d2..3753029 100644
  
                if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
                        ret = -EFAULT;
-diff --git a/fs/stack.c b/fs/stack.c
-index 67716f6..cc1443d 100644
---- a/fs/stack.c
-+++ b/fs/stack.c
-@@ -1,24 +1,82 @@
-+/*
-+ * Copyright (c) 2006-2009 Erez Zadok
-+ * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
-+ * Copyright (c) 2006-2009 Stony Brook University
-+ * Copyright (c) 2006-2009 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 <linux/module.h>
- #include <linux/fs.h>
- #include <linux/fs_stack.h>
--/* does _NOT_ require i_mutex to be held.
-+/*
-+ * does _NOT_ require i_mutex to be held.
-  *
-  * 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)
- {
--      i_size_write(dst, i_size_read((struct inode *)src));
--      dst->i_blocks = src->i_blocks;
-+      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);
--/* copy all attributes; get_nlinks is optional way to override the i_nlink
-+/*
-+ * copy all attributes; get_nlinks is optional way to override the i_nlink
-  * copying
-  */
--void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
--                              int (*get_nlinks)(struct inode *))
-+void fsstack_copy_attr_all(struct inode *dest, const struct inode *src)
- {
-       dest->i_mode = src->i_mode;
-       dest->i_uid = src->i_uid;
-@@ -29,14 +87,6 @@ void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
-       dest->i_ctime = src->i_ctime;
-       dest->i_blkbits = src->i_blkbits;
-       dest->i_flags = src->i_flags;
--
--      /*
--       * Update the nlinks AFTER updating the above fields, because the
--       * get_links callback may depend on them.
--       */
--      if (!get_nlinks)
--              dest->i_nlink = src->i_nlink;
--      else
--              dest->i_nlink = (*get_nlinks)(dest);
-+      dest->i_nlink = src->i_nlink;
- }
- EXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
 diff --git a/fs/unionfs/Kconfig b/fs/unionfs/Kconfig
 new file mode 100644
 index 0000000..f3c1ac4
@@ -856,11 +748,11 @@ index 0000000..f3c1ac4
 +        If you say Y here, you can turn on debugging output from Unionfs.
 diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
 new file mode 100644
-index 0000000..9c466a5
+index 0000000..60b6060
 --- /dev/null
 +++ b/fs/unionfs/Makefile
 @@ -0,0 +1,17 @@
-+UNIONFS_VERSION="2.5.3 (for 2.6.31)"
++UNIONFS_VERSION="2.5.11 (for 3.3.0-rc3)"
 +
 +EXTRA_CFLAGS += -DUNIONFS_VERSION=\"$(UNIONFS_VERSION)\"
 +
@@ -879,12 +771,12 @@ index 0000000..9c466a5
 +endif
 diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
 new file mode 100644
-index 0000000..587f984
+index 0000000..71cacfe
 --- /dev/null
 +++ b/fs/unionfs/commonfops.c
-@@ -0,0 +1,896 @@
+@@ -0,0 +1,901 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -893,8 +785,8 @@ index 0000000..587f984
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -1323,31 +1215,36 @@ index 0000000..587f984
 +}
 +
 +/* unionfs_open helper function: open a directory */
-+static int __open_dir(struct inode *inode, struct file *file)
++static int __open_dir(struct inode *inode, struct file *file,
++                    struct dentry *parent)
 +{
 +      struct dentry *lower_dentry;
 +      struct file *lower_file;
 +      int bindex, bstart, bend;
-+      struct vfsmount *mnt;
++      struct vfsmount *lower_mnt;
++      struct dentry *dentry = file->f_path.dentry;
 +
-+      bstart = fbstart(file) = dbstart(file->f_path.dentry);
-+      bend = fbend(file) = dbend(file->f_path.dentry);
++      bstart = fbstart(file) = dbstart(dentry);
++      bend = fbend(file) = dbend(dentry);
 +
 +      for (bindex = bstart; bindex <= bend; bindex++) {
 +              lower_dentry =
-+                      unionfs_lower_dentry_idx(file->f_path.dentry, bindex);
++                      unionfs_lower_dentry_idx(dentry, bindex);
 +              if (!lower_dentry)
 +                      continue;
 +
 +              dget(lower_dentry);
-+              unionfs_mntget(file->f_path.dentry, bindex);
-+              mnt = unionfs_lower_mnt_idx(file->f_path.dentry, bindex);
-+              lower_file = dentry_open(lower_dentry, mnt, file->f_flags,
++              lower_mnt = unionfs_mntget(dentry, bindex);
++              if (!lower_mnt)
++                      lower_mnt = unionfs_mntget(parent, bindex);
++              lower_file = dentry_open(lower_dentry, lower_mnt, file->f_flags,
 +                                       current_cred());
 +              if (IS_ERR(lower_file))
 +                      return PTR_ERR(lower_file);
 +
 +              unionfs_set_lower_file_idx(file, bindex, lower_file);
++              if (!unionfs_lower_mnt_idx(dentry, bindex))
++                      unionfs_set_lower_mnt_idx(dentry, bindex, lower_mnt);
 +
 +              /*
 +               * The branchget goes after the open, because otherwise
@@ -1367,18 +1264,20 @@ index 0000000..587f984
 +      struct file *lower_file;
 +      int lower_flags;
 +      int bindex, bstart, bend;
++      struct dentry *dentry = file->f_path.dentry;
++      struct vfsmount *lower_mnt;
 +
-+      lower_dentry = unionfs_lower_dentry(file->f_path.dentry);
++      lower_dentry = unionfs_lower_dentry(dentry);
 +      lower_flags = file->f_flags;
 +
-+      bstart = fbstart(file) = dbstart(file->f_path.dentry);
-+      bend = fbend(file) = dbend(file->f_path.dentry);
++      bstart = fbstart(file) = dbstart(dentry);
++      bend = fbend(file) = dbend(dentry);
 +
 +      /*
 +       * check for the permission for lower file.  If the error is
 +       * COPYUP_ERR, copyup the file.
 +       */
-+      if (lower_dentry->d_inode && is_robranch(file->f_path.dentry)) {
++      if (lower_dentry->d_inode && is_robranch(dentry)) {
 +              /*
 +               * if the open will change the file, copy it up otherwise
 +               * defer it.
@@ -1391,8 +1290,11 @@ index 0000000..587f984
 +                      for (bindex = bstart - 1; bindex >= 0; bindex--) {
 +                              err = copyup_file(parent->d_inode, file,
 +                                                bstart, bindex, size);
-+                              if (!err)
++                              if (!err) {
++                                      /* only one regular file open */
++                                      fbend(file) = fbstart(file);
 +                                      break;
++                              }
 +                      }
 +                      return err;
 +              } else {
@@ -1410,11 +1312,9 @@ index 0000000..587f984
 +       * dentry_open will decrement mnt refcnt if err.
 +       * otherwise fput() will do an mntput() for us upon file close.
 +       */
-+      unionfs_mntget(file->f_path.dentry, bstart);
-+      lower_file =
-+              dentry_open(lower_dentry,
-+                          unionfs_lower_mnt_idx(file->f_path.dentry, bstart),
-+                          lower_flags, current_cred());
++      lower_mnt = unionfs_mntget(dentry, bstart);
++      lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags,
++                               current_cred());
 +      if (IS_ERR(lower_file))
 +              return PTR_ERR(lower_file);
 +
@@ -1483,7 +1383,7 @@ index 0000000..587f984
 +       * these lower file structs
 +       */
 +      if (S_ISDIR(inode->i_mode))
-+              err = __open_dir(inode, file);  /* open a dir */
++              err = __open_dir(inode, file, parent); /* open a dir */
 +      else
 +              err = __open_file(inode, file, parent); /* open a file */
 +
@@ -1533,7 +1433,7 @@ index 0000000..587f984
 +      struct dentry *dentry = file->f_path.dentry;
 +      struct dentry *parent;
 +      int bindex, bstart, bend;
-+      int fgen, err = 0;
++      int err = 0;
 +
 +      /*
 +       * Since mm/memory.c:might_fault() (under PROVE_LOCKING) was
@@ -1569,7 +1469,6 @@ index 0000000..587f984
 +      inodeinfo = UNIONFS_I(inode);
 +
 +      /* fput all the lower files */
-+      fgen = atomic_read(&fileinfo->generation);
 +      bstart = fbstart(file);
 +      bend = fbend(file);
 +
@@ -1624,12 +1523,10 @@ index 0000000..587f984
 +              goto out;
 +      if (lower_file->f_op->unlocked_ioctl) {
 +              err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
-+      } else if (lower_file->f_op->ioctl) {
-+              lock_kernel();
-+              err = lower_file->f_op->ioctl(
-+                      lower_file->f_path.dentry->d_inode,
-+                      lower_file, cmd, arg);
-+              unlock_kernel();
++#ifdef CONFIG_COMPAT
++      } else if (lower_file->f_op->compat_ioctl) {
++              err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
++#endif
 +      }
 +
 +out:
@@ -1781,12 +1678,12 @@ index 0000000..587f984
 +}
 diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
 new file mode 100644
-index 0000000..c43cc7f
+index 0000000..078ca27
 --- /dev/null
 +++ b/fs/unionfs/copyup.c
-@@ -0,0 +1,897 @@
+@@ -0,0 +1,899 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -1795,8 +1692,8 @@ index 0000000..c43cc7f
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -2112,9 +2009,11 @@ index 0000000..c43cc7f
 +
 +      kfree(buf);
 +
++#if 0
++      /* XXX: code no longer needed? */
 +      if (!err)
-+              err = output_file->f_op->fsync(output_file,
-+                                             new_lower_dentry, 0);
++              err = output_file->f_op->fsync(output_file, 0);
++#endif
 +
 +      if (err)
 +              goto out_close_out;
@@ -2684,15 +2583,15 @@ index 0000000..c43cc7f
 +}
 diff --git a/fs/unionfs/debug.c b/fs/unionfs/debug.c
 new file mode 100644
-index 0000000..3fd641a
+index 0000000..21ce90c
 --- /dev/null
 +++ b/fs/unionfs/debug.c
-@@ -0,0 +1,533 @@
+@@ -0,0 +1,551 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -2700,6 +2599,7 @@ index 0000000..3fd641a
 + */
 +
 +#include "union.h"
++#include "../mount.h"
 +
 +/*
 + * Helper debugging functions for maintainers (and for users to report back
@@ -3052,12 +2952,13 @@ index 0000000..3fd641a
 +              pr_debug(" CF0: file/dentry=%p:%p fstart/end=%d:%d\n",
 +                       file, dentry, fstart, fend);
 +      }
-+      if (unlikely(fstart != dstart)) {
++      /* d_deleted dentries can be ignored for this test */
++      if (unlikely(fstart != dstart) && !d_deleted(dentry)) {
 +              PRINT_CALLER(fname, fxn, line);
 +              pr_debug(" CF1: file/dentry=%p:%p fstart=%d dstart=%d\n",
 +                       file, dentry, fstart, dstart);
 +      }
-+      if (unlikely(fend != dend)) {
++      if (unlikely(fend != dend) && !d_deleted(dentry)) {
 +              PRINT_CALLER(fname, fxn, line);
 +              pr_debug(" CF2: file/dentry=%p:%p fend=%d dend=%d\n",
 +                       file, dentry, fend, dend);
@@ -3128,11 +3029,27 @@ index 0000000..3fd641a
 +                      PRINT_CALLER(fname, fxn, line);
 +                      pr_debug(" CND1: lower_file of type %s\n",
 +                               file->f_path.dentry->d_sb->s_type->name);
-+                      BUG();
 +              }
 +      }
 +}
 +
++static unsigned int __mnt_get_count(struct vfsmount *mnt)
++{
++      struct mount *m = real_mount(mnt);
++#ifdef CONFIG_SMP
++      unsigned int count = 0;
++      int cpu;
++
++      for_each_possible_cpu(cpu) {
++              count += per_cpu_ptr(m->mnt_pcp, cpu)->mnt_count;
++      }
++
++      return count;
++#else
++      return m->mnt_count;
++#endif
++}
++
 +/* useful to track vfsmount leaks that could cause EBUSY on unmount */
 +void __show_branch_counts(const struct super_block *sb,
 +                        const char *file, const char *fxn, int line)
@@ -3147,7 +3064,7 @@ index 0000000..3fd641a
 +              else
 +                      mnt = NULL;
 +              printk(KERN_CONT "%d:",
-+                     (mnt ? atomic_read(&mnt->mnt_count) : -99));
++                     (mnt ? __mnt_get_count(mnt) : -99));
 +      }
 +      printk(KERN_CONT "%s:%s:%d\n", file, fxn, line);
 +}
@@ -3223,12 +3140,12 @@ index 0000000..3fd641a
 +}
 diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
 new file mode 100644
-index 0000000..85b5d3c
+index 0000000..1628dad
 --- /dev/null
 +++ b/fs/unionfs/dentry.c
-@@ -0,0 +1,397 @@
+@@ -0,0 +1,409 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -3237,8 +3154,8 @@ index 0000000..85b5d3c
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -3421,6 +3338,9 @@ index 0000000..85b5d3c
 +      bend = dbend(dentry);
 +      BUG_ON(bstart == -1);
 +      for (bindex = bstart; bindex <= bend; bindex++) {
++              int err;
++              struct nameidata lower_nd;
++
 +              lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
 +              if (!lower_dentry || !lower_dentry->d_op
 +                  || !lower_dentry->d_op->d_revalidate)
@@ -3433,8 +3353,14 @@ index 0000000..85b5d3c
 +               * invariants).  We will open lower files as and when needed
 +               * later on.
 +               */
-+              if (!lower_dentry->d_op->d_revalidate(lower_dentry, NULL))
++              err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++              if (unlikely(err < 0)) {
++                      valid = false;
++                      break;
++              }
++              if (!lower_dentry->d_op->d_revalidate(lower_dentry, &lower_nd))
 +                      valid = false;
++              release_lower_nd(&lower_nd, err);
 +      }
 +
 +      if (!dentry->d_inode ||
@@ -3535,12 +3461,15 @@ index 0000000..85b5d3c
 +}
 +
 +static int unionfs_d_revalidate(struct dentry *dentry,
-+                              struct nameidata *nd_unused)
++                              struct nameidata *nd)
 +{
 +      bool valid = true;
 +      int err = 1;            /* 1 means valid for the VFS */
 +      struct dentry *parent;
 +
++      if (nd && nd->flags & LOOKUP_RCU)
++              return -ECHILD;
++
 +      unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
 +      parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
 +      unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
@@ -3626,12 +3555,12 @@ index 0000000..85b5d3c
 +};
 diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
 new file mode 100644
-index 0000000..eccb9ae
+index 0000000..72a9c1a
 --- /dev/null
 +++ b/fs/unionfs/dirfops.c
 @@ -0,0 +1,302 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -3640,8 +3569,8 @@ index 0000000..eccb9ae
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -3934,12 +3863,12 @@ index 0000000..eccb9ae
 +};
 diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
 new file mode 100644
-index 0000000..2ecaafa
+index 0000000..62ec9af
 --- /dev/null
 +++ b/fs/unionfs/dirhelper.c
 @@ -0,0 +1,158 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -3948,8 +3877,8 @@ index 0000000..2ecaafa
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -4098,12 +4027,12 @@ index 0000000..2ecaafa
 +}
 diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
 new file mode 100644
-index 0000000..04ffa85
+index 0000000..ae1b86a
 --- /dev/null
 +++ b/fs/unionfs/fanout.h
 @@ -0,0 +1,407 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005      Arun M. Krishnakumar
@@ -4111,8 +4040,8 @@ index 0000000..04ffa85
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -4511,12 +4440,12 @@ index 0000000..04ffa85
 +#endif        /* not _FANOUT_H */
 diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c
 new file mode 100644
-index 0000000..281169e
+index 0000000..f583c8f
 --- /dev/null
 +++ b/fs/unionfs/file.c
-@@ -0,0 +1,380 @@
+@@ -0,0 +1,386 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -4525,8 +4454,8 @@ index 0000000..281169e
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -4615,7 +4544,7 @@ index 0000000..281169e
 +      struct file *lower_file;
 +      struct dentry *dentry = file->f_path.dentry;
 +      struct dentry *parent;
-+      struct vm_operations_struct *saved_vm_ops = NULL;
++      const struct vm_operations_struct *saved_vm_ops = NULL;
 +
 +      /*
 +       * Since mm/memory.c:might_fault() (under PROVE_LOCKING) was
@@ -4705,15 +4634,17 @@ index 0000000..281169e
 +      return err;
 +}
 +
-+int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++int unionfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 +{
 +      int bindex, bstart, bend;
 +      struct file *lower_file;
++      struct dentry *dentry = file->f_path.dentry;
 +      struct dentry *lower_dentry;
 +      struct dentry *parent;
 +      struct inode *lower_inode, *inode;
 +      int err = -EINVAL;
 +
++      lockdep_off();
 +      unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
 +      parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
 +      unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
@@ -4723,6 +4654,10 @@ index 0000000..281169e
 +              goto out;
 +      unionfs_check_file(file);
 +
++      err = generic_file_fsync(file, start, end, datasync);
++      if (err)
++              goto out;
++
 +      bstart = fbstart(file);
 +      bend = fbend(file);
 +      if (bstart < 0 || bend < 0)
@@ -4740,13 +4675,9 @@ index 0000000..281169e
 +                      continue;
 +              lower_file = unionfs_lower_file_idx(file, bindex);
 +              lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-+              mutex_lock(&lower_inode->i_mutex);
-+              err = lower_inode->i_fop->fsync(lower_file,
-+                                              lower_dentry,
-+                                              datasync);
++              err = vfs_fsync_range(lower_file, start, end, datasync);
 +              if (!err && bindex == bstart)
 +                      fsstack_copy_attr_times(inode, lower_inode);
-+              mutex_unlock(&lower_inode->i_mutex);
 +              if (err)
 +                      goto out;
 +      }
@@ -4757,6 +4688,7 @@ index 0000000..281169e
 +      unionfs_unlock_dentry(dentry);
 +      unionfs_unlock_parent(dentry, parent);
 +      unionfs_read_unlock(dentry->d_sb);
++      lockdep_on();
 +      return err;
 +}
 +
@@ -4886,6 +4818,9 @@ index 0000000..281169e
 +      .write          = unionfs_write,
 +      .readdir        = unionfs_file_readdir,
 +      .unlocked_ioctl = unionfs_ioctl,
++#ifdef CONFIG_COMPAT
++      .compat_ioctl   = unionfs_ioctl,
++#endif
 +      .mmap           = unionfs_mmap,
 +      .open           = unionfs_open,
 +      .flush          = unionfs_flush,
@@ -4897,12 +4832,12 @@ index 0000000..281169e
 +};
 diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
 new file mode 100644
-index 0000000..bd5a3b3
+index 0000000..dd522c2
 --- /dev/null
 +++ b/fs/unionfs/inode.c
-@@ -0,0 +1,1055 @@
+@@ -0,0 +1,1085 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -4911,8 +4846,8 @@ index 0000000..bd5a3b3
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -5000,7 +4935,7 @@ index 0000000..bd5a3b3
 +}
 +
 +static int unionfs_create(struct inode *dir, struct dentry *dentry,
-+                        int mode, struct nameidata *nd_unused)
++                        umode_t mode, struct nameidata *nd_unused)
 +{
 +      int err = 0;
 +      struct dentry *lower_dentry = NULL;
@@ -5028,12 +4963,12 @@ index 0000000..bd5a3b3
 +      lower_parent_dentry = lock_parent(lower_dentry);
 +      if (IS_ERR(lower_parent_dentry)) {
 +              err = PTR_ERR(lower_parent_dentry);
-+              goto out;
++              goto out_unlock;
 +      }
 +
 +      err = init_lower_nd(&lower_nd, LOOKUP_CREATE);
 +      if (unlikely(err < 0))
-+              goto out;
++              goto out_unlock;
 +      err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
 +                       &lower_nd);
 +      release_lower_nd(&lower_nd, err);
@@ -5045,12 +4980,12 @@ index 0000000..bd5a3b3
 +                      fsstack_copy_inode_size(dir,
 +                                              lower_parent_dentry->d_inode);
 +                      /* update no. of links on parent directory */
-+                      dir->i_nlink = unionfs_get_nlinks(dir);
++                      set_nlink(dir, unionfs_get_nlinks(dir));
 +              }
 +      }
 +
++out_unlock:
 +      unlock_dir(lower_parent_dentry);
-+
 +out:
 +      if (!err) {
 +              unionfs_postcopyup_setmnt(dentry);
@@ -5156,7 +5091,7 @@ index 0000000..bd5a3b3
 +              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);
++              set_nlink(dir, unionfs_get_nlinks(dir));
 +              err = 0;
 +      }
 +      if (err)
@@ -5231,7 +5166,8 @@ index 0000000..bd5a3b3
 +      fsstack_copy_inode_size(dir, lower_new_dentry->d_parent->d_inode);
 +
 +      /* propagate number of hard-links */
-+      old_dentry->d_inode->i_nlink = unionfs_get_nlinks(old_dentry->d_inode);
++      set_nlink(old_dentry->d_inode,
++                unionfs_get_nlinks(old_dentry->d_inode));
 +      /* new dentry's ctime may have changed due to hard-link counts */
 +      unionfs_copy_attr_times(new_dentry->d_inode);
 +
@@ -5293,7 +5229,7 @@ index 0000000..bd5a3b3
 +      lower_parent_dentry = lock_parent(lower_dentry);
 +      if (IS_ERR(lower_parent_dentry)) {
 +              err = PTR_ERR(lower_parent_dentry);
-+              goto out;
++              goto out_unlock;
 +      }
 +
 +      mode = S_IALLUGO;
@@ -5305,12 +5241,12 @@ index 0000000..bd5a3b3
 +                      fsstack_copy_inode_size(dir,
 +                                              lower_parent_dentry->d_inode);
 +                      /* update no. of links on parent directory */
-+                      dir->i_nlink = unionfs_get_nlinks(dir);
++                      set_nlink(dir, unionfs_get_nlinks(dir));
 +              }
 +      }
 +
++out_unlock:
 +      unlock_dir(lower_parent_dentry);
-+
 +out:
 +      dput(wh_dentry);
 +      kfree(name);
@@ -5326,7 +5262,7 @@ index 0000000..bd5a3b3
 +      return err;
 +}
 +
-+static int unionfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++static int unionfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 +{
 +      int err = 0;
 +      struct dentry *lower_dentry = NULL;
@@ -5417,7 +5353,7 @@ index 0000000..bd5a3b3
 +                                              lower_parent_dentry->d_inode);
 +
 +                      /* update number of links on parent directory */
-+                      dir->i_nlink = unionfs_get_nlinks(dir);
++                      set_nlink(dir, unionfs_get_nlinks(dir));
 +              }
 +
 +              err = make_dir_opaque(dentry, dbstart(dentry));
@@ -5450,7 +5386,7 @@ index 0000000..bd5a3b3
 +      return err;
 +}
 +
-+static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++static int unionfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
 +                       dev_t dev)
 +{
 +      int err = 0;
@@ -5486,7 +5422,7 @@ index 0000000..bd5a3b3
 +      lower_parent_dentry = lock_parent(lower_dentry);
 +      if (IS_ERR(lower_parent_dentry)) {
 +              err = PTR_ERR(lower_parent_dentry);
-+              goto out;
++              goto out_unlock;
 +      }
 +
 +      err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev);
@@ -5497,12 +5433,12 @@ index 0000000..bd5a3b3
 +                      fsstack_copy_inode_size(dir,
 +                                              lower_parent_dentry->d_inode);
 +                      /* update no. of links on parent directory */
-+                      dir->i_nlink = unionfs_get_nlinks(dir);
++                      set_nlink(dir, unionfs_get_nlinks(dir));
 +              }
 +      }
 +
++out_unlock:
 +      unlock_dir(lower_parent_dentry);
-+
 +out:
 +      dput(wh_dentry);
 +      kfree(name);
@@ -5619,6 +5555,7 @@ index 0000000..bd5a3b3
 +                           void *cookie)
 +{
 +      struct dentry *parent;
++      char *buf;
 +
 +      unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
 +      parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
@@ -5629,8 +5566,13 @@ index 0000000..bd5a3b3
 +                     "unionfs: put_link failed to revalidate dentry\n");
 +
 +      unionfs_check_dentry(dentry);
++#if 0
++      /* XXX: can't run this check b/c this fxn can receive a poisoned 'nd' PTR */
 +      unionfs_check_nd(nd);
-+      kfree(nd_get_link(nd));
++#endif
++      buf = nd_get_link(nd);
++      if (!IS_ERR(buf))
++              kfree(buf);
 +      unionfs_unlock_dentry(dentry);
 +      unionfs_unlock_parent(dentry, parent);
 +      unionfs_read_unlock(dentry->d_sb);
@@ -5664,7 +5606,7 @@ index 0000000..bd5a3b3
 +                              return -EACCES;
 +              }
 +      } else {
-+              retval = generic_permission(inode, mask, NULL);
++              retval = generic_permission(inode, mask);
 +      }
 +      if (retval)
 +              return retval;
@@ -5686,13 +5628,12 @@ index 0000000..bd5a3b3
 +      struct inode *lower_inode = NULL;
 +      int err = 0;
 +      int bindex, bstart, bend;
-+      const int is_file = !S_ISDIR(inode->i_mode);
++      int is_file;
 +      const int write_mask = (mask & MAY_WRITE) && !(mask & MAY_READ);
-+      struct inode *inode_grabbed = igrab(inode);
-+      struct dentry *dentry = d_find_alias(inode);
++      struct inode *inode_grabbed;
 +
-+      if (dentry)
-+              unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++      inode_grabbed = igrab(inode);
++      is_file = !S_ISDIR(inode->i_mode);
 +
 +      if (!UNIONFS_I(inode)->lower_inodes) {
 +              if (is_file)    /* dirs can be unlinked but chdir'ed to */
@@ -5757,7 +5698,7 @@ index 0000000..bd5a3b3
 +              if (err && err == -EACCES &&
 +                  is_robranch_super(inode->i_sb, bindex) &&
 +                  lower_inode->i_sb->s_magic == NFS_SUPER_MAGIC)
-+                      err = generic_permission(lower_inode, mask, NULL);
++                      err = generic_permission(lower_inode, mask);
 +
 +              /*
 +               * The permissions are an intersection of the overall directory
@@ -5781,10 +5722,6 @@ index 0000000..bd5a3b3
 +
 +out:
 +      unionfs_check_inode(inode);
-+      if (dentry) {
-+              unionfs_unlock_dentry(dentry);
-+              dput(dentry);
-+      }
 +      iput(inode_grabbed);
 +      return err;
 +}
@@ -5798,6 +5735,12 @@ index 0000000..bd5a3b3
 +      struct inode *lower_inode;
 +      int bstart, bend, bindex;
 +      loff_t size;
++      struct iattr lower_ia;
++
++      /* check if user has permission to change inode */
++      err = inode_change_ok(dentry->d_inode, ia);
++      if (err)
++              goto out_err;
 +
 +      unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
 +      parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
@@ -5824,7 +5767,12 @@ index 0000000..bd5a3b3
 +              err = -EINVAL;
 +              goto out;
 +      }
-+      lower_inode = unionfs_lower_inode(inode);
++
++      /*
++       * Get the lower inode directly from lower dentry, in case ibstart
++       * is -1 (which happens when the file is open but unlinked.
++       */
++      lower_inode = lower_dentry->d_inode;
 +
 +      /* check if user has permission to change lower inode */
 +      err = inode_change_ok(lower_inode, ia);
@@ -5859,6 +5807,16 @@ index 0000000..bd5a3b3
 +              /* get updated lower_dentry/inode after copyup */
 +              lower_dentry = unionfs_lower_dentry(dentry);
 +              lower_inode = unionfs_lower_inode(inode);
++              /*
++               * check for whiteouts in writeable branch, and remove them
++               * if necessary.
++               */
++              if (lower_dentry) {
++                      err = check_unlink_whiteout(dentry, lower_dentry,
++                                                  bindex);
++                      if (err > 0) /* ignore if whiteout found and removed */
++                              err = 0;
++              }
 +      }
 +
 +      /*
@@ -5885,8 +5843,15 @@ index 0000000..bd5a3b3
 +       * unlinked (no inode->i_sb and i_ino==0.  This happens if someone
 +       * tries to open(), unlink(), then ftruncate() a file.
 +       */
++      /* prepare our own lower struct iattr (with our own lower file) */
++      memcpy(&lower_ia, ia, sizeof(lower_ia));
++      if (ia->ia_valid & ATTR_FILE) {
++              lower_ia.ia_file = unionfs_lower_file(ia->ia_file);
++              BUG_ON(!lower_ia.ia_file); // XXX?
++      }
++
 +      mutex_lock(&lower_dentry->d_inode->i_mutex);
-+      err = notify_change(lower_dentry, ia);
++      err = notify_change(lower_dentry, &lower_ia);
 +      mutex_unlock(&lower_dentry->d_inode->i_mutex);
 +      if (err)
 +              goto out;
@@ -5914,7 +5879,7 @@ index 0000000..bd5a3b3
 +      unionfs_unlock_dentry(dentry);
 +      unionfs_unlock_parent(dentry, parent);
 +      unionfs_read_unlock(dentry->d_sb);
-+
++out_err:
 +      return err;
 +}
 +
@@ -5958,12 +5923,12 @@ index 0000000..bd5a3b3
 +};
 diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
 new file mode 100644
-index 0000000..6361541
+index 0000000..041d674
 --- /dev/null
 +++ b/fs/unionfs/lookup.c
-@@ -0,0 +1,569 @@
+@@ -0,0 +1,570 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -5972,8 +5937,8 @@ index 0000000..6361541
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -5994,17 +5959,17 @@ index 0000000..6361541
 +                          const char *name, struct vfsmount **new_mnt)
 +{
 +      struct dentry *dentry = NULL;
-+      struct nameidata lower_nd;
++      struct path lower_path = {NULL, NULL};
 +      int err;
 +
 +      /* we use flags=0 to get basic lookup */
-+      err = vfs_path_lookup(base, mnt, name, 0, &lower_nd);
++      err = vfs_path_lookup(base, mnt, name, 0, &lower_path);
 +
 +      switch (err) {
 +      case 0: /* no error */
-+              dentry = lower_nd.path.dentry;
++              dentry = lower_path.dentry;
 +              if (new_mnt)
-+                      *new_mnt = lower_nd.path.mnt; /* rc already inc'ed */
++                      *new_mnt = lower_path.mnt; /* rc already inc'ed */
 +              break;
 +      case -ENOENT:
 +               /*
@@ -6016,7 +5981,7 @@ index 0000000..6361541
 +                */
 +              dentry = lookup_lck_len(name, base, strlen(name));
 +              if (new_mnt)
-+                      *new_mnt = mntget(lower_nd.path.mnt);
++                      *new_mnt = mntget(lower_path.mnt);
 +              break;
 +      default: /* all other real errors */
 +              dentry = ERR_PTR(err);
@@ -6275,7 +6240,8 @@ index 0000000..6361541
 +      verify_locked(parent);
 +
 +      /* must initialize dentry operations */
-+      dentry->d_op = &unionfs_dops;
++      if (lookupmode == INTERPOSE_LOOKUP)
++              d_set_d_op(dentry, &unionfs_dops);
 +
 +      /* We never partial lookup the root directory. */
 +      if (IS_ROOT(dentry))
@@ -6533,12 +6499,12 @@ index 0000000..6361541
 +}
 diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
 new file mode 100644
-index 0000000..c58405c
+index 0000000..ee78f1d
 --- /dev/null
 +++ b/fs/unionfs/main.c
-@@ -0,0 +1,758 @@
+@@ -0,0 +1,752 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -6547,8 +6513,8 @@ index 0000000..c58405c
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -6684,7 +6650,7 @@ index 0000000..c58405c
 +                       * properly.  Finally we must return this new
 +                       * dentry.
 +                       */
-+                      spliced->d_op = &unionfs_dops;
++                      d_set_d_op(spliced, &unionfs_dops);
 +                      spliced->d_fsdata = dentry->d_fsdata;
 +                      dentry->d_fsdata = NULL;
 +                      dentry = spliced;
@@ -6754,14 +6720,14 @@ index 0000000..c58405c
 + * 2) it exists
 + * 3) is a directory
 + */
-+int check_branch(struct nameidata *nd)
++int check_branch(const struct path *path)
 +{
 +      /* XXX: remove in ODF code -- stacking unions allowed there */
-+      if (!strcmp(nd->path.dentry->d_sb->s_type->name, UNIONFS_NAME))
++      if (!strcmp(path->dentry->d_sb->s_type->name, UNIONFS_NAME))
 +              return -EINVAL;
-+      if (!nd->path.dentry->d_inode)
++      if (!path->dentry->d_inode)
 +              return -ENOENT;
-+      if (!S_ISDIR(nd->path.dentry->d_inode->i_mode))
++      if (!S_ISDIR(path->dentry->d_inode->i_mode))
 +              return -ENOTDIR;
 +      return 0;
 +}
@@ -6813,7 +6779,7 @@ index 0000000..c58405c
 +static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info
 +                           *lower_root_info, char *options)
 +{
-+      struct nameidata nd;
++      struct path path;
 +      char *name;
 +      int err = 0;
 +      int branches = 1;
@@ -6826,7 +6792,7 @@ index 0000000..c58405c
 +      if (options[0] == '\0') {
 +              printk(KERN_ERR "unionfs: no branches specified\n");
 +              err = -EINVAL;
-+              goto out;
++              goto out_return;
 +      }
 +
 +      /*
@@ -6842,14 +6808,17 @@ index 0000000..c58405c
 +              kcalloc(branches, sizeof(struct unionfs_data), GFP_KERNEL);
 +      if (unlikely(!UNIONFS_SB(sb)->data)) {
 +              err = -ENOMEM;
-+              goto out;
++              goto out_return;
 +      }
 +
 +      lower_root_info->lower_paths =
 +              kcalloc(branches, sizeof(struct path), GFP_KERNEL);
 +      if (unlikely(!lower_root_info->lower_paths)) {
 +              err = -ENOMEM;
-+              goto out;
++              /* free the underlying pointer array */
++              kfree(UNIONFS_SB(sb)->data);
++              UNIONFS_SB(sb)->data = NULL;
++              goto out_return;
 +      }
 +
 +      /* now parsing a string such as "b1:b2=rw:b3=ro:b4" */
@@ -6886,7 +6855,7 @@ index 0000000..c58405c
 +                      goto out;
 +              }
 +
-+              err = path_lookup(name, LOOKUP_FOLLOW, &nd);
++              err = kern_path(name, LOOKUP_FOLLOW, &path);
 +              if (err) {
 +                      printk(KERN_ERR "unionfs: error accessing "
 +                             "lower directory '%s' (error %d)\n",
@@ -6894,16 +6863,16 @@ index 0000000..c58405c
 +                      goto out;
 +              }
 +
-+              err = check_branch(&nd);
++              err = check_branch(&path);
 +              if (err) {
 +                      printk(KERN_ERR "unionfs: lower directory "
 +                             "'%s' is not a valid branch\n", name);
-+                      path_put(&nd.path);
++                      path_put(&path);
 +                      goto out;
 +              }
 +
-+              lower_root_info->lower_paths[bindex].dentry = nd.path.dentry;
-+              lower_root_info->lower_paths[bindex].mnt = nd.path.mnt;
++              lower_root_info->lower_paths[bindex].dentry = path.dentry;
++              lower_root_info->lower_paths[bindex].mnt = path.mnt;
 +
 +              set_branchperms(sb, bindex, perms);
 +              set_branch_count(sb, bindex, 0);
@@ -6966,6 +6935,7 @@ index 0000000..c58405c
 +              lower_root_info->lower_paths = NULL;
 +              UNIONFS_SB(sb)->data = NULL;
 +      }
++out_return:
 +      return err;
 +}
 +
@@ -7061,32 +7031,6 @@ index 0000000..c58405c
 +}
 +
 +/*
-+ * our custom d_alloc_root work-alike
-+ *
-+ * we can't use d_alloc_root if we want to use our own interpose function
-+ * unchanged, so we simply call our own "fake" d_alloc_root
-+ */
-+static struct dentry *unionfs_d_alloc_root(struct super_block *sb)
-+{
-+      struct dentry *ret = NULL;
-+
-+      if (sb) {
-+              static const struct qstr name = {
-+                      .name = "/",
-+                      .len = 1
-+              };
-+
-+              ret = d_alloc(NULL, &name);
-+              if (likely(ret)) {
-+                      ret->d_op = &unionfs_dops;
-+                      ret->d_sb = sb;
-+                      ret->d_parent = ret;
-+              }
-+      }
-+      return ret;
-+}
-+
-+/*
 + * There is no need to lock the unionfs_super_info's rwsem as there is no
 + * way anyone can have a reference to the superblock at this point in time.
 + */
@@ -7096,6 +7040,7 @@ index 0000000..c58405c
 +      int err = 0;
 +      struct unionfs_dentry_info *lower_root_info = NULL;
 +      int bindex, bstart, bend;
++      struct inode *inode = NULL;
 +
 +      if (!raw_data) {
 +              printk(KERN_ERR
@@ -7153,12 +7098,18 @@ index 0000000..c58405c
 +
 +      sb->s_op = &unionfs_sops;
 +
-+      /* See comment next to the definition of unionfs_d_alloc_root */
-+      sb->s_root = unionfs_d_alloc_root(sb);
++      /* get a new inode and allocate our root dentry */
++      inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO));
++      if (IS_ERR(inode)) {
++              err = PTR_ERR(inode);
++              goto out_dput;
++      }
++      sb->s_root = d_make_root(inode);
 +      if (unlikely(!sb->s_root)) {
 +              err = -ENOMEM;
 +              goto out_dput;
 +      }
++      d_set_d_op(sb->s_root, &unionfs_dops);
 +
 +      /* link the upper and lower dentries */
 +      sb->s_root->d_fsdata = NULL;
@@ -7166,6 +7117,8 @@ index 0000000..c58405c
 +      if (unlikely(err))
 +              goto out_freedpd;
 +
++      /* if get here: cannot have error */
++
 +      /* Set the lower dentries for s_root */
 +      for (bindex = bstart; bindex <= bend; bindex++) {
 +              struct dentry *d;
@@ -7183,15 +7136,18 @@ index 0000000..c58405c
 +      /* Set the generation number to one, since this is for the mount. */
 +      atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);
 +
++      if (atomic_read(&inode->i_count) <= 1)
++              unionfs_fill_inode(sb->s_root, inode);
++
 +      /*
-+       * Call interpose to create the upper level inode.  Only
-+       * INTERPOSE_LOOKUP can return a value other than 0 on err.
++       * No need to call interpose because we already have a positive
++       * dentry, which was instantiated by d_alloc_root.  Just need to
++       * d_rehash it.
 +       */
-+      err = PTR_ERR(unionfs_interpose(sb->s_root, sb, 0));
++      d_rehash(sb->s_root);
++
 +      unionfs_unlock_dentry(sb->s_root);
-+      if (!err)
-+              goto out;
-+      /* else fall through */
++      goto out; /* all is well */
 +
 +out_freedpd:
 +      if (UNIONFS_D(sb->s_root)) {
@@ -7200,6 +7156,9 @@ index 0000000..c58405c
 +      }
 +      dput(sb->s_root);
 +
++out_iput:
++      iput(inode);
++
 +out_dput:
 +      if (lower_root_info && !IS_ERR(lower_root_info)) {
 +              for (bindex = lower_root_info->bstart;
@@ -7228,22 +7187,23 @@ index 0000000..c58405c
 +      return err;
 +}
 +
-+static int unionfs_get_sb(struct file_system_type *fs_type,
-+                        int flags, const char *dev_name,
-+                        void *raw_data, struct vfsmount *mnt)
++static struct dentry *unionfs_mount(struct file_system_type *fs_type,
++                                  int flags, const char *dev_name,
++                                  void *raw_data)
 +{
-+      int err;
-+      err = get_sb_nodev(fs_type, flags, raw_data, unionfs_read_super, mnt);
-+      if (!err)
-+              UNIONFS_SB(mnt->mnt_sb)->dev_name =
++      struct dentry *dentry;
++
++      dentry = mount_nodev(fs_type, flags, raw_data, unionfs_read_super);
++      if (!IS_ERR(dentry))
++              UNIONFS_SB(dentry->d_sb)->dev_name =
 +                      kstrdup(dev_name, GFP_KERNEL);
-+      return err;
++      return dentry;
 +}
 +
 +static struct file_system_type unionfs_fs_type = {
 +      .owner          = THIS_MODULE,
 +      .name           = UNIONFS_NAME,
-+      .get_sb         = unionfs_get_sb,
++      .mount          = unionfs_mount,
 +      .kill_sb        = generic_shutdown_super,
 +      .fs_flags       = FS_REVAL_DOT,
 +};
@@ -7297,12 +7257,12 @@ index 0000000..c58405c
 +module_exit(exit_unionfs_fs);
 diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
 new file mode 100644
-index 0000000..18b05d5
+index 0000000..bcc5652
 --- /dev/null
 +++ b/fs/unionfs/mmap.c
 @@ -0,0 +1,89 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -7312,8 +7272,8 @@ index 0000000..18b05d5
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -7342,7 +7302,7 @@ index 0000000..18b05d5
 +{
 +      int err;
 +      struct file *file, *lower_file;
-+      struct vm_operations_struct *lower_vm_ops;
++      const struct vm_operations_struct *lower_vm_ops;
 +      struct vm_area_struct lower_vma;
 +
 +      BUG_ON(!vma);
@@ -7392,12 +7352,12 @@ index 0000000..18b05d5
 +};
 diff --git a/fs/unionfs/rdstate.c b/fs/unionfs/rdstate.c
 new file mode 100644
-index 0000000..485464b
+index 0000000..59b7333
 --- /dev/null
 +++ b/fs/unionfs/rdstate.c
 @@ -0,0 +1,285 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -7406,8 +7366,8 @@ index 0000000..485464b
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -7560,7 +7520,7 @@ index 0000000..485464b
 +
 +static void free_filldir_node(struct filldir_node *node)
 +{
-+      if (node->namelen >= DNAME_INLINE_LEN_MIN)
++      if (node->namelen >= DNAME_INLINE_LEN)
 +              kfree(node->name);
 +      kmem_cache_free(unionfs_filldir_cachep, node);
 +}
@@ -7661,7 +7621,7 @@ index 0000000..485464b
 +      new->bindex = bindex;
 +      new->whiteout = whiteout;
 +
-+      if (namelen < DNAME_INLINE_LEN_MIN) {
++      if (namelen < DNAME_INLINE_LEN) {
 +              new->name = new->iname;
 +      } else {
 +              new->name = kmalloc(namelen + 1, GFP_KERNEL);
@@ -7683,12 +7643,12 @@ index 0000000..485464b
 +}
 diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
 new file mode 100644
-index 0000000..ed13260
+index 0000000..ce85b84
 --- /dev/null
 +++ b/fs/unionfs/rename.c
-@@ -0,0 +1,520 @@
+@@ -0,0 +1,522 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -7697,8 +7657,8 @@ index 0000000..ed13260
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -7717,6 +7677,7 @@ index 0000000..ed13260
 +      struct dentry *lower_dentry;
 +      struct dentry *lower_parent;
 +      int err = 0;
++      struct nameidata lower_nd;
 +
 +      verify_locked(dentry);
 +
@@ -7724,8 +7685,12 @@ index 0000000..ed13260
 +
 +      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);
++      err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++      if (unlikely(err < 0))
++              goto out;
++      lower_dentry = lookup_one_len_nd(dentry->d_name.name, lower_parent,
++                                       dentry->d_name.len, &lower_nd);
++      release_lower_nd(&lower_nd, err);
 +      if (IS_ERR(lower_dentry)) {
 +              err = PTR_ERR(lower_dentry);
 +              goto out;
@@ -7797,8 +7762,6 @@ index 0000000..ed13260
 +      lower_old_dir_dentry = dget_parent(lower_old_dentry);
 +      lower_new_dir_dentry = dget_parent(lower_new_dentry);
 +
-+      /* see Documentation/filesystems/unionfs/issues.txt */
-+      lockdep_off();
 +      trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
 +      /* source should not be ancenstor of target */
 +      if (trap == lower_old_dentry) {
@@ -7819,7 +7782,6 @@ index 0000000..ed13260
 +              fsstack_copy_attr_times(new_dir, lower_new_dir_dentry->d_inode);
 +      }
 +      unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
-+      lockdep_on();
 +
 +      dput(lower_old_dir_dentry);
 +      dput(lower_new_dir_dentry);
@@ -7899,8 +7861,8 @@ index 0000000..ed13260
 +              fsstack_copy_attr_times(new_parent->d_inode,
 +                                      unlink_dir_dentry->d_inode);
 +              /* propagate number of hard-links */
-+              new_parent->d_inode->i_nlink =
-+                      unionfs_get_nlinks(new_parent->d_inode);
++              set_nlink(new_parent->d_inode,
++                        unionfs_get_nlinks(new_parent->d_inode));
 +
 +              unlock_dir(unlink_dir_dentry);
 +              if (!err) {
@@ -8209,18 +8171,18 @@ index 0000000..ed13260
 +}
 diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
 new file mode 100644
-index 0000000..5dd487a
+index 0000000..b923742
 --- /dev/null
 +++ b/fs/unionfs/sioq.c
 @@ -0,0 +1,101 @@
 +/*
-+ * Copyright (c) 2006-2009 Erez Zadok
++ * Copyright (c) 2006-2011 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-2009 Stony Brook University
-+ * Copyright (c) 2006-2009 The Research Foundation of SUNY
++ * Copyright (c) 2006-2011 Stony Brook University
++ * Copyright (c) 2006-2011 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
@@ -8316,18 +8278,18 @@ index 0000000..5dd487a
 +}
 diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
 new file mode 100644
-index 0000000..3d7869a
+index 0000000..c2dfb94
 --- /dev/null
 +++ b/fs/unionfs/sioq.h
 @@ -0,0 +1,91 @@
 +/*
-+ * Copyright (c) 2006-2009 Erez Zadok
++ * Copyright (c) 2006-2011 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-2009 Stony Brook University
-+ * Copyright (c) 2006-2009 The Research Foundation of SUNY
++ * Copyright (c) 2006-2011 Stony Brook University
++ * Copyright (c) 2006-2011 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
@@ -8413,12 +8375,12 @@ index 0000000..3d7869a
 +#endif /* not _SIOQ_H */
 diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
 new file mode 100644
-index 0000000..018b4fd
+index 0000000..e7fc5a5
 --- /dev/null
 +++ b/fs/unionfs/subr.c
 @@ -0,0 +1,95 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8427,8 +8389,8 @@ index 0000000..018b4fd
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -8510,16 +8472,16 @@ index 0000000..018b4fd
 +       * Update the nlinks AFTER updating the above fields, because the
 +       * get_links callback may depend on them.
 +       */
-+      dest->i_nlink = unionfs_get_nlinks(dest);
++      set_nlink(dest, unionfs_get_nlinks(dest));
 +}
 diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
 new file mode 100644
-index 0000000..ded7b84
+index 0000000..b99f14d
 --- /dev/null
 +++ b/fs/unionfs/super.c
-@@ -0,0 +1,1047 @@
+@@ -0,0 +1,1030 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -8528,8 +8490,8 @@ index 0000000..ded7b84
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -8594,31 +8556,6 @@ index 0000000..ded7b84
 +}
 +
 +/*
-+ * we now define delete_inode, because there are two VFS paths that may
-+ * destroy an inode: one of them calls clear inode before doing everything
-+ * else that's needed, and the other is fine.  This way we truncate the inode
-+ * size (and its pages) and then clear our own inode, which will do an iput
-+ * on our and the lower inode.
-+ *
-+ * No need to lock sb info's rwsem.
-+ */
-+static void unionfs_delete_inode(struct inode *inode)
-+{
-+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-+      spin_lock(&inode->i_lock);
-+#endif
-+      i_size_write(inode, 0); /* every f/s seems to do that */
-+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-+      spin_unlock(&inode->i_lock);
-+#endif
-+
-+      if (inode->i_data.nrpages)
-+              truncate_inode_pages(&inode->i_data, 0);
-+
-+      clear_inode(inode);
-+}
-+
-+/*
 + * final actions when unmounting a file system
 + *
 + * No need to lock rwsem.
@@ -8671,6 +8608,7 @@ index 0000000..ded7b84
 +      struct super_block *sb;
 +      struct dentry *lower_dentry;
 +      struct dentry *parent;
++      struct path lower_path;
 +      bool valid;
 +
 +      sb = dentry->d_sb;
@@ -8687,7 +8625,10 @@ index 0000000..ded7b84
 +      unionfs_check_dentry(dentry);
 +
 +      lower_dentry = unionfs_lower_dentry(sb->s_root);
-+      err = vfs_statfs(lower_dentry, buf);
++      lower_path.dentry = lower_dentry;
++      lower_path.mnt = unionfs_mntget(sb->s_root, 0);
++      err = vfs_statfs(&lower_path, buf);
++      mntput(lower_path.mnt);
 +
 +      /* set return buf to our f/s to avoid confusing user-level utils */
 +      buf->f_type = UNIONFS_SUPER_MAGIC;
@@ -8724,7 +8665,7 @@ index 0000000..ded7b84
 +      int err = -EINVAL;
 +      int perms, idx;
 +      char *modename = strchr(optarg, '=');
-+      struct nameidata nd;
++      struct path path;
 +
 +      /* by now, optarg contains the branch name */
 +      if (!*optarg) {
@@ -8751,7 +8692,7 @@ index 0000000..ded7b84
 +       * and cache-coherency resolved, we'll address the branch-path
 +       * uniqueness.
 +       */
-+      err = path_lookup(optarg, LOOKUP_FOLLOW, &nd);
++      err = kern_path(optarg, LOOKUP_FOLLOW, &path);
 +      if (err) {
 +              printk(KERN_ERR "unionfs: error accessing "
 +                     "lower directory \"%s\" (error %d)\n",
@@ -8759,10 +8700,10 @@ index 0000000..ded7b84
 +              goto out;
 +      }
 +      for (idx = 0; idx < cur_branches; idx++)
-+              if (nd.path.mnt == new_lower_paths[idx].mnt &&
-+                  nd.path.dentry == new_lower_paths[idx].dentry)
++              if (path.mnt == new_lower_paths[idx].mnt &&
++                  path.dentry == new_lower_paths[idx].dentry)
 +                      break;
-+      path_put(&nd.path);     /* no longer needed */
++      path_put(&path);        /* no longer needed */
 +      if (idx == cur_branches) {
 +              err = -ENOENT;  /* err may have been reset above */
 +              printk(KERN_ERR "unionfs: branch \"%s\" "
@@ -8785,7 +8726,7 @@ index 0000000..ded7b84
 +{
 +      int err = -EINVAL;
 +      int idx;
-+      struct nameidata nd;
++      struct path path;
 +
 +      /* optarg contains the branch name to delete */
 +
@@ -8795,7 +8736,7 @@ index 0000000..ded7b84
 +       * and cache-coherency resolved, we'll address the branch-path
 +       * uniqueness.
 +       */
-+      err = path_lookup(optarg, LOOKUP_FOLLOW, &nd);
++      err = kern_path(optarg, LOOKUP_FOLLOW, &path);
 +      if (err) {
 +              printk(KERN_ERR "unionfs: error accessing "
 +                     "lower directory \"%s\" (error %d)\n",
@@ -8803,10 +8744,10 @@ index 0000000..ded7b84
 +              goto out;
 +      }
 +      for (idx = 0; idx < cur_branches; idx++)
-+              if (nd.path.mnt == new_lower_paths[idx].mnt &&
-+                  nd.path.dentry == new_lower_paths[idx].dentry)
++              if (path.mnt == new_lower_paths[idx].mnt &&
++                  path.dentry == new_lower_paths[idx].dentry)
 +                      break;
-+      path_put(&nd.path);     /* no longer needed */
++      path_put(&path);        /* no longer needed */
 +      if (idx == cur_branches) {
 +              printk(KERN_ERR "unionfs: branch \"%s\" "
 +                     "not found\n", optarg);
@@ -8852,7 +8793,7 @@ index 0000000..ded7b84
 +      int perms;
 +      int idx = 0;            /* default: insert at beginning */
 +      char *new_branch , *modename = NULL;
-+      struct nameidata nd;
++      struct path path;
 +
 +      /*
 +       * optarg can be of several forms:
@@ -8880,7 +8821,7 @@ index 0000000..ded7b84
 +       * and cache-coherency resolved, we'll address the branch-path
 +       * uniqueness.
 +       */
-+      err = path_lookup(optarg, LOOKUP_FOLLOW, &nd);
++      err = kern_path(optarg, LOOKUP_FOLLOW, &path);
 +      if (err) {
 +              printk(KERN_ERR "unionfs: error accessing "
 +                     "lower directory \"%s\" (error %d)\n",
@@ -8888,10 +8829,10 @@ index 0000000..ded7b84
 +              goto out;
 +      }
 +      for (idx = 0; idx < cur_branches; idx++)
-+              if (nd.path.mnt == new_lower_paths[idx].mnt &&
-+                  nd.path.dentry == new_lower_paths[idx].dentry)
++              if (path.mnt == new_lower_paths[idx].mnt &&
++                  path.dentry == new_lower_paths[idx].dentry)
 +                      break;
-+      path_put(&nd.path);     /* no longer needed */
++      path_put(&path);        /* no longer needed */
 +      if (idx == cur_branches) {
 +              printk(KERN_ERR "unionfs: branch \"%s\" "
 +                     "not found\n", optarg);
@@ -8920,7 +8861,7 @@ index 0000000..ded7b84
 +                     "branch \"%s\"\n", modename, new_branch);
 +              goto out;
 +      }
-+      err = path_lookup(new_branch, LOOKUP_FOLLOW, &nd);
++      err = kern_path(new_branch, LOOKUP_FOLLOW, &path);
 +      if (err) {
 +              printk(KERN_ERR "unionfs: error accessing "
 +                     "lower directory \"%s\" (error %d)\n",
@@ -8934,11 +8875,11 @@ index 0000000..ded7b84
 +       * because this code base doesn't support stacking unionfs: the ODF
 +       * code base supports that correctly.
 +       */
-+      err = check_branch(&nd);
++      err = check_branch(&path);
 +      if (err) {
 +              printk(KERN_ERR "unionfs: lower directory "
 +                     "\"%s\" is not a valid branch\n", optarg);
-+              path_put(&nd.path);
++              path_put(&path);
 +              goto out;
 +      }
 +
@@ -8955,10 +8896,10 @@ index 0000000..ded7b84
 +              memmove(&new_lower_paths[idx+1], &new_lower_paths[idx],
 +                      (cur_branches - idx) * sizeof(struct path));
 +      }
-+      new_lower_paths[idx].dentry = nd.path.dentry;
-+      new_lower_paths[idx].mnt = nd.path.mnt;
++      new_lower_paths[idx].dentry = path.dentry;
++      new_lower_paths[idx].mnt = path.mnt;
 +
-+      new_data[idx].sb = nd.path.dentry->d_sb;
++      new_data[idx].sb = path.dentry->d_sb;
 +      atomic_set(&new_data[idx].open_files, 0);
 +      new_data[idx].branchperms = perms;
 +      new_data[idx].branch_id = ++*high_branch_id; /* assign new branch ID */
@@ -9110,10 +9051,10 @@ index 0000000..ded7b84
 +              path_get(&tmp_lower_paths[i]); /* drop refs at end of fxn */
 +
 +      /*******************************************************************
-+       * For each branch command, do path_lookup on the requested branch,
++       * For each branch command, do kern_path on the requested branch,
 +       * and apply the change to a temp branch list.  To handle errors, we
 +       * already dup'ed the old arrays (above), and increased the refcnts
-+       * on various f/s objects.  So now we can do all the path_lookups
++       * on various f/s objects.  So now we can do all the kern_path'ss
 +       * and branch-management commands on the new arrays.  If it fail mid
 +       * way, we free the tmp arrays and *put all objects.  If we succeed,
 +       * then we free old arrays and *put its objects, and then replace
@@ -9368,13 +9309,16 @@ index 0000000..ded7b84
 + *
 + * No need to lock sb info's rwsem.
 + */
-+static void unionfs_clear_inode(struct inode *inode)
++static void unionfs_evict_inode(struct inode *inode)
 +{
 +      int bindex, bstart, bend;
 +      struct inode *lower_inode;
 +      struct list_head *pos, *n;
 +      struct unionfs_dir_state *rdstate;
 +
++      truncate_inode_pages(&inode->i_data, 0);
++      end_writeback(inode);
++
 +      list_for_each_safe(pos, n, &UNIONFS_I(inode)->readdircache) {
 +              rdstate = list_entry(pos, struct unionfs_dir_state, cache);
 +              list_del(&rdstate->cache);
@@ -9458,7 +9402,8 @@ index 0000000..ded7b84
 + *
 + * No need to grab sb info's rwsem.
 + */
-+static int unionfs_write_inode(struct inode *inode, int sync)
++static int unionfs_write_inode(struct inode *inode,
++                             struct writeback_control *wbc)
 +{
 +      struct list_head *pos, *n;
 +      struct unionfs_dir_state *rdstate;
@@ -9502,17 +9447,18 @@ index 0000000..ded7b84
 +      unionfs_read_unlock(sb);
 +}
 +
-+static int unionfs_show_options(struct seq_file *m, struct vfsmount *mnt)
++static int unionfs_show_options(struct seq_file *m, struct dentry *root)
 +{
-+      struct super_block *sb = mnt->mnt_sb;
++      struct super_block *sb = root->d_sb;
 +      int ret = 0;
 +      char *tmp_page;
 +      char *path;
 +      int bindex, bstart, bend;
 +      int perms;
 +
++      /* to prevent a silly lockdep warning with namespace_sem */
++      lockdep_off();
 +      unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
-+
 +      unionfs_lock_dentry(sb->s_root, UNIONFS_DMUTEX_CHILD);
 +
 +      tmp_page = (char *) __get_free_page(GFP_KERNEL);
@@ -9547,18 +9493,17 @@ index 0000000..ded7b84
 +      free_page((unsigned long) tmp_page);
 +
 +      unionfs_unlock_dentry(sb->s_root);
-+
 +      unionfs_read_unlock(sb);
++      lockdep_on();
 +
 +      return ret;
 +}
 +
 +struct super_operations unionfs_sops = {
-+      .delete_inode   = unionfs_delete_inode,
 +      .put_super      = unionfs_put_super,
 +      .statfs         = unionfs_statfs,
 +      .remount_fs     = unionfs_remount_fs,
-+      .clear_inode    = unionfs_clear_inode,
++      .evict_inode    = unionfs_evict_inode,
 +      .umount_begin   = unionfs_umount_begin,
 +      .show_options   = unionfs_show_options,
 +      .write_inode    = unionfs_write_inode,
@@ -9567,12 +9512,12 @@ index 0000000..ded7b84
 +};
 diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
 new file mode 100644
-index 0000000..17a0056
+index 0000000..8e7fcfb
 --- /dev/null
 +++ b/fs/unionfs/union.h
-@@ -0,0 +1,670 @@
+@@ -0,0 +1,681 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005      Arun M. Krishnakumar
@@ -9580,8 +9525,8 @@ index 0000000..17a0056
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -9606,7 +9551,6 @@ index 0000000..17a0056
 +#include <linux/seq_file.h>
 +#include <linux/slab.h>
 +#include <linux/spinlock.h>
-+#include <linux/smp_lock.h>
 +#include <linux/statfs.h>
 +#include <linux/string.h>
 +#include <linux/vmalloc.h>
@@ -9620,8 +9564,9 @@ index 0000000..17a0056
 +#include <linux/mman.h>
 +#include <linux/backing-dev.h>
 +#include <linux/splice.h>
++#include <linux/sched.h>
++
 +
-+#include <asm/system.h>
 +
 +#include <linux/union_fs.h>
 +
@@ -9670,7 +9615,7 @@ index 0000000..17a0056
 +      struct unionfs_dir_state *rdstate;
 +      struct file **lower_files;
 +      int *saved_branch_ids; /* IDs of branches when file was opened */
-+      struct vm_operations_struct *lower_vm_ops;
++      const struct vm_operations_struct *lower_vm_ops;
 +      bool wrote_to_file;     /* for delayed copyup */
 +};
 +
@@ -9763,7 +9708,7 @@ index 0000000..17a0056
 +      int whiteout;
 +
 +      /* Inline name, so we don't need to separately kmalloc small ones */
-+      char iname[DNAME_INLINE_LEN_MIN];
++      char iname[DNAME_INLINE_LEN];
 +};
 +
 +/* Directory hash table. */
@@ -9989,7 +9934,7 @@ index 0000000..17a0056
 +extern int unionfs_flush(struct file *file, fl_owner_t id);
 +extern long unionfs_ioctl(struct file *file, unsigned int cmd,
 +                        unsigned long arg);
-+extern int unionfs_fsync(struct file *file, struct dentry *dentry,
++extern int unionfs_fsync(struct file *file, loff_t start, loff_t end,
 +                       int datasync);
 +extern int unionfs_fasync(int fd, struct file *file, int flag);
 +
@@ -10111,7 +10056,7 @@ index 0000000..17a0056
 +/*
 + * EXTERNALS:
 + */
-+extern int check_branch(struct nameidata *nd);
++extern int check_branch(const struct path *path);
 +extern int parse_branch_mode(const char *name, int *perms);
 +
 +/* locking helpers */
@@ -10140,9 +10085,19 @@ index 0000000..17a0056
 +                                          struct dentry *base, int len)
 +{
 +      struct dentry *d;
++      struct nameidata lower_nd;
++      int err;
++
++      err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++      if (unlikely(err < 0)) {
++              d = ERR_PTR(err);
++              goto out;
++      }
 +      mutex_lock(&base->d_inode->i_mutex);
-+      d = lookup_one_len(name, base, len);
++      d = lookup_one_len_nd(name, base, len, &lower_nd);
++      release_lower_nd(&lower_nd, err);
 +      mutex_unlock(&base->d_inode->i_mutex);
++out:
 +      return d;
 +}
 +
@@ -10237,18 +10192,19 @@ index 0000000..17a0056
 +#define show_inode_times(i)           do { } while (0)
 +#define show_dinode_times(d)          do { } while (0)
 +#define show_inode_counts(i)          do { } while (0)
++#define UDBG                          do { } while (0)
 +
 +#endif /* not CONFIG_UNION_FS_DEBUG */
 +
 +#endif        /* not _UNION_H_ */
 diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
 new file mode 100644
-index 0000000..b6d8e10
+index 0000000..25943a5
 --- /dev/null
 +++ b/fs/unionfs/unlink.c
-@@ -0,0 +1,282 @@
+@@ -0,0 +1,278 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -10257,8 +10213,8 @@ index 0000000..b6d8e10
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -10433,17 +10389,13 @@ index 0000000..b6d8e10
 +      /* avoid destroying the lower inode if the file is in use */
 +      dget(lower_dentry);
 +      err = is_robranch(dentry);
-+      if (!err) {
-+              /* see Documentation/filesystems/unionfs/issues.txt */
-+              lockdep_off();
++      if (!err)
 +              err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
-+              lockdep_on();
-+      }
 +      dput(lower_dentry);
 +
 +      fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
 +      /* propagate number of hard-links */
-+      dentry->d_inode->i_nlink = unionfs_get_nlinks(dentry->d_inode);
++      set_nlink(dentry->d_inode, unionfs_get_nlinks(dentry->d_inode));
 +
 +out:
 +      if (lower_dir_dentry)
@@ -10531,12 +10483,12 @@ index 0000000..b6d8e10
 +}
 diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
 new file mode 100644
-index 0000000..626006a
+index 0000000..582cef2
 --- /dev/null
 +++ b/fs/unionfs/whiteout.c
-@@ -0,0 +1,584 @@
+@@ -0,0 +1,601 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -10545,8 +10497,8 @@ index 0000000..626006a
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -10740,8 +10692,8 @@ index 0000000..626006a
 + * 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).
++ * If it finds both a regular file and a whiteout, delete whiteout (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
@@ -10771,13 +10723,10 @@ index 0000000..626006a
 +      }
 +
 +      /* 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",
++      if (unlikely(lower_dentry->d_inode))
++              printk(KERN_WARNING "unionfs: removing whiteout; regular "
++                     "file exists in directory %s (branch %d)\n",
 +                     lower_dir_dentry->d_name.name, bindex);
-+              goto out_dput;
-+      }
 +
 +      /* check if branch is writeable */
 +      err = is_robranch_super(dentry->d_sb, bindex);
@@ -11021,6 +10970,7 @@ index 0000000..626006a
 +      struct dentry *wh_lower_dentry;
 +      struct inode *lower_inode;
 +      struct sioq_args args;
++      struct nameidata lower_nd;
 +
 +      lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
 +      lower_inode = lower_dentry->d_inode;
@@ -11030,9 +10980,16 @@ index 0000000..626006a
 +      mutex_lock(&lower_inode->i_mutex);
 +
 +      if (!inode_permission(lower_inode, MAY_EXEC)) {
++              err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++              if (unlikely(err < 0)) {
++                      mutex_unlock(&lower_inode->i_mutex);
++                      goto out;
++              }
 +              wh_lower_dentry =
-+                      lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
-+                                     sizeof(UNIONFS_DIR_OPAQUE) - 1);
++                      lookup_one_len_nd(UNIONFS_DIR_OPAQUE, lower_dentry,
++                                        sizeof(UNIONFS_DIR_OPAQUE) - 1,
++                                        &lower_nd);
++              release_lower_nd(&lower_nd, err);
 +      } else {
 +              args.is_opaque.dentry = lower_dentry;
 +              run_sioq(__is_opaque_dir, &args);
@@ -11057,9 +11014,17 @@ index 0000000..626006a
 +void __is_opaque_dir(struct work_struct *work)
 +{
 +      struct sioq_args *args = container_of(work, struct sioq_args, work);
++      struct nameidata lower_nd;
++      int err;
 +
-+      args->ret = lookup_one_len(UNIONFS_DIR_OPAQUE, args->is_opaque.dentry,
-+                                 sizeof(UNIONFS_DIR_OPAQUE) - 1);
++      err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++      if (unlikely(err < 0))
++              return;
++      args->ret = lookup_one_len_nd(UNIONFS_DIR_OPAQUE,
++                                    args->is_opaque.dentry,
++                                    sizeof(UNIONFS_DIR_OPAQUE) - 1,
++                                    &lower_nd);
++      release_lower_nd(&lower_nd, err);
 +      complete(&args->comp);
 +}
 +
@@ -11095,8 +11060,12 @@ index 0000000..626006a
 +             !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);
++      err = init_lower_nd(&nd, LOOKUP_OPEN);
++      if (unlikely(err < 0))
++              goto out;
++      diropq = lookup_one_len_nd(UNIONFS_DIR_OPAQUE, lower_dentry,
++                                 sizeof(UNIONFS_DIR_OPAQUE) - 1, &nd);
++      release_lower_nd(&nd, err);
 +      if (IS_ERR(diropq)) {
 +              err = PTR_ERR(diropq);
 +              goto out;
@@ -11121,12 +11090,12 @@ index 0000000..626006a
 +}
 diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
 new file mode 100644
-index 0000000..af72cca
+index 0000000..a93d803
 --- /dev/null
 +++ b/fs/unionfs/xattr.c
 @@ -0,0 +1,173 @@
 +/*
-+ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
 + * Copyright (c) 2003-2006 Charles P. Wright
 + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
 + * Copyright (c) 2005-2006 Junjiro Okajima
@@ -11135,8 +11104,8 @@ index 0000000..af72cca
 + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 + * Copyright (c) 2003      Puja Gupta
 + * Copyright (c) 2003      Harikesavan Krishnan
-+ * Copyright (c) 2003-2009 Stony Brook University
-+ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 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
@@ -11299,10 +11268,10 @@ index 0000000..af72cca
 +      return err;
 +}
 diff --git a/include/linux/fs_stack.h b/include/linux/fs_stack.h
-index bb516ce..64f1ced 100644
+index da317c7..64f1ced 100644
 --- a/include/linux/fs_stack.h
 +++ b/include/linux/fs_stack.h
-@@ -1,17 +1,27 @@
+@@ -1,7 +1,19 @@
 +/*
 + * Copyright (c) 2006-2009 Erez Zadok
 + * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
@@ -11323,23 +11292,11 @@ index bb516ce..64f1ced 100644
   * filesystems; none of these functions require i_mutex to be held.
   */
  
- #include <linux/fs.h>
- /* externs for fs/stack.c */
--extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
--                              int (*get_nlinks)(struct inode *));
--
--extern void fsstack_copy_inode_size(struct inode *dst, const struct inode *src);
-+extern void fsstack_copy_attr_all(struct inode *dest, 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,
 diff --git a/include/linux/magic.h b/include/linux/magic.h
-index 1923327..c3fc308 100644
+index 2d4beab..39f5798 100644
 --- a/include/linux/magic.h
 +++ b/include/linux/magic.h
-@@ -45,6 +45,8 @@
+@@ -50,6 +50,8 @@
  #define REISER2FS_SUPER_MAGIC_STRING  "ReIsEr2Fs"
  #define REISER2FS_JR_SUPER_MAGIC_STRING       "ReIsEr3Fs"
  
@@ -11348,11 +11305,27 @@ index 1923327..c3fc308 100644
  #define SMB_SUPER_MAGIC               0x517B
  #define USBDEVICE_SUPER_MAGIC 0x9fa2
  #define CGROUP_SUPER_MAGIC    0x27e0eb
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index ffc0213..99802c3 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -84,8 +84,11 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+               int (*open)(struct inode *, struct file *));
++extern void release_open_intent(struct nameidata *);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry *lookup_one_len_nd(const char *, struct dentry *, int,
++                                    struct nameidata *nd);
+ extern int follow_down_one(struct path *);
+ extern int follow_down(struct path *);
 diff --git a/include/linux/splice.h b/include/linux/splice.h
-index 18e7c7c..af56841 100644
+index 26e5b61..28213e6 100644
 --- a/include/linux/splice.h
 +++ b/include/linux/splice.h
-@@ -81,5 +81,10 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+@@ -81,6 +81,11 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
                              struct splice_pipe_desc *);
  extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
                                      splice_direct_actor *);
@@ -11362,7 +11335,8 @@ index 18e7c7c..af56841 100644
 +                        struct pipe_inode_info *pipe, size_t len,
 +                        unsigned int flags);
  
- #endif
+ /*
+  * for dynamic pipe sizing
 diff --git a/include/linux/union_fs.h b/include/linux/union_fs.h
 new file mode 100644
 index 0000000..c84d97e
@@ -11392,10 +11366,10 @@ index 0000000..c84d97e
 +#endif /* _LINUX_UNIONFS_H */
 +
 diff --git a/security/security.c b/security/security.c
-index dc7674f..aa3f061 100644
+index d754249..f7e8373 100644
 --- a/security/security.c
 +++ b/security/security.c
-@@ -519,6 +519,7 @@ int security_inode_permission(struct inode *inode, int mask)
+@@ -538,6 +538,7 @@ int security_inode_permission(struct inode *inode, int mask)
                return 0;
        return security_ops->inode_permission(inode, mask);
  }
This page took 0.183717 seconds and 4 git commands to generate.