+
+For more information, see <http://unionfs.filesystems.org/>.
diff --git a/MAINTAINERS b/MAINTAINERS
-index 560ecce..09e38d6 100644
+index f0358cd..7ae0669 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -6276,6 +6276,14 @@ F: Documentation/cdrom/
+@@ -6375,6 +6375,14 @@ F: Documentation/cdrom/
F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
M: Artem Bityutskiy <dedekind1@gmail.com>
W: http://www.linux-mtd.infradead.org/
diff --git a/fs/Kconfig b/fs/Kconfig
-index 3db9caa..3dc2dfd 100644
+index 19891aa..ac8a074 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
-@@ -170,6 +170,7 @@ if MISC_FILESYSTEMS
+@@ -187,6 +187,7 @@ if MISC_FILESYSTEMS
source "fs/adfs/Kconfig"
source "fs/affs/Kconfig"
source "fs/ecryptfs/Kconfig"
source "fs/hfsplus/Kconfig"
source "fs/befs/Kconfig"
diff --git a/fs/Makefile b/fs/Makefile
-index a7f7cef..672664b 100644
+index fb68c2b..8ca9290 100644
--- a/fs/Makefile
+++ b/fs/Makefile
-@@ -81,6 +81,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/
obj-$(CONFIG_NFS_FS) += nfs/
obj-$(CONFIG_EXPORTFS) += exportfs/
diff --git a/fs/namei.c b/fs/namei.c
-index 0087cf9..d3118a7 100644
+index 0223c41..5d0261e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
-@@ -562,6 +562,7 @@ void release_open_intent(struct nameidata *nd)
+@@ -484,6 +484,7 @@ void release_open_intent(struct nameidata *nd)
fput(file);
}
}
static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
+@@ -1740,6 +1741,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(int dfd, const char __user *name, unsigned flags,
+ struct path *path)
+ {
+@@ -3339,6 +3376,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 50a5d97..a3af841 100644
+index aa866d3..421ab86 100644
--- a/fs/splice.c
+++ b/fs/splice.c
-@@ -1081,8 +1081,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
+@@ -1085,8 +1085,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
/*
* Attempt to initiate a splice from pipe to file.
*/
{
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
loff_t *, size_t, unsigned int);
-@@ -1105,13 +1105,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+@@ -1109,13 +1109,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
return splice_write(pipe, out, ppos, len, flags);
}
{
ssize_t (*splice_read)(struct file *, loff_t *,
struct pipe_inode_info *, size_t, unsigned int);
-@@ -1131,6 +1132,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
+@@ -1135,6 +1136,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
return splice_read(in, ppos, pipe, len, flags);
}
/**
* splice_direct_to_actor - splices data directly between two non-pipes
-@@ -1200,7 +1202,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+@@ -1204,7 +1206,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;
if (unlikely(ret <= 0))
goto out_release;
-@@ -1259,8 +1261,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
+@@ -1263,8 +1265,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
{
struct file *file = sd->u.file;
}
/**
-@@ -1345,7 +1347,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+@@ -1349,7 +1351,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
} else
off = &out->f_pos;
if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
ret = -EFAULT;
-@@ -1365,7 +1367,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+@@ -1369,7 +1371,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
} else
off = &in->f_pos;
+ 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..10a321a
+index 0000000..0ece303
--- /dev/null
+++ b/fs/unionfs/Makefile
@@ -0,0 +1,17 @@
-+UNIONFS_VERSION="2.5.8 (for 2.6.38-rc7)"
++UNIONFS_VERSION="2.5.9.2 (for 3.0.0-rc4)"
+
+EXTRA_CFLAGS += -DUNIONFS_VERSION=\"$(UNIONFS_VERSION)\"
+
+endif
diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
new file mode 100644
-index 0000000..51ea65e
+index 0000000..0a271f4
--- /dev/null
+++ b/fs/unionfs/commonfops.c
@@ -0,0 +1,896 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ * someone has copied up this file from underneath us, we also need
+ * to refresh things.
+ */
-+ if (d_deleted(dentry) ||
++ if ((d_deleted(dentry) && dbstart(dentry) >= fbstart(file)) ||
+ (sbgen <= fgen &&
+ dbstart(dentry) == fbstart(file) &&
+ unionfs_lower_file(file)))
+ 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 {
+ 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
+ inodeinfo = UNIONFS_I(inode);
+
+ /* fput all the lower files */
-+ fgen = atomic_read(&fileinfo->generation);
+ bstart = fbstart(file);
+ bend = fbend(file);
+
+ if (lower_file->f_op->unlocked_ioctl) {
+ err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
+#ifdef CONFIG_COMPAT
-+ } else if (lower_file->f_op->ioctl) {
-+ err = lower_file->f_op->compat_ioctl(
-+ lower_file->f_path.dentry->d_inode,
-+ lower_file, cmd, arg);
++ } else if (lower_file->f_op->compat_ioctl) {
++ err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+#endif
+ }
+
+}
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
new file mode 100644
-index 0000000..bba3a75
+index 0000000..37c2654
--- /dev/null
+++ b/fs/unionfs/copyup.c
@@ -0,0 +1,896 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/debug.c b/fs/unionfs/debug.c
new file mode 100644
-index 0000000..a76f92a
+index 0000000..6092e69
--- /dev/null
+++ b/fs/unionfs/debug.c
@@ -0,0 +1,548 @@
+/*
-+ * Copyright (c) 2003-2010 Erez Zadok
++ * Copyright (c) 2003-2011 Erez Zadok
+ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
new file mode 100644
-index 0000000..a0c3bba
+index 0000000..c0205a4
--- /dev/null
+++ b/fs/unionfs/dentry.c
-@@ -0,0 +1,397 @@
+@@ -0,0 +1,406 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ 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)
+ * 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 ||
+};
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
new file mode 100644
-index 0000000..7da0ff0
+index 0000000..72a9c1a
--- /dev/null
+++ b/fs/unionfs/dirfops.c
@@ -0,0 +1,302 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+};
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
new file mode 100644
-index 0000000..033343b
+index 0000000..62ec9af
--- /dev/null
+++ b/fs/unionfs/dirhelper.c
@@ -0,0 +1,158 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
new file mode 100644
-index 0000000..5b77eac
+index 0000000..ae1b86a
--- /dev/null
+++ b/fs/unionfs/fanout.h
@@ -0,0 +1,407 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+#endif /* not _FANOUT_H */
diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c
new file mode 100644
-index 0000000..1c694c3
+index 0000000..416c52f
--- /dev/null
+++ b/fs/unionfs/file.c
@@ -0,0 +1,382 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+};
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
new file mode 100644
-index 0000000..0066238
+index 0000000..b207c13
--- /dev/null
+++ b/fs/unionfs/inode.c
-@@ -0,0 +1,1077 @@
+@@ -0,0 +1,1099 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ 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;
++ struct dentry *dentry;
+
-+ if (flags & IPERM_FLAG_RCU)
-+ return -ECHILD;
++ if (flags & IPERM_FLAG_RCU) {
++ err = -ECHILD;
++ goto out_nograb;
++ }
+
++ dentry = d_find_alias(inode);
+ 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 */
+ err = -ESTALE; /* force revalidate */
+ dput(dentry);
+ }
+ iput(inode_grabbed);
++out_nograb:
+ return err;
+}
+
+ 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);
+ /* 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;
++ }
+ }
+
+ /*
+};
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
new file mode 100644
-index 0000000..b63c17e
+index 0000000..3cbde56
--- /dev/null
+++ b/fs/unionfs/lookup.c
@@ -0,0 +1,569 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
new file mode 100644
-index 0000000..9ee58eb
+index 0000000..fa52f61
--- /dev/null
+++ b/fs/unionfs/main.c
-@@ -0,0 +1,762 @@
+@@ -0,0 +1,763 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ * 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;
+}
+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;
+ 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",
+ 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);
+ 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 (!PTR_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,
+};
+module_exit(exit_unionfs_fs);
diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
new file mode 100644
-index 0000000..1f70535
+index 0000000..bcc5652
--- /dev/null
+++ b/fs/unionfs/mmap.c
@@ -0,0 +1,89 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+};
diff --git a/fs/unionfs/rdstate.c b/fs/unionfs/rdstate.c
new file mode 100644
-index 0000000..d57f1f8
+index 0000000..59b7333
--- /dev/null
+++ b/fs/unionfs/rdstate.c
@@ -0,0 +1,285 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
new file mode 100644
-index 0000000..936700e
+index 0000000..c8ab910
--- /dev/null
+++ b/fs/unionfs/rename.c
-@@ -0,0 +1,517 @@
+@@ -0,0 +1,522 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ struct dentry *lower_dentry;
+ struct dentry *lower_parent;
+ int err = 0;
++ struct nameidata lower_nd;
+
+ verify_locked(dentry);
+
+
+ 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;
+}
diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
new file mode 100644
-index 0000000..760c580
+index 0000000..b923742
--- /dev/null
+++ b/fs/unionfs/sioq.c
@@ -0,0 +1,101 @@
+/*
-+ * Copyright (c) 2006-2010 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-2010 Stony Brook University
-+ * Copyright (c) 2006-2010 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
+}
diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
new file mode 100644
-index 0000000..b26d248
+index 0000000..c2dfb94
--- /dev/null
+++ b/fs/unionfs/sioq.h
@@ -0,0 +1,91 @@
+/*
-+ * Copyright (c) 2006-2010 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-2010 Stony Brook University
-+ * Copyright (c) 2006-2010 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
+#endif /* not _SIOQ_H */
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
new file mode 100644
-index 0000000..570a344
+index 0000000..bdca2f7
--- /dev/null
+++ b/fs/unionfs/subr.c
@@ -0,0 +1,95 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
new file mode 100644
-index 0000000..45bb9bf
+index 0000000..c3ac814
--- /dev/null
+++ b/fs/unionfs/super.c
-@@ -0,0 +1,1029 @@
+@@ -0,0 +1,1030 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ 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) {
+ * 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",
+ 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\" "
+{
+ int err = -EINVAL;
+ int idx;
-+ struct nameidata nd;
++ struct path path;
+
+ /* optarg contains the branch name to delete */
+
+ * 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",
+ 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);
+ 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:
+ * 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",
+ 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);
+ "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",
+ * 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;
+ }
+
+ 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 */
+ 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
+ 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);
+ free_page((unsigned long) tmp_page);
+
+ unionfs_unlock_dentry(sb->s_root);
-+
+ unionfs_read_unlock(sb);
++ lockdep_on();
+
+ return ret;
+}
+};
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
new file mode 100644
-index 0000000..6c7b9aa
+index 0000000..1821705
--- /dev/null
+++ b/fs/unionfs/union.h
-@@ -0,0 +1,669 @@
+@@ -0,0 +1,679 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+#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>
+#include <linux/mman.h>
+#include <linux/backing-dev.h>
+#include <linux/splice.h>
++#include <linux/sched.h>
+
+#include <asm/system.h>
+
+/*
+ * 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 */
+ 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;
+}
+
+#endif /* not _UNION_H_ */
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
new file mode 100644
-index 0000000..542c513
+index 0000000..bf447bb
--- /dev/null
+++ b/fs/unionfs/unlink.c
@@ -0,0 +1,278 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+}
diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
new file mode 100644
-index 0000000..405073a
+index 0000000..582cef2
--- /dev/null
+++ b/fs/unionfs/whiteout.c
-@@ -0,0 +1,584 @@
+@@ -0,0 +1,601 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
+ * 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
+ }
+
+ /* 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);
+ 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;
+ 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);
+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);
+}
+
+ !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;
+}
diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
new file mode 100644
-index 0000000..9002e06
+index 0000000..a93d803
--- /dev/null
+++ b/fs/unionfs/xattr.c
@@ -0,0 +1,173 @@
+/*
-+ * Copyright (c) 2003-2010 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
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003 Puja Gupta
+ * Copyright (c) 2003 Harikesavan Krishnan
-+ * Copyright (c) 2003-2010 Stony Brook University
-+ * Copyright (c) 2003-2010 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
*/
diff --git a/include/linux/magic.h b/include/linux/magic.h
-index 62730ea..bd9832b 100644
+index 1e5df2a..01ee54d 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
-@@ -48,6 +48,8 @@
+@@ -50,6 +50,8 @@
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
#define USBDEVICE_SUPER_MAGIC 0x9fa2
#define CGROUP_SUPER_MAGIC 0x27e0eb
diff --git a/include/linux/namei.h b/include/linux/namei.h
-index f276d4f..cf4ec6c 100644
+index eba45ea..8e19e9c 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
-@@ -78,6 +78,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+@@ -81,8 +81,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 997c3b4..54f5501 100644
--- a/include/linux/splice.h
+#endif /* _LINUX_UNIONFS_H */
+
diff --git a/security/security.c b/security/security.c
-index 7b7308a..abdb5a5 100644
+index 4ba6d4c..093d8b4 100644
--- a/security/security.c
+++ b/security/security.c
-@@ -511,6 +511,7 @@ int security_inode_permission(struct inode *inode, int mask)
+@@ -520,6 +520,7 @@ int security_inode_permission(struct inode *inode, int mask)
return 0;
- return security_ops->inode_permission(inode, mask);
+ return security_ops->inode_permission(inode, mask, 0);
}
+EXPORT_SYMBOL(security_inode_permission);
int security_inode_exec_permission(struct inode *inode, unsigned int flags)
{
-diff -purN orig/fs/unionfs/commonfops.c linux-2.6.36/fs/unionfs/commonfops.c
---- orig/fs/unionfs/commonfops.c 2010-10-21 16:29:51.033693283 -0400
-+++ linux-2.6.36/fs/unionfs/commonfops.c 2010-10-27 10:15:30.337131546 -0400
-@@ -740,10 +740,8 @@ static long do_ioctl(struct file *file,
- if (lower_file->f_op->unlocked_ioctl) {
- err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
- #ifdef CONFIG_COMPAT
-- } else if (lower_file->f_op->ioctl) {
-- err = lower_file->f_op->compat_ioctl(
-- lower_file->f_path.dentry->d_inode,
-- lower_file, cmd, arg);
-+ } else if (lower_file->f_op->compat_ioctl) {
-+ err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
- #endif
- }
-
\ No newline at end of file