Commit 9e79c497 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

btrfs: send: make ensure_commit_roots_uptodate() simpler and more efficient

Before starting a send operation we have to make sure that every root has
its commit root matching the regular root, to that send doesn't find stale
inodes in the commit root (inodes that were deleted in the regular root)
and fails the inode lookups with -ESTALE.

Currently we keep looking for roots used by the send operation and as soon
as we find one we commit the current transaction (or a new one since
btrfs_join_transaction() creates one if there isn't any running or the
running one is in a state >= TRANS_STATE_UNBLOCKED). It's pointless to
keep looking until we don't find any, because after the first transaction
commit all the other roots are updated too, as they were already tagged in
the fs_info->fs_roots_radix radix tree when they were modified in order to
have a commit root different from the regular root.

Currently we are also always passing the main send root into
btrfs_join_transaction(), which despite not having any functional issue,
it is not optimal because in case the root wasn't modified we end up
adding it to fs_info->fs_roots_radix and then update its root item in the
root tree when committing the transaction, causing unnecessary work.

So simplify and make this more efficient by removing the looping and by
passing the first root we found that is modified as the argument to
btrfs_join_transaction().
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent cab0d862
......@@ -7998,32 +7998,29 @@ static int send_subvol(struct send_ctx *sctx)
*/
static int ensure_commit_roots_uptodate(struct send_ctx *sctx)
{
int i;
struct btrfs_trans_handle *trans = NULL;
struct btrfs_trans_handle *trans;
struct btrfs_root *root = sctx->parent_root;
again:
if (sctx->parent_root &&
sctx->parent_root->node != sctx->parent_root->commit_root)
if (root && root->node != root->commit_root)
goto commit_trans;
for (i = 0; i < sctx->clone_roots_cnt; i++)
if (sctx->clone_roots[i].root->node !=
sctx->clone_roots[i].root->commit_root)
for (int i = 0; i < sctx->clone_roots_cnt; i++) {
root = sctx->clone_roots[i].root;
if (root->node != root->commit_root)
goto commit_trans;
if (trans)
return btrfs_end_transaction(trans);
}
return 0;
commit_trans:
/* Use any root, all fs roots will get their commit roots updated. */
if (!trans) {
trans = btrfs_join_transaction(sctx->send_root);
/*
* Use the first root we found. We could use any but that would cause
* an unnecessary update of the root's item in the root tree when
* committing the transaction if that root wasn't changed before.
*/
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
goto again;
}
return btrfs_commit_transaction(trans);
}
......
Markdown is supported
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