aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-30 12:05:21 -0400
committerJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-31 13:53:08 -0400
commit3301958b7c1dae8f0f5ded63aa881e0b71e78464 (patch)
tree11d1c098981a65bcbe11f4be594d6e9855f55448 /fs/btrfs
parent95a06077f7edbd00d32612562be4d857a5b7df54 (diff)
Btrfs: add inodes before dropping the extent lock in find_all_leafs
We must build up the inode list with the extent lock held after following indirect refs. This also requires an extension to ulists, which allows to modify the stored aux value in case a key already exists in the list. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/backref.c36
-rw-r--r--fs/btrfs/ulist.c11
-rw-r--r--fs/btrfs/ulist.h2
3 files changed, 43 insertions, 6 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 0ac47f2834d1..3f75895c919b 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -106,6 +106,7 @@ struct __prelim_ref {
106 struct btrfs_key key_for_search; 106 struct btrfs_key key_for_search;
107 int level; 107 int level;
108 int count; 108 int count;
109 struct extent_inode_elem *inode_list;
109 u64 parent; 110 u64 parent;
110 u64 wanted_disk_byte; 111 u64 wanted_disk_byte;
111}; 112};
@@ -166,6 +167,7 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
166 else 167 else
167 memset(&ref->key_for_search, 0, sizeof(ref->key_for_search)); 168 memset(&ref->key_for_search, 0, sizeof(ref->key_for_search));
168 169
170 ref->inode_list = NULL;
169 ref->level = level; 171 ref->level = level;
170 ref->count = count; 172 ref->count = count;
171 ref->parent = parent; 173 ref->parent = parent;
@@ -181,14 +183,21 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
181 const u64 *extent_item_pos) 183 const u64 *extent_item_pos)
182{ 184{
183 int ret; 185 int ret;
184 int slot; 186 int slot = path->slots[level];
185 struct extent_buffer *eb = path->nodes[level]; 187 struct extent_buffer *eb = path->nodes[level];
186 struct btrfs_file_extent_item *fi; 188 struct btrfs_file_extent_item *fi;
189 struct extent_inode_elem *eie = NULL;
187 u64 disk_byte; 190 u64 disk_byte;
188 u64 wanted_objectid = key->objectid; 191 u64 wanted_objectid = key->objectid;
189 192
190add_parent: 193add_parent:
191 ret = ulist_add(parents, eb->start, 0, GFP_NOFS); 194 if (level == 0 && extent_item_pos) {
195 fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
196 ret = check_extent_in_eb(key, eb, fi, *extent_item_pos, &eie);
197 if (ret < 0)
198 return ret;
199 }
200 ret = ulist_add(parents, eb->start, (unsigned long)eie, GFP_NOFS);
192 if (ret < 0) 201 if (ret < 0)
193 return ret; 202 return ret;
194 203
@@ -202,6 +211,7 @@ add_parent:
202 * repeat this until we don't find any additional EXTENT_DATA items. 211 * repeat this until we don't find any additional EXTENT_DATA items.
203 */ 212 */
204 while (1) { 213 while (1) {
214 eie = NULL;
205 ret = btrfs_next_leaf(root, path); 215 ret = btrfs_next_leaf(root, path);
206 if (ret < 0) 216 if (ret < 0)
207 return ret; 217 return ret;
@@ -346,6 +356,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
346 ULIST_ITER_INIT(&uiter); 356 ULIST_ITER_INIT(&uiter);
347 node = ulist_next(parents, &uiter); 357 node = ulist_next(parents, &uiter);
348 ref->parent = node ? node->val : 0; 358 ref->parent = node ? node->val : 0;
359 ref->inode_list =
360 node ? (struct extent_inode_elem *)node->aux : 0;
349 361
350 /* additional parents require new refs being added here */ 362 /* additional parents require new refs being added here */
351 while ((node = ulist_next(parents, &uiter))) { 363 while ((node = ulist_next(parents, &uiter))) {
@@ -356,6 +368,8 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
356 } 368 }
357 memcpy(new_ref, ref, sizeof(*ref)); 369 memcpy(new_ref, ref, sizeof(*ref));
358 new_ref->parent = node->val; 370 new_ref->parent = node->val;
371 new_ref->inode_list =
372 (struct extent_inode_elem *)node->aux;
359 list_add(&new_ref->list, &ref->list); 373 list_add(&new_ref->list, &ref->list);
360 } 374 }
361 ulist_reinit(parents); 375 ulist_reinit(parents);
@@ -879,7 +893,7 @@ again:
879 } 893 }
880 if (ref->count && ref->parent) { 894 if (ref->count && ref->parent) {
881 struct extent_inode_elem *eie = NULL; 895 struct extent_inode_elem *eie = NULL;
882 if (extent_item_pos) { 896 if (extent_item_pos && !ref->inode_list) {
883 u32 bsz; 897 u32 bsz;
884 struct extent_buffer *eb; 898 struct extent_buffer *eb;
885 bsz = btrfs_level_size(fs_info->extent_root, 899 bsz = btrfs_level_size(fs_info->extent_root,
@@ -889,10 +903,22 @@ again:
889 BUG_ON(!eb); 903 BUG_ON(!eb);
890 ret = find_extent_in_eb(eb, bytenr, 904 ret = find_extent_in_eb(eb, bytenr,
891 *extent_item_pos, &eie); 905 *extent_item_pos, &eie);
906 ref->inode_list = eie;
892 free_extent_buffer(eb); 907 free_extent_buffer(eb);
893 } 908 }
894 ret = ulist_add(refs, ref->parent, 909 ret = ulist_add_merge(refs, ref->parent,
895 (unsigned long)eie, GFP_NOFS); 910 (unsigned long)ref->inode_list,
911 (unsigned long *)&eie, GFP_NOFS);
912 if (!ret && extent_item_pos) {
913 /*
914 * we've recorded that parent, so we must extend
915 * its inode list here
916 */
917 BUG_ON(!eie);
918 while (eie->next)
919 eie = eie->next;
920 eie->next = ref->inode_list;
921 }
896 BUG_ON(ret < 0); 922 BUG_ON(ret < 0);
897 } 923 }
898 kfree(ref); 924 kfree(ref);
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
index 17e68bdc307c..2ef59400ad6e 100644
--- a/fs/btrfs/ulist.c
+++ b/fs/btrfs/ulist.c
@@ -146,11 +146,20 @@ EXPORT_SYMBOL(ulist_free);
146int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, 146int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
147 unsigned long gfp_mask) 147 unsigned long gfp_mask)
148{ 148{
149 return ulist_add_merge(ulist, val, aux, NULL, gfp_mask);
150}
151
152int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
153 unsigned long *old_aux, unsigned long gfp_mask)
154{
149 int i; 155 int i;
150 156
151 for (i = 0; i < ulist->nnodes; ++i) { 157 for (i = 0; i < ulist->nnodes; ++i) {
152 if (ulist->nodes[i].val == val) 158 if (ulist->nodes[i].val == val) {
159 if (old_aux)
160 *old_aux = ulist->nodes[i].aux;
153 return 0; 161 return 0;
162 }
154 } 163 }
155 164
156 if (ulist->nnodes >= ulist->nodes_alloced) { 165 if (ulist->nnodes >= ulist->nodes_alloced) {
diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
index 62d2574f775a..f1b1bf00c5a9 100644
--- a/fs/btrfs/ulist.h
+++ b/fs/btrfs/ulist.h
@@ -67,6 +67,8 @@ struct ulist *ulist_alloc(unsigned long gfp_mask);
67void ulist_free(struct ulist *ulist); 67void ulist_free(struct ulist *ulist);
68int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, 68int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
69 unsigned long gfp_mask); 69 unsigned long gfp_mask);
70int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux,
71 unsigned long *old_aux, unsigned long gfp_mask);
70struct ulist_node *ulist_next(struct ulist *ulist, 72struct ulist_node *ulist_next(struct ulist *ulist,
71 struct ulist_iterator *uiter); 73 struct ulist_iterator *uiter);
72 74