diff options
Diffstat (limited to 'fs/btrfs/backref.c')
| -rw-r--r-- | fs/btrfs/backref.c | 149 |
1 files changed, 75 insertions, 74 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 8f7d1237b7a0..a256f3b2a845 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
| @@ -179,61 +179,74 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, | |||
| 179 | 179 | ||
| 180 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | 180 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, |
| 181 | struct ulist *parents, int level, | 181 | struct ulist *parents, int level, |
| 182 | struct btrfs_key *key, u64 time_seq, | 182 | struct btrfs_key *key_for_search, u64 time_seq, |
| 183 | u64 wanted_disk_byte, | 183 | u64 wanted_disk_byte, |
| 184 | const u64 *extent_item_pos) | 184 | const u64 *extent_item_pos) |
| 185 | { | 185 | { |
| 186 | int ret; | 186 | int ret = 0; |
| 187 | int slot = path->slots[level]; | 187 | int slot; |
| 188 | struct extent_buffer *eb = path->nodes[level]; | 188 | struct extent_buffer *eb; |
| 189 | struct btrfs_key key; | ||
| 189 | struct btrfs_file_extent_item *fi; | 190 | struct btrfs_file_extent_item *fi; |
| 190 | struct extent_inode_elem *eie = NULL; | 191 | struct extent_inode_elem *eie = NULL; |
| 191 | u64 disk_byte; | 192 | u64 disk_byte; |
| 192 | u64 wanted_objectid = key->objectid; | ||
| 193 | 193 | ||
| 194 | add_parent: | 194 | if (level != 0) { |
| 195 | if (level == 0 && extent_item_pos) { | 195 | eb = path->nodes[level]; |
| 196 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); | 196 | ret = ulist_add(parents, eb->start, 0, GFP_NOFS); |
| 197 | ret = check_extent_in_eb(key, eb, fi, *extent_item_pos, &eie); | ||
| 198 | if (ret < 0) | 197 | if (ret < 0) |
| 199 | return ret; | 198 | return ret; |
| 200 | } | ||
| 201 | ret = ulist_add(parents, eb->start, (unsigned long)eie, GFP_NOFS); | ||
| 202 | if (ret < 0) | ||
| 203 | return ret; | ||
| 204 | |||
| 205 | if (level != 0) | ||
| 206 | return 0; | 199 | return 0; |
| 200 | } | ||
| 207 | 201 | ||
| 208 | /* | 202 | /* |
| 209 | * if the current leaf is full with EXTENT_DATA items, we must | 203 | * We normally enter this function with the path already pointing to |
| 210 | * check the next one if that holds a reference as well. | 204 | * the first item to check. But sometimes, we may enter it with |
| 211 | * ref->count cannot be used to skip this check. | 205 | * slot==nritems. In that case, go to the next leaf before we continue. |
| 212 | * repeat this until we don't find any additional EXTENT_DATA items. | ||
| 213 | */ | 206 | */ |
| 214 | while (1) { | 207 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) |
| 215 | eie = NULL; | ||
| 216 | ret = btrfs_next_old_leaf(root, path, time_seq); | 208 | ret = btrfs_next_old_leaf(root, path, time_seq); |
| 217 | if (ret < 0) | ||
| 218 | return ret; | ||
| 219 | if (ret) | ||
| 220 | return 0; | ||
| 221 | 209 | ||
| 210 | while (!ret) { | ||
| 222 | eb = path->nodes[0]; | 211 | eb = path->nodes[0]; |
| 223 | for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) { | 212 | slot = path->slots[0]; |
| 224 | btrfs_item_key_to_cpu(eb, key, slot); | 213 | |
| 225 | if (key->objectid != wanted_objectid || | 214 | btrfs_item_key_to_cpu(eb, &key, slot); |
| 226 | key->type != BTRFS_EXTENT_DATA_KEY) | 215 | |
| 227 | return 0; | 216 | if (key.objectid != key_for_search->objectid || |
| 228 | fi = btrfs_item_ptr(eb, slot, | 217 | key.type != BTRFS_EXTENT_DATA_KEY) |
| 229 | struct btrfs_file_extent_item); | 218 | break; |
| 230 | disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); | 219 | |
| 231 | if (disk_byte == wanted_disk_byte) | 220 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); |
| 232 | goto add_parent; | 221 | disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); |
| 222 | |||
| 223 | if (disk_byte == wanted_disk_byte) { | ||
| 224 | eie = NULL; | ||
| 225 | if (extent_item_pos) { | ||
| 226 | ret = check_extent_in_eb(&key, eb, fi, | ||
| 227 | *extent_item_pos, | ||
| 228 | &eie); | ||
| 229 | if (ret < 0) | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | if (!ret) { | ||
| 233 | ret = ulist_add(parents, eb->start, | ||
| 234 | (unsigned long)eie, GFP_NOFS); | ||
| 235 | if (ret < 0) | ||
| 236 | break; | ||
| 237 | if (!extent_item_pos) { | ||
| 238 | ret = btrfs_next_old_leaf(root, path, | ||
| 239 | time_seq); | ||
| 240 | continue; | ||
| 241 | } | ||
| 242 | } | ||
| 233 | } | 243 | } |
| 244 | ret = btrfs_next_old_item(root, path, time_seq); | ||
| 234 | } | 245 | } |
| 235 | 246 | ||
| 236 | return 0; | 247 | if (ret > 0) |
| 248 | ret = 0; | ||
| 249 | return ret; | ||
| 237 | } | 250 | } |
| 238 | 251 | ||
| 239 | /* | 252 | /* |
| @@ -250,7 +263,6 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
| 250 | struct btrfs_path *path; | 263 | struct btrfs_path *path; |
| 251 | struct btrfs_root *root; | 264 | struct btrfs_root *root; |
| 252 | struct btrfs_key root_key; | 265 | struct btrfs_key root_key; |
| 253 | struct btrfs_key key = {0}; | ||
| 254 | struct extent_buffer *eb; | 266 | struct extent_buffer *eb; |
| 255 | int ret = 0; | 267 | int ret = 0; |
| 256 | int root_level; | 268 | int root_level; |
| @@ -289,17 +301,19 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
| 289 | goto out; | 301 | goto out; |
| 290 | 302 | ||
| 291 | eb = path->nodes[level]; | 303 | eb = path->nodes[level]; |
| 292 | if (!eb) { | 304 | while (!eb) { |
| 293 | WARN_ON(1); | 305 | if (!level) { |
| 294 | ret = 1; | 306 | WARN_ON(1); |
| 295 | goto out; | 307 | ret = 1; |
| 308 | goto out; | ||
| 309 | } | ||
| 310 | level--; | ||
| 311 | eb = path->nodes[level]; | ||
| 296 | } | 312 | } |
| 297 | 313 | ||
| 298 | if (level == 0) | 314 | ret = add_all_parents(root, path, parents, level, &ref->key_for_search, |
| 299 | btrfs_item_key_to_cpu(eb, &key, path->slots[0]); | 315 | time_seq, ref->wanted_disk_byte, |
| 300 | 316 | extent_item_pos); | |
| 301 | ret = add_all_parents(root, path, parents, level, &key, time_seq, | ||
| 302 | ref->wanted_disk_byte, extent_item_pos); | ||
| 303 | out: | 317 | out: |
| 304 | btrfs_free_path(path); | 318 | btrfs_free_path(path); |
| 305 | return ret; | 319 | return ret; |
| @@ -759,9 +773,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
| 759 | */ | 773 | */ |
| 760 | static int find_parent_nodes(struct btrfs_trans_handle *trans, | 774 | static int find_parent_nodes(struct btrfs_trans_handle *trans, |
| 761 | struct btrfs_fs_info *fs_info, u64 bytenr, | 775 | struct btrfs_fs_info *fs_info, u64 bytenr, |
| 762 | u64 delayed_ref_seq, u64 time_seq, | 776 | u64 time_seq, struct ulist *refs, |
| 763 | struct ulist *refs, struct ulist *roots, | 777 | struct ulist *roots, const u64 *extent_item_pos) |
| 764 | const u64 *extent_item_pos) | ||
| 765 | { | 778 | { |
| 766 | struct btrfs_key key; | 779 | struct btrfs_key key; |
| 767 | struct btrfs_path *path; | 780 | struct btrfs_path *path; |
| @@ -823,8 +836,9 @@ again: | |||
| 823 | btrfs_put_delayed_ref(&head->node); | 836 | btrfs_put_delayed_ref(&head->node); |
| 824 | goto again; | 837 | goto again; |
| 825 | } | 838 | } |
| 826 | ret = __add_delayed_refs(head, delayed_ref_seq, | 839 | ret = __add_delayed_refs(head, time_seq, |
| 827 | &prefs_delayed); | 840 | &prefs_delayed); |
| 841 | mutex_unlock(&head->mutex); | ||
| 828 | if (ret) { | 842 | if (ret) { |
| 829 | spin_unlock(&delayed_refs->lock); | 843 | spin_unlock(&delayed_refs->lock); |
| 830 | goto out; | 844 | goto out; |
| @@ -918,8 +932,6 @@ again: | |||
| 918 | } | 932 | } |
| 919 | 933 | ||
| 920 | out: | 934 | out: |
| 921 | if (head) | ||
| 922 | mutex_unlock(&head->mutex); | ||
| 923 | btrfs_free_path(path); | 935 | btrfs_free_path(path); |
| 924 | while (!list_empty(&prefs)) { | 936 | while (!list_empty(&prefs)) { |
| 925 | ref = list_first_entry(&prefs, struct __prelim_ref, list); | 937 | ref = list_first_entry(&prefs, struct __prelim_ref, list); |
| @@ -968,8 +980,7 @@ static void free_leaf_list(struct ulist *blocks) | |||
| 968 | */ | 980 | */ |
| 969 | static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | 981 | static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, |
| 970 | struct btrfs_fs_info *fs_info, u64 bytenr, | 982 | struct btrfs_fs_info *fs_info, u64 bytenr, |
| 971 | u64 delayed_ref_seq, u64 time_seq, | 983 | u64 time_seq, struct ulist **leafs, |
| 972 | struct ulist **leafs, | ||
| 973 | const u64 *extent_item_pos) | 984 | const u64 *extent_item_pos) |
| 974 | { | 985 | { |
| 975 | struct ulist *tmp; | 986 | struct ulist *tmp; |
| @@ -984,7 +995,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | |||
| 984 | return -ENOMEM; | 995 | return -ENOMEM; |
| 985 | } | 996 | } |
| 986 | 997 | ||
| 987 | ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq, | 998 | ret = find_parent_nodes(trans, fs_info, bytenr, |
| 988 | time_seq, *leafs, tmp, extent_item_pos); | 999 | time_seq, *leafs, tmp, extent_item_pos); |
| 989 | ulist_free(tmp); | 1000 | ulist_free(tmp); |
| 990 | 1001 | ||
| @@ -1011,8 +1022,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, | |||
| 1011 | */ | 1022 | */ |
| 1012 | int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | 1023 | int btrfs_find_all_roots(struct btrfs_trans_handle *trans, |
| 1013 | struct btrfs_fs_info *fs_info, u64 bytenr, | 1024 | struct btrfs_fs_info *fs_info, u64 bytenr, |
| 1014 | u64 delayed_ref_seq, u64 time_seq, | 1025 | u64 time_seq, struct ulist **roots) |
| 1015 | struct ulist **roots) | ||
| 1016 | { | 1026 | { |
| 1017 | struct ulist *tmp; | 1027 | struct ulist *tmp; |
| 1018 | struct ulist_node *node = NULL; | 1028 | struct ulist_node *node = NULL; |
| @@ -1030,7 +1040,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
| 1030 | 1040 | ||
| 1031 | ULIST_ITER_INIT(&uiter); | 1041 | ULIST_ITER_INIT(&uiter); |
| 1032 | while (1) { | 1042 | while (1) { |
| 1033 | ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq, | 1043 | ret = find_parent_nodes(trans, fs_info, bytenr, |
| 1034 | time_seq, tmp, *roots, NULL); | 1044 | time_seq, tmp, *roots, NULL); |
| 1035 | if (ret < 0 && ret != -ENOENT) { | 1045 | if (ret < 0 && ret != -ENOENT) { |
| 1036 | ulist_free(tmp); | 1046 | ulist_free(tmp); |
| @@ -1112,10 +1122,10 @@ static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, | |||
| 1112 | * required for the path to fit into the buffer. in that case, the returned | 1122 | * required for the path to fit into the buffer. in that case, the returned |
| 1113 | * value will be smaller than dest. callers must check this! | 1123 | * value will be smaller than dest. callers must check this! |
| 1114 | */ | 1124 | */ |
| 1115 | static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | 1125 | char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, |
| 1116 | struct btrfs_inode_ref *iref, | 1126 | struct btrfs_inode_ref *iref, |
| 1117 | struct extent_buffer *eb_in, u64 parent, | 1127 | struct extent_buffer *eb_in, u64 parent, |
| 1118 | char *dest, u32 size) | 1128 | char *dest, u32 size) |
| 1119 | { | 1129 | { |
| 1120 | u32 len; | 1130 | u32 len; |
| 1121 | int slot; | 1131 | int slot; |
| @@ -1363,11 +1373,9 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
| 1363 | struct ulist *roots = NULL; | 1373 | struct ulist *roots = NULL; |
| 1364 | struct ulist_node *ref_node = NULL; | 1374 | struct ulist_node *ref_node = NULL; |
| 1365 | struct ulist_node *root_node = NULL; | 1375 | struct ulist_node *root_node = NULL; |
| 1366 | struct seq_list seq_elem = {}; | ||
| 1367 | struct seq_list tree_mod_seq_elem = {}; | 1376 | struct seq_list tree_mod_seq_elem = {}; |
| 1368 | struct ulist_iterator ref_uiter; | 1377 | struct ulist_iterator ref_uiter; |
| 1369 | struct ulist_iterator root_uiter; | 1378 | struct ulist_iterator root_uiter; |
| 1370 | struct btrfs_delayed_ref_root *delayed_refs = NULL; | ||
| 1371 | 1379 | ||
| 1372 | pr_debug("resolving all inodes for extent %llu\n", | 1380 | pr_debug("resolving all inodes for extent %llu\n", |
| 1373 | extent_item_objectid); | 1381 | extent_item_objectid); |
| @@ -1378,16 +1386,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
| 1378 | trans = btrfs_join_transaction(fs_info->extent_root); | 1386 | trans = btrfs_join_transaction(fs_info->extent_root); |
| 1379 | if (IS_ERR(trans)) | 1387 | if (IS_ERR(trans)) |
| 1380 | return PTR_ERR(trans); | 1388 | return PTR_ERR(trans); |
| 1381 | |||
| 1382 | delayed_refs = &trans->transaction->delayed_refs; | ||
| 1383 | spin_lock(&delayed_refs->lock); | ||
| 1384 | btrfs_get_delayed_seq(delayed_refs, &seq_elem); | ||
| 1385 | spin_unlock(&delayed_refs->lock); | ||
| 1386 | btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); | 1389 | btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); |
| 1387 | } | 1390 | } |
| 1388 | 1391 | ||
| 1389 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, | 1392 | ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, |
| 1390 | seq_elem.seq, tree_mod_seq_elem.seq, &refs, | 1393 | tree_mod_seq_elem.seq, &refs, |
| 1391 | &extent_item_pos); | 1394 | &extent_item_pos); |
| 1392 | if (ret) | 1395 | if (ret) |
| 1393 | goto out; | 1396 | goto out; |
| @@ -1395,8 +1398,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
| 1395 | ULIST_ITER_INIT(&ref_uiter); | 1398 | ULIST_ITER_INIT(&ref_uiter); |
| 1396 | while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { | 1399 | while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { |
| 1397 | ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, | 1400 | ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, |
| 1398 | seq_elem.seq, | 1401 | tree_mod_seq_elem.seq, &roots); |
| 1399 | tree_mod_seq_elem.seq, &roots); | ||
| 1400 | if (ret) | 1402 | if (ret) |
| 1401 | break; | 1403 | break; |
| 1402 | ULIST_ITER_INIT(&root_uiter); | 1404 | ULIST_ITER_INIT(&root_uiter); |
| @@ -1418,7 +1420,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, | |||
| 1418 | out: | 1420 | out: |
| 1419 | if (!search_commit_root) { | 1421 | if (!search_commit_root) { |
| 1420 | btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); | 1422 | btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); |
| 1421 | btrfs_put_delayed_seq(delayed_refs, &seq_elem); | ||
| 1422 | btrfs_end_transaction(trans, fs_info->extent_root); | 1423 | btrfs_end_transaction(trans, fs_info->extent_root); |
| 1423 | } | 1424 | } |
| 1424 | 1425 | ||
| @@ -1530,7 +1531,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, | |||
| 1530 | ipath->fspath->bytes_left - s_ptr : 0; | 1531 | ipath->fspath->bytes_left - s_ptr : 0; |
| 1531 | 1532 | ||
| 1532 | fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; | 1533 | fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; |
| 1533 | fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb, | 1534 | fspath = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb, |
| 1534 | inum, fspath_min, bytes_left); | 1535 | inum, fspath_min, bytes_left); |
| 1535 | if (IS_ERR(fspath)) | 1536 | if (IS_ERR(fspath)) |
| 1536 | return PTR_ERR(fspath); | 1537 | return PTR_ERR(fspath); |
