diff mbox series

[10/13] btrfs: do not BUG_ON() on tree mod log failures at push_nodes_for_insert()

Message ID 3dfd1a4c01795433444b45268da1ae75563642c1.1686164820.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: some fixes and updates around handling errors for tree mod log operations | expand

Commit Message

Filipe Manana June 7, 2023, 7:24 p.m. UTC
From: Filipe Manana <fdmanana@suse.com>

At push_nodes_for_insert(), instead of doing a BUG_ON() in case we fail to
record tree mod log operations, do a transaction abort and return the
error to the caller. There's really no need for the BUG_ON() as we can
release all resources in this context, and we have to abort because other
future tree searches that use the tree mod log (btrfs_search_old_slot())
may get inconsistent results if other operations modify the tree after
that failure and before the tree mod log based search.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

Comments

Qu Wenruo June 8, 2023, 9:02 a.m. UTC | #1
On 2023/6/8 03:24, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> At push_nodes_for_insert(), instead of doing a BUG_ON() in case we fail to
> record tree mod log operations, do a transaction abort and return the
> error to the caller. There's really no need for the BUG_ON() as we can
> release all resources in this context, and we have to abort because other
> future tree searches that use the tree mod log (btrfs_search_old_slot())
> may get inconsistent results if other operations modify the tree after
> that failure and before the tree mod log based search.
>
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>   fs/btrfs/ctree.c | 14 ++++++++++++--
>   1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 2971e7d70d04..e3c949fa136f 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -1300,7 +1300,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
>   			btrfs_node_key(mid, &disk_key, 0);
>   			ret = btrfs_tree_mod_log_insert_key(parent, pslot,
>   					BTRFS_MOD_LOG_KEY_REPLACE);
> -			BUG_ON(ret < 0);
> +			if (ret < 0) {
> +				btrfs_tree_unlock(left);
> +				free_extent_buffer(left);

I'm not sure if we only need to unlock and free @left.

As just lines below, we have a two branches which one unlock and free @mid.

Thanks,
Qu

> +				btrfs_abort_transaction(trans, ret);
> +				return ret;
> +			}
>   			btrfs_set_node_key(parent, &disk_key, pslot);
>   			btrfs_mark_buffer_dirty(parent);
>   			if (btrfs_header_nritems(left) > orig_slot) {
> @@ -1355,7 +1360,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
>   			btrfs_node_key(right, &disk_key, 0);
>   			ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
>   					BTRFS_MOD_LOG_KEY_REPLACE);
> -			BUG_ON(ret < 0);
> +			if (ret < 0) {
> +				btrfs_tree_unlock(right);
> +				free_extent_buffer(right);
> +				btrfs_abort_transaction(trans, ret);
> +				return ret;
> +			}
>   			btrfs_set_node_key(parent, &disk_key, pslot + 1);
>   			btrfs_mark_buffer_dirty(parent);
>
Filipe Manana June 8, 2023, 9:46 a.m. UTC | #2
On Thu, Jun 8, 2023 at 10:02 AM Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>
>
>
> On 2023/6/8 03:24, fdmanana@kernel.org wrote:
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > At push_nodes_for_insert(), instead of doing a BUG_ON() in case we fail to
> > record tree mod log operations, do a transaction abort and return the
> > error to the caller. There's really no need for the BUG_ON() as we can
> > release all resources in this context, and we have to abort because other
> > future tree searches that use the tree mod log (btrfs_search_old_slot())
> > may get inconsistent results if other operations modify the tree after
> > that failure and before the tree mod log based search.
> >
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > ---
> >   fs/btrfs/ctree.c | 14 ++++++++++++--
> >   1 file changed, 12 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> > index 2971e7d70d04..e3c949fa136f 100644
> > --- a/fs/btrfs/ctree.c
> > +++ b/fs/btrfs/ctree.c
> > @@ -1300,7 +1300,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
> >                       btrfs_node_key(mid, &disk_key, 0);
> >                       ret = btrfs_tree_mod_log_insert_key(parent, pslot,
> >                                       BTRFS_MOD_LOG_KEY_REPLACE);
> > -                     BUG_ON(ret < 0);
> > +                     if (ret < 0) {
> > +                             btrfs_tree_unlock(left);
> > +                             free_extent_buffer(left);
>
> I'm not sure if we only need to unlock and free @left.
>
> As just lines below, we have a two branches which one unlock and free @mid.

mid is part of the path, so we shouldn't touch it at this point.
It's released by the caller doing a btrfs_release_path() or btrfs_free_path().

Those branches unlock and free mid because they are replacing it in the path.

Thanks.

>
> Thanks,
> Qu
>
> > +                             btrfs_abort_transaction(trans, ret);
> > +                             return ret;
> > +                     }
> >                       btrfs_set_node_key(parent, &disk_key, pslot);
> >                       btrfs_mark_buffer_dirty(parent);
> >                       if (btrfs_header_nritems(left) > orig_slot) {
> > @@ -1355,7 +1360,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
> >                       btrfs_node_key(right, &disk_key, 0);
> >                       ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
> >                                       BTRFS_MOD_LOG_KEY_REPLACE);
> > -                     BUG_ON(ret < 0);
> > +                     if (ret < 0) {
> > +                             btrfs_tree_unlock(right);
> > +                             free_extent_buffer(right);
> > +                             btrfs_abort_transaction(trans, ret);
> > +                             return ret;
> > +                     }
> >                       btrfs_set_node_key(parent, &disk_key, pslot + 1);
> >                       btrfs_mark_buffer_dirty(parent);
> >
Qu Wenruo June 8, 2023, 10:19 a.m. UTC | #3
On 2023/6/8 17:46, Filipe Manana wrote:
> On Thu, Jun 8, 2023 at 10:02 AM Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>>
>>
>>
>> On 2023/6/8 03:24, fdmanana@kernel.org wrote:
>>> From: Filipe Manana <fdmanana@suse.com>
>>>
>>> At push_nodes_for_insert(), instead of doing a BUG_ON() in case we fail to
>>> record tree mod log operations, do a transaction abort and return the
>>> error to the caller. There's really no need for the BUG_ON() as we can
>>> release all resources in this context, and we have to abort because other
>>> future tree searches that use the tree mod log (btrfs_search_old_slot())
>>> may get inconsistent results if other operations modify the tree after
>>> that failure and before the tree mod log based search.
>>>
>>> Signed-off-by: Filipe Manana <fdmanana@suse.com>
>>> ---
>>>    fs/btrfs/ctree.c | 14 ++++++++++++--
>>>    1 file changed, 12 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
>>> index 2971e7d70d04..e3c949fa136f 100644
>>> --- a/fs/btrfs/ctree.c
>>> +++ b/fs/btrfs/ctree.c
>>> @@ -1300,7 +1300,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
>>>                        btrfs_node_key(mid, &disk_key, 0);
>>>                        ret = btrfs_tree_mod_log_insert_key(parent, pslot,
>>>                                        BTRFS_MOD_LOG_KEY_REPLACE);
>>> -                     BUG_ON(ret < 0);
>>> +                     if (ret < 0) {
>>> +                             btrfs_tree_unlock(left);
>>> +                             free_extent_buffer(left);
>>
>> I'm not sure if we only need to unlock and free @left.
>>
>> As just lines below, we have a two branches which one unlock and free @mid.
>
> mid is part of the path, so we shouldn't touch it at this point.
> It's released by the caller doing a btrfs_release_path() or btrfs_free_path().
>
> Those branches unlock and free mid because they are replacing it in the path.

Thanks for the detailed reason.

Then this looks good to me.

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
>
> Thanks.
>
>>
>> Thanks,
>> Qu
>>
>>> +                             btrfs_abort_transaction(trans, ret);
>>> +                             return ret;
>>> +                     }
>>>                        btrfs_set_node_key(parent, &disk_key, pslot);
>>>                        btrfs_mark_buffer_dirty(parent);
>>>                        if (btrfs_header_nritems(left) > orig_slot) {
>>> @@ -1355,7 +1360,12 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
>>>                        btrfs_node_key(right, &disk_key, 0);
>>>                        ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
>>>                                        BTRFS_MOD_LOG_KEY_REPLACE);
>>> -                     BUG_ON(ret < 0);
>>> +                     if (ret < 0) {
>>> +                             btrfs_tree_unlock(right);
>>> +                             free_extent_buffer(right);
>>> +                             btrfs_abort_transaction(trans, ret);
>>> +                             return ret;
>>> +                     }
>>>                        btrfs_set_node_key(parent, &disk_key, pslot + 1);
>>>                        btrfs_mark_buffer_dirty(parent);
>>>
diff mbox series

Patch

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 2971e7d70d04..e3c949fa136f 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1300,7 +1300,12 @@  static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 			btrfs_node_key(mid, &disk_key, 0);
 			ret = btrfs_tree_mod_log_insert_key(parent, pslot,
 					BTRFS_MOD_LOG_KEY_REPLACE);
-			BUG_ON(ret < 0);
+			if (ret < 0) {
+				btrfs_tree_unlock(left);
+				free_extent_buffer(left);
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
 			btrfs_set_node_key(parent, &disk_key, pslot);
 			btrfs_mark_buffer_dirty(parent);
 			if (btrfs_header_nritems(left) > orig_slot) {
@@ -1355,7 +1360,12 @@  static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 			btrfs_node_key(right, &disk_key, 0);
 			ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1,
 					BTRFS_MOD_LOG_KEY_REPLACE);
-			BUG_ON(ret < 0);
+			if (ret < 0) {
+				btrfs_tree_unlock(right);
+				free_extent_buffer(right);
+				btrfs_abort_transaction(trans, ret);
+				return ret;
+			}
 			btrfs_set_node_key(parent, &disk_key, pslot + 1);
 			btrfs_mark_buffer_dirty(parent);