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
signature.asc
Description: Digital signature
_______________________________________________ unionfs mailing list unionfs@mail.fsl.cs.sunysb.edu http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs