Commit 5ccf9203 authored by Tyler Hicks's avatar Tyler Hicks

eCryptfs: Cleanup inode initialization code

The eCryptfs inode get, initialization, and dentry interposition code
has two separate paths. One is for when dentry interposition is needed
after doing things like a mkdir in the lower filesystem and the other
is needed after a lookup. Unlocking new inodes and doing a d_add() needs
to happen at different times, depending on which type of dentry
interposing is being done.

This patch cleans up the inode get and initialization code paths and
splits them up so that the locking and d_add() differences mentioned
above can be handled appropriately in a later patch.
Signed-off-by: default avatarTyler Hicks <tyhicks@linux.vnet.ibm.com>
Tested-by: default avatarDavid <david@unsolicited.net>
parent c4f79073
...@@ -628,9 +628,6 @@ struct ecryptfs_open_req { ...@@ -628,9 +628,6 @@ struct ecryptfs_open_req {
struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct inode *ecryptfs_get_inode(struct inode *lower_inode,
struct super_block *sb); struct super_block *sb);
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode); void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
struct dentry *lower_dentry,
struct inode *ecryptfs_dir_inode);
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
size_t *decrypted_name_size, size_t *decrypted_name_size,
struct dentry *ecryptfs_dentry, struct dentry *ecryptfs_dentry,
......
...@@ -58,85 +58,87 @@ static int ecryptfs_inode_test(struct inode *inode, void *lower_inode) ...@@ -58,85 +58,87 @@ static int ecryptfs_inode_test(struct inode *inode, void *lower_inode)
return 0; return 0;
} }
static int ecryptfs_inode_set(struct inode *inode, void *lower_inode) static int ecryptfs_inode_set(struct inode *inode, void *opaque)
{ {
ecryptfs_set_inode_lower(inode, (struct inode *)lower_inode); struct inode *lower_inode = opaque;
inode->i_ino = ((struct inode *)lower_inode)->i_ino;
ecryptfs_set_inode_lower(inode, lower_inode);
fsstack_copy_attr_all(inode, lower_inode);
/* i_size will be overwritten for encrypted regular files */
fsstack_copy_inode_size(inode, lower_inode);
inode->i_ino = lower_inode->i_ino;
inode->i_version++; inode->i_version++;
inode->i_mapping->a_ops = &ecryptfs_aops;
if (S_ISLNK(inode->i_mode))
inode->i_op = &ecryptfs_symlink_iops;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &ecryptfs_dir_iops;
else
inode->i_op = &ecryptfs_main_iops; inode->i_op = &ecryptfs_main_iops;
if (S_ISDIR(inode->i_mode))
inode->i_fop = &ecryptfs_dir_fops;
else if (special_file(inode->i_mode))
init_special_inode(inode, inode->i_mode, inode->i_rdev);
else
inode->i_fop = &ecryptfs_main_fops; inode->i_fop = &ecryptfs_main_fops;
inode->i_mapping->a_ops = &ecryptfs_aops;
return 0; return 0;
} }
struct inode *ecryptfs_get_inode(struct inode *lower_inode, static struct inode *__ecryptfs_get_inode(struct inode *lower_inode,
struct super_block *sb) struct super_block *sb)
{ {
struct inode *inode; struct inode *inode;
int rc = 0;
if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) { if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb))
rc = -EXDEV; return ERR_PTR(-EXDEV);
goto out; if (!igrab(lower_inode))
} return ERR_PTR(-ESTALE);
if (!igrab(lower_inode)) {
rc = -ESTALE;
goto out;
}
inode = iget5_locked(sb, (unsigned long)lower_inode, inode = iget5_locked(sb, (unsigned long)lower_inode,
ecryptfs_inode_test, ecryptfs_inode_set, ecryptfs_inode_test, ecryptfs_inode_set,
lower_inode); lower_inode);
if (!inode) { if (!inode) {
rc = -EACCES;
iput(lower_inode); iput(lower_inode);
goto out; return ERR_PTR(-EACCES);
} }
if (inode->i_state & I_NEW) if (!(inode->i_state & I_NEW))
unlock_new_inode(inode);
else
iput(lower_inode); iput(lower_inode);
if (S_ISLNK(lower_inode->i_mode))
inode->i_op = &ecryptfs_symlink_iops; return inode;
else if (S_ISDIR(lower_inode->i_mode)) }
inode->i_op = &ecryptfs_dir_iops;
if (S_ISDIR(lower_inode->i_mode)) struct inode *ecryptfs_get_inode(struct inode *lower_inode,
inode->i_fop = &ecryptfs_dir_fops; struct super_block *sb)
if (special_file(lower_inode->i_mode)) {
init_special_inode(inode, lower_inode->i_mode, struct inode *inode = __ecryptfs_get_inode(lower_inode, sb);
lower_inode->i_rdev);
fsstack_copy_attr_all(inode, lower_inode); if (!IS_ERR(inode) && (inode->i_state & I_NEW))
/* This size will be overwritten for real files w/ headers and unlock_new_inode(inode);
* other metadata */
fsstack_copy_inode_size(inode, lower_inode);
return inode; return inode;
out:
return ERR_PTR(rc);
} }
#define ECRYPTFS_INTERPOSE_FLAG_D_ADD 0x00000001
/** /**
* ecryptfs_interpose * ecryptfs_interpose
* @lower_dentry: Existing dentry in the lower filesystem * @lower_dentry: Existing dentry in the lower filesystem
* @dentry: ecryptfs' dentry * @dentry: ecryptfs' dentry
* @sb: ecryptfs's super_block * @sb: ecryptfs's super_block
* @flags: flags to govern behavior of interpose procedure
* *
* Interposes upper and lower dentries. * Interposes upper and lower dentries.
* *
* Returns zero on success; non-zero otherwise * Returns zero on success; non-zero otherwise
*/ */
static int ecryptfs_interpose(struct dentry *lower_dentry, static int ecryptfs_interpose(struct dentry *lower_dentry,
struct dentry *dentry, struct super_block *sb, struct dentry *dentry, struct super_block *sb)
u32 flags)
{ {
struct inode *lower_inode = lower_dentry->d_inode; struct inode *inode = ecryptfs_get_inode(lower_dentry->d_inode, sb);
struct inode *inode = ecryptfs_get_inode(lower_inode, sb);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
if (flags & ECRYPTFS_INTERPOSE_FLAG_D_ADD)
d_add(dentry, inode);
else
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
} }
...@@ -218,7 +220,7 @@ ecryptfs_do_create(struct inode *directory_inode, ...@@ -218,7 +220,7 @@ ecryptfs_do_create(struct inode *directory_inode,
goto out_lock; goto out_lock;
} }
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
directory_inode->i_sb, 0); directory_inode->i_sb);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n"); ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
goto out_lock; goto out_lock;
...@@ -305,15 +307,15 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, ...@@ -305,15 +307,15 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
} }
/** /**
* ecryptfs_lookup_and_interpose_lower - Perform a lookup * ecryptfs_lookup_interpose - Dentry interposition for a lookup
*/ */
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, static int ecryptfs_lookup_interpose(struct dentry *ecryptfs_dentry,
struct dentry *lower_dentry, struct dentry *lower_dentry,
struct inode *ecryptfs_dir_inode) struct inode *ecryptfs_dir_inode)
{ {
struct dentry *lower_dir_dentry; struct dentry *lower_dir_dentry;
struct vfsmount *lower_mnt; struct vfsmount *lower_mnt;
struct inode *lower_inode; struct inode *inode, *lower_inode;
struct ecryptfs_crypt_stat *crypt_stat; struct ecryptfs_crypt_stat *crypt_stat;
char *page_virt = NULL; char *page_virt = NULL;
int put_lower = 0, rc = 0; int put_lower = 0, rc = 0;
...@@ -341,14 +343,16 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, ...@@ -341,14 +343,16 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
d_add(ecryptfs_dentry, NULL); d_add(ecryptfs_dentry, NULL);
goto out; goto out;
} }
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, inode = __ecryptfs_get_inode(lower_inode, ecryptfs_dir_inode->i_sb);
ecryptfs_dir_inode->i_sb, if (IS_ERR(inode)) {
ECRYPTFS_INTERPOSE_FLAG_D_ADD); rc = PTR_ERR(inode);
if (rc) {
printk(KERN_ERR "%s: Error interposing; rc = [%d]\n", printk(KERN_ERR "%s: Error interposing; rc = [%d]\n",
__func__, rc); __func__, rc);
goto out; goto out;
} }
if (inode->i_state & I_NEW)
unlock_new_inode(inode);
d_add(ecryptfs_dentry, inode);
if (S_ISDIR(lower_inode->i_mode)) if (S_ISDIR(lower_inode->i_mode))
goto out; goto out;
if (S_ISLNK(lower_inode->i_mode)) if (S_ISLNK(lower_inode->i_mode))
...@@ -442,12 +446,12 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, ...@@ -442,12 +446,12 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
goto out_d_drop; goto out_d_drop;
} }
if (lower_dentry->d_inode) if (lower_dentry->d_inode)
goto lookup_and_interpose; goto interpose;
mount_crypt_stat = &ecryptfs_superblock_to_private( mount_crypt_stat = &ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat; ecryptfs_dentry->d_sb)->mount_crypt_stat;
if (!(mount_crypt_stat if (!(mount_crypt_stat
&& (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
goto lookup_and_interpose; goto interpose;
dput(lower_dentry); dput(lower_dentry);
rc = ecryptfs_encrypt_and_encode_filename( rc = ecryptfs_encrypt_and_encode_filename(
&encrypted_and_encoded_name, &encrypted_and_encoded_name_size, &encrypted_and_encoded_name, &encrypted_and_encoded_name_size,
...@@ -470,8 +474,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, ...@@ -470,8 +474,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
encrypted_and_encoded_name); encrypted_and_encoded_name);
goto out_d_drop; goto out_d_drop;
} }
lookup_and_interpose: interpose:
rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry,
ecryptfs_dir_inode); ecryptfs_dir_inode);
goto out; goto out;
out_d_drop: out_d_drop:
...@@ -500,7 +504,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -500,7 +504,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
lower_new_dentry); lower_new_dentry);
if (rc || !lower_new_dentry->d_inode) if (rc || !lower_new_dentry->d_inode)
goto out_lock; goto out_lock;
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
if (rc) if (rc)
goto out_lock; goto out_lock;
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
...@@ -567,7 +571,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -567,7 +571,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
kfree(encoded_symname); kfree(encoded_symname);
if (rc || !lower_dentry->d_inode) if (rc || !lower_dentry->d_inode)
goto out_lock; goto out_lock;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
if (rc) if (rc)
goto out_lock; goto out_lock;
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
...@@ -591,7 +595,7 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -591,7 +595,7 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode); rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
if (rc || !lower_dentry->d_inode) if (rc || !lower_dentry->d_inode)
goto out; goto out;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
if (rc) if (rc)
goto out; goto out;
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
...@@ -639,7 +643,7 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ...@@ -639,7 +643,7 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev); rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
if (rc || !lower_dentry->d_inode) if (rc || !lower_dentry->d_inode)
goto out; goto out;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
if (rc) if (rc)
goto out; goto out;
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment