I was investigating how I could enable crossing mount points in the
lower filesystem in eCryptfs, and Charles pointed me to some code in
the FiST templates that has me concerned:

---
inode = iget(sb, wrapfs_iunique(sb, 10));
---

So what happens with lookup on hard links to the same lower inode?
wrapfs_lookup() goes ahead and calls wrapfs_interpose() for the new
dentry, which calls iget() with a uniquely generated inode number. As
far as I can tell, we wind up with *two* stacked inodes for the lower
inode, with two separate stacked mappings associated with one lower
mapping. If I'm reading the code right, that's bad news.

Shaggy pointed out that there are userspace utilities that actually
care about the inode number being the same for the same file. For
instance, backup or archiving tools that check the inode number to
determine whether to store the data in a file or a pointer to the data
in the file that has already been archived.

I am thinking that one answer to this issue is to add a new void
*i_stacked_inode to the inode struct. If an existing valid lower inode
is found on interpose, then just associate the stacked inode pointed
to by i_stacked_inode with the stacked dentry.

Steve French mentioned something about NFS having had to recently to
deal with this too, so I Cc'd David Howells in case he has any
insight.

Alternatively, I kicked around some ideas about adding an inode
allocation hash table to keep track of this stuff, but I really think
making the lower inodes ``stacked aware'' is the best solution in
terms of storage and performance.

The two patches below (against 2.6.18-rc2-mm1) associate the vfsmount
with the dentry and then add a new build option to put a back
reference from the lower inode to the upper. They're completely
untested (hey, it compiles! ship it!), but they illustrate the
direction I'm going. Any thoughts on this approach?

By the way, I am thinking that this CONFIG_STACK_FS option will
eventually govern other stackable filesystem support in the VFS in the
near future.

Thanks,
Mike

P.S. - I think the nameidata stuff will work with NFSv4 and CIFS in
2.6.18-rc2-mm1. I think we only care about preserving the flags now; no
lookup intent file funny stuff seems to be going on anywhere...

---

Associate vfsmount with dentry. Update nameidata handling to preserve
dentry and vfsmount on revalidate call to lower filesystem.

---

 fs/ecryptfs/crypto.c          |    5 +--
 fs/ecryptfs/dentry.c          |   18 +++++++-----
 fs/ecryptfs/ecryptfs_kernel.h |   19 ++++++++++--
 fs/ecryptfs/file.c            |    5 +--
 fs/ecryptfs/inode.c           |   63 ++++++++++++++++++++++++-----------------
 fs/ecryptfs/main.c            |    4 ++-
 fs/ecryptfs/super.c           |   19 +++++-------
 7 files changed, 78 insertions(+), 55 deletions(-)

diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 100881e..8a7fd11 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1141,14 +1141,13 @@ int ecryptfs_cipher_code_to_string(char 
  * Returns zero on success; non-zero otherwise
  */
 int ecryptfs_read_header_region(char *data, struct dentry *dentry,
-                               struct nameidata *nd)
+                               struct vfsmount *mnt)
 {
-       struct vfsmount *mnt;
        struct file *file;
        mm_segment_t oldfs;
        int rc;
 
-       mnt = mntget(nd->mnt);
+       mnt = mntget(mnt);
        file = dentry_open(dentry, mnt, O_RDONLY);
        if (IS_ERR(file)) {
                ecryptfs_printk(KERN_DEBUG, "Error opening file to "
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
index 6f19fc4..f0d2a43 100644
--- a/fs/ecryptfs/dentry.c
+++ b/fs/ecryptfs/dentry.c
@@ -41,17 +41,21 @@ #include "ecryptfs_kernel.h"
  */
 static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
+       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+       struct dentry *dentry_save;
+       struct vfsmount *vfsmount_save;
        int rc = 1;
-       struct dentry *lower_dentry;
-       struct nameidata lower_nd;
 
-       lower_dentry = ecryptfs_dentry_to_lower(dentry);
        if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
                goto out;
-       memcpy(&lower_nd, nd, sizeof(struct nameidata));
-       lower_nd.dentry = lower_dentry;
-       lower_nd.mnt = ecryptfs_superblock_to_private(dentry->d_sb)->lower_mnt;
-       rc = lower_dentry->d_op->d_revalidate(lower_dentry, &lower_nd);
+       dentry_save = nd->dentry;
+       vfsmount_save = nd->mnt;
+       nd->dentry = lower_dentry;
+       nd->mnt = lower_mnt;
+       rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
+       nd->dentry = dentry_save;
+       nd->mnt = vfsmount_save;
 out:
        return rc;
 }
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 28b9083..349ce2a 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -216,9 +216,11 @@ struct ecryptfs_inode_info {
        struct ecryptfs_crypt_stat crypt_stat;
 };
 
-/* dentry private data. */
+/* dentry private data. Each dentry must keep track of a lower
+ * vfsmount too. */
 struct ecryptfs_dentry_info {
        struct dentry *wdi_dentry;
+       struct vfsmount *lower_mnt;
        struct ecryptfs_crypt_stat *crypt_stat;
 };
 
@@ -243,7 +245,6 @@ struct ecryptfs_mount_crypt_stat {
 /* superblock private data. */
 struct ecryptfs_sb_info {
        struct super_block *wsi_sb;
-       struct vfsmount *lower_mnt;
        struct ecryptfs_mount_crypt_stat mount_crypt_stat;
 };
 
@@ -362,6 +363,18 @@ ecryptfs_set_dentry_lower(struct dentry 
                lower_dentry;
 }
 
+static inline struct vfsmount *
+ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
+{
+       return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
+}
+
+static inline void
+ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount 
*lower_mnt)
+{
+       ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
+               lower_mnt;
+}
 
 #define ecryptfs_printk(type, fmt, arg...) \
         __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
@@ -445,7 +458,7 @@ int ecryptfs_read_headers(struct dentry 
 int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
 int contains_ecryptfs_marker(char *data);
 int ecryptfs_read_header_region(char *data, struct dentry *dentry,
-                               struct nameidata *nd);
+                               struct vfsmount *mnt);
 u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
 int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
 void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 6ddbd0c..c84e1d2 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -117,8 +117,7 @@ static ssize_t ecryptfs_read_update_atim
                rc = wait_on_sync_kiocb(iocb);
        if (rc >= 0) {
                lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
-               lower_vfsmount = ecryptfs_superblock_to_private(
-                       file->f_dentry->d_inode->i_sb)->lower_mnt;
+               lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
                touch_atime(lower_vfsmount, lower_dentry);
        }
        return rc;
@@ -246,7 +245,7 @@ static int ecryptfs_open(struct inode *i
                lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
        if (file->f_flags & O_APPEND)
                lower_flags &= ~O_APPEND;
-       lower_mnt = ecryptfs_superblock_to_private(inode->i_sb)->lower_mnt;
+       lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
        mntget(lower_mnt);
        /* Corresponding fput() in ecryptfs_release() */
        lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 859ae65..d8659ff 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -101,7 +101,7 @@ void ecryptfs_copy_attr_all(struct inode
  * @lower_dentry: New file's dentry in the lower fs
  * @ecryptfs_dentry: New file's dentry in ecryptfs
  * @mode: The mode of the new file
- * @nd: nameidata of ecryptfs' parent's dentry & vfsmnt
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
  *
  * Creates the file in the lower file system.
  *
@@ -109,18 +109,22 @@ void ecryptfs_copy_attr_all(struct inode
  */
 static int
 ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
-                               struct dentry *lower_dentry,
-                               struct dentry *ecryptfs_dentry, int mode,
+                               struct dentry *dentry, int mode,
                                struct nameidata *nd)
 {
+       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+       struct dentry *dentry_save;
+       struct vfsmount *vfsmount_save;
        int rc;
-       struct nameidata lower_nd;
 
-       memcpy(&lower_nd, nd, sizeof(struct nameidata));
-       lower_nd.dentry = lower_dentry;
-       lower_nd.mnt = ecryptfs_superblock_to_private(
-               ecryptfs_dentry->d_sb)->lower_mnt;
-       rc = vfs_create(lower_dir_inode, lower_dentry, mode, &lower_nd);
+       dentry_save = nd->dentry;
+       vfsmount_save = nd->mnt;
+       nd->dentry = lower_dentry;
+       nd->mnt = lower_mnt;
+       rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
+       nd->dentry = dentry_save;
+       nd->mnt = vfsmount_save;
        return rc;
 }
 
@@ -129,7 +133,7 @@ ecryptfs_create_underlying_file(struct i
  * @directory_inode: inode of the new file's dentry's parent in ecryptfs
  * @ecryptfs_dentry: New file's dentry in ecryptfs
  * @mode: The mode of the new file
- * @nd: nameidata of ecryptfs' parent's dentry & vfsmnt
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
  *
  * Creates the underlying file and the eCryptfs inode which will link to
  * it. It will also update the eCryptfs directory inode to mimic the
@@ -155,8 +159,7 @@ ecryptfs_do_create(struct inode *directo
                goto out;
        }
        rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
-                                            lower_dentry, ecryptfs_dentry,
-                                            mode, nd);
+                                            ecryptfs_dentry, mode, nd);
        if (unlikely(rc)) {
                ecryptfs_printk(KERN_ERR,
                                "Failure to create underlying file\n");
@@ -248,7 +251,7 @@ static int ecryptfs_initialize_file(stru
 #if BITS_PER_LONG != 32
        lower_flags |= O_LARGEFILE;
 #endif
-       lower_mnt = ecryptfs_superblock_to_private(inode->i_sb)->lower_mnt;
+       lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
        mntget(lower_mnt);
        /* Corresponding fput() at end of this function */
        lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags);
@@ -332,6 +335,7 @@ static struct dentry *ecryptfs_lookup(st
        int rc = 0;
        struct dentry *lower_dir_dentry;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_mnt;
        struct dentry *tlower_dentry = NULL;
        char *encoded_name;
        unsigned int encoded_namelen;
@@ -358,6 +362,7 @@ static struct dentry *ecryptfs_lookup(st
        lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
                                      encoded_namelen - 1);
        kfree(encoded_name);
+       lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
        if (IS_ERR(lower_dentry)) {
                ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
                rc = PTR_ERR(lower_dentry);
@@ -379,6 +384,7 @@ static struct dentry *ecryptfs_lookup(st
                goto out_dput;
        }
        ecryptfs_set_dentry_lower(dentry, lower_dentry);
+       ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
        if (!lower_dentry->d_inode) {
                /* We want to add because we couldn't find in lower */
                d_add(dentry, NULL);
@@ -419,7 +425,7 @@ static struct dentry *ecryptfs_lookup(st
                goto out_dput;
        }
        memset(page_virt, 0, PAGE_CACHE_SIZE);
-       rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd);
+       rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt);
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
        if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
                ecryptfs_set_default_sizes(crypt_stat);
@@ -801,6 +807,7 @@ int ecryptfs_truncate(struct dentry *den
        int rc = 0;
        struct inode *inode = dentry->d_inode;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_mnt;
        struct file fake_ecryptfs_file, *lower_file = NULL;
        struct ecryptfs_crypt_stat *crypt_stat;
        loff_t i_size = i_size_read(inode);
@@ -826,10 +833,9 @@ int ecryptfs_truncate(struct dentry *den
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        /* This dget & mntget is released through fput at out_fput: */
        dget(lower_dentry);
-       mntget(ecryptfs_superblock_to_private(inode->i_sb)->lower_mnt);
-       lower_file = dentry_open(
-               lower_dentry,
-               ecryptfs_superblock_to_private(inode->i_sb)->lower_mnt, O_RDWR);
+       lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+       mntget(lower_mnt);
+       lower_file = dentry_open(lower_dentry, lower_mnt, O_RDWR);
        if (unlikely(IS_ERR(lower_file))) {
                rc = PTR_ERR(lower_file);
                goto out_free;
@@ -885,15 +891,20 @@ out:
 static int
 ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
-       struct inode *lower_inode;
-       int rc = 0;
+       int rc;
 
-       lower_inode = ecryptfs_inode_to_lower(inode);
-       if (nd)
-               ecryptfs_printk(KERN_DEBUG, "nd->dentry = [%p]\n",
-                               nd->dentry);
-       rc = permission(lower_inode, mask, nd);
-       return rc;
+        if (nd) {
+               struct vfsmount *vfsmnt_save = nd->mnt;
+               struct dentry *dentry_save = nd->dentry;
+
+               nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry);
+               nd->dentry = ecryptfs_dentry_to_lower(nd->dentry);
+               rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
+               nd->mnt = vfsmnt_save;
+               nd->dentry = dentry_save;
+        } else
+               rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
+        return rc;
 }
 
 /**
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 27d3acd..d2e1cb0 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -452,6 +452,7 @@ static int ecryptfs_read_super(struct su
        int rc;
        struct nameidata nd;
        struct dentry *lower_root;
+       struct vfsmount *lower_mnt;
 
        memset(&nd, 0, sizeof(struct nameidata));
        rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
@@ -460,16 +461,17 @@ static int ecryptfs_read_super(struct su
                goto out_free;
        }
        lower_root = nd.dentry;
-       ecryptfs_superblock_to_private(sb)->lower_mnt = nd.mnt;
        if (!lower_root->d_inode) {
                ecryptfs_printk(KERN_WARNING,
                                "No directory to interpose on\n");
                rc = -ENOENT;
                goto out_free;
        }
+       lower_mnt = nd.mnt;
        ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
        sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
        ecryptfs_set_dentry_lower(sb->s_root, lower_root);
+       ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
        if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
                goto out_free;
        rc = 0;
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index 47a306b..120f060 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -108,7 +108,6 @@ static void ecryptfs_put_super(struct su
 {
        struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
 
-       mntput(sb_info->lower_mnt);
        ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
        kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
        ecryptfs_set_superblock_private(sb, NULL);
@@ -152,10 +151,10 @@ static void ecryptfs_clear_inode(struct 
  */
 static void ecryptfs_umount_begin(struct vfsmount *vfsmnt, int flags)
 {
-       struct vfsmount *lower_mnt;
+       struct vfsmount *lower_mnt =
+               ecryptfs_dentry_to_lower_mnt(vfsmnt->mnt_sb->s_root);
        struct super_block *lower_sb;
 
-       lower_mnt = ecryptfs_superblock_to_private(vfsmnt->mnt_sb)->lower_mnt;
        lower_sb = lower_mnt->mnt_sb;
        if (lower_sb->s_op->umount_begin)
                lower_sb->s_op->umount_begin(lower_mnt, flags);
@@ -170,22 +169,18 @@ static void ecryptfs_umount_begin(struct
 static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
        struct super_block *sb = mnt->mnt_sb;
-       struct dentry *lower_root_dentry;
-       struct ecryptfs_sb_info *sb_info;
-       struct vfsmount *lower_mount;
-       int rc = 0;
-       char *tmp_page = NULL;
+       struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
+       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
+       char *tmp_page;
        char *path;
+       int rc = 0;
 
        tmp_page = (char *)__get_free_page(GFP_KERNEL);
        if (!tmp_page) {
                rc = -ENOMEM;
                goto out;
        }
-       lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
-       sb_info = ecryptfs_superblock_to_private(sb);
-       lower_mount = sb_info->lower_mnt;
-       path = d_path(lower_root_dentry, lower_mount, tmp_page, PAGE_SIZE);
+       path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
        if (IS_ERR(path)) {
                rc = PTR_ERR(path);
                goto out;
---

Allocate a unique inode number for the eCryptfs inodes. Introduce back
reference from lower inode to stacked inode to deal with crossing
mountpoints.

---

 fs/Kconfig                    |   11 ++++++++++
 fs/ecryptfs/ecryptfs_kernel.h |   45 ++++++++++++++++++++++++++++++++++++++++++
 fs/ecryptfs/main.c            |   16 ++++----------
 fs/ecryptfs/super.c           |    1 
 fs/inode.c                    |    5 +++-
 include/linux/fs.h            |    3 ++
 6 files changed, 69 insertions(+), 12 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index afacf48..30c78b9 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -443,6 +443,14 @@ config QUOTA
          with the quota tools. Probably the quota support is only useful for
          multi user systems. If unsure, say N.
 
+config STACK_FS
+       bool "Stacked filesystem support"
+       default y
+       help
+         Select Y to enable all features in stacked filesystems (such
+         as eCryptfs and Unionfs).  Slightly increases the size of
+         inodes in memory.  If unsure, say Y.
+
 config QFMT_V1
        tristate "Old quota format support"
        depends on QUOTA
@@ -984,6 +992,9 @@ config ECRYPT_FS
          Encrypted filesystem that operates on the VFS layer.  See
          Documentation/ecryptfs.txt to learn more about eCryptfs.
 
+         It is strongly recommended that you also enable ``Stacked
+         filesystem support'' (CONFIG_STACK_FS) if you build eCryptfs.
+
          To compile this file system support as a module, choose M here: the
          module will be called ecryptfs.
 
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 349ce2a..3e8f377 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -376,6 +376,51 @@ ecryptfs_set_dentry_lower_mnt(struct den
                lower_mnt;
 }
 
+#ifdef CONFIG_STACK_FS
+static inline int
+ecryptfs_get_inode(struct inode **inode, struct inode *lower_inode,
+                  struct super_block *sb)
+{
+       *inode = lower_inode->i_stacked_inode;
+       if (!*inode) {
+               *inode = iget(sb, iunique(sb, 0));
+               if (!*inode)
+                       return -EACCES;
+               lower_inode->i_stacked_inode = *inode;
+       }
+       return 0;
+}
+#else
+static inline int
+ecryptfs_get_inode(struct inode **inode, struct inode *lower_inode,
+                  struct super_block *sb)
+{
+       /* Without CONFIG_STACK_FS enabled, we have no way to safely
+        * cross mount points in the lower filesystem. */
+       if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
+               printk(KERN_ERR "Cannot cross mount point in lower filesystem; "
+                      "recompile your kernel with CONFIG_STACK_FS to enable "
+                      "this feature.\n");
+               return -EXDEV;
+       }
+       *inode = iget(sb, lower_inode->i_ino);
+       if (!*inode)
+               return -EACCES;
+       return 0;
+}
+#endif /* CONFIG_STACK_FS */
+
+#ifdef CONFIG_STACK_FS
+static inline void ecryptfs_clear_inode_stacking(struct inode *inode)
+{
+       struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
+
+       lower_inode->i_stacked_inode = NULL;
+}
+#else
+static inline void ecryptfs_clear_inode_stacking(struct inode *inode) { }
+#endif /* CONFIG_STACK_FS */
+
 #define ecryptfs_printk(type, fmt, arg...) \
         __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
 void __ecryptfs_printk(const char *fmt, ...);
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index d2e1cb0..119c0a5 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -77,22 +77,16 @@ int ecryptfs_interpose(struct dentry *lo
                       struct super_block *sb, int flag)
 {
        struct inode *lower_inode;
-       int rc = 0;
        struct inode *inode;
+       int rc = 0;
 
        lower_inode = lower_dentry->d_inode;
-       if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
-               rc = -EXDEV;
-               goto out;
-       }
-       inode = iget(sb, lower_inode->i_ino);
-       if (!inode) {
-               rc = -EACCES;
+       rc = ecryptfs_get_inode(&inode, lower_inode, sb);
+       if (rc) {
+               printk(KERN_ERR "Error getting inode\n");
                goto out;
        }
-       /* This check is required here because if we failed to allocated the
-        * required space for an inode_info_cache struct, then the only way
-        * we know we failed, is by the pointer being NULL */
+       /* Did we succeed in allocating ecryptfs_inode_info? */
        if (!ecryptfs_inode_to_private(inode)) {
                ecryptfs_printk(KERN_ERR, "Out of memory. Failure to "
                                "allocate memory in ecryptfs_read_inode.\n");
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index 120f060..d96aa65 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -138,6 +138,7 @@ static int ecryptfs_statfs(struct dentry
  */
 static void ecryptfs_clear_inode(struct inode *inode)
 {
+       ecryptfs_clear_inode_stacking(inode);
        iput(ecryptfs_inode_to_lower(inode));
 }
 
diff --git a/fs/inode.c b/fs/inode.c
index 89ce5ba..3d3efc2 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -163,7 +163,10 @@ #endif
                                bdi = 
sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
                        mapping->backing_dev_info = bdi;
                }
-               inode->i_private = 0;
+               inode->i_private = NULL;
+#ifdef CONFIG_STACK_FS
+               inode->i_stacked_inode = NULL;
+#endif
                inode->i_mapping = mapping;
        }
        return inode;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6cd7004..306a028 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -578,6 +578,9 @@ #endif
        atomic_t                i_writecount;
        void                    *i_security;
        void                    *i_private; /* fs or device private pointer */
+#ifdef CONFIG_STACK_FS
+       struct inode            *i_stacked_inode; /* stackable fs support */
+#endif
 #ifdef __NEED_I_SIZE_ORDERED
        seqcount_t              i_size_seqcount;
 #endif

Attachment: signature.asc
Description: Digital signature

_______________________________________________
unionfs mailing list
unionfs@mail.fsl.cs.sunysb.edu
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to