diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/backref.c | 36 | ||||
-rw-r--r-- | fs/btrfs/ulist.c | 11 | ||||
-rw-r--r-- | fs/btrfs/ulist.h | 2 |
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 | ||
190 | add_parent: | 193 | add_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); | |||
146 | int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, | 146 | int 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 | |||
152 | int 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); | |||
67 | void ulist_free(struct ulist *ulist); | 67 | void ulist_free(struct ulist *ulist); |
68 | int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, | 68 | int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, |
69 | unsigned long gfp_mask); | 69 | unsigned long gfp_mask); |
70 | int ulist_add_merge(struct ulist *ulist, u64 val, unsigned long aux, | ||
71 | unsigned long *old_aux, unsigned long gfp_mask); | ||
70 | struct ulist_node *ulist_next(struct ulist *ulist, | 72 | struct ulist_node *ulist_next(struct ulist *ulist, |
71 | struct ulist_iterator *uiter); | 73 | struct ulist_iterator *uiter); |
72 | 74 | ||