diff mbox

Btrfs: convert to add transaction protection for btrfs send

Message ID 1391009539-2326-2-git-send-email-wangshilong1991@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wang Shilong Jan. 29, 2014, 3:32 p.m. UTC
From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>

I sent a patch to kick off transaction from btrfs send, however it gets
a regression that btrfs send try to search extent commit root without
transaction protection.

To fix this regression, we have two ideas:

 1. don't use extent commit root for sending.

 2. add transaction protection to use extent commit root safely.

Both approaches need transaction actually, however, the first approach
will add extent tree lock contention, so we'd better adopt the second
approach.

Luckily, now we only need transaction protection when iterating
extent root, the protection's *range* is smaller than before.

Cc: Josef Bacik <jbacik@fb.com>
Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
---
 fs/btrfs/send.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 04c07ed..8d5e151 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4511,6 +4511,7 @@  static int process_extent(struct send_ctx *sctx,
 			  struct btrfs_key *key)
 {
 	struct clone_root *found_clone = NULL;
+	struct btrfs_trans_handle *trans;
 	int ret = 0;
 
 	if (S_ISLNK(sctx->cur_inode_mode))
@@ -4551,10 +4552,24 @@  static int process_extent(struct send_ctx *sctx,
 			}
 		}
 	}
+	/*
+	 * We need to make sure the transaction does not get committed
+	 * while we are walking backrefs on extent commit root.
+	 */
+	trans = btrfs_join_transaction(sctx->send_root);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto out;
+	}
 
 	ret = find_extent_clone(sctx, path, key->objectid, key->offset,
 			sctx->cur_inode_size, &found_clone);
-	if (ret != -ENOENT && ret < 0)
+	if (ret != -ENOENT && ret < 0) {
+		btrfs_end_transaction(trans, sctx->send_root);
+		goto out;
+	}
+	ret = btrfs_end_transaction(trans, sctx->send_root);
+	if (ret)
 		goto out;
 
 	ret = send_write_or_clone(sctx, path, key, found_clone);