diff options
Diffstat (limited to 'fs/btrfs/uuid-tree.c')
-rw-r--r-- | fs/btrfs/uuid-tree.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c index 04a04fa0f7c4..dd0dea3766f7 100644 --- a/fs/btrfs/uuid-tree.c +++ b/fs/btrfs/uuid-tree.c | |||
@@ -233,3 +233,126 @@ out: | |||
233 | btrfs_free_path(path); | 233 | btrfs_free_path(path); |
234 | return ret; | 234 | return ret; |
235 | } | 235 | } |
236 | |||
237 | static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type, | ||
238 | u64 subid) | ||
239 | { | ||
240 | struct btrfs_trans_handle *trans; | ||
241 | int ret; | ||
242 | |||
243 | /* 1 - for the uuid item */ | ||
244 | trans = btrfs_start_transaction(uuid_root, 1); | ||
245 | if (IS_ERR(trans)) { | ||
246 | ret = PTR_ERR(trans); | ||
247 | goto out; | ||
248 | } | ||
249 | |||
250 | ret = btrfs_uuid_tree_rem(trans, uuid_root, uuid, type, subid); | ||
251 | btrfs_end_transaction(trans, uuid_root); | ||
252 | |||
253 | out: | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info, | ||
258 | int (*check_func)(struct btrfs_fs_info *, u8 *, u8, | ||
259 | u64)) | ||
260 | { | ||
261 | struct btrfs_root *root = fs_info->uuid_root; | ||
262 | struct btrfs_key key; | ||
263 | struct btrfs_key max_key; | ||
264 | struct btrfs_path *path; | ||
265 | int ret = 0; | ||
266 | struct extent_buffer *leaf; | ||
267 | int slot; | ||
268 | u32 item_size; | ||
269 | unsigned long offset; | ||
270 | |||
271 | path = btrfs_alloc_path(); | ||
272 | if (!path) { | ||
273 | ret = -ENOMEM; | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | key.objectid = 0; | ||
278 | key.type = 0; | ||
279 | key.offset = 0; | ||
280 | max_key.objectid = (u64)-1; | ||
281 | max_key.type = (u8)-1; | ||
282 | max_key.offset = (u64)-1; | ||
283 | |||
284 | again_search_slot: | ||
285 | path->keep_locks = 1; | ||
286 | ret = btrfs_search_forward(root, &key, &max_key, path, 0); | ||
287 | if (ret) { | ||
288 | if (ret > 0) | ||
289 | ret = 0; | ||
290 | goto out; | ||
291 | } | ||
292 | |||
293 | while (1) { | ||
294 | cond_resched(); | ||
295 | leaf = path->nodes[0]; | ||
296 | slot = path->slots[0]; | ||
297 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
298 | |||
299 | if (key.type != BTRFS_UUID_KEY_SUBVOL && | ||
300 | key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) | ||
301 | goto skip; | ||
302 | |||
303 | offset = btrfs_item_ptr_offset(leaf, slot); | ||
304 | item_size = btrfs_item_size_nr(leaf, slot); | ||
305 | if (!IS_ALIGNED(item_size, sizeof(u64))) { | ||
306 | pr_warn("btrfs: uuid item with illegal size %lu!\n", | ||
307 | (unsigned long)item_size); | ||
308 | goto skip; | ||
309 | } | ||
310 | while (item_size) { | ||
311 | u8 uuid[BTRFS_UUID_SIZE]; | ||
312 | __le64 subid_le; | ||
313 | u64 subid_cpu; | ||
314 | |||
315 | put_unaligned_le64(key.objectid, uuid); | ||
316 | put_unaligned_le64(key.offset, uuid + sizeof(u64)); | ||
317 | read_extent_buffer(leaf, &subid_le, offset, | ||
318 | sizeof(subid_le)); | ||
319 | subid_cpu = le64_to_cpu(subid_le); | ||
320 | ret = check_func(fs_info, uuid, key.type, subid_cpu); | ||
321 | if (ret < 0) | ||
322 | goto out; | ||
323 | if (ret > 0) { | ||
324 | btrfs_release_path(path); | ||
325 | ret = btrfs_uuid_iter_rem(root, uuid, key.type, | ||
326 | subid_cpu); | ||
327 | if (ret == 0) { | ||
328 | /* | ||
329 | * this might look inefficient, but the | ||
330 | * justification is that it is an | ||
331 | * exception that check_func returns 1, | ||
332 | * and that in the regular case only one | ||
333 | * entry per UUID exists. | ||
334 | */ | ||
335 | goto again_search_slot; | ||
336 | } | ||
337 | if (ret < 0 && ret != -ENOENT) | ||
338 | goto out; | ||
339 | } | ||
340 | item_size -= sizeof(subid_le); | ||
341 | offset += sizeof(subid_le); | ||
342 | } | ||
343 | |||
344 | skip: | ||
345 | ret = btrfs_next_item(root, path); | ||
346 | if (ret == 0) | ||
347 | continue; | ||
348 | else if (ret > 0) | ||
349 | ret = 0; | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | out: | ||
354 | btrfs_free_path(path); | ||
355 | if (ret) | ||
356 | pr_warn("btrfs: btrfs_uuid_tree_iterate failed %d\n", ret); | ||
357 | return 0; | ||
358 | } | ||