diff options
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r-- | fs/btrfs/backref.c | 118 |
1 files changed, 62 insertions, 56 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 3f75895c919b..a383c18e74e8 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -179,60 +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 wanted_disk_byte, | 182 | struct btrfs_key *key_for_search, u64 time_seq, |
183 | u64 wanted_disk_byte, | ||
183 | const u64 *extent_item_pos) | 184 | const u64 *extent_item_pos) |
184 | { | 185 | { |
185 | int ret; | 186 | int ret = 0; |
186 | int slot = path->slots[level]; | 187 | int slot; |
187 | struct extent_buffer *eb = path->nodes[level]; | 188 | struct extent_buffer *eb; |
189 | struct btrfs_key key; | ||
188 | struct btrfs_file_extent_item *fi; | 190 | struct btrfs_file_extent_item *fi; |
189 | struct extent_inode_elem *eie = NULL; | 191 | struct extent_inode_elem *eie = NULL; |
190 | u64 disk_byte; | 192 | u64 disk_byte; |
191 | u64 wanted_objectid = key->objectid; | ||
192 | 193 | ||
193 | add_parent: | 194 | if (level != 0) { |
194 | if (level == 0 && extent_item_pos) { | 195 | eb = path->nodes[level]; |
195 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); | 196 | ret = ulist_add(parents, eb->start, 0, GFP_NOFS); |
196 | ret = check_extent_in_eb(key, eb, fi, *extent_item_pos, &eie); | ||
197 | if (ret < 0) | 197 | if (ret < 0) |
198 | return ret; | 198 | return ret; |
199 | } | ||
200 | ret = ulist_add(parents, eb->start, (unsigned long)eie, GFP_NOFS); | ||
201 | if (ret < 0) | ||
202 | return ret; | ||
203 | |||
204 | if (level != 0) | ||
205 | return 0; | 199 | return 0; |
200 | } | ||
206 | 201 | ||
207 | /* | 202 | /* |
208 | * if the current leaf is full with EXTENT_DATA items, we must | 203 | * We normally enter this function with the path already pointing to |
209 | * check the next one if that holds a reference as well. | 204 | * the first item to check. But sometimes, we may enter it with |
210 | * ref->count cannot be used to skip this check. | 205 | * slot==nritems. In that case, go to the next leaf before we continue. |
211 | * repeat this until we don't find any additional EXTENT_DATA items. | ||
212 | */ | 206 | */ |
213 | while (1) { | 207 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) |
214 | eie = NULL; | 208 | ret = btrfs_next_old_leaf(root, path, time_seq); |
215 | ret = btrfs_next_leaf(root, path); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | if (ret) | ||
219 | return 0; | ||
220 | 209 | ||
210 | while (!ret) { | ||
221 | eb = path->nodes[0]; | 211 | eb = path->nodes[0]; |
222 | for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) { | 212 | slot = path->slots[0]; |
223 | btrfs_item_key_to_cpu(eb, key, slot); | 213 | |
224 | if (key->objectid != wanted_objectid || | 214 | btrfs_item_key_to_cpu(eb, &key, slot); |
225 | key->type != BTRFS_EXTENT_DATA_KEY) | 215 | |
226 | return 0; | 216 | if (key.objectid != key_for_search->objectid || |
227 | fi = btrfs_item_ptr(eb, slot, | 217 | key.type != BTRFS_EXTENT_DATA_KEY) |
228 | struct btrfs_file_extent_item); | 218 | break; |
229 | disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); | 219 | |
230 | if (disk_byte == wanted_disk_byte) | 220 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); |
231 | 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 | } | ||
232 | } | 243 | } |
244 | ret = btrfs_next_old_item(root, path, time_seq); | ||
233 | } | 245 | } |
234 | 246 | ||
235 | return 0; | 247 | if (ret > 0) |
248 | ret = 0; | ||
249 | return ret; | ||
236 | } | 250 | } |
237 | 251 | ||
238 | /* | 252 | /* |
@@ -249,7 +263,6 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
249 | struct btrfs_path *path; | 263 | struct btrfs_path *path; |
250 | struct btrfs_root *root; | 264 | struct btrfs_root *root; |
251 | struct btrfs_key root_key; | 265 | struct btrfs_key root_key; |
252 | struct btrfs_key key = {0}; | ||
253 | struct extent_buffer *eb; | 266 | struct extent_buffer *eb; |
254 | int ret = 0; | 267 | int ret = 0; |
255 | int root_level; | 268 | int root_level; |
@@ -288,25 +301,19 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
288 | goto out; | 301 | goto out; |
289 | 302 | ||
290 | eb = path->nodes[level]; | 303 | eb = path->nodes[level]; |
291 | if (!eb) { | 304 | while (!eb) { |
292 | WARN_ON(1); | 305 | if (!level) { |
293 | ret = 1; | 306 | WARN_ON(1); |
294 | goto out; | 307 | ret = 1; |
295 | } | 308 | goto out; |
296 | |||
297 | if (level == 0) { | ||
298 | if (ret == 1 && path->slots[0] >= btrfs_header_nritems(eb)) { | ||
299 | ret = btrfs_next_leaf(root, path); | ||
300 | if (ret) | ||
301 | goto out; | ||
302 | eb = path->nodes[0]; | ||
303 | } | 309 | } |
304 | 310 | level--; | |
305 | btrfs_item_key_to_cpu(eb, &key, path->slots[0]); | 311 | eb = path->nodes[level]; |
306 | } | 312 | } |
307 | 313 | ||
308 | ret = add_all_parents(root, path, parents, level, &key, | 314 | ret = add_all_parents(root, path, parents, level, &ref->key_for_search, |
309 | ref->wanted_disk_byte, extent_item_pos); | 315 | time_seq, ref->wanted_disk_byte, |
316 | extent_item_pos); | ||
310 | out: | 317 | out: |
311 | btrfs_free_path(path); | 318 | btrfs_free_path(path); |
312 | return ret; | 319 | return ret; |
@@ -832,6 +839,7 @@ again: | |||
832 | } | 839 | } |
833 | ret = __add_delayed_refs(head, delayed_ref_seq, | 840 | ret = __add_delayed_refs(head, delayed_ref_seq, |
834 | &prefs_delayed); | 841 | &prefs_delayed); |
842 | mutex_unlock(&head->mutex); | ||
835 | if (ret) { | 843 | if (ret) { |
836 | spin_unlock(&delayed_refs->lock); | 844 | spin_unlock(&delayed_refs->lock); |
837 | goto out; | 845 | goto out; |
@@ -925,8 +933,6 @@ again: | |||
925 | } | 933 | } |
926 | 934 | ||
927 | out: | 935 | out: |
928 | if (head) | ||
929 | mutex_unlock(&head->mutex); | ||
930 | btrfs_free_path(path); | 936 | btrfs_free_path(path); |
931 | while (!list_empty(&prefs)) { | 937 | while (!list_empty(&prefs)) { |
932 | ref = list_first_entry(&prefs, struct __prelim_ref, list); | 938 | ref = list_first_entry(&prefs, struct __prelim_ref, list); |