diff mbox series

[1/2] ocfs2: clear links count in ocfs2_mknod() if an error occurs

Message ID d8147c41-fb2b-bdf7-b660-1f3c8448c33f@huawei.com (mailing list archive)
State New, archived
Headers show
Series [1/2] ocfs2: clear links count in ocfs2_mknod() if an error occurs | expand

Commit Message

Wangyan May 26, 2020, 7:45 a.m. UTC
In this condition, the inode can not be wiped when error happened.
ocfs2_mkdir()
  ->ocfs2_mknod()
    ->ocfs2_mknod_locked()
      ->__ocfs2_mknod_locked()
        ->ocfs2_set_links_count() // i_links_count is 2
    -> ... // an error accrue, goto roll_back or leave.
    ->ocfs2_commit_trans()
    ->iput(inode)
      ->evict()
        ->ocfs2_evict_inode()
          ->ocfs2_delete_inode()
            ->ocfs2_inode_lock()
              ->ocfs2_inode_lock_update()
                ->ocfs2_refresh_inode()
                  ->set_nlink();    // inode->i_nlink is 2 now.
            /* if wipe is 0, it will goto bail_unlock_inode */
            ->ocfs2_query_inode_wipe()
              ->if (inode->i_nlink) return; // wipe is 0.
            /* inode can not be wiped */
            ->ocfs2_wipe_inode()
So, we need clear links before the transaction committed.

Signed-off-by: Yan Wang <wangyan122@huawei.com>
Reviewed-by: Jun Piao <piaojun@huawei.com>
---
 fs/ocfs2/namei.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

Comments

Andrew Morton May 27, 2020, 10:52 p.m. UTC | #1
On Tue, 26 May 2020 15:45:35 +0800 Wangyan <wangyan122@huawei.com> wrote:

> In this condition, the inode can not be wiped when error happened.
> ocfs2_mkdir()
>   ->ocfs2_mknod()
>     ->ocfs2_mknod_locked()
>       ->__ocfs2_mknod_locked()
>         ->ocfs2_set_links_count() // i_links_count is 2
>     -> ... // an error accrue, goto roll_back or leave.
>     ->ocfs2_commit_trans()
>     ->iput(inode)
>       ->evict()
>         ->ocfs2_evict_inode()
>           ->ocfs2_delete_inode()
>             ->ocfs2_inode_lock()
>               ->ocfs2_inode_lock_update()
>                 ->ocfs2_refresh_inode()
>                   ->set_nlink();    // inode->i_nlink is 2 now.
>             /* if wipe is 0, it will goto bail_unlock_inode */
>             ->ocfs2_query_inode_wipe()
>               ->if (inode->i_nlink) return; // wipe is 0.
>             /* inode can not be wiped */
>             ->ocfs2_wipe_inode()
> So, we need clear links before the transaction committed.

Do we think these fixes should be backported into -stable kernels?
Wangyan May 28, 2020, 12:43 a.m. UTC | #2
Yes, I think these fixes should be backported into -stable kernels.

On 2020/5/28 6:52, Andrew Morton wrote:
> On Tue, 26 May 2020 15:45:35 +0800 Wangyan <wangyan122@huawei.com> wrote:
> 
>> In this condition, the inode can not be wiped when error happened.
>> ocfs2_mkdir()
>>   ->ocfs2_mknod()
>>     ->ocfs2_mknod_locked()
>>       ->__ocfs2_mknod_locked()
>>         ->ocfs2_set_links_count() // i_links_count is 2
>>     -> ... // an error accrue, goto roll_back or leave.
>>     ->ocfs2_commit_trans()
>>     ->iput(inode)
>>       ->evict()
>>         ->ocfs2_evict_inode()
>>           ->ocfs2_delete_inode()
>>             ->ocfs2_inode_lock()
>>               ->ocfs2_inode_lock_update()
>>                 ->ocfs2_refresh_inode()
>>                   ->set_nlink();    // inode->i_nlink is 2 now.
>>             /* if wipe is 0, it will goto bail_unlock_inode */
>>             ->ocfs2_query_inode_wipe()
>>               ->if (inode->i_nlink) return; // wipe is 0.
>>             /* inode can not be wiped */
>>             ->ocfs2_wipe_inode()
>> So, we need clear links before the transaction committed.
> 
> Do we think these fixes should be backported into -stable kernels?
> 
> 
> 
> .
>
Joseph Qi June 1, 2020, 8:30 a.m. UTC | #3
Hi,

On 2020/5/26 15:45, Wangyan wrote:
> In this condition, the inode can not be wiped when error happened.
> ocfs2_mkdir()
>   ->ocfs2_mknod()
>     ->ocfs2_mknod_locked()
>       ->__ocfs2_mknod_locked()
>         ->ocfs2_set_links_count() // i_links_count is 2
>     -> ... // an error accrue, goto roll_back or leave.
>     ->ocfs2_commit_trans()
>     ->iput(inode)
>       ->evict()
>         ->ocfs2_evict_inode()
>           ->ocfs2_delete_inode()
>             ->ocfs2_inode_lock()
>               ->ocfs2_inode_lock_update()
>                 ->ocfs2_refresh_inode()
>                   ->set_nlink();    // inode->i_nlink is 2 now.
>             /* if wipe is 0, it will goto bail_unlock_inode */
>             ->ocfs2_query_inode_wipe()
>               ->if (inode->i_nlink) return; // wipe is 0.
>             /* inode can not be wiped */
>             ->ocfs2_wipe_inode()
> So, we need clear links before the transaction committed.
> 
> Signed-off-by: Yan Wang <wangyan122@huawei.com>
> Reviewed-by: Jun Piao <piaojun@huawei.com>
> ---
>  fs/ocfs2/namei.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
> index 5381020aaa9a..e61fdd8972ec 100644
> --- a/fs/ocfs2/namei.c
> +++ b/fs/ocfs2/namei.c
> @@ -453,8 +453,12 @@ static int ocfs2_mknod(struct inode *dir,
>  leave:
>  	if (status < 0 && did_quota_inode)
>  		dquot_free_inode(inode);
> -	if (handle)
> +	if (handle) {
> +		if (status < 0 && new_fe_bh != NULL)
> +			ocfs2_set_links_count((struct ocfs2_dinode *)
> +					new_fe_bh->b_data, 0);

Seems no need to do this rollback under handle?
Only if (status < 0 && new_fe_bh) will be okay.

>  		ocfs2_commit_trans(osb, handle);
> +	}
> 
>  	ocfs2_inode_unlock(dir, 1);
>  	if (did_block_signals)
> @@ -598,6 +602,8 @@ static int __ocfs2_mknod_locked(struct inode *dir,
>  leave:
>  	if (status < 0) {
>  		if (*new_fe_bh) {
> +			if (fe)
> +				ocfs2_set_links_count(fe, 0);

Leave this to caller will be enough.

Thanks,
Joseph

>  			brelse(*new_fe_bh);>  			*new_fe_bh = NULL;
>  		}
> @@ -2023,8 +2029,12 @@ static int ocfs2_symlink(struct inode *dir,
>  					ocfs2_clusters_to_bytes(osb->sb, 1));
>  	if (status < 0 && did_quota_inode)
>  		dquot_free_inode(inode);
> -	if (handle)
> +	if (handle) {
> +		if (status < 0 && new_fe_bh != NULL)
> +			ocfs2_set_links_count((struct ocfs2_dinode *)
> +					new_fe_bh->b_data, 0);
>  		ocfs2_commit_trans(osb, handle);
> +	}
> 
>  	ocfs2_inode_unlock(dir, 1);
>  	if (did_block_signals)
>
Andrew Morton Aug. 7, 2020, 3:49 a.m. UTC | #4
On Mon, 1 Jun 2020 16:30:30 +0800 Joseph Qi <jiangqi903@gmail.com> wrote:

> Hi,
> 
> On 2020/5/26 15:45, Wangyan wrote:
> > In this condition, the inode can not be wiped when error happened.
> > ocfs2_mkdir()
> >   ->ocfs2_mknod()
> >     ->ocfs2_mknod_locked()
> >       ->__ocfs2_mknod_locked()
> >         ->ocfs2_set_links_count() // i_links_count is 2
> >     -> ... // an error accrue, goto roll_back or leave.
> >     ->ocfs2_commit_trans()
> >     ->iput(inode)
> >       ->evict()
> >         ->ocfs2_evict_inode()
> >           ->ocfs2_delete_inode()
> >             ->ocfs2_inode_lock()
> >               ->ocfs2_inode_lock_update()
> >                 ->ocfs2_refresh_inode()
> >                   ->set_nlink();    // inode->i_nlink is 2 now.
> >             /* if wipe is 0, it will goto bail_unlock_inode */
> >             ->ocfs2_query_inode_wipe()
> >               ->if (inode->i_nlink) return; // wipe is 0.
> >             /* inode can not be wiped */
> >             ->ocfs2_wipe_inode()
> > So, we need clear links before the transaction committed.
> > 
> > Signed-off-by: Yan Wang <wangyan122@huawei.com>
> > Reviewed-by: Jun Piao <piaojun@huawei.com>
> > ---
> >  fs/ocfs2/namei.c | 14 ++++++++++++--
> >  1 file changed, 12 insertions(+), 2 deletions(-)
> > 
> > diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
> > index 5381020aaa9a..e61fdd8972ec 100644
> > --- a/fs/ocfs2/namei.c
> > +++ b/fs/ocfs2/namei.c
> > @@ -453,8 +453,12 @@ static int ocfs2_mknod(struct inode *dir,
> >  leave:
> >  	if (status < 0 && did_quota_inode)
> >  		dquot_free_inode(inode);
> > -	if (handle)
> > +	if (handle) {
> > +		if (status < 0 && new_fe_bh != NULL)
> > +			ocfs2_set_links_count((struct ocfs2_dinode *)
> > +					new_fe_bh->b_data, 0);
> 
> Seems no need to do this rollback under handle?
> Only if (status < 0 && new_fe_bh) will be okay.
> 
> >  		ocfs2_commit_trans(osb, handle);
> > +	}
> > 
> >  	ocfs2_inode_unlock(dir, 1);
> >  	if (did_block_signals)
> > @@ -598,6 +602,8 @@ static int __ocfs2_mknod_locked(struct inode *dir,
> >  leave:
> >  	if (status < 0) {
> >  		if (*new_fe_bh) {
> > +			if (fe)
> > +				ocfs2_set_links_count(fe, 0);
> 
> Leave this to caller will be enough.

Are we still awaiting a response to these review comments?
Andrew Morton Oct. 16, 2022, 11:32 p.m. UTC | #5
I've been sitting on this patch series for over two years!  I assume
the problem isn't terribly serious.

Can we please come to a decision on how to proceed?  Thanks.

The current patches from the mm tree are below.

From: Wangyan <wangyan122@huawei.com>
Subject: ocfs2: clear links count in ocfs2_mknod() if an error occurs

In this condition, the inode can not be wiped when error happened.
ocfs2_mkdir()
  ->ocfs2_mknod()
    ->ocfs2_mknod_locked()
      ->__ocfs2_mknod_locked()
        ->ocfs2_set_links_count() // i_links_count is 2
    -> ... // an error accrue, goto roll_back or leave.
    ->ocfs2_commit_trans()
    ->iput(inode)
      ->evict()
        ->ocfs2_evict_inode()
          ->ocfs2_delete_inode()
            ->ocfs2_inode_lock()
              ->ocfs2_inode_lock_update()
                ->ocfs2_refresh_inode()
                  ->set_nlink();    // inode->i_nlink is 2 now.
            /* if wipe is 0, it will goto bail_unlock_inode */
            ->ocfs2_query_inode_wipe()
              ->if (inode->i_nlink) return; // wipe is 0.
            /* inode can not be wiped */
            ->ocfs2_wipe_inode()
So, we need clear links before the transaction committed.

Link: http://lkml.kernel.org/r/d8147c41-fb2b-bdf7-b660-1f3c8448c33f@huawei.com
Signed-off-by: Yan Wang <wangyan122@huawei.com>
Reviewed-by: Jun Piao <piaojun@huawei.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Joseph Qi <jiangqi903@gmail.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Gang He <ghe@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 fs/ocfs2/namei.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

--- a/fs/ocfs2/namei.c~ocfs2-clear-links-count-in-ocfs2_mknod-if-an-error-occurs
+++ a/fs/ocfs2/namei.c
@@ -454,8 +454,12 @@ roll_back:
 leave:
 	if (status < 0 && did_quota_inode)
 		dquot_free_inode(inode);
-	if (handle)
+	if (handle) {
+		if (status < 0 && new_fe_bh != NULL)
+			ocfs2_set_links_count((struct ocfs2_dinode *)
+					new_fe_bh->b_data, 0);
 		ocfs2_commit_trans(osb, handle);
+	}
 
 	ocfs2_inode_unlock(dir, 1);
 	if (did_block_signals)
@@ -599,6 +603,8 @@ static int __ocfs2_mknod_locked(struct i
 leave:
 	if (status < 0) {
 		if (*new_fe_bh) {
+			if (fe)
+				ocfs2_set_links_count(fe, 0);
 			brelse(*new_fe_bh);
 			*new_fe_bh = NULL;
 		}
@@ -2028,8 +2034,12 @@ bail:
 					ocfs2_clusters_to_bytes(osb->sb, 1));
 	if (status < 0 && did_quota_inode)
 		dquot_free_inode(inode);
-	if (handle)
+	if (handle) {
+		if (status < 0 && new_fe_bh != NULL)
+			ocfs2_set_links_count((struct ocfs2_dinode *)
+					new_fe_bh->b_data, 0);
 		ocfs2_commit_trans(osb, handle);
+	}
 
 	ocfs2_inode_unlock(dir, 1);
 	if (did_block_signals)
Joseph Qi Oct. 17, 2022, 1:57 a.m. UTC | #6
Hi Andrew,

On 10/17/22 7:32 AM, Andrew Morton wrote:
> 
> I've been sitting on this patch series for over two years!  I assume
> the problem isn't terribly serious.
> 
> Can we please come to a decision on how to proceed?  Thanks.
> 
> The current patches from the mm tree are below.
> 
It seems I commented before, but without any response.
I'll take a look and send a new version base on the latest base today.

Thanks,
Joseph
diff mbox series

Patch

diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 5381020aaa9a..e61fdd8972ec 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -453,8 +453,12 @@  static int ocfs2_mknod(struct inode *dir,
 leave:
 	if (status < 0 && did_quota_inode)
 		dquot_free_inode(inode);
-	if (handle)
+	if (handle) {
+		if (status < 0 && new_fe_bh != NULL)
+			ocfs2_set_links_count((struct ocfs2_dinode *)
+					new_fe_bh->b_data, 0);
 		ocfs2_commit_trans(osb, handle);
+	}

 	ocfs2_inode_unlock(dir, 1);
 	if (did_block_signals)
@@ -598,6 +602,8 @@  static int __ocfs2_mknod_locked(struct inode *dir,
 leave:
 	if (status < 0) {
 		if (*new_fe_bh) {
+			if (fe)
+				ocfs2_set_links_count(fe, 0);
 			brelse(*new_fe_bh);
 			*new_fe_bh = NULL;
 		}
@@ -2023,8 +2029,12 @@  static int ocfs2_symlink(struct inode *dir,
 					ocfs2_clusters_to_bytes(osb->sb, 1));
 	if (status < 0 && did_quota_inode)
 		dquot_free_inode(inode);
-	if (handle)
+	if (handle) {
+		if (status < 0 && new_fe_bh != NULL)
+			ocfs2_set_links_count((struct ocfs2_dinode *)
+					new_fe_bh->b_data, 0);
 		ocfs2_commit_trans(osb, handle);
+	}

 	ocfs2_inode_unlock(dir, 1);
 	if (did_block_signals)