diff options
Diffstat (limited to 'fs/ecryptfs/inode.c')
-rw-r--r-- | fs/ecryptfs/inode.c | 222 |
1 files changed, 61 insertions, 161 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index bd33f87a190..4d4cc6a90cd 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -74,16 +74,20 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, unsigned int flags_save; int rc; - dentry_save = nd->path.dentry; - vfsmount_save = nd->path.mnt; - flags_save = nd->flags; - nd->path.dentry = lower_dentry; - nd->path.mnt = lower_mnt; - nd->flags &= ~LOOKUP_OPEN; + if (nd) { + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + flags_save = nd->flags; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; + nd->flags &= ~LOOKUP_OPEN; + } rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); - nd->path.dentry = dentry_save; - nd->path.mnt = vfsmount_save; - nd->flags = flags_save; + if (nd) { + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; + nd->flags = flags_save; + } return rc; } @@ -139,26 +143,6 @@ out: } /** - * grow_file - * @ecryptfs_dentry: the eCryptfs dentry - * - * This is the code which will grow the file to its correct size. - */ -static int grow_file(struct dentry *ecryptfs_dentry) -{ - struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; - char zero_virt[] = { 0x00 }; - int rc = 0; - - rc = ecryptfs_write(ecryptfs_inode, zero_virt, 0, 1); - i_size_write(ecryptfs_inode, 0); - rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); - ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |= - ECRYPTFS_NEW_FILE; - return rc; -} - -/** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs @@ -177,7 +161,6 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } - crypt_stat->flags |= ECRYPTFS_NEW_FILE; ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_dentry); if (rc) { @@ -185,22 +168,18 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) "context; rc = [%d]\n", rc); goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " + "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry); - if (rc) { - printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); - goto out; - } - rc = grow_file(ecryptfs_dentry); if (rc) - printk(KERN_ERR "Error growing file; rc = [%d]\n", rc); + printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); + ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); out: return rc; } @@ -241,17 +220,14 @@ out: */ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, - struct inode *ecryptfs_dir_inode, - struct nameidata *ecryptfs_nd) + struct inode *ecryptfs_dir_inode) { struct dentry *lower_dir_dentry; struct vfsmount *lower_mnt; struct inode *lower_inode; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; - u64 file_size; - int rc = 0; + int put_lower = 0, rc = 0; lower_dir_dentry = lower_dentry->d_parent; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( @@ -290,8 +266,6 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, goto out; if (special_file(lower_inode->i_mode)) goto out; - if (!ecryptfs_nd) - goto out; /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER); if (!page_virt) { @@ -300,14 +274,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, rc = -ENOMEM; goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " + "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free_kmem; } + put_lower = 1; crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ @@ -325,18 +300,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, } crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } - mount_crypt_stat = &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; - if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { - if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - file_size = (crypt_stat->metadata_size - + i_size_read(lower_dentry->d_inode)); - else - file_size = i_size_read(lower_dentry->d_inode); - } else { - file_size = get_unaligned_be64(page_virt); - } - i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size); + ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode); out_free_kmem: kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; @@ -345,79 +309,12 @@ out_put: mntput(lower_mnt); d_drop(ecryptfs_dentry); out: + if (put_lower) + ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); return rc; } /** - * ecryptfs_new_lower_dentry - * @name: The name of the new dentry. - * @lower_dir_dentry: Parent directory of the new dentry. - * @nd: nameidata from last lookup. - * - * Create a new dentry or get it from lower parent dir. - */ -static struct dentry * -ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry, - struct nameidata *nd) -{ - struct dentry *new_dentry; - struct dentry *tmp; - struct inode *lower_dir_inode; - - lower_dir_inode = lower_dir_dentry->d_inode; - - tmp = d_alloc(lower_dir_dentry, name); - if (!tmp) - return ERR_PTR(-ENOMEM); - - mutex_lock(&lower_dir_inode->i_mutex); - new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd); - mutex_unlock(&lower_dir_inode->i_mutex); - - if (!new_dentry) - new_dentry = tmp; - else - dput(tmp); - - return new_dentry; -} - - -/** - * ecryptfs_lookup_one_lower - * @ecryptfs_dentry: The eCryptfs dentry that we are looking up - * @lower_dir_dentry: lower parent directory - * @name: lower file name - * - * Get the lower dentry from vfs. If lower dentry does not exist yet, - * create it. - */ -static struct dentry * -ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry, - struct dentry *lower_dir_dentry, struct qstr *name) -{ - struct nameidata nd; - struct vfsmount *lower_mnt; - int err; - - lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( - ecryptfs_dentry->d_parent)); - err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd); - mntput(lower_mnt); - - if (!err) { - /* we dont need the mount */ - mntput(nd.path.mnt); - return nd.path.dentry; - } - if (err != -ENOENT) - return ERR_PTR(err); - - /* create a new lower dentry */ - return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd); -} - -/** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up @@ -434,7 +331,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; - struct qstr lower_name; int rc = 0; if ((ecryptfs_dentry->d_name.len == 1 @@ -444,20 +340,14 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, goto out_d_drop; } lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); - lower_name.name = ecryptfs_dentry->d_name.name; - lower_name.len = ecryptfs_dentry->d_name.len; - 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_dir_dentry->d_inode, &lower_name); - if (rc < 0) - goto out_d_drop; - } - lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry, &lower_name); + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, + lower_dir_dentry, + ecryptfs_dentry->d_name.len); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); - ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " + ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; @@ -479,28 +369,21 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, "filename; rc = [%d]\n", __func__, rc); goto out_d_drop; } - lower_name.name = encrypted_and_encoded_name; - lower_name.len = encrypted_and_encoded_name_size; - 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_dir_dentry->d_inode, &lower_name); - if (rc < 0) - goto out_d_drop; - } - lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry, &lower_name); + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + lower_dentry = lookup_one_len(encrypted_and_encoded_name, + lower_dir_dentry, + encrypted_and_encoded_name_size); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); - ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " + ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; } lookup_and_interpose: rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, - ecryptfs_dir_inode, - ecryptfs_nd); + ecryptfs_dir_inode); goto out; out_d_drop: d_drop(ecryptfs_dentry); @@ -644,8 +527,6 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) dget(lower_dentry); rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); dput(lower_dentry); - if (!rc) - d_delete(lower_dentry); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; unlock_dir(lower_dir_dentry); @@ -716,8 +597,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); - dput(lower_new_dentry->d_parent); - dput(lower_old_dentry->d_parent); + dput(lower_new_dir_dentry); + dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; @@ -865,8 +746,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, if (unlikely((ia->ia_size == i_size))) { lower_ia->ia_valid &= ~ATTR_SIZE; - goto out; + return 0; } + rc = ecryptfs_get_lower_file(dentry); + if (rc) + return rc; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; /* Switch on growing or shrinking file */ if (ia->ia_size > i_size) { @@ -944,6 +828,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, lower_ia->ia_valid &= ~ATTR_SIZE; } out: + ecryptfs_put_lower_file(inode); return rc; } @@ -1019,7 +904,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; + rc = ecryptfs_get_lower_file(dentry); + if (rc) { + mutex_unlock(&crypt_stat->cs_mutex); + goto out; + } rc = ecryptfs_read_metadata(dentry); + ecryptfs_put_lower_file(inode); if (rc) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { @@ -1033,10 +924,17 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) goto out; } rc = 0; - crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); } } mutex_unlock(&crypt_stat->cs_mutex); + if (S_ISREG(inode->i_mode)) { + rc = filemap_write_and_wait(inode->i_mapping); + if (rc) + goto out; + fsstack_copy_attr_all(inode, lower_inode); + } memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); @@ -1092,6 +990,8 @@ int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, rc = vfs_getattr(ecryptfs_dentry_to_lower_mnt(dentry), ecryptfs_dentry_to_lower(dentry), &lower_stat); if (!rc) { + fsstack_copy_attr_all(dentry->d_inode, + ecryptfs_inode_to_lower(dentry->d_inode)); generic_fillattr(dentry->d_inode, stat); stat->blocks = lower_stat.blocks; } |