diff options
-rw-r--r-- | fs/btrfs/ctree.c | 6 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/send.c | 48 |
3 files changed, 39 insertions, 16 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9d89c1648e8e..1bcfcdb23cf4 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -2769,9 +2769,13 @@ again: | |||
2769 | * the commit roots are read only | 2769 | * the commit roots are read only |
2770 | * so we always do read locks | 2770 | * so we always do read locks |
2771 | */ | 2771 | */ |
2772 | if (p->need_commit_sem) | ||
2773 | down_read(&root->fs_info->commit_root_sem); | ||
2772 | b = root->commit_root; | 2774 | b = root->commit_root; |
2773 | extent_buffer_get(b); | 2775 | extent_buffer_get(b); |
2774 | level = btrfs_header_level(b); | 2776 | level = btrfs_header_level(b); |
2777 | if (p->need_commit_sem) | ||
2778 | up_read(&root->fs_info->commit_root_sem); | ||
2775 | if (!p->skip_locking) | 2779 | if (!p->skip_locking) |
2776 | btrfs_tree_read_lock(b); | 2780 | btrfs_tree_read_lock(b); |
2777 | } else { | 2781 | } else { |
@@ -5436,6 +5440,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5436 | * the right if possible or go up and right. | 5440 | * the right if possible or go up and right. |
5437 | */ | 5441 | */ |
5438 | 5442 | ||
5443 | down_read(&left_root->fs_info->commit_root_sem); | ||
5439 | left_level = btrfs_header_level(left_root->commit_root); | 5444 | left_level = btrfs_header_level(left_root->commit_root); |
5440 | left_root_level = left_level; | 5445 | left_root_level = left_level; |
5441 | left_path->nodes[left_level] = left_root->commit_root; | 5446 | left_path->nodes[left_level] = left_root->commit_root; |
@@ -5445,6 +5450,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root, | |||
5445 | right_root_level = right_level; | 5450 | right_root_level = right_level; |
5446 | right_path->nodes[right_level] = right_root->commit_root; | 5451 | right_path->nodes[right_level] = right_root->commit_root; |
5447 | extent_buffer_get(right_path->nodes[right_level]); | 5452 | extent_buffer_get(right_path->nodes[right_level]); |
5453 | up_read(&left_root->fs_info->commit_root_sem); | ||
5448 | 5454 | ||
5449 | if (left_level == 0) | 5455 | if (left_level == 0) |
5450 | btrfs_item_key_to_cpu(left_path->nodes[left_level], | 5456 | btrfs_item_key_to_cpu(left_path->nodes[left_level], |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4253ab257c9c..d8a669ed5506 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -609,6 +609,7 @@ struct btrfs_path { | |||
609 | unsigned int skip_locking:1; | 609 | unsigned int skip_locking:1; |
610 | unsigned int leave_spinning:1; | 610 | unsigned int leave_spinning:1; |
611 | unsigned int search_commit_root:1; | 611 | unsigned int search_commit_root:1; |
612 | unsigned int need_commit_sem:1; | ||
612 | }; | 613 | }; |
613 | 614 | ||
614 | /* | 615 | /* |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 6b5f13659317..ab34a23838ef 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. |