diff options
Diffstat (limited to 'fs/ecryptfs')
-rw-r--r-- | fs/ecryptfs/dentry.c | 9 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 11 | ||||
-rw-r--r-- | fs/ecryptfs/main.c | 155 | ||||
-rw-r--r-- | fs/ecryptfs/super.c | 12 |
4 files changed, 92 insertions, 95 deletions
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index 906e803f7f79..6fc4f319b550 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c @@ -44,12 +44,17 @@ */ 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 *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *dentry_save; struct vfsmount *vfsmount_save; int rc = 1; + if (nd->flags & LOOKUP_RCU) + return -ECHILD; + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; dentry_save = nd->path.dentry; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 9d1a22d62765..64ff02330752 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -260,7 +260,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, ecryptfs_dentry->d_parent)); lower_inode = lower_dentry->d_inode; fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); - BUG_ON(!atomic_read(&lower_dentry->d_count)); + BUG_ON(!lower_dentry->d_count); ecryptfs_set_dentry_private(ecryptfs_dentry, kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL)); @@ -441,7 +441,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct qstr lower_name; int rc = 0; - ecryptfs_dentry->d_op = &ecryptfs_dops; if ((ecryptfs_dentry->d_name.len == 1 && !strcmp(ecryptfs_dentry->d_name.name, ".")) || (ecryptfs_dentry->d_name.len == 2 @@ -454,7 +453,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, lower_name.hash = ecryptfs_dentry->d_name.hash; if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, - &lower_name); + lower_dir_dentry->d_inode, &lower_name); if (rc < 0) goto out_d_drop; } @@ -489,7 +488,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, lower_name.hash = full_name_hash(lower_name.name, lower_name.len); if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, - &lower_name); + lower_dir_dentry->d_inode, &lower_name); if (rc < 0) goto out_d_drop; } @@ -980,8 +979,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) } static int -ecryptfs_permission(struct inode *inode, int mask) +ecryptfs_permission(struct inode *inode, int mask, unsigned int flags) { + if (flags & IPERM_FLAG_RCU) + return -ECHILD; return inode_permission(ecryptfs_inode_to_lower(inode), mask); } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a9dbd62518e6..9ed476906327 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -141,21 +141,9 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) return rc; } -/** - * ecryptfs_interpose - * @lower_dentry: Existing dentry in the lower filesystem - * @dentry: ecryptfs' dentry - * @sb: ecryptfs's super_block - * @flags: flags to govern behavior of interpose procedure - * - * Interposes upper and lower dentries. - * - * Returns zero on success; non-zero otherwise - */ -int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, - struct super_block *sb, u32 flags) +static inode *ecryptfs_get_inode(struct inode *lower_inode, + struct super_block *sb) { - struct inode *lower_inode; struct inode *inode; int rc = 0; @@ -189,17 +177,38 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, if (special_file(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); - dentry->d_op = &ecryptfs_dops; 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); + return inode; +out: + return ERR_PTR(rc); +} + +/** + * ecryptfs_interpose + * @lower_dentry: Existing dentry in the lower filesystem + * @dentry: ecryptfs' dentry + * @sb: ecryptfs's super_block + * @flags: flags to govern behavior of interpose procedure + * + * Interposes upper and lower dentries. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, + struct super_block *sb, u32 flags) +{ + struct inode *lower_inode = lower_dentry->d_inode; + struct inode *inode = ecryptfs_get_inode(lower_inode, sb); + if (IS_ERR(inode) + return PTR_ERR(inode); if (flags & ECRYPTFS_INTERPOSE_FLAG_D_ADD) d_add(dentry, inode); else d_instantiate(dentry, inode); -out: - return rc; + return 0; } enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, @@ -492,59 +501,11 @@ struct kmem_cache *ecryptfs_sb_info_cache; static struct file_system_type ecryptfs_fs_type; /** - * ecryptfs_read_super - * @sb: The ecryptfs super block - * @dev_name: The path to mount over - * - * Read the super block of the lower filesystem, and use - * ecryptfs_interpose to create our initial inode and super block - * struct. - */ -static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) -{ - struct path path; - int rc; - - rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); - if (rc) { - ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); - goto out; - } - if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { - rc = -EINVAL; - printk(KERN_ERR "Mount on filesystem of type " - "eCryptfs explicitly disallowed due to " - "known incompatibilities\n"); - goto out_free; - } - ecryptfs_set_superblock_lower(sb, path.dentry->d_sb); - sb->s_maxbytes = path.dentry->d_sb->s_maxbytes; - sb->s_blocksize = path.dentry->d_sb->s_blocksize; - ecryptfs_set_dentry_lower(sb->s_root, path.dentry); - ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt); - rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0); - if (rc) - goto out_free; - rc = 0; - goto out; -out_free: - path_put(&path); -out: - return rc; -} - -/** * ecryptfs_get_sb * @fs_type * @flags * @dev_name: The path to mount over * @raw_data: The options passed into the kernel - * - * The whole ecryptfs_get_sb process is broken into 3 functions: - * ecryptfs_parse_options(): handle options passed to ecryptfs, if any - * ecryptfs_read_super(): this accesses the lower filesystem and uses - * ecryptfs_interpose to perform most of the linking - * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c) */ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) @@ -553,6 +514,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags struct ecryptfs_sb_info *sbi; struct ecryptfs_dentry_info *root_info; const char *err = "Getting sb failed"; + struct inode *inode; + struct path path; int rc; sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); @@ -575,10 +538,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_flags = flags; rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY); - if (rc) { - deactivate_locked_super(s); - goto out; - } + if (rc) + goto out1; ecryptfs_set_superblock_private(s, sbi); s->s_bdi = &sbi->bdi; @@ -586,34 +547,54 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags /* ->kill_sb() will take care of sbi after that point */ sbi = NULL; s->s_op = &ecryptfs_sops; + s->s_d_op = &ecryptfs_dops; - rc = -ENOMEM; - s->s_root = d_alloc(NULL, &(const struct qstr) { - .hash = 0,.name = "/",.len = 1}); + err = "Reading sb failed"; + rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + if (rc) { + ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); + goto out1; + } + if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { + rc = -EINVAL; + printk(KERN_ERR "Mount on filesystem of type " + "eCryptfs explicitly disallowed due to " + "known incompatibilities\n"); + goto out_free; + } + ecryptfs_set_superblock_lower(s, path.dentry->d_sb); + s->s_maxbytes = path.dentry->d_sb->s_maxbytes; + s->s_blocksize = path.dentry->d_sb->s_blocksize; + + inode = ecryptfs_get_inode(path.dentry->d_inode, s); + rc = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_free; + + s->s_root = d_alloc_root(inode); if (!s->s_root) { - deactivate_locked_super(s); - goto out; + iput(inode); + rc = -ENOMEM; + goto out_free; } - s->s_root->d_op = &ecryptfs_dops; - s->s_root->d_sb = s; - s->s_root->d_parent = s->s_root; + rc = -ENOMEM; root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL); - if (!root_info) { - deactivate_locked_super(s); - goto out; - } + if (!root_info) + goto out_free; + /* ->kill_sb() will take care of root_info */ ecryptfs_set_dentry_private(s->s_root, root_info); + ecryptfs_set_dentry_lower(s->s_root, path.dentry); + ecryptfs_set_dentry_lower_mnt(s->s_root, path.mnt); + s->s_flags |= MS_ACTIVE; - rc = ecryptfs_read_super(s, dev_name); - if (rc) { - deactivate_locked_super(s); - err = "Reading sb failed"; - goto out; - } return dget(s->s_root); +out_free: + path_put(&path); +out1: + deactivate_locked_super(s); out: if (sbi) { ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat); diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 2720178b7718..3042fe123a34 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -62,6 +62,16 @@ out: return inode; } +static void ecryptfs_i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + struct ecryptfs_inode_info *inode_info; + inode_info = ecryptfs_inode_to_private(inode); + + INIT_LIST_HEAD(&inode->i_dentry); + kmem_cache_free(ecryptfs_inode_info_cache, inode_info); +} + /** * ecryptfs_destroy_inode * @inode: The ecryptfs inode @@ -88,7 +98,7 @@ static void ecryptfs_destroy_inode(struct inode *inode) } } ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); - kmem_cache_free(ecryptfs_inode_info_cache, inode_info); + call_rcu(&inode->i_rcu, ecryptfs_i_callback); } /** |