Linux Btrfs filesystem development
 help / color / mirror / Atom feed
* [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c
@ 2025-11-13 16:56 fdmanana
  2025-11-13 16:56 ` [PATCH 1/8] btrfs: fix leaf leak in an error path in btrfs_del_items() fdmanana
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

Trivial changes, details in the change logs.

Filipe Manana (8):
  btrfs: fix leaf leak in an error path in btrfs_del_items()
  btrfs: remove pointless return value update in btrfs_del_items()
  btrfs: add unlikely to critical error in btrfs_extend_item()
  btrfs: always use left leaf variable in __push_leaf_right()
  btrfs: remove duplicated leaf dirty status clearing in __push_leaf_right()
  btrfs: always use right leaf variable in __push_leaf_left()
  btrfs: abort transaction on item count overflow in __push_leaf_left()
  btrfs: update check_skip variable after unlocking current node

 fs/btrfs/ctree.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

-- 
2.47.2


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/8] btrfs: fix leaf leak in an error path in btrfs_del_items()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 2/8] btrfs: remove pointless return value update " fdmanana
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

If the call to btrfs_del_leaf() fails we return without decrementing the
extra ref we took on the leaf, therefore leaking it. Fix this by ensuring
we drop the ref count before returning the error.

Fixes: 751a27615dda ("btrfs: do not BUG_ON() on tree mod log failures at btrfs_del_ptr()")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index f6a9b6bbf78b..614aa4b56571 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4562,9 +4562,9 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 			if (btrfs_header_nritems(leaf) == 0) {
 				path->slots[1] = slot;
 				ret = btrfs_del_leaf(trans, root, path, leaf);
+				free_extent_buffer(leaf);
 				if (ret < 0)
 					return ret;
-				free_extent_buffer(leaf);
 				ret = 0;
 			} else {
 				/* if we're still in the path, make sure
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/8] btrfs: remove pointless return value update in btrfs_del_items()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
  2025-11-13 16:56 ` [PATCH 1/8] btrfs: fix leaf leak in an error path in btrfs_del_items() fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 3/8] btrfs: add unlikely to critical error in btrfs_extend_item() fdmanana
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

The call to btrfs_del_leaf() can only return an error (negative value) or
zero (success). If we didn't get an error then 'ret' is zero, so it's
pointless to set it to zero again.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ctree.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 614aa4b56571..e683f961742a 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4565,7 +4565,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 				free_extent_buffer(leaf);
 				if (ret < 0)
 					return ret;
-				ret = 0;
 			} else {
 				/* if we're still in the path, make sure
 				 * we're dirty.  Otherwise, one of the
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/8] btrfs: add unlikely to critical error in btrfs_extend_item()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
  2025-11-13 16:56 ` [PATCH 1/8] btrfs: fix leaf leak in an error path in btrfs_del_items() fdmanana
  2025-11-13 16:56 ` [PATCH 2/8] btrfs: remove pointless return value update " fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 4/8] btrfs: always use left leaf variable in __push_leaf_right() fdmanana
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

It's not expected to get a data size less than the leaf's free space,
which would lead to a leaf dump and BUG(), so tag the if statement's
expression as unlikely, hinting the compiler to potentially generate
better code.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index e683f961742a..b5cf1b6f5adc 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4106,7 +4106,7 @@ void btrfs_extend_item(struct btrfs_trans_handle *trans,
 	nritems = btrfs_header_nritems(leaf);
 	data_end = leaf_data_end(leaf);
 
-	if (btrfs_leaf_free_space(leaf) < data_size) {
+	if (unlikely(btrfs_leaf_free_space(leaf) < data_size)) {
 		btrfs_print_leaf(leaf);
 		BUG();
 	}
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/8] btrfs: always use left leaf variable in __push_leaf_right()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (2 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 3/8] btrfs: add unlikely to critical error in btrfs_extend_item() fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 5/8] btrfs: remove duplicated leaf dirty status clearing " fdmanana
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

The 'left' variable points to path->nodes[0] and path->nodes[0] is never
changed, but some places use 'left' while others refer to path->nodes[0].
Update all sites to use 'left' as not only it's shorter it's also easier
to reason since it means the left leaf and avoids any confusion with the
sibling right leaf.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index b5cf1b6f5adc..dada50d86731 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3214,10 +3214,10 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
 	/* then fixup the leaf pointer in the path */
 	if (path->slots[0] >= left_nritems) {
 		path->slots[0] -= left_nritems;
-		if (btrfs_header_nritems(path->nodes[0]) == 0)
-			btrfs_clear_buffer_dirty(trans, path->nodes[0]);
-		btrfs_tree_unlock(path->nodes[0]);
-		free_extent_buffer(path->nodes[0]);
+		if (btrfs_header_nritems(left) == 0)
+			btrfs_clear_buffer_dirty(trans, left);
+		btrfs_tree_unlock(left);
+		free_extent_buffer(left);
 		path->nodes[0] = right;
 		path->slots[1] += 1;
 	} else {
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/8] btrfs: remove duplicated leaf dirty status clearing in __push_leaf_right()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (3 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 4/8] btrfs: always use left leaf variable in __push_leaf_right() fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 6/8] btrfs: always use right leaf variable in __push_leaf_left() fdmanana
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

We have already called btrfs_clear_buffer_dirty() against the left leaf in
the code above:

  btrfs_set_header_nritems(left, left_nritems);

  if (left_nritems)
       btrfs_mark_buffer_dirty(trans, left);
  else
       btrfs_clear_buffer_dirty(trans, left);

So remove the second check for a 0 number of items in the left leaf and
calling again btrfs_clear_buffer_dirty() against the left leaf.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index dada50d86731..7265dd661cde 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3214,8 +3214,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
 	/* then fixup the leaf pointer in the path */
 	if (path->slots[0] >= left_nritems) {
 		path->slots[0] -= left_nritems;
-		if (btrfs_header_nritems(left) == 0)
-			btrfs_clear_buffer_dirty(trans, left);
 		btrfs_tree_unlock(left);
 		free_extent_buffer(left);
 		path->nodes[0] = right;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/8] btrfs: always use right leaf variable in __push_leaf_left()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (4 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 5/8] btrfs: remove duplicated leaf dirty status clearing " fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 7/8] btrfs: abort transaction on item count overflow " fdmanana
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

The 'right' variable points to path->nodes[0] and path->nodes[0] is never
changed, but some places use 'right' while others refer to path->nodes[0].
Update all sites to use 'right' as not only it's shorter it's also easier
to reason since it means the right leaf and avoids any confusion with the
sibling left leaf.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 7265dd661cde..57b7d09d85cc 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3428,8 +3428,8 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
 	/* then fixup the leaf pointer in the path */
 	if (path->slots[0] < push_items) {
 		path->slots[0] += old_left_nritems;
-		btrfs_tree_unlock(path->nodes[0]);
-		free_extent_buffer(path->nodes[0]);
+		btrfs_tree_unlock(right);
+		free_extent_buffer(right);
 		path->nodes[0] = left;
 		path->slots[1] -= 1;
 	} else {
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/8] btrfs: abort transaction on item count overflow in __push_leaf_left()
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (5 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 6/8] btrfs: always use right leaf variable in __push_leaf_left() fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 16:56 ` [PATCH 8/8] btrfs: update check_skip variable after unlocking current node fdmanana
  2025-11-13 21:56 ` [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c Qu Wenruo
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

If we try to push an item count from the right leaf that is greater than
the number of items in the leaf, we just emit a warning. This should
never happen but if it does we get an underflow in the new number of
items in the right leaf and chaos follows from it. So replace the warning
with proper error handling, by aborting the transaction and returning
-EUCLEAN, and proper logging by using btrfs_crit() instead of WARN(),
which gives us proper formatting and information about the filesystem.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 57b7d09d85cc..8b54daf3d0e7 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3393,9 +3393,13 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
 	btrfs_set_header_nritems(left, old_left_nritems + push_items);
 
 	/* fixup right node */
-	if (push_items > right_nritems)
-		WARN(1, KERN_CRIT "push items %d nr %u\n", push_items,
-		       right_nritems);
+	if (unlikely(push_items > right_nritems)) {
+		ret = -EUCLEAN;
+		btrfs_abort_transaction(trans, ret);
+		btrfs_crit(fs_info, "push items (%d) > right leaf items (%u)",
+			   push_items, right_nritems);
+		goto out;
+	}
 
 	if (push_items < right_nritems) {
 		push_space = btrfs_item_offset(right, push_items - 1) -
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/8] btrfs: update check_skip variable after unlocking current node
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (6 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 7/8] btrfs: abort transaction on item count overflow " fdmanana
@ 2025-11-13 16:56 ` fdmanana
  2025-11-13 21:56 ` [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c Qu Wenruo
  8 siblings, 0 replies; 10+ messages in thread
From: fdmanana @ 2025-11-13 16:56 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

There's no need to update the local variable 'check_skip' to false inside
the critical section delimited by the lock of the current node, so do it
after unlocking the node.

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

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 8b54daf3d0e7..46262939e873 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1435,8 +1435,8 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
 		}
 
 		if (i >= lowest_unlock && i > skip_level) {
-			check_skip = false;
 			btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
+			check_skip = false;
 			path->locks[i] = 0;
 			if (write_lock_level &&
 			    i > min_write_lock_level &&
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c
  2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
                   ` (7 preceding siblings ...)
  2025-11-13 16:56 ` [PATCH 8/8] btrfs: update check_skip variable after unlocking current node fdmanana
@ 2025-11-13 21:56 ` Qu Wenruo
  8 siblings, 0 replies; 10+ messages in thread
From: Qu Wenruo @ 2025-11-13 21:56 UTC (permalink / raw)
  To: fdmanana, linux-btrfs



在 2025/11/14 03:26, fdmanana@kernel.org 写道:
> From: Filipe Manana <fdmanana@suse.com>
> 
> Trivial changes, details in the change logs.

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

Thanks,
Qu

> 
> Filipe Manana (8):
>    btrfs: fix leaf leak in an error path in btrfs_del_items()
>    btrfs: remove pointless return value update in btrfs_del_items()
>    btrfs: add unlikely to critical error in btrfs_extend_item()
>    btrfs: always use left leaf variable in __push_leaf_right()
>    btrfs: remove duplicated leaf dirty status clearing in __push_leaf_right()
>    btrfs: always use right leaf variable in __push_leaf_left()
>    btrfs: abort transaction on item count overflow in __push_leaf_left()
>    btrfs: update check_skip variable after unlocking current node
> 
>   fs/btrfs/ctree.c | 27 ++++++++++++++-------------
>   1 file changed, 14 insertions(+), 13 deletions(-)
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-11-13 21:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-13 16:56 [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c fdmanana
2025-11-13 16:56 ` [PATCH 1/8] btrfs: fix leaf leak in an error path in btrfs_del_items() fdmanana
2025-11-13 16:56 ` [PATCH 2/8] btrfs: remove pointless return value update " fdmanana
2025-11-13 16:56 ` [PATCH 3/8] btrfs: add unlikely to critical error in btrfs_extend_item() fdmanana
2025-11-13 16:56 ` [PATCH 4/8] btrfs: always use left leaf variable in __push_leaf_right() fdmanana
2025-11-13 16:56 ` [PATCH 5/8] btrfs: remove duplicated leaf dirty status clearing " fdmanana
2025-11-13 16:56 ` [PATCH 6/8] btrfs: always use right leaf variable in __push_leaf_left() fdmanana
2025-11-13 16:56 ` [PATCH 7/8] btrfs: abort transaction on item count overflow " fdmanana
2025-11-13 16:56 ` [PATCH 8/8] btrfs: update check_skip variable after unlocking current node fdmanana
2025-11-13 21:56 ` [PATCH 0/8] btrfs: a bug fix and some cleanups in ctree.c Qu Wenruo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox