diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 195 |
1 files changed, 111 insertions, 84 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 3775947429b2..aded3ef3d3d4 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -66,6 +66,16 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | static void free_inode_elem_list(struct extent_inode_elem *eie) | ||
70 | { | ||
71 | struct extent_inode_elem *eie_next; | ||
72 | |||
73 | for (; eie; eie = eie_next) { | ||
74 | eie_next = eie->next; | ||
75 | kfree(eie); | ||
76 | } | ||
77 | } | ||
78 | |||
69 | static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte, | 79 | static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte, |
70 | u64 extent_item_pos, | 80 | u64 extent_item_pos, |
71 | struct extent_inode_elem **eie) | 81 | struct extent_inode_elem **eie) |
@@ -209,18 +219,19 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, | |||
209 | } | 219 | } |
210 | 220 | ||
211 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | 221 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, |
212 | struct ulist *parents, int level, | 222 | struct ulist *parents, struct __prelim_ref *ref, |
213 | struct btrfs_key *key_for_search, u64 time_seq, | 223 | int level, u64 time_seq, const u64 *extent_item_pos) |
214 | u64 wanted_disk_byte, | ||
215 | const u64 *extent_item_pos) | ||
216 | { | 224 | { |
217 | int ret = 0; | 225 | int ret = 0; |
218 | int slot; | 226 | int slot; |
219 | struct extent_buffer *eb; | 227 | struct extent_buffer *eb; |
220 | struct btrfs_key key; | 228 | struct btrfs_key key; |
229 | struct btrfs_key *key_for_search = &ref->key_for_search; | ||
221 | struct btrfs_file_extent_item *fi; | 230 | struct btrfs_file_extent_item *fi; |
222 | struct extent_inode_elem *eie = NULL, *old = NULL; | 231 | struct extent_inode_elem *eie = NULL, *old = NULL; |
223 | u64 disk_byte; | 232 | u64 disk_byte; |
233 | u64 wanted_disk_byte = ref->wanted_disk_byte; | ||
234 | u64 count = 0; | ||
224 | 235 | ||
225 | if (level != 0) { | 236 | if (level != 0) { |
226 | eb = path->nodes[level]; | 237 | eb = path->nodes[level]; |
@@ -238,7 +249,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
238 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) | 249 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) |
239 | ret = btrfs_next_old_leaf(root, path, time_seq); | 250 | ret = btrfs_next_old_leaf(root, path, time_seq); |
240 | 251 | ||
241 | while (!ret) { | 252 | while (!ret && count < ref->count) { |
242 | eb = path->nodes[0]; | 253 | eb = path->nodes[0]; |
243 | slot = path->slots[0]; | 254 | slot = path->slots[0]; |
244 | 255 | ||
@@ -254,6 +265,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
254 | if (disk_byte == wanted_disk_byte) { | 265 | if (disk_byte == wanted_disk_byte) { |
255 | eie = NULL; | 266 | eie = NULL; |
256 | old = NULL; | 267 | old = NULL; |
268 | count++; | ||
257 | if (extent_item_pos) { | 269 | if (extent_item_pos) { |
258 | ret = check_extent_in_eb(&key, eb, fi, | 270 | ret = check_extent_in_eb(&key, eb, fi, |
259 | *extent_item_pos, | 271 | *extent_item_pos, |
@@ -273,6 +285,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
273 | old = old->next; | 285 | old = old->next; |
274 | old->next = eie; | 286 | old->next = eie; |
275 | } | 287 | } |
288 | eie = NULL; | ||
276 | } | 289 | } |
277 | next: | 290 | next: |
278 | ret = btrfs_next_old_item(root, path, time_seq); | 291 | ret = btrfs_next_old_item(root, path, time_seq); |
@@ -280,6 +293,8 @@ next: | |||
280 | 293 | ||
281 | if (ret > 0) | 294 | if (ret > 0) |
282 | ret = 0; | 295 | ret = 0; |
296 | else if (ret < 0) | ||
297 | free_inode_elem_list(eie); | ||
283 | return ret; | 298 | return ret; |
284 | } | 299 | } |
285 | 300 | ||
@@ -299,23 +314,34 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
299 | int ret = 0; | 314 | int ret = 0; |
300 | int root_level; | 315 | int root_level; |
301 | int level = ref->level; | 316 | int level = ref->level; |
317 | int index; | ||
302 | 318 | ||
303 | root_key.objectid = ref->root_id; | 319 | root_key.objectid = ref->root_id; |
304 | root_key.type = BTRFS_ROOT_ITEM_KEY; | 320 | root_key.type = BTRFS_ROOT_ITEM_KEY; |
305 | root_key.offset = (u64)-1; | 321 | root_key.offset = (u64)-1; |
322 | |||
323 | index = srcu_read_lock(&fs_info->subvol_srcu); | ||
324 | |||
306 | root = btrfs_read_fs_root_no_name(fs_info, &root_key); | 325 | root = btrfs_read_fs_root_no_name(fs_info, &root_key); |
307 | if (IS_ERR(root)) { | 326 | if (IS_ERR(root)) { |
327 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
308 | ret = PTR_ERR(root); | 328 | ret = PTR_ERR(root); |
309 | goto out; | 329 | goto out; |
310 | } | 330 | } |
311 | 331 | ||
312 | root_level = btrfs_old_root_level(root, time_seq); | 332 | root_level = btrfs_old_root_level(root, time_seq); |
313 | 333 | ||
314 | if (root_level + 1 == level) | 334 | if (root_level + 1 == level) { |
335 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
315 | goto out; | 336 | goto out; |
337 | } | ||
316 | 338 | ||
317 | path->lowest_level = level; | 339 | path->lowest_level = level; |
318 | ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq); | 340 | ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq); |
341 | |||
342 | /* root node has been locked, we can release @subvol_srcu safely here */ | ||
343 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
344 | |||
319 | pr_debug("search slot in root %llu (level %d, ref count %d) returned " | 345 | pr_debug("search slot in root %llu (level %d, ref count %d) returned " |
320 | "%d for key (%llu %u %llu)\n", | 346 | "%d for key (%llu %u %llu)\n", |
321 | ref->root_id, level, ref->count, ret, | 347 | ref->root_id, level, ref->count, ret, |
@@ -334,9 +360,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
334 | eb = path->nodes[level]; | 360 | eb = path->nodes[level]; |
335 | } | 361 | } |
336 | 362 | ||
337 | ret = add_all_parents(root, path, parents, level, &ref->key_for_search, | 363 | ret = add_all_parents(root, path, parents, ref, level, time_seq, |
338 | time_seq, ref->wanted_disk_byte, | 364 | extent_item_pos); |
339 | extent_item_pos); | ||
340 | out: | 365 | out: |
341 | path->lowest_level = 0; | 366 | path->lowest_level = 0; |
342 | btrfs_release_path(path); | 367 | btrfs_release_path(path); |
@@ -376,10 +401,16 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, | |||
376 | continue; | 401 | continue; |
377 | err = __resolve_indirect_ref(fs_info, path, time_seq, ref, | 402 | err = __resolve_indirect_ref(fs_info, path, time_seq, ref, |
378 | parents, extent_item_pos); | 403 | parents, extent_item_pos); |
379 | if (err == -ENOMEM) | 404 | /* |
380 | goto out; | 405 | * we can only tolerate ENOENT,otherwise,we should catch error |
381 | if (err) | 406 | * and return directly. |
407 | */ | ||
408 | if (err == -ENOENT) { | ||
382 | continue; | 409 | continue; |
410 | } else if (err) { | ||
411 | ret = err; | ||
412 | goto out; | ||
413 | } | ||
383 | 414 | ||
384 | /* we put the first parent into the ref at hand */ | 415 | /* we put the first parent into the ref at hand */ |
385 | ULIST_ITER_INIT(&uiter); | 416 | ULIST_ITER_INIT(&uiter); |
@@ -538,14 +569,13 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
538 | if (extent_op && extent_op->update_key) | 569 | if (extent_op && extent_op->update_key) |
539 | btrfs_disk_key_to_cpu(&op_key, &extent_op->key); | 570 | btrfs_disk_key_to_cpu(&op_key, &extent_op->key); |
540 | 571 | ||
541 | while ((n = rb_prev(n))) { | 572 | spin_lock(&head->lock); |
573 | n = rb_first(&head->ref_root); | ||
574 | while (n) { | ||
542 | struct btrfs_delayed_ref_node *node; | 575 | struct btrfs_delayed_ref_node *node; |
543 | node = rb_entry(n, struct btrfs_delayed_ref_node, | 576 | node = rb_entry(n, struct btrfs_delayed_ref_node, |
544 | rb_node); | 577 | rb_node); |
545 | if (node->bytenr != head->node.bytenr) | 578 | n = rb_next(n); |
546 | break; | ||
547 | WARN_ON(node->is_head); | ||
548 | |||
549 | if (node->seq > seq) | 579 | if (node->seq > seq) |
550 | continue; | 580 | continue; |
551 | 581 | ||
@@ -612,10 +642,10 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, | |||
612 | WARN_ON(1); | 642 | WARN_ON(1); |
613 | } | 643 | } |
614 | if (ret) | 644 | if (ret) |
615 | return ret; | 645 | break; |
616 | } | 646 | } |
617 | 647 | spin_unlock(&head->lock); | |
618 | return 0; | 648 | return ret; |
619 | } | 649 | } |
620 | 650 | ||
621 | /* | 651 | /* |
@@ -828,6 +858,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
828 | struct list_head prefs_delayed; | 858 | struct list_head prefs_delayed; |
829 | struct list_head prefs; | 859 | struct list_head prefs; |
830 | struct __prelim_ref *ref; | 860 | struct __prelim_ref *ref; |
861 | struct extent_inode_elem *eie = NULL; | ||
831 | 862 | ||
832 | INIT_LIST_HEAD(&prefs); | 863 | INIT_LIST_HEAD(&prefs); |
833 | INIT_LIST_HEAD(&prefs_delayed); | 864 | INIT_LIST_HEAD(&prefs_delayed); |
@@ -882,15 +913,15 @@ again: | |||
882 | btrfs_put_delayed_ref(&head->node); | 913 | btrfs_put_delayed_ref(&head->node); |
883 | goto again; | 914 | goto again; |
884 | } | 915 | } |
916 | spin_unlock(&delayed_refs->lock); | ||
885 | ret = __add_delayed_refs(head, time_seq, | 917 | ret = __add_delayed_refs(head, time_seq, |
886 | &prefs_delayed); | 918 | &prefs_delayed); |
887 | mutex_unlock(&head->mutex); | 919 | mutex_unlock(&head->mutex); |
888 | if (ret) { | 920 | if (ret) |
889 | spin_unlock(&delayed_refs->lock); | ||
890 | goto out; | 921 | goto out; |
891 | } | 922 | } else { |
923 | spin_unlock(&delayed_refs->lock); | ||
892 | } | 924 | } |
893 | spin_unlock(&delayed_refs->lock); | ||
894 | } | 925 | } |
895 | 926 | ||
896 | if (path->slots[0]) { | 927 | if (path->slots[0]) { |
@@ -941,7 +972,6 @@ again: | |||
941 | goto out; | 972 | goto out; |
942 | } | 973 | } |
943 | if (ref->count && ref->parent) { | 974 | if (ref->count && ref->parent) { |
944 | struct extent_inode_elem *eie = NULL; | ||
945 | if (extent_item_pos && !ref->inode_list) { | 975 | if (extent_item_pos && !ref->inode_list) { |
946 | u32 bsz; | 976 | u32 bsz; |
947 | struct extent_buffer *eb; | 977 | struct extent_buffer *eb; |
@@ -976,6 +1006,7 @@ again: | |||
976 | eie = eie->next; | 1006 | eie = eie->next; |
977 | eie->next = ref->inode_list; | 1007 | eie->next = ref->inode_list; |
978 | } | 1008 | } |
1009 | eie = NULL; | ||
979 | } | 1010 | } |
980 | list_del(&ref->list); | 1011 | list_del(&ref->list); |
981 | kmem_cache_free(btrfs_prelim_ref_cache, ref); | 1012 | kmem_cache_free(btrfs_prelim_ref_cache, ref); |
@@ -994,7 +1025,8 @@ out: | |||
994 | list_del(&ref->list); | 1025 | list_del(&ref->list); |
995 | kmem_cache_free(btrfs_prelim_ref_cache, ref); | 1026 | kmem_cache_free(btrfs_prelim_ref_cache, ref); |
996 | } | 1027 | } |
997 | 1028 | if (ret < 0) | |
1029 | free_inode_elem_list(eie); | ||
998 | return ret; | 1030 | return ret; |
999 | } | 1031 | } |
1000 | 1032 | ||
@@ -1002,7 +1034,6 @@ static void free_leaf_list(struct ulist *blocks) | |||
1002 | { | 1034 | { |
1003 | struct ulist_node *node = NULL; | 1035 | struct ulist_node *node = NULL; |
1004 | struct extent_inode_elem *eie; | 1036 | struct extent_inode_elem *eie; |
1005 | struct extent_inode_elem *eie_next; | ||
1006 | struct ulist_iterator uiter; | 1037 | struct ulist_iterator uiter; |
1007 | 1038 | ||
1008 | ULIST_ITER_INIT(&uiter); | 1039 | ULIST_ITER_INIT(&uiter); |
@@ -1010,10 +1041,7 @@ static void free_leaf_list(struct ulist *blocks) | |||
1010 | if (!node->aux) | 1041 | if (!node->aux) |
1011 | continue; | 1042 | continue; |
1012 | eie = (struct extent_inode_elem *)(uintptr_t)node->aux; | 1043 | eie = (struct extent_inode_elem *)(uintptr_t)node->aux; |
1013 | for (; eie; eie = eie_next) { | 1044 | free_inode_elem_list(eie); |
1014 | eie_next = eie->next; | ||
1015 | kfree(eie); | ||
1016 | } | ||
1017 | node->aux = 0; | 1045 | node->aux = 0; |
1018 | } | 1046 | } |
1019 | 1047 | ||
@@ -1101,44 +1129,13 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1101 | if (!node) | 1129 | if (!node) |
1102 | break; | 1130 | break; |
1103 | bytenr = node->val; | 1131 | bytenr = node->val; |
1132 | cond_resched(); | ||
1104 | } | 1133 | } |
1105 | 1134 | ||
1106 | ulist_free(tmp); | 1135 | ulist_free(tmp); |
1107 | return 0; | 1136 | return 0; |
1108 | } | 1137 | } |
1109 | 1138 | ||
1110 | |||
1111 | static int __inode_info(u64 inum, u64 ioff, u8 key_type, | ||
1112 | struct btrfs_root *fs_root, struct btrfs_path *path, | ||
1113 | struct btrfs_key *found_key) | ||
1114 | { | ||
1115 | int ret; | ||
1116 | struct btrfs_key key; | ||
1117 | struct extent_buffer *eb; | ||
1118 | |||
1119 | key.type = key_type; | ||
1120 | key.objectid = inum; | ||
1121 | key.offset = ioff; | ||
1122 | |||
1123 | ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); | ||
1124 | if (ret < 0) | ||
1125 | return ret; | ||
1126 | |||
1127 | eb = path->nodes[0]; | ||
1128 | if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { | ||
1129 | ret = btrfs_next_leaf(fs_root, path); | ||
1130 | if (ret) | ||
1131 | return ret; | ||
1132 | eb = path->nodes[0]; | ||
1133 | } | ||
1134 | |||
1135 | btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); | ||
1136 | if (found_key->type != key.type || found_key->objectid != key.objectid) | ||
1137 | return 1; | ||
1138 | |||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | /* | 1139 | /* |
1143 | * this makes the path point to (inum INODE_ITEM ioff) | 1140 | * this makes the path point to (inum INODE_ITEM ioff) |
1144 | */ | 1141 | */ |
@@ -1146,16 +1143,16 @@ int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, | |||
1146 | struct btrfs_path *path) | 1143 | struct btrfs_path *path) |
1147 | { | 1144 | { |
1148 | struct btrfs_key key; | 1145 | struct btrfs_key key; |
1149 | return __inode_info(inum, ioff, BTRFS_INODE_ITEM_KEY, fs_root, path, | 1146 | return btrfs_find_item(fs_root, path, inum, ioff, |
1150 | &key); | 1147 | BTRFS_INODE_ITEM_KEY, &key); |
1151 | } | 1148 | } |
1152 | 1149 | ||
1153 | static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, | 1150 | static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, |
1154 | struct btrfs_path *path, | 1151 | struct btrfs_path *path, |
1155 | struct btrfs_key *found_key) | 1152 | struct btrfs_key *found_key) |
1156 | { | 1153 | { |
1157 | return __inode_info(inum, ioff, BTRFS_INODE_REF_KEY, fs_root, path, | 1154 | return btrfs_find_item(fs_root, path, inum, ioff, |
1158 | found_key); | 1155 | BTRFS_INODE_REF_KEY, found_key); |
1159 | } | 1156 | } |
1160 | 1157 | ||
1161 | int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, | 1158 | int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, |
@@ -1335,20 +1332,45 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, | |||
1335 | ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); | 1332 | ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); |
1336 | if (ret < 0) | 1333 | if (ret < 0) |
1337 | return ret; | 1334 | return ret; |
1338 | ret = btrfs_previous_item(fs_info->extent_root, path, | ||
1339 | 0, BTRFS_EXTENT_ITEM_KEY); | ||
1340 | if (ret < 0) | ||
1341 | return ret; | ||
1342 | 1335 | ||
1343 | btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); | 1336 | while (1) { |
1337 | u32 nritems; | ||
1338 | if (path->slots[0] == 0) { | ||
1339 | btrfs_set_path_blocking(path); | ||
1340 | ret = btrfs_prev_leaf(fs_info->extent_root, path); | ||
1341 | if (ret != 0) { | ||
1342 | if (ret > 0) { | ||
1343 | pr_debug("logical %llu is not within " | ||
1344 | "any extent\n", logical); | ||
1345 | ret = -ENOENT; | ||
1346 | } | ||
1347 | return ret; | ||
1348 | } | ||
1349 | } else { | ||
1350 | path->slots[0]--; | ||
1351 | } | ||
1352 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
1353 | if (nritems == 0) { | ||
1354 | pr_debug("logical %llu is not within any extent\n", | ||
1355 | logical); | ||
1356 | return -ENOENT; | ||
1357 | } | ||
1358 | if (path->slots[0] == nritems) | ||
1359 | path->slots[0]--; | ||
1360 | |||
1361 | btrfs_item_key_to_cpu(path->nodes[0], found_key, | ||
1362 | path->slots[0]); | ||
1363 | if (found_key->type == BTRFS_EXTENT_ITEM_KEY || | ||
1364 | found_key->type == BTRFS_METADATA_ITEM_KEY) | ||
1365 | break; | ||
1366 | } | ||
1367 | |||
1344 | if (found_key->type == BTRFS_METADATA_ITEM_KEY) | 1368 | if (found_key->type == BTRFS_METADATA_ITEM_KEY) |
1345 | size = fs_info->extent_root->leafsize; | 1369 | size = fs_info->extent_root->leafsize; |
1346 | else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) | 1370 | else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) |
1347 | size = found_key->offset; | 1371 | size = found_key->offset; |
1348 | 1372 | ||
1349 | if ((found_key->type != BTRFS_EXTENT_ITEM_KEY && | 1373 | if (found_key->objectid > logical || |
1350 | found_key->type != BTRFS_METADATA_ITEM_KEY) || | ||
1351 | found_key->objectid > logical || | ||
1352 | found_key->objectid + size <= logical) { | 1374 | found_key->objectid + size <= logical) { |
1353 | pr_debug("logical %llu is not within any extent\n", logical); | 1375 | pr_debug("logical %llu is not within any extent\n", logical); |
1354 | return -ENOENT; | 1376 | return -ENOENT; |
@@ -1601,7 +1623,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, | |||
1601 | struct btrfs_key found_key; | 1623 | struct btrfs_key found_key; |
1602 | 1624 | ||
1603 | while (!ret) { | 1625 | while (!ret) { |
1604 | path->leave_spinning = 1; | ||
1605 | ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, | 1626 | ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, |
1606 | &found_key); | 1627 | &found_key); |
1607 | if (ret < 0) | 1628 | if (ret < 0) |
@@ -1614,9 +1635,12 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, | |||
1614 | 1635 | ||
1615 | parent = found_key.offset; | 1636 | parent = found_key.offset; |
1616 | slot = path->slots[0]; | 1637 | slot = path->slots[0]; |
1617 | eb = path->nodes[0]; | 1638 | eb = btrfs_clone_extent_buffer(path->nodes[0]); |
1618 | /* make sure we can use eb after releasing the path */ | 1639 | if (!eb) { |
1619 | atomic_inc(&eb->refs); | 1640 | ret = -ENOMEM; |
1641 | break; | ||
1642 | } | ||
1643 | extent_buffer_get(eb); | ||
1620 | btrfs_tree_read_lock(eb); | 1644 | btrfs_tree_read_lock(eb); |
1621 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); | 1645 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); |
1622 | btrfs_release_path(path); | 1646 | btrfs_release_path(path); |
@@ -1674,17 +1698,20 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, | |||
1674 | ++found; | 1698 | ++found; |
1675 | 1699 | ||
1676 | slot = path->slots[0]; | 1700 | slot = path->slots[0]; |
1677 | eb = path->nodes[0]; | 1701 | eb = btrfs_clone_extent_buffer(path->nodes[0]); |
1678 | /* make sure we can use eb after releasing the path */ | 1702 | if (!eb) { |
1679 | atomic_inc(&eb->refs); | 1703 | ret = -ENOMEM; |
1704 | break; | ||
1705 | } | ||
1706 | extent_buffer_get(eb); | ||
1680 | 1707 | ||
1681 | btrfs_tree_read_lock(eb); | 1708 | btrfs_tree_read_lock(eb); |
1682 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); | 1709 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); |
1683 | btrfs_release_path(path); | 1710 | btrfs_release_path(path); |
1684 | 1711 | ||
1685 | leaf = path->nodes[0]; | 1712 | leaf = path->nodes[0]; |
1686 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | 1713 | item_size = btrfs_item_size_nr(leaf, slot); |
1687 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | 1714 | ptr = btrfs_item_ptr_offset(leaf, slot); |
1688 | cur_offset = 0; | 1715 | cur_offset = 0; |
1689 | 1716 | ||
1690 | while (cur_offset < item_size) { | 1717 | while (cur_offset < item_size) { |