diff mbox series

[v2] ocfs2: roll back the reference count modification of the parent directory if an error occurs

Message ID a47da8dd-dc3d-41d7-fdd6-53dc6ea0335f@huawei.com (mailing list archive)
State New, archived
Headers show
Series [v2] ocfs2: roll back the reference count modification of the parent directory if an error occurs | expand

Commit Message

wangjian March 17, 2020, 2:26 a.m. UTC
Under some conditions, the directory cannot be deleted.
The specific scenarios are as follows: (for example,
/mnt/ocfs2 is the mount point)

1. Create the /mnt/ocfs2/p_dir directory. At this time,
the i_nlink corresponding to the inode of
the /mnt/ocfs2/p_dir directory is equal to 2.

2. During the process of creating the
/mnt/ocfs2/p_dir/s_dir directory, if the call to the inc_nlink
function in ocfs2_mknod succeeds, the functions such as
ocfs2_init_acl, ocfs2_init_security_set, and ocfs2_dentry_attach_lock fail.
At this time, the i_nlink corresponding to the inode of the
/mnt/ocfs2/p_dir directory is equal to 3, but /mnt/ocfs2/p_dir/s_dir
is not added to the /mnt/ocfs2/p_dir directory entry.

3. Delete the /mnt/ocfs2/p_dir directory (rm -rf /mnt/ocfs2/p_dir).
At this time, it is found that the i_nlink corresponding to
the inode corresponding to the /mnt/ocfs2/p_dir directory is equal to 3.
Therefore, the /mnt/ocfs2/p_dir directory cannot be deleted.

Signed-off-by: Jian wang <wangjian161@huawei.com>
---
  ocfs2/namei.c | 8 ++++++++
  1 file changed, 8 insertions(+)

Comments

Joseph Qi March 17, 2020, 4:29 a.m. UTC | #1
On 2020/3/17 10:26, wangjian wrote:
> Under some conditions, the directory cannot be deleted.
> The specific scenarios are as follows: (for example,
> /mnt/ocfs2 is the mount point)
> 
> 1. Create the /mnt/ocfs2/p_dir directory. At this time,
> the i_nlink corresponding to the inode of
> the /mnt/ocfs2/p_dir directory is equal to 2.
> 
> 2. During the process of creating the
> /mnt/ocfs2/p_dir/s_dir directory, if the call to the inc_nlink
> function in ocfs2_mknod succeeds, the functions such as
> ocfs2_init_acl, ocfs2_init_security_set, and ocfs2_dentry_attach_lock fail.
> At this time, the i_nlink corresponding to the inode of the
> /mnt/ocfs2/p_dir directory is equal to 3, but /mnt/ocfs2/p_dir/s_dir
> is not added to the /mnt/ocfs2/p_dir directory entry.
> 
> 3. Delete the /mnt/ocfs2/p_dir directory (rm -rf /mnt/ocfs2/p_dir).
> At this time, it is found that the i_nlink corresponding to
> the inode corresponding to the /mnt/ocfs2/p_dir directory is equal to 3.
> Therefore, the /mnt/ocfs2/p_dir directory cannot be deleted.
> 
> Signed-off-by: Jian wang <wangjian161@huawei.com>
> ---
>  ocfs2/namei.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/ocfs2/namei.c b/ocfs2/namei.c
> index 8ea51cf..f34ce0b 100644
> --- a/ocfs2/namei.c
> +++ b/ocfs2/namei.c
> @@ -247,6 +247,7 @@ static int ocfs2_mknod(struct inode *dir,
>      sigset_t oldset;
>      int did_block_signals = 0;
>      struct ocfs2_dentry_lock *dl = NULL;
> +    int link_inc = 0;
>  
>      trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
>                (unsigned long long)OCFS2_I(dir)->ip_blkno,
> @@ -399,6 +400,7 @@ static int ocfs2_mknod(struct inode *dir,
>          ocfs2_add_links_count(dirfe, 1);
>          ocfs2_journal_dirty(handle, parent_fe_bh);
>          inc_nlink(dir);
> +        link_inc = 1;
>      }
>  
>      status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
> @@ -444,6 +446,12 @@ static int ocfs2_mknod(struct inode *dir,
>      d_instantiate(dentry, inode);
>      status = 0;
>  leave:
> +    if (status < 0 && S_ISDIR(mode) && link_inc != 0) {
> +        ocfs2_add_links_count(dirfe, -1);
> +        ocfs2_journal_dirty(handle, parent_fe_bh);
> +        drop_nlink(dir);
> +    }
> +

link_inc implies S_ISDIR(mode), so (status < 0 && link_inc) is
enough.
And it seems that no need to dirty parent_fe_bh again.

Thanks,
Joseph

>      if (status < 0 && did_quota_inode)
>          dquot_free_inode(inode);
>      if (handle)
piaojun March 17, 2020, 6:24 a.m. UTC | #2
On 2020/3/17 10:26, wangjian wrote:
> Under some conditions, the directory cannot be deleted.
> The specific scenarios are as follows: (for example,
> /mnt/ocfs2 is the mount point)
> 
> 1. Create the /mnt/ocfs2/p_dir directory. At this time,
> the i_nlink corresponding to the inode of
> the /mnt/ocfs2/p_dir directory is equal to 2.
> 
> 2. During the process of creating the
> /mnt/ocfs2/p_dir/s_dir directory, if the call to the inc_nlink
> function in ocfs2_mknod succeeds, the functions such as
> ocfs2_init_acl, ocfs2_init_security_set, and ocfs2_dentry_attach_lock fail.
> At this time, the i_nlink corresponding to the inode of the
> /mnt/ocfs2/p_dir directory is equal to 3, but /mnt/ocfs2/p_dir/s_dir
> is not added to the /mnt/ocfs2/p_dir directory entry.
> 
> 3. Delete the /mnt/ocfs2/p_dir directory (rm -rf /mnt/ocfs2/p_dir).
> At this time, it is found that the i_nlink corresponding to
> the inode corresponding to the /mnt/ocfs2/p_dir directory is equal to 3.
> Therefore, the /mnt/ocfs2/p_dir directory cannot be deleted.
> 
> Signed-off-by: Jian wang <wangjian161@huawei.com>
> ---
>  ocfs2/namei.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/ocfs2/namei.c b/ocfs2/namei.c
> index 8ea51cf..f34ce0b 100644
> --- a/ocfs2/namei.c
> +++ b/ocfs2/namei.c
> @@ -247,6 +247,7 @@ static int ocfs2_mknod(struct inode *dir,
>  	sigset_t oldset;
>  	int did_block_signals = 0;
>  	struct ocfs2_dentry_lock *dl = NULL;
> +	int link_inc = 0;
>  
>  	trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
>  			  (unsigned long long)OCFS2_I(dir)->ip_blkno,
> @@ -399,6 +400,7 @@ static int ocfs2_mknod(struct inode *dir,
>  		ocfs2_add_links_count(dirfe, 1);
>  		ocfs2_journal_dirty(handle, parent_fe_bh);
>  		inc_nlink(dir);
> +		link_inc = 1;
>  	}
>  
>  	status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
> @@ -444,6 +446,12 @@ static int ocfs2_mknod(struct inode *dir,
>  	d_instantiate(dentry, inode);
>  	status = 0;
>  leave:
> +	if (status < 0 && S_ISDIR(mode) && link_inc != 0) {
> +		ocfs2_add_links_count(dirfe, -1);
> +		ocfs2_journal_dirty(handle, parent_fe_bh);
There is no need to re-dirty 'parent_fe_bh'. And I suggest adding a new
roll_back tag to handle this, just like ocfs2_orphan_add() does.

Jun
Joseph Qi March 17, 2020, 8:17 a.m. UTC | #3
On 2020/3/17 14:24, piaojun wrote:
> 
> 
> On 2020/3/17 10:26, wangjian wrote:
>> Under some conditions, the directory cannot be deleted.
>> The specific scenarios are as follows: (for example,
>> /mnt/ocfs2 is the mount point)
>>
>> 1. Create the /mnt/ocfs2/p_dir directory. At this time,
>> the i_nlink corresponding to the inode of
>> the /mnt/ocfs2/p_dir directory is equal to 2.
>>
>> 2. During the process of creating the
>> /mnt/ocfs2/p_dir/s_dir directory, if the call to the inc_nlink
>> function in ocfs2_mknod succeeds, the functions such as
>> ocfs2_init_acl, ocfs2_init_security_set, and ocfs2_dentry_attach_lock fail.
>> At this time, the i_nlink corresponding to the inode of the
>> /mnt/ocfs2/p_dir directory is equal to 3, but /mnt/ocfs2/p_dir/s_dir
>> is not added to the /mnt/ocfs2/p_dir directory entry.
>>
>> 3. Delete the /mnt/ocfs2/p_dir directory (rm -rf /mnt/ocfs2/p_dir).
>> At this time, it is found that the i_nlink corresponding to
>> the inode corresponding to the /mnt/ocfs2/p_dir directory is equal to 3.
>> Therefore, the /mnt/ocfs2/p_dir directory cannot be deleted.
>>
>> Signed-off-by: Jian wang <wangjian161@huawei.com>
>> ---
>>  ocfs2/namei.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/ocfs2/namei.c b/ocfs2/namei.c
>> index 8ea51cf..f34ce0b 100644
>> --- a/ocfs2/namei.c
>> +++ b/ocfs2/namei.c
>> @@ -247,6 +247,7 @@ static int ocfs2_mknod(struct inode *dir,
>>  	sigset_t oldset;
>>  	int did_block_signals = 0;
>>  	struct ocfs2_dentry_lock *dl = NULL;
>> +	int link_inc = 0;
>>  
>>  	trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
>>  			  (unsigned long long)OCFS2_I(dir)->ip_blkno,
>> @@ -399,6 +400,7 @@ static int ocfs2_mknod(struct inode *dir,
>>  		ocfs2_add_links_count(dirfe, 1);
>>  		ocfs2_journal_dirty(handle, parent_fe_bh);
>>  		inc_nlink(dir);
>> +		link_inc = 1;
>>  	}
>>  
>>  	status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
>> @@ -444,6 +446,12 @@ static int ocfs2_mknod(struct inode *dir,
>>  	d_instantiate(dentry, inode);
>>  	status = 0;
>>  leave:
>> +	if (status < 0 && S_ISDIR(mode) && link_inc != 0) {
>> +		ocfs2_add_links_count(dirfe, -1);
>> +		ocfs2_journal_dirty(handle, parent_fe_bh);
> There is no need to re-dirty 'parent_fe_bh'. And I suggest adding a new
> roll_back tag to handle this, just like ocfs2_orphan_add() does.
> 
Good idea, that will be more clearly and we don't need the flag link_inc any more.

Thanks,
Joseph
diff mbox series

Patch

diff --git a/ocfs2/namei.c b/ocfs2/namei.c
index 8ea51cf..f34ce0b 100644
--- a/ocfs2/namei.c
+++ b/ocfs2/namei.c
@@ -247,6 +247,7 @@  static int ocfs2_mknod(struct inode *dir,
  	sigset_t oldset;
  	int did_block_signals = 0;
  	struct ocfs2_dentry_lock *dl = NULL;
+	int link_inc = 0;
  
  	trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
  			  (unsigned long long)OCFS2_I(dir)->ip_blkno,
@@ -399,6 +400,7 @@  static int ocfs2_mknod(struct inode *dir,
  		ocfs2_add_links_count(dirfe, 1);
  		ocfs2_journal_dirty(handle, parent_fe_bh);
  		inc_nlink(dir);
+		link_inc = 1;
  	}
  
  	status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
@@ -444,6 +446,12 @@  static int ocfs2_mknod(struct inode *dir,
  	d_instantiate(dentry, inode);
  	status = 0;
  leave:
+	if (status < 0 && S_ISDIR(mode) && link_inc != 0) {
+		ocfs2_add_links_count(dirfe, -1);
+		ocfs2_journal_dirty(handle, parent_fe_bh);
+		drop_nlink(dir);
+	}
+
  	if (status < 0 && did_quota_inode)
  		dquot_free_inode(inode);
  	if (handle)