Patchwork [1/1] eCryptfs: Copy up attributes of the lower target inode after rename

login
register
mail settings
Submitter Colin King
Date Sept. 15, 2012, 7:10 p.m.
Message ID <1347736223-5644-2-git-send-email-colin.king@canonical.com>
Download mbox | patch
Permalink /patch/184095/
State New
Headers show

Comments

Colin King - Sept. 15, 2012, 7:10 p.m.
From: Tyler Hicks <tyhicks@canonical.com>

After calling into the lower filesystem to do a rename, the lower target
inode's attributes were not copied up to the eCryptfs target inode. This
resulted in the eCryptfs target inode staying around, rather than being
evicted, because i_nlink was not updated for the eCryptfs inode. This
also meant that eCryptfs didn't do the final iput() on the lower target
inode so it stayed around, as well. This would result in a failure to
free up space occupied by the target file in the rename() operation.
Both target inodes would eventually be evicted when the eCryptfs
filesystem was unmounted.

This patch calls fsstack_copy_attr_all() after the lower filesystem
does its ->rename() so that important inode attributes, such as i_nlink,
are updated at the eCryptfs layer. ecryptfs_evict_inode() is now called
and eCryptfs can drop its final reference on the lower inode.

BugLink: http://launchpad.net/bugs/561129

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Tested-by: Colin Ian King <colin.king@canonical.com>
Cc: <stable@vger.kernel.org> [2.6.39+]
(upstream cherry pick 8335eafc2859e1a26282bef7c3d19f3d68868b8a)
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 fs/ecryptfs/inode.c |    5 +++++
 1 file changed, 5 insertions(+)
Brad Figg - Sept. 16, 2012, 6:07 a.m.
On 09/15/2012 12:10 PM, Colin King wrote:
> From: Tyler Hicks <tyhicks@canonical.com>
> 
> After calling into the lower filesystem to do a rename, the lower target
> inode's attributes were not copied up to the eCryptfs target inode. This
> resulted in the eCryptfs target inode staying around, rather than being
> evicted, because i_nlink was not updated for the eCryptfs inode. This
> also meant that eCryptfs didn't do the final iput() on the lower target
> inode so it stayed around, as well. This would result in a failure to
> free up space occupied by the target file in the rename() operation.
> Both target inodes would eventually be evicted when the eCryptfs
> filesystem was unmounted.
> 
> This patch calls fsstack_copy_attr_all() after the lower filesystem
> does its ->rename() so that important inode attributes, such as i_nlink,
> are updated at the eCryptfs layer. ecryptfs_evict_inode() is now called
> and eCryptfs can drop its final reference on the lower inode.
> 
> BugLink: http://launchpad.net/bugs/561129
> 
> Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
> Tested-by: Colin Ian King <colin.king@canonical.com>
> Cc: <stable@vger.kernel.org> [2.6.39+]
> (upstream cherry pick 8335eafc2859e1a26282bef7c3d19f3d68868b8a)
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  fs/ecryptfs/inode.c |    5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
> index 534b129..cc7709e 100644
> --- a/fs/ecryptfs/inode.c
> +++ b/fs/ecryptfs/inode.c
> @@ -619,6 +619,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>  	struct dentry *lower_old_dir_dentry;
>  	struct dentry *lower_new_dir_dentry;
>  	struct dentry *trap = NULL;
> +	struct inode *target_inode;
>  
>  	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
>  	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
> @@ -626,6 +627,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>  	dget(lower_new_dentry);
>  	lower_old_dir_dentry = dget_parent(lower_old_dentry);
>  	lower_new_dir_dentry = dget_parent(lower_new_dentry);
> +	target_inode = new_dentry->d_inode;
>  	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
>  	/* source should not be ancestor of target */
>  	if (trap == lower_old_dentry) {
> @@ -641,6 +643,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>  			lower_new_dir_dentry->d_inode, lower_new_dentry);
>  	if (rc)
>  		goto out_lock;
> +	if (target_inode)
> +		fsstack_copy_attr_all(target_inode,
> +				      ecryptfs_inode_to_lower(target_inode));
>  	fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
>  	if (new_dir != old_dir)
>  		fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
>

Patch

diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 534b129..cc7709e 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -619,6 +619,7 @@  ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct dentry *lower_old_dir_dentry;
 	struct dentry *lower_new_dir_dentry;
 	struct dentry *trap = NULL;
+	struct inode *target_inode;
 
 	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
 	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
@@ -626,6 +627,7 @@  ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	dget(lower_new_dentry);
 	lower_old_dir_dentry = dget_parent(lower_old_dentry);
 	lower_new_dir_dentry = dget_parent(lower_new_dentry);
+	target_inode = new_dentry->d_inode;
 	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
 	/* source should not be ancestor of target */
 	if (trap == lower_old_dentry) {
@@ -641,6 +643,9 @@  ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			lower_new_dir_dentry->d_inode, lower_new_dentry);
 	if (rc)
 		goto out_lock;
+	if (target_inode)
+		fsstack_copy_attr_all(target_inode,
+				      ecryptfs_inode_to_lower(target_inode));
 	fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
 	if (new_dir != old_dir)
 		fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);