aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/uuid-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/uuid-tree.c')
-rw-r--r--fs/btrfs/uuid-tree.c123
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
237static 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
253out:
254 return ret;
255}
256
257int 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
284again_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
344skip:
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
353out:
354 btrfs_free_path(path);
355 if (ret)
356 pr_warn("btrfs: btrfs_uuid_tree_iterate failed %d\n", ret);
357 return 0;
358}