aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/backref.c
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-17 10:43:03 -0400
committerJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-26 06:17:52 -0400
commit976b1908d97bd8cbd024ba7aafaa3fb637ea8e13 (patch)
tree77d53f8b40ea6a1692fbf93bdc2bbc0daf01e85c /fs/btrfs/backref.c
parentd5c88b735fdf2ef796bb937396dd58dac84e8407 (diff)
Btrfs: look into the extent during find_all_leafs
Before this patch we called find_all_leafs for a data extent, then called find_all_roots and then looked into the extent to grab the information we were seeking. This was done without holding the leaves locked to avoid deadlocks. However, this can obviouly race with concurrent tree modifications. Instead, we now look into the extent while we're holding the lock during find_all_leafs and store this information together with the leaf list. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r--fs/btrfs/backref.c240
1 files changed, 157 insertions, 83 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 366978c5cdd3..fd13101aafa3 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -24,6 +24,79 @@
24#include "delayed-ref.h" 24#include "delayed-ref.h"
25#include "locking.h" 25#include "locking.h"
26 26
27struct extent_inode_elem {
28 u64 inum;
29 u64 offset;
30 struct extent_inode_elem *next;
31};
32
33static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
34 struct btrfs_file_extent_item *fi,
35 u64 extent_item_pos,
36 struct extent_inode_elem **eie)
37{
38 u64 data_offset;
39 u64 data_len;
40 struct extent_inode_elem *e;
41
42 data_offset = btrfs_file_extent_offset(eb, fi);
43 data_len = btrfs_file_extent_num_bytes(eb, fi);
44
45 if (extent_item_pos < data_offset ||
46 extent_item_pos >= data_offset + data_len)
47 return 1;
48
49 e = kmalloc(sizeof(*e), GFP_NOFS);
50 if (!e)
51 return -ENOMEM;
52
53 e->next = *eie;
54 e->inum = key->objectid;
55 e->offset = key->offset + (extent_item_pos - data_offset);
56 *eie = e;
57
58 return 0;
59}
60
61static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,
62 u64 extent_item_pos,
63 struct extent_inode_elem **eie)
64{
65 u64 disk_byte;
66 struct btrfs_key key;
67 struct btrfs_file_extent_item *fi;
68 int slot;
69 int nritems;
70 int extent_type;
71 int ret;
72
73 /*
74 * from the shared data ref, we only have the leaf but we need
75 * the key. thus, we must look into all items and see that we
76 * find one (some) with a reference to our extent item.
77 */
78 nritems = btrfs_header_nritems(eb);
79 for (slot = 0; slot < nritems; ++slot) {
80 btrfs_item_key_to_cpu(eb, &key, slot);
81 if (key.type != BTRFS_EXTENT_DATA_KEY)
82 continue;
83 fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
84 extent_type = btrfs_file_extent_type(eb, fi);
85 if (extent_type == BTRFS_FILE_EXTENT_INLINE)
86 continue;
87 /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */
88 disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
89 if (disk_byte != wanted_disk_byte)
90 continue;
91
92 ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie);
93 if (ret < 0)
94 return ret;
95 }
96
97 return 0;
98}
99
27/* 100/*
28 * this structure records all encountered refs on the way up to the root 101 * this structure records all encountered refs on the way up to the root
29 */ 102 */
@@ -103,15 +176,16 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
103} 176}
104 177
105static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, 178static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
106 struct ulist *parents, 179 struct ulist *parents, int level,
107 struct extent_buffer *eb, int level, 180 struct btrfs_key *key, u64 wanted_disk_byte,
108 u64 wanted_objectid, u64 wanted_disk_byte) 181 const u64 *extent_item_pos)
109{ 182{
110 int ret; 183 int ret;
111 int slot; 184 int slot;
185 struct extent_buffer *eb = path->nodes[level];
112 struct btrfs_file_extent_item *fi; 186 struct btrfs_file_extent_item *fi;
113 struct btrfs_key key;
114 u64 disk_byte; 187 u64 disk_byte;
188 u64 wanted_objectid = key->objectid;
115 189
116add_parent: 190add_parent:
117 ret = ulist_add(parents, eb->start, 0, GFP_NOFS); 191 ret = ulist_add(parents, eb->start, 0, GFP_NOFS);
@@ -136,9 +210,9 @@ add_parent:
136 210
137 eb = path->nodes[0]; 211 eb = path->nodes[0];
138 for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) { 212 for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) {
139 btrfs_item_key_to_cpu(eb, &key, slot); 213 btrfs_item_key_to_cpu(eb, key, slot);
140 if (key.objectid != wanted_objectid || 214 if (key->objectid != wanted_objectid ||
141 key.type != BTRFS_EXTENT_DATA_KEY) 215 key->type != BTRFS_EXTENT_DATA_KEY)
142 return 0; 216 return 0;
143 fi = btrfs_item_ptr(eb, slot, 217 fi = btrfs_item_ptr(eb, slot,
144 struct btrfs_file_extent_item); 218 struct btrfs_file_extent_item);
@@ -158,7 +232,8 @@ add_parent:
158static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, 232static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
159 int search_commit_root, 233 int search_commit_root,
160 struct __prelim_ref *ref, 234 struct __prelim_ref *ref,
161 struct ulist *parents) 235 struct ulist *parents,
236 const u64 *extent_item_pos)
162{ 237{
163 struct btrfs_path *path; 238 struct btrfs_path *path;
164 struct btrfs_root *root; 239 struct btrfs_root *root;
@@ -219,9 +294,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
219 btrfs_item_key_to_cpu(eb, &key, path->slots[0]); 294 btrfs_item_key_to_cpu(eb, &key, path->slots[0]);
220 } 295 }
221 296
222 /* the last two parameters will only be used for level == 0 */ 297 ret = add_all_parents(root, path, parents, level, &key,
223 ret = add_all_parents(root, path, parents, eb, level, key.objectid, 298 ref->wanted_disk_byte, extent_item_pos);
224 ref->wanted_disk_byte);
225out: 299out:
226 btrfs_free_path(path); 300 btrfs_free_path(path);
227 return ret; 301 return ret;
@@ -232,7 +306,8 @@ out:
232 */ 306 */
233static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, 307static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
234 int search_commit_root, 308 int search_commit_root,
235 struct list_head *head) 309 struct list_head *head,
310 const u64 *extent_item_pos)
236{ 311{
237 int err; 312 int err;
238 int ret = 0; 313 int ret = 0;
@@ -258,7 +333,7 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
258 if (ref->count == 0) 333 if (ref->count == 0)
259 continue; 334 continue;
260 err = __resolve_indirect_ref(fs_info, search_commit_root, 335 err = __resolve_indirect_ref(fs_info, search_commit_root,
261 ref, parents); 336 ref, parents, extent_item_pos);
262 if (err) { 337 if (err) {
263 if (ret == 0) 338 if (ret == 0)
264 ret = err; 339 ret = err;
@@ -675,7 +750,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
675 */ 750 */
676static int find_parent_nodes(struct btrfs_trans_handle *trans, 751static int find_parent_nodes(struct btrfs_trans_handle *trans,
677 struct btrfs_fs_info *fs_info, u64 bytenr, 752 struct btrfs_fs_info *fs_info, u64 bytenr,
678 u64 seq, struct ulist *refs, struct ulist *roots) 753 u64 seq, struct ulist *refs, struct ulist *roots,
754 const u64 *extent_item_pos)
679{ 755{
680 struct btrfs_key key; 756 struct btrfs_key key;
681 struct btrfs_path *path; 757 struct btrfs_path *path;
@@ -778,7 +854,8 @@ again:
778 if (ret) 854 if (ret)
779 goto out; 855 goto out;
780 856
781 ret = __resolve_indirect_refs(fs_info, search_commit_root, &prefs); 857 ret = __resolve_indirect_refs(fs_info, search_commit_root, &prefs,
858 extent_item_pos);
782 if (ret) 859 if (ret)
783 goto out; 860 goto out;
784 861
@@ -797,7 +874,21 @@ again:
797 BUG_ON(ret < 0); 874 BUG_ON(ret < 0);
798 } 875 }
799 if (ref->count && ref->parent) { 876 if (ref->count && ref->parent) {
800 ret = ulist_add(refs, ref->parent, 0, GFP_NOFS); 877 struct extent_inode_elem *eie = NULL;
878 if (extent_item_pos) {
879 u32 bsz;
880 struct extent_buffer *eb;
881 bsz = btrfs_level_size(fs_info->extent_root,
882 info_level);
883 eb = read_tree_block(fs_info->extent_root,
884 ref->parent, bsz, 0);
885 BUG_ON(!eb);
886 ret = find_extent_in_eb(eb, bytenr,
887 *extent_item_pos, &eie);
888 free_extent_buffer(eb);
889 }
890 ret = ulist_add(refs, ref->parent,
891 (unsigned long)eie, GFP_NOFS);
801 BUG_ON(ret < 0); 892 BUG_ON(ret < 0);
802 } 893 }
803 kfree(ref); 894 kfree(ref);
@@ -822,6 +913,28 @@ out:
822 return ret; 913 return ret;
823} 914}
824 915
916static void free_leaf_list(struct ulist *blocks)
917{
918 struct ulist_node *node = NULL;
919 struct extent_inode_elem *eie;
920 struct extent_inode_elem *eie_next;
921 struct ulist_iterator uiter;
922
923 ULIST_ITER_INIT(&uiter);
924 while ((node = ulist_next(blocks, &uiter))) {
925 if (!node->aux)
926 continue;
927 eie = (struct extent_inode_elem *)node->aux;
928 for (; eie; eie = eie_next) {
929 eie_next = eie->next;
930 kfree(eie);
931 }
932 node->aux = 0;
933 }
934
935 ulist_free(blocks);
936}
937
825/* 938/*
826 * Finds all leafs with a reference to the specified combination of bytenr and 939 * Finds all leafs with a reference to the specified combination of bytenr and
827 * offset. key_list_head will point to a list of corresponding keys (caller must 940 * offset. key_list_head will point to a list of corresponding keys (caller must
@@ -832,7 +945,8 @@ out:
832 */ 945 */
833static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, 946static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
834 struct btrfs_fs_info *fs_info, u64 bytenr, 947 struct btrfs_fs_info *fs_info, u64 bytenr,
835 u64 num_bytes, u64 seq, struct ulist **leafs) 948 u64 seq, struct ulist **leafs,
949 const u64 *extent_item_pos)
836{ 950{
837 struct ulist *tmp; 951 struct ulist *tmp;
838 int ret; 952 int ret;
@@ -846,11 +960,12 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
846 return -ENOMEM; 960 return -ENOMEM;
847 } 961 }
848 962
849 ret = find_parent_nodes(trans, fs_info, bytenr, seq, *leafs, tmp); 963 ret = find_parent_nodes(trans, fs_info, bytenr, seq, *leafs, tmp,
964 extent_item_pos);
850 ulist_free(tmp); 965 ulist_free(tmp);
851 966
852 if (ret < 0 && ret != -ENOENT) { 967 if (ret < 0 && ret != -ENOENT) {
853 ulist_free(*leafs); 968 free_leaf_list(*leafs);
854 return ret; 969 return ret;
855 } 970 }
856 971
@@ -872,7 +987,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
872 */ 987 */
873int btrfs_find_all_roots(struct btrfs_trans_handle *trans, 988int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
874 struct btrfs_fs_info *fs_info, u64 bytenr, 989 struct btrfs_fs_info *fs_info, u64 bytenr,
875 u64 num_bytes, u64 seq, struct ulist **roots) 990 u64 seq, struct ulist **roots)
876{ 991{
877 struct ulist *tmp; 992 struct ulist *tmp;
878 struct ulist_node *node = NULL; 993 struct ulist_node *node = NULL;
@@ -891,7 +1006,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
891 ULIST_ITER_INIT(&uiter); 1006 ULIST_ITER_INIT(&uiter);
892 while (1) { 1007 while (1) {
893 ret = find_parent_nodes(trans, fs_info, bytenr, seq, 1008 ret = find_parent_nodes(trans, fs_info, bytenr, seq,
894 tmp, *roots); 1009 tmp, *roots, NULL);
895 if (ret < 0 && ret != -ENOENT) { 1010 if (ret < 0 && ret != -ENOENT) {
896 ulist_free(tmp); 1011 ulist_free(tmp);
897 ulist_free(*roots); 1012 ulist_free(*roots);
@@ -1183,67 +1298,25 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
1183 return 0; 1298 return 0;
1184} 1299}
1185 1300
1186static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, u64 logical, 1301static int iterate_leaf_refs(struct extent_inode_elem *inode_list,
1187 u64 orig_extent_item_objectid, 1302 u64 root, u64 extent_item_objectid,
1188 u64 extent_item_pos, u64 root,
1189 iterate_extent_inodes_t *iterate, void *ctx) 1303 iterate_extent_inodes_t *iterate, void *ctx)
1190{ 1304{
1191 u64 disk_byte; 1305 struct extent_inode_elem *eie;
1192 struct btrfs_key key;
1193 struct btrfs_file_extent_item *fi;
1194 struct extent_buffer *eb;
1195 int slot;
1196 int nritems;
1197 int ret = 0; 1306 int ret = 0;
1198 int extent_type;
1199 u64 data_offset;
1200 u64 data_len;
1201
1202 eb = read_tree_block(fs_info->tree_root, logical,
1203 fs_info->tree_root->leafsize, 0);
1204 if (!eb)
1205 return -EIO;
1206
1207 /*
1208 * from the shared data ref, we only have the leaf but we need
1209 * the key. thus, we must look into all items and see that we
1210 * find one (some) with a reference to our extent item.
1211 */
1212 nritems = btrfs_header_nritems(eb);
1213 for (slot = 0; slot < nritems; ++slot) {
1214 btrfs_item_key_to_cpu(eb, &key, slot);
1215 if (key.type != BTRFS_EXTENT_DATA_KEY)
1216 continue;
1217 fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
1218 extent_type = btrfs_file_extent_type(eb, fi);
1219 if (extent_type == BTRFS_FILE_EXTENT_INLINE)
1220 continue;
1221 /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */
1222 disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
1223 if (disk_byte != orig_extent_item_objectid)
1224 continue;
1225
1226 data_offset = btrfs_file_extent_offset(eb, fi);
1227 data_len = btrfs_file_extent_num_bytes(eb, fi);
1228
1229 if (extent_item_pos < data_offset ||
1230 extent_item_pos >= data_offset + data_len)
1231 continue;
1232 1307
1308 for (eie = inode_list; eie; eie = eie->next) {
1233 pr_debug("ref for %llu resolved, key (%llu EXTEND_DATA %llu), " 1309 pr_debug("ref for %llu resolved, key (%llu EXTEND_DATA %llu), "
1234 "root %llu\n", orig_extent_item_objectid, 1310 "root %llu\n", extent_item_objectid,
1235 key.objectid, key.offset, root); 1311 eie->inum, eie->offset, root);
1236 ret = iterate(key.objectid, 1312 ret = iterate(eie->inum, eie->offset, root, ctx);
1237 key.offset + (extent_item_pos - data_offset),
1238 root, ctx);
1239 if (ret) { 1313 if (ret) {
1240 pr_debug("stopping iteration because ret=%d\n", ret); 1314 pr_debug("stopping iteration for %llu due to ret=%d\n",
1315 extent_item_objectid, ret);
1241 break; 1316 break;
1242 } 1317 }
1243 } 1318 }
1244 1319
1245 free_extent_buffer(eb);
1246
1247 return ret; 1320 return ret;
1248} 1321}
1249 1322
@@ -1287,30 +1360,31 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
1287 } 1360 }
1288 1361
1289 ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, 1362 ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
1290 extent_item_pos, seq_elem.seq, 1363 seq_elem.seq, &refs, &extent_item_pos);
1291 &refs);
1292
1293 if (ret) 1364 if (ret)
1294 goto out; 1365 goto out;
1295 1366
1296 ULIST_ITER_INIT(&ref_uiter); 1367 ULIST_ITER_INIT(&ref_uiter);
1297 while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { 1368 while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
1298 ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -1, 1369 ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
1299 seq_elem.seq, &roots); 1370 seq_elem.seq, &roots);
1300 if (ret) 1371 if (ret)
1301 break; 1372 break;
1302 ULIST_ITER_INIT(&root_uiter); 1373 ULIST_ITER_INIT(&root_uiter);
1303 while (!ret && (root_node = ulist_next(roots, &root_uiter))) { 1374 while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
1304 pr_debug("root %llu references leaf %llu\n", 1375 pr_debug("root %llu references leaf %llu, data list "
1305 root_node->val, ref_node->val); 1376 "%#lx\n", root_node->val, ref_node->val,
1306 ret = iterate_leaf_refs(fs_info, ref_node->val, 1377 ref_node->aux);
1307 extent_item_objectid, 1378 ret = iterate_leaf_refs(
1308 extent_item_pos, root_node->val, 1379 (struct extent_inode_elem *)ref_node->aux,
1309 iterate, ctx); 1380 root_node->val, extent_item_objectid,
1381 iterate, ctx);
1310 } 1382 }
1383 ulist_free(roots);
1384 roots = NULL;
1311 } 1385 }
1312 1386
1313 ulist_free(refs); 1387 free_leaf_list(refs);
1314 ulist_free(roots); 1388 ulist_free(roots);
1315out: 1389out:
1316 if (!search_commit_root) { 1390 if (!search_commit_root) {