diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 117 |
1 files changed, 42 insertions, 75 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 9b6da9d55f9a..1ac3ca98c429 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -493,6 +493,7 @@ static struct btrfs_path *alloc_path_for_send(void) | |||
493 | return NULL; | 493 | return NULL; |
494 | path->search_commit_root = 1; | 494 | path->search_commit_root = 1; |
495 | path->skip_locking = 1; | 495 | path->skip_locking = 1; |
496 | path->need_commit_sem = 1; | ||
496 | return path; | 497 | return path; |
497 | } | 498 | } |
498 | 499 | ||
@@ -771,29 +772,22 @@ out: | |||
771 | /* | 772 | /* |
772 | * Helper function to retrieve some fields from an inode item. | 773 | * Helper function to retrieve some fields from an inode item. |
773 | */ | 774 | */ |
774 | static int get_inode_info(struct btrfs_root *root, | 775 | static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path, |
775 | u64 ino, u64 *size, u64 *gen, | 776 | u64 ino, u64 *size, u64 *gen, u64 *mode, u64 *uid, |
776 | u64 *mode, u64 *uid, u64 *gid, | 777 | u64 *gid, u64 *rdev) |
777 | u64 *rdev) | ||
778 | { | 778 | { |
779 | int ret; | 779 | int ret; |
780 | struct btrfs_inode_item *ii; | 780 | struct btrfs_inode_item *ii; |
781 | struct btrfs_key key; | 781 | struct btrfs_key key; |
782 | struct btrfs_path *path; | ||
783 | |||
784 | path = alloc_path_for_send(); | ||
785 | if (!path) | ||
786 | return -ENOMEM; | ||
787 | 782 | ||
788 | key.objectid = ino; | 783 | key.objectid = ino; |
789 | key.type = BTRFS_INODE_ITEM_KEY; | 784 | key.type = BTRFS_INODE_ITEM_KEY; |
790 | key.offset = 0; | 785 | key.offset = 0; |
791 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 786 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
792 | if (ret < 0) | ||
793 | goto out; | ||
794 | if (ret) { | 787 | if (ret) { |
795 | ret = -ENOENT; | 788 | if (ret > 0) |
796 | goto out; | 789 | ret = -ENOENT; |
790 | return ret; | ||
797 | } | 791 | } |
798 | 792 | ||
799 | ii = btrfs_item_ptr(path->nodes[0], path->slots[0], | 793 | ii = btrfs_item_ptr(path->nodes[0], path->slots[0], |
@@ -811,7 +805,22 @@ static int get_inode_info(struct btrfs_root *root, | |||
811 | if (rdev) | 805 | if (rdev) |
812 | *rdev = btrfs_inode_rdev(path->nodes[0], ii); | 806 | *rdev = btrfs_inode_rdev(path->nodes[0], ii); |
813 | 807 | ||
814 | out: | 808 | return ret; |
809 | } | ||
810 | |||
811 | static int get_inode_info(struct btrfs_root *root, | ||
812 | u64 ino, u64 *size, u64 *gen, | ||
813 | u64 *mode, u64 *uid, u64 *gid, | ||
814 | u64 *rdev) | ||
815 | { | ||
816 | struct btrfs_path *path; | ||
817 | int ret; | ||
818 | |||
819 | path = alloc_path_for_send(); | ||
820 | if (!path) | ||
821 | return -ENOMEM; | ||
822 | ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid, | ||
823 | rdev); | ||
815 | btrfs_free_path(path); | 824 | btrfs_free_path(path); |
816 | return ret; | 825 | return ret; |
817 | } | 826 | } |
@@ -1085,6 +1094,7 @@ out: | |||
1085 | struct backref_ctx { | 1094 | struct backref_ctx { |
1086 | struct send_ctx *sctx; | 1095 | struct send_ctx *sctx; |
1087 | 1096 | ||
1097 | struct btrfs_path *path; | ||
1088 | /* number of total found references */ | 1098 | /* number of total found references */ |
1089 | u64 found; | 1099 | u64 found; |
1090 | 1100 | ||
@@ -1155,8 +1165,9 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_) | |||
1155 | * There are inodes that have extents that lie behind its i_size. Don't | 1165 | * There are inodes that have extents that lie behind its i_size. Don't |
1156 | * accept clones from these extents. | 1166 | * accept clones from these extents. |
1157 | */ | 1167 | */ |
1158 | ret = get_inode_info(found->root, ino, &i_size, NULL, NULL, NULL, NULL, | 1168 | ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, NULL, |
1159 | NULL); | 1169 | NULL, NULL, NULL); |
1170 | btrfs_release_path(bctx->path); | ||
1160 | if (ret < 0) | 1171 | if (ret < 0) |
1161 | return ret; | 1172 | return ret; |
1162 | 1173 | ||
@@ -1235,12 +1246,17 @@ static int find_extent_clone(struct send_ctx *sctx, | |||
1235 | if (!tmp_path) | 1246 | if (!tmp_path) |
1236 | return -ENOMEM; | 1247 | return -ENOMEM; |
1237 | 1248 | ||
1249 | /* We only use this path under the commit sem */ | ||
1250 | tmp_path->need_commit_sem = 0; | ||
1251 | |||
1238 | backref_ctx = kmalloc(sizeof(*backref_ctx), GFP_NOFS); | 1252 | backref_ctx = kmalloc(sizeof(*backref_ctx), GFP_NOFS); |
1239 | if (!backref_ctx) { | 1253 | if (!backref_ctx) { |
1240 | ret = -ENOMEM; | 1254 | ret = -ENOMEM; |
1241 | goto out; | 1255 | goto out; |
1242 | } | 1256 | } |
1243 | 1257 | ||
1258 | backref_ctx->path = tmp_path; | ||
1259 | |||
1244 | if (data_offset >= ino_size) { | 1260 | if (data_offset >= ino_size) { |
1245 | /* | 1261 | /* |
1246 | * There may be extents that lie behind the file's size. | 1262 | * There may be extents that lie behind the file's size. |
@@ -1268,8 +1284,10 @@ static int find_extent_clone(struct send_ctx *sctx, | |||
1268 | } | 1284 | } |
1269 | logical = disk_byte + btrfs_file_extent_offset(eb, fi); | 1285 | logical = disk_byte + btrfs_file_extent_offset(eb, fi); |
1270 | 1286 | ||
1287 | down_read(&sctx->send_root->fs_info->commit_root_sem); | ||
1271 | ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path, | 1288 | ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path, |
1272 | &found_key, &flags); | 1289 | &found_key, &flags); |
1290 | up_read(&sctx->send_root->fs_info->commit_root_sem); | ||
1273 | btrfs_release_path(tmp_path); | 1291 | btrfs_release_path(tmp_path); |
1274 | 1292 | ||
1275 | if (ret < 0) | 1293 | if (ret < 0) |
@@ -4418,6 +4436,9 @@ static int send_hole(struct send_ctx *sctx, u64 end) | |||
4418 | p = fs_path_alloc(); | 4436 | p = fs_path_alloc(); |
4419 | if (!p) | 4437 | if (!p) |
4420 | return -ENOMEM; | 4438 | return -ENOMEM; |
4439 | ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); | ||
4440 | if (ret < 0) | ||
4441 | goto tlv_put_failure; | ||
4421 | memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE); | 4442 | memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE); |
4422 | while (offset < end) { | 4443 | while (offset < end) { |
4423 | len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE); | 4444 | len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE); |
@@ -4425,9 +4446,6 @@ static int send_hole(struct send_ctx *sctx, u64 end) | |||
4425 | ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); | 4446 | ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); |
4426 | if (ret < 0) | 4447 | if (ret < 0) |
4427 | break; | 4448 | break; |
4428 | ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); | ||
4429 | if (ret < 0) | ||
4430 | break; | ||
4431 | TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); | 4449 | TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); |
4432 | TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); | 4450 | TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); |
4433 | TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len); | 4451 | TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len); |
@@ -4968,7 +4986,9 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) | |||
4968 | 4986 | ||
4969 | if (S_ISREG(sctx->cur_inode_mode)) { | 4987 | if (S_ISREG(sctx->cur_inode_mode)) { |
4970 | if (need_send_hole(sctx)) { | 4988 | if (need_send_hole(sctx)) { |
4971 | if (sctx->cur_inode_last_extent == (u64)-1) { | 4989 | if (sctx->cur_inode_last_extent == (u64)-1 || |
4990 | sctx->cur_inode_last_extent < | ||
4991 | sctx->cur_inode_size) { | ||
4972 | ret = get_last_extent(sctx, (u64)-1); | 4992 | ret = get_last_extent(sctx, (u64)-1); |
4973 | if (ret) | 4993 | if (ret) |
4974 | goto out; | 4994 | goto out; |
@@ -5367,57 +5387,21 @@ out: | |||
5367 | static int full_send_tree(struct send_ctx *sctx) | 5387 | static int full_send_tree(struct send_ctx *sctx) |
5368 | { | 5388 | { |
5369 | int ret; | 5389 | int ret; |
5370 | struct btrfs_trans_handle *trans = NULL; | ||
5371 | struct btrfs_root *send_root = sctx->send_root; | 5390 | struct btrfs_root *send_root = sctx->send_root; |
5372 | struct btrfs_key key; | 5391 | struct btrfs_key key; |
5373 | struct btrfs_key found_key; | 5392 | struct btrfs_key found_key; |
5374 | struct btrfs_path *path; | 5393 | struct btrfs_path *path; |
5375 | struct extent_buffer *eb; | 5394 | struct extent_buffer *eb; |
5376 | int slot; | 5395 | int slot; |
5377 | u64 start_ctransid; | ||
5378 | u64 ctransid; | ||
5379 | 5396 | ||
5380 | path = alloc_path_for_send(); | 5397 | path = alloc_path_for_send(); |
5381 | if (!path) | 5398 | if (!path) |
5382 | return -ENOMEM; | 5399 | return -ENOMEM; |
5383 | 5400 | ||
5384 | spin_lock(&send_root->root_item_lock); | ||
5385 | start_ctransid = btrfs_root_ctransid(&send_root->root_item); | ||
5386 | spin_unlock(&send_root->root_item_lock); | ||
5387 | |||
5388 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; | 5401 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; |
5389 | key.type = BTRFS_INODE_ITEM_KEY; | 5402 | key.type = BTRFS_INODE_ITEM_KEY; |
5390 | key.offset = 0; | 5403 | key.offset = 0; |
5391 | 5404 | ||
5392 | join_trans: | ||
5393 | /* | ||
5394 | * We need to make sure the transaction does not get committed | ||
5395 | * while we do anything on commit roots. Join a transaction to prevent | ||
5396 | * this. | ||
5397 | */ | ||
5398 | trans = btrfs_join_transaction(send_root); | ||
5399 | if (IS_ERR(trans)) { | ||
5400 | ret = PTR_ERR(trans); | ||
5401 | trans = NULL; | ||
5402 | goto out; | ||
5403 | } | ||
5404 | |||
5405 | /* | ||
5406 | * Make sure the tree has not changed after re-joining. We detect this | ||
5407 | * by comparing start_ctransid and ctransid. They should always match. | ||
5408 | */ | ||
5409 | spin_lock(&send_root->root_item_lock); | ||
5410 | ctransid = btrfs_root_ctransid(&send_root->root_item); | ||
5411 | spin_unlock(&send_root->root_item_lock); | ||
5412 | |||
5413 | if (ctransid != start_ctransid) { | ||
5414 | WARN(1, KERN_WARNING "BTRFS: the root that you're trying to " | ||
5415 | "send was modified in between. This is " | ||
5416 | "probably a bug.\n"); | ||
5417 | ret = -EIO; | ||
5418 | goto out; | ||
5419 | } | ||
5420 | |||
5421 | ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); | 5405 | ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); |
5422 | if (ret < 0) | 5406 | if (ret < 0) |
5423 | goto out; | 5407 | goto out; |
@@ -5425,19 +5409,6 @@ join_trans: | |||
5425 | goto out_finish; | 5409 | goto out_finish; |
5426 | 5410 | ||
5427 | while (1) { | 5411 | while (1) { |
5428 | /* | ||
5429 | * When someone want to commit while we iterate, end the | ||
5430 | * joined transaction and rejoin. | ||
5431 | */ | ||
5432 | if (btrfs_should_end_transaction(trans, send_root)) { | ||
5433 | ret = btrfs_end_transaction(trans, send_root); | ||
5434 | trans = NULL; | ||
5435 | if (ret < 0) | ||
5436 | goto out; | ||
5437 | btrfs_release_path(path); | ||
5438 | goto join_trans; | ||
5439 | } | ||
5440 | |||
5441 | eb = path->nodes[0]; | 5412 | eb = path->nodes[0]; |
5442 | slot = path->slots[0]; | 5413 | slot = path->slots[0]; |
5443 | btrfs_item_key_to_cpu(eb, &found_key, slot); | 5414 | btrfs_item_key_to_cpu(eb, &found_key, slot); |
@@ -5465,12 +5436,6 @@ out_finish: | |||
5465 | 5436 | ||
5466 | out: | 5437 | out: |
5467 | btrfs_free_path(path); | 5438 | btrfs_free_path(path); |
5468 | if (trans) { | ||
5469 | if (!ret) | ||
5470 | ret = btrfs_end_transaction(trans, send_root); | ||
5471 | else | ||
5472 | btrfs_end_transaction(trans, send_root); | ||
5473 | } | ||
5474 | return ret; | 5439 | return ret; |
5475 | } | 5440 | } |
5476 | 5441 | ||
@@ -5718,7 +5683,9 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
5718 | NULL); | 5683 | NULL); |
5719 | sort_clone_roots = 1; | 5684 | sort_clone_roots = 1; |
5720 | 5685 | ||
5686 | current->journal_info = (void *)BTRFS_SEND_TRANS_STUB; | ||
5721 | ret = send_subvol(sctx); | 5687 | ret = send_subvol(sctx); |
5688 | current->journal_info = NULL; | ||
5722 | if (ret < 0) | 5689 | if (ret < 0) |
5723 | goto out; | 5690 | goto out; |
5724 | 5691 | ||