* [PATCH 0/4] btrfs: some code cleanups in ctree.c
@ 2025-11-14 7:24 Sun YangKai
2025-11-14 7:24 ` [PATCH 1/4] btrfs: extract root promotion logic into promote_child_to_root() Sun YangKai
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Sun YangKai @ 2025-11-14 7:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sun YangKai
No functional change. Details in change logs.
*** BLURB HERE ***
Sun YangKai (4):
btrfs: extract root promotion logic into promote_child_to_root()
btrfs: optimize balance_level() path reference handling
btrfs: simplify leaf traversal after path release in
btrfs_next_old_leaf()
btrfs: remove redundant level reset in btrfs_del_items()
fs/btrfs/ctree.c | 164 +++++++++++++++++++++++++----------------------
1 file changed, 88 insertions(+), 76 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] btrfs: extract root promotion logic into promote_child_to_root()
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
@ 2025-11-14 7:24 ` Sun YangKai
2025-11-14 7:24 ` [PATCH 2/4] btrfs: optimize balance_level() path reference handling Sun YangKai
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Sun YangKai @ 2025-11-14 7:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sun YangKai
The balance_level() function is overly long and contains a cold code path
that handles promoting a child node to root when the root has only one item.
This code has distinct logic that is clearer and more maintainable when
isolated in its own function.
No functional change.
Signed-off-by: Sun YangKai <sunk67188@gmail.com>
---
fs/btrfs/ctree.c | 116 +++++++++++++++++++++++++++++------------------
1 file changed, 71 insertions(+), 45 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 561658aca018..2369aa8ab455 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -861,6 +861,76 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
return eb;
}
+/*
+ * Promote a child node to become the new tree root.
+ *
+ * This helper is called during rebalancing when the root node contains only
+ * a single item (nritems == 1). We can reduce the tree height by promoting
+ * that child to become the new root and freeing the old root node. The path
+ * locks and references are updated accordingly.
+ *
+ * @trans: Transaction handle
+ * @root: Tree root structure to update
+ * @path: Path holding nodes and locks
+ * @level: Level of the parent (old root)
+ * @parent: The parent (old root) with exactly one item
+ *
+ * Return: 0 on success, negative errno on failure. The transaction is aborted
+ * on critical errors.
+ */
+static noinline int promote_child_to_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ int level,
+ struct extent_buffer *parent)
+{
+ struct extent_buffer *child;
+ int ret = 0;
+
+ ASSERT(btrfs_header_nritems(parent) == 1);
+
+ child = btrfs_read_node_slot(parent, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ btrfs_tree_lock(child);
+ ret = btrfs_cow_block(trans, root, child, parent, 0, &child,
+ BTRFS_NESTING_COW);
+ if (ret) {
+ btrfs_tree_unlock(child);
+ free_extent_buffer(child);
+ return ret;
+ }
+
+ ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
+ if (unlikely(ret < 0)) {
+ btrfs_tree_unlock(child);
+ free_extent_buffer(child);
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ rcu_assign_pointer(root->node, child);
+
+ add_root_to_dirty_list(root);
+ btrfs_tree_unlock(child);
+
+ path->locks[level] = 0;
+ path->nodes[level] = NULL;
+ btrfs_clear_buffer_dirty(trans, parent);
+ btrfs_tree_unlock(parent);
+ /* once for the path */
+ free_extent_buffer(parent);
+
+ root_sub_used_bytes(root);
+ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), parent, 0, 1);
+ /* once for the root ptr */
+ free_extent_buffer_stale(parent);
+ if (unlikely(ret < 0)) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+ return 0;
+}
/*
* node level balancing, used to make sure nodes are in proper order for
* item deletion. We balance from the top down, so we have to make sure
@@ -900,55 +970,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
* by promoting the node below to a root
*/
if (!parent) {
- struct extent_buffer *child;
-
if (btrfs_header_nritems(mid) != 1)
return 0;
/* promote the child to a root */
- child = btrfs_read_node_slot(mid, 0);
- if (IS_ERR(child)) {
- ret = PTR_ERR(child);
- goto out;
- }
-
- btrfs_tree_lock(child);
- ret = btrfs_cow_block(trans, root, child, mid, 0, &child,
- BTRFS_NESTING_COW);
- if (ret) {
- btrfs_tree_unlock(child);
- free_extent_buffer(child);
- goto out;
- }
-
- ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
- if (unlikely(ret < 0)) {
- btrfs_tree_unlock(child);
- free_extent_buffer(child);
- btrfs_abort_transaction(trans, ret);
- goto out;
- }
- rcu_assign_pointer(root->node, child);
-
- add_root_to_dirty_list(root);
- btrfs_tree_unlock(child);
-
- path->locks[level] = 0;
- path->nodes[level] = NULL;
- btrfs_clear_buffer_dirty(trans, mid);
- btrfs_tree_unlock(mid);
- /* once for the path */
- free_extent_buffer(mid);
-
- root_sub_used_bytes(root);
- ret = btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
- /* once for the root ptr */
- free_extent_buffer_stale(mid);
- if (unlikely(ret < 0)) {
- btrfs_abort_transaction(trans, ret);
- goto out;
- }
- return 0;
+ return promote_child_to_root(trans, root, path, level, mid);
}
if (btrfs_header_nritems(mid) >
BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] btrfs: optimize balance_level() path reference handling
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
2025-11-14 7:24 ` [PATCH 1/4] btrfs: extract root promotion logic into promote_child_to_root() Sun YangKai
@ 2025-11-14 7:24 ` Sun YangKai
2025-11-14 7:24 ` [PATCH 3/4] btrfs: simplify leaf traversal after path release in btrfs_next_old_leaf() Sun YangKai
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Sun YangKai @ 2025-11-14 7:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sun YangKai
Instead of incrementing refcount on left node when it's referenced by path,
simply transfer ownership to path and set left to NULL. This eliminates:
- Unnecessary refcount increment/decrement operations
- Redundant conditional checks for left node cleanup
The path now consistently owns the left node reference when used.
Signed-off-by: Sun YangKai <sunk67188@gmail.com>
---
fs/btrfs/ctree.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 2369aa8ab455..a477839cf22c 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1127,11 +1127,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
/* update the path */
if (left) {
if (btrfs_header_nritems(left) > orig_slot) {
- refcount_inc(&left->refs);
/* left was locked after cow */
path->nodes[level] = left;
path->slots[level + 1] -= 1;
path->slots[level] = orig_slot;
+ /* left is now owned by path */
+ left = NULL;
if (mid) {
btrfs_tree_unlock(mid);
free_extent_buffer(mid);
@@ -1151,8 +1152,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
free_extent_buffer(right);
}
if (left) {
- if (path->nodes[level] != left)
- btrfs_tree_unlock(left);
+ btrfs_tree_unlock(left);
free_extent_buffer(left);
}
return ret;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] btrfs: simplify leaf traversal after path release in btrfs_next_old_leaf()
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
2025-11-14 7:24 ` [PATCH 1/4] btrfs: extract root promotion logic into promote_child_to_root() Sun YangKai
2025-11-14 7:24 ` [PATCH 2/4] btrfs: optimize balance_level() path reference handling Sun YangKai
@ 2025-11-14 7:24 ` Sun YangKai
2025-11-14 7:24 ` [PATCH 4/4] btrfs: remove redundant level reset in btrfs_del_items() Sun YangKai
2025-11-18 20:46 ` [PATCH 0/4] btrfs: some code cleanups in ctree.c David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: Sun YangKai @ 2025-11-14 7:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sun YangKai
After releasing the path in btrfs_next_old_leaf(), we need to re-check the leaf
because a balance operation may have added items or removed the last item. The
original code handled this with two separate conditional blocks, the second
marked with a lengthy comment explaining a "missed case".
Merge these two blocks into a single logical structure that handles both
scenarios more clearly.
Also update the comment to be more concise and accurate, incorporating the
explanation directly into the main block rather than a separate annotation.
No functional change.
Signed-off-by: Sun YangKai <sunk67188@gmail.com>
---
fs/btrfs/ctree.c | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index a477839cf22c..0ef80f2a2a8b 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4858,34 +4858,22 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
nritems = btrfs_header_nritems(path->nodes[0]);
/*
- * by releasing the path above we dropped all our locks. A balance
- * could have added more items next to the key that used to be
- * at the very end of the block. So, check again here and
- * advance the path if there are now more items available.
- */
- if (nritems > 0 && path->slots[0] < nritems - 1) {
- if (ret == 0)
- path->slots[0]++;
- ret = 0;
- goto done;
- }
- /*
- * So the above check misses one case:
- * - after releasing the path above, someone has removed the item that
- * used to be at the very end of the block, and balance between leafs
- * gets another one with bigger key.offset to replace it.
+ * By releasing the path above we dropped all our locks. A balance
+ * could have happened and
*
- * This one should be returned as well, or we can get leaf corruption
- * later(esp. in __btrfs_drop_extents()).
+ * 1. added more items after the previous last item
+ * 2. deleted the previous last item
*
- * And a bit more explanation about this check,
- * with ret > 0, the key isn't found, the path points to the slot
- * where it should be inserted, so the path->slots[0] item must be the
- * bigger one.
+ * So, check again here and advance the path if there are now more items available.
*/
- if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
- ret = 0;
- goto done;
+ if (nritems > 0 && path->slots[0] <= nritems - 1) {
+ if (ret == 0 && path->slots[0] != nritems - 1) {
+ path->slots[0]++;
+ goto done;
+ } else if (ret > 0) {
+ ret = 0;
+ goto done;
+ }
}
while (level < BTRFS_MAX_LEVEL) {
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] btrfs: remove redundant level reset in btrfs_del_items()
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
` (2 preceding siblings ...)
2025-11-14 7:24 ` [PATCH 3/4] btrfs: simplify leaf traversal after path release in btrfs_next_old_leaf() Sun YangKai
@ 2025-11-14 7:24 ` Sun YangKai
2025-11-18 20:46 ` [PATCH 0/4] btrfs: some code cleanups in ctree.c David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: Sun YangKai @ 2025-11-14 7:24 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sun YangKai
When btrfs_del_items() empties a leaf, it deletes the leaf unless it's
the root node. For the root leaf case, the code used to reset its level
to 0 via btrfs_set_header_level(). This is redundant as leaf nodes
always have level == 0.
Remove the unnecessary level assignment and invert the conditional to
handle only the non-root leaf deletion. The root leaf is correctly left
as-is.
No functional change.
Signed-off-by: Sun YangKai <sunk67188@gmail.com>
---
fs/btrfs/ctree.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 0ef80f2a2a8b..3c4aea71bbbf 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -4524,9 +4524,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
/* delete the leaf if we've emptied it */
if (nritems == 0) {
- if (leaf == root->node) {
- btrfs_set_header_level(leaf, 0);
- } else {
+ if (leaf != root->node) {
btrfs_clear_buffer_dirty(trans, leaf);
ret = btrfs_del_leaf(trans, root, path, leaf);
if (ret < 0)
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] btrfs: some code cleanups in ctree.c
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
` (3 preceding siblings ...)
2025-11-14 7:24 ` [PATCH 4/4] btrfs: remove redundant level reset in btrfs_del_items() Sun YangKai
@ 2025-11-18 20:46 ` David Sterba
4 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2025-11-18 20:46 UTC (permalink / raw)
To: Sun YangKai; +Cc: linux-btrfs
On Fri, Nov 14, 2025 at 03:24:44PM +0800, Sun YangKai wrote:
> No functional change. Details in change logs.
>
> *** BLURB HERE ***
You still might want to give an overall idea of the cleanups if they're
related. No big deal if it's terse or copies (parts of) changelog of the
most significant change. Cleanups that mix functional and non-functional
changes might focus only on the functional changes. This basically helps
to set up the level of review and expectations. As you touch code that's
fundamental to the whole b-tree operations I feel we're fine to have
less clean and optimal code rather than to introduce subtle bugs.
> Sun YangKai (4):
> btrfs: extract root promotion logic into promote_child_to_root()
> btrfs: optimize balance_level() path reference handling
> btrfs: simplify leaf traversal after path release in
> btrfs_next_old_leaf()
> btrfs: remove redundant level reset in btrfs_del_items()
I've put the patches to linux-next a few days ago and reviewed them
today again. I'll put them to for-next soon, all seem good. If you send
more cleanups in the future please keep it to small incremental and
understandable changes like this patchset does. Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-11-18 20:46 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-14 7:24 [PATCH 0/4] btrfs: some code cleanups in ctree.c Sun YangKai
2025-11-14 7:24 ` [PATCH 1/4] btrfs: extract root promotion logic into promote_child_to_root() Sun YangKai
2025-11-14 7:24 ` [PATCH 2/4] btrfs: optimize balance_level() path reference handling Sun YangKai
2025-11-14 7:24 ` [PATCH 3/4] btrfs: simplify leaf traversal after path release in btrfs_next_old_leaf() Sun YangKai
2025-11-14 7:24 ` [PATCH 4/4] btrfs: remove redundant level reset in btrfs_del_items() Sun YangKai
2025-11-18 20:46 ` [PATCH 0/4] btrfs: some code cleanups in ctree.c David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox