Commit a4b6e07d authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: limit balancing work while flushing delayed refs



The delayed reference mechanism is responsible for all updates to the
extent allocation trees, including those updates created while processing
the delayed references.

This commit tries to limit the amount of work that gets created during
the final run of delayed refs before a commit.  It avoids cowing new blocks
unless it is required to finish the commit, and so it avoids new allocations
that were not really required.

The goal is to avoid infinite loops where we are always making more work
on the final run of delayed refs.  Over the long term we'll make a
special log for the last delayed ref updates as well.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 5d13a98f
...@@ -949,6 +949,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -949,6 +949,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
BTRFS_NODEPTRS_PER_BLOCK(root) / 4) BTRFS_NODEPTRS_PER_BLOCK(root) / 4)
return 0; return 0;
if (trans->transaction->delayed_refs.flushing &&
btrfs_header_nritems(mid) > 2)
return 0;
if (btrfs_header_nritems(mid) < 2) if (btrfs_header_nritems(mid) < 2)
err_on_enospc = 1; err_on_enospc = 1;
...@@ -2159,7 +2163,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, ...@@ -2159,7 +2163,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
ret = insert_new_root(trans, root, path, level + 1); ret = insert_new_root(trans, root, path, level + 1);
if (ret) if (ret)
return ret; return ret;
} else { } else if (!trans->transaction->delayed_refs.flushing) {
ret = push_nodes_for_insert(trans, root, path, level); ret = push_nodes_for_insert(trans, root, path, level);
c = path->nodes[level]; c = path->nodes[level];
if (!ret && btrfs_header_nritems(c) < if (!ret && btrfs_header_nritems(c) <
...@@ -2848,7 +2852,8 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, ...@@ -2848,7 +2852,8 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
int num_doubles = 0; int num_doubles = 0;
/* first try to make some room by pushing left and right */ /* first try to make some room by pushing left and right */
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY &&
!trans->transaction->delayed_refs.flushing) {
wret = push_leaf_right(trans, root, path, data_size, 0); wret = push_leaf_right(trans, root, path, data_size, 0);
if (wret < 0) if (wret < 0)
return wret; return wret;
...@@ -3786,7 +3791,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -3786,7 +3791,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
} }
/* delete the leaf if it is mostly empty */ /* delete the leaf if it is mostly empty */
if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) { if (used < BTRFS_LEAF_DATA_SIZE(root) / 4 &&
!trans->transaction->delayed_refs.flushing) {
/* push_leaf_left fixes the path. /* push_leaf_left fixes the path.
* make sure the path still points to our leaf * make sure the path still points to our leaf
* for possible call to del_ptr below * for possible call to del_ptr below
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment