Revert "Btrfs: remove transaction from btrfs send"

This reverts commit 41ce9970a8.
Previously i was thinking we can use readonly root's commit root
safely while it is not true, readonly root may be cowed with the
following cases.

1.snapshot send root will cow source root.
2.balance,device operations will also cow readonly send root
to relocate.

So i have two ideas to make us safe to use commit root.

-->approach 1:
make it protected by transaction and end transaction properly and we research
next item from root node(see btrfs_search_slot_for_read()).

-->approach 2:
add another counter to local root structure to sync snapshot with send.
and add a global counter to sync send with exclusive device operations.

So with approach 2, send can use commit root safely, because we make sure
send root can not be cowed during send. Unfortunately, it make codes *ugly*
and more complex to maintain.

To make snapshot and send exclusively, device operations and send operation
exclusively with each other is a little confusing for common users.

So why not drop into previous way.

Cc: Josef Bacik <jbacik@fb.com>
Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
This commit is contained in:
Wang Shilong 2014-02-08 23:46:36 +08:00 committed by Josef Bacik
parent bcbba5e659
commit dcfd5ad2fc

View file

@ -5104,6 +5104,7 @@ static int changed_cb(struct btrfs_root *left_root,
static int full_send_tree(struct send_ctx *sctx)
{
int ret;
struct btrfs_trans_handle *trans = NULL;
struct btrfs_root *send_root = sctx->send_root;
struct btrfs_key key;
struct btrfs_key found_key;
@ -5125,6 +5126,19 @@ static int full_send_tree(struct send_ctx *sctx)
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
join_trans:
/*
* We need to make sure the transaction does not get committed
* while we do anything on commit roots. Join a transaction to prevent
* this.
*/
trans = btrfs_join_transaction(send_root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;
goto out;
}
/*
* Make sure the tree has not changed after re-joining. We detect this
* by comparing start_ctransid and ctransid. They should always match.
@ -5148,6 +5162,19 @@ static int full_send_tree(struct send_ctx *sctx)
goto out_finish;
while (1) {
/*
* When someone want to commit while we iterate, end the
* joined transaction and rejoin.
*/
if (btrfs_should_end_transaction(trans, send_root)) {
ret = btrfs_end_transaction(trans, send_root);
trans = NULL;
if (ret < 0)
goto out;
btrfs_release_path(path);
goto join_trans;
}
eb = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(eb, &found_key, slot);
@ -5175,6 +5202,12 @@ static int full_send_tree(struct send_ctx *sctx)
out:
btrfs_free_path(path);
if (trans) {
if (!ret)
ret = btrfs_end_transaction(trans, send_root);
else
btrfs_end_transaction(trans, send_root);
}
return ret;
}