aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/backref.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r--fs/btrfs/backref.c94
1 files changed, 52 insertions, 42 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 8f7d1237b7a0..7301cdb4b2cb 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
180static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, 180static 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
194add_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;
@@ -295,11 +307,9 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
295 goto out; 307 goto out;
296 } 308 }
297 309
298 if (level == 0) 310 ret = add_all_parents(root, path, parents, level, &ref->key_for_search,
299 btrfs_item_key_to_cpu(eb, &key, path->slots[0]); 311 time_seq, ref->wanted_disk_byte,
300 312 extent_item_pos);
301 ret = add_all_parents(root, path, parents, level, &key, time_seq,
302 ref->wanted_disk_byte, extent_item_pos);
303out: 313out:
304 btrfs_free_path(path); 314 btrfs_free_path(path);
305 return ret; 315 return ret;