18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) STRATO AG 2013. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/uuid.h> 78c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 88c2ecf20Sopenharmony_ci#include "ctree.h" 98c2ecf20Sopenharmony_ci#include "transaction.h" 108c2ecf20Sopenharmony_ci#include "disk-io.h" 118c2ecf20Sopenharmony_ci#include "print-tree.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci key->type = type; 178c2ecf20Sopenharmony_ci key->objectid = get_unaligned_le64(uuid); 188c2ecf20Sopenharmony_ci key->offset = get_unaligned_le64(uuid + sizeof(u64)); 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */ 228c2ecf20Sopenharmony_cistatic int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid, 238c2ecf20Sopenharmony_ci u8 type, u64 subid) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci int ret; 268c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 278c2ecf20Sopenharmony_ci struct extent_buffer *eb; 288c2ecf20Sopenharmony_ci int slot; 298c2ecf20Sopenharmony_ci u32 item_size; 308c2ecf20Sopenharmony_ci unsigned long offset; 318c2ecf20Sopenharmony_ci struct btrfs_key key; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!uuid_root)) { 348c2ecf20Sopenharmony_ci ret = -ENOENT; 358c2ecf20Sopenharmony_ci goto out; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 398c2ecf20Sopenharmony_ci if (!path) { 408c2ecf20Sopenharmony_ci ret = -ENOMEM; 418c2ecf20Sopenharmony_ci goto out; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci btrfs_uuid_to_key(uuid, type, &key); 458c2ecf20Sopenharmony_ci ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0); 468c2ecf20Sopenharmony_ci if (ret < 0) { 478c2ecf20Sopenharmony_ci goto out; 488c2ecf20Sopenharmony_ci } else if (ret > 0) { 498c2ecf20Sopenharmony_ci ret = -ENOENT; 508c2ecf20Sopenharmony_ci goto out; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci eb = path->nodes[0]; 548c2ecf20Sopenharmony_ci slot = path->slots[0]; 558c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(eb, slot); 568c2ecf20Sopenharmony_ci offset = btrfs_item_ptr_offset(eb, slot); 578c2ecf20Sopenharmony_ci ret = -ENOENT; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!IS_ALIGNED(item_size, sizeof(u64))) { 608c2ecf20Sopenharmony_ci btrfs_warn(uuid_root->fs_info, 618c2ecf20Sopenharmony_ci "uuid item with illegal size %lu!", 628c2ecf20Sopenharmony_ci (unsigned long)item_size); 638c2ecf20Sopenharmony_ci goto out; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci while (item_size) { 668c2ecf20Sopenharmony_ci __le64 data; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci read_extent_buffer(eb, &data, offset, sizeof(data)); 698c2ecf20Sopenharmony_ci if (le64_to_cpu(data) == subid) { 708c2ecf20Sopenharmony_ci ret = 0; 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci offset += sizeof(data); 748c2ecf20Sopenharmony_ci item_size -= sizeof(data); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciout: 788c2ecf20Sopenharmony_ci btrfs_free_path(path); 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciint btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, 838c2ecf20Sopenharmony_ci u64 subid_cpu) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 868c2ecf20Sopenharmony_ci struct btrfs_root *uuid_root = fs_info->uuid_root; 878c2ecf20Sopenharmony_ci int ret; 888c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 898c2ecf20Sopenharmony_ci struct btrfs_key key; 908c2ecf20Sopenharmony_ci struct extent_buffer *eb; 918c2ecf20Sopenharmony_ci int slot; 928c2ecf20Sopenharmony_ci unsigned long offset; 938c2ecf20Sopenharmony_ci __le64 subid_le; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu); 968c2ecf20Sopenharmony_ci if (ret != -ENOENT) 978c2ecf20Sopenharmony_ci return ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!uuid_root)) { 1008c2ecf20Sopenharmony_ci ret = -EINVAL; 1018c2ecf20Sopenharmony_ci goto out; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci btrfs_uuid_to_key(uuid, type, &key); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 1078c2ecf20Sopenharmony_ci if (!path) { 1088c2ecf20Sopenharmony_ci ret = -ENOMEM; 1098c2ecf20Sopenharmony_ci goto out; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, uuid_root, path, &key, 1138c2ecf20Sopenharmony_ci sizeof(subid_le)); 1148c2ecf20Sopenharmony_ci if (ret >= 0) { 1158c2ecf20Sopenharmony_ci /* Add an item for the type for the first time */ 1168c2ecf20Sopenharmony_ci eb = path->nodes[0]; 1178c2ecf20Sopenharmony_ci slot = path->slots[0]; 1188c2ecf20Sopenharmony_ci offset = btrfs_item_ptr_offset(eb, slot); 1198c2ecf20Sopenharmony_ci } else if (ret == -EEXIST) { 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * An item with that type already exists. 1228c2ecf20Sopenharmony_ci * Extend the item and store the new subid at the end. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci btrfs_extend_item(path, sizeof(subid_le)); 1258c2ecf20Sopenharmony_ci eb = path->nodes[0]; 1268c2ecf20Sopenharmony_ci slot = path->slots[0]; 1278c2ecf20Sopenharmony_ci offset = btrfs_item_ptr_offset(eb, slot); 1288c2ecf20Sopenharmony_ci offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 1318c2ecf20Sopenharmony_ci "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!", 1328c2ecf20Sopenharmony_ci ret, (unsigned long long)key.objectid, 1338c2ecf20Sopenharmony_ci (unsigned long long)key.offset, type); 1348c2ecf20Sopenharmony_ci goto out; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ret = 0; 1388c2ecf20Sopenharmony_ci subid_le = cpu_to_le64(subid_cpu); 1398c2ecf20Sopenharmony_ci write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le)); 1408c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(eb); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciout: 1438c2ecf20Sopenharmony_ci btrfs_free_path(path); 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ciint btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, 1488c2ecf20Sopenharmony_ci u64 subid) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 1518c2ecf20Sopenharmony_ci struct btrfs_root *uuid_root = fs_info->uuid_root; 1528c2ecf20Sopenharmony_ci int ret; 1538c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 1548c2ecf20Sopenharmony_ci struct btrfs_key key; 1558c2ecf20Sopenharmony_ci struct extent_buffer *eb; 1568c2ecf20Sopenharmony_ci int slot; 1578c2ecf20Sopenharmony_ci unsigned long offset; 1588c2ecf20Sopenharmony_ci u32 item_size; 1598c2ecf20Sopenharmony_ci unsigned long move_dst; 1608c2ecf20Sopenharmony_ci unsigned long move_src; 1618c2ecf20Sopenharmony_ci unsigned long move_len; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!uuid_root)) { 1648c2ecf20Sopenharmony_ci ret = -EINVAL; 1658c2ecf20Sopenharmony_ci goto out; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci btrfs_uuid_to_key(uuid, type, &key); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 1718c2ecf20Sopenharmony_ci if (!path) { 1728c2ecf20Sopenharmony_ci ret = -ENOMEM; 1738c2ecf20Sopenharmony_ci goto out; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1); 1778c2ecf20Sopenharmony_ci if (ret < 0) { 1788c2ecf20Sopenharmony_ci btrfs_warn(fs_info, "error %d while searching for uuid item!", 1798c2ecf20Sopenharmony_ci ret); 1808c2ecf20Sopenharmony_ci goto out; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci if (ret > 0) { 1838c2ecf20Sopenharmony_ci ret = -ENOENT; 1848c2ecf20Sopenharmony_ci goto out; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci eb = path->nodes[0]; 1888c2ecf20Sopenharmony_ci slot = path->slots[0]; 1898c2ecf20Sopenharmony_ci offset = btrfs_item_ptr_offset(eb, slot); 1908c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(eb, slot); 1918c2ecf20Sopenharmony_ci if (!IS_ALIGNED(item_size, sizeof(u64))) { 1928c2ecf20Sopenharmony_ci btrfs_warn(fs_info, "uuid item with illegal size %lu!", 1938c2ecf20Sopenharmony_ci (unsigned long)item_size); 1948c2ecf20Sopenharmony_ci ret = -ENOENT; 1958c2ecf20Sopenharmony_ci goto out; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci while (item_size) { 1988c2ecf20Sopenharmony_ci __le64 read_subid; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid)); 2018c2ecf20Sopenharmony_ci if (le64_to_cpu(read_subid) == subid) 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci offset += sizeof(read_subid); 2048c2ecf20Sopenharmony_ci item_size -= sizeof(read_subid); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (!item_size) { 2088c2ecf20Sopenharmony_ci ret = -ENOENT; 2098c2ecf20Sopenharmony_ci goto out; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(eb, slot); 2138c2ecf20Sopenharmony_ci if (item_size == sizeof(subid)) { 2148c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, uuid_root, path); 2158c2ecf20Sopenharmony_ci goto out; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci move_dst = offset; 2198c2ecf20Sopenharmony_ci move_src = offset + sizeof(subid); 2208c2ecf20Sopenharmony_ci move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot)); 2218c2ecf20Sopenharmony_ci memmove_extent_buffer(eb, move_dst, move_src, move_len); 2228c2ecf20Sopenharmony_ci btrfs_truncate_item(path, item_size - sizeof(subid), 1); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciout: 2258c2ecf20Sopenharmony_ci btrfs_free_path(path); 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type, 2308c2ecf20Sopenharmony_ci u64 subid) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans; 2338c2ecf20Sopenharmony_ci int ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 1 - for the uuid item */ 2368c2ecf20Sopenharmony_ci trans = btrfs_start_transaction(uuid_root, 1); 2378c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 2388c2ecf20Sopenharmony_ci ret = PTR_ERR(trans); 2398c2ecf20Sopenharmony_ci goto out; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = btrfs_uuid_tree_remove(trans, uuid, type, subid); 2438c2ecf20Sopenharmony_ci btrfs_end_transaction(trans); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ciout: 2468c2ecf20Sopenharmony_ci return ret; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* 2508c2ecf20Sopenharmony_ci * Check if there's an matching subvolume for given UUID 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * Return: 2538c2ecf20Sopenharmony_ci * 0 check succeeded, the entry is not outdated 2548c2ecf20Sopenharmony_ci * > 0 if the check failed, the caller should remove the entry 2558c2ecf20Sopenharmony_ci * < 0 if an error occurred 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic int btrfs_check_uuid_tree_entry(struct btrfs_fs_info *fs_info, 2588c2ecf20Sopenharmony_ci u8 *uuid, u8 type, u64 subvolid) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci int ret = 0; 2618c2ecf20Sopenharmony_ci struct btrfs_root *subvol_root; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (type != BTRFS_UUID_KEY_SUBVOL && 2648c2ecf20Sopenharmony_ci type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) 2658c2ecf20Sopenharmony_ci goto out; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci subvol_root = btrfs_get_fs_root(fs_info, subvolid, true); 2688c2ecf20Sopenharmony_ci if (IS_ERR(subvol_root)) { 2698c2ecf20Sopenharmony_ci ret = PTR_ERR(subvol_root); 2708c2ecf20Sopenharmony_ci if (ret == -ENOENT) 2718c2ecf20Sopenharmony_ci ret = 1; 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci switch (type) { 2768c2ecf20Sopenharmony_ci case BTRFS_UUID_KEY_SUBVOL: 2778c2ecf20Sopenharmony_ci if (memcmp(uuid, subvol_root->root_item.uuid, BTRFS_UUID_SIZE)) 2788c2ecf20Sopenharmony_ci ret = 1; 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci case BTRFS_UUID_KEY_RECEIVED_SUBVOL: 2818c2ecf20Sopenharmony_ci if (memcmp(uuid, subvol_root->root_item.received_uuid, 2828c2ecf20Sopenharmony_ci BTRFS_UUID_SIZE)) 2838c2ecf20Sopenharmony_ci ret = 1; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci btrfs_put_root(subvol_root); 2878c2ecf20Sopenharmony_ciout: 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciint btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct btrfs_root *root = fs_info->uuid_root; 2948c2ecf20Sopenharmony_ci struct btrfs_key key; 2958c2ecf20Sopenharmony_ci struct btrfs_path *path; 2968c2ecf20Sopenharmony_ci int ret = 0; 2978c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 2988c2ecf20Sopenharmony_ci int slot; 2998c2ecf20Sopenharmony_ci u32 item_size; 3008c2ecf20Sopenharmony_ci unsigned long offset; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 3038c2ecf20Sopenharmony_ci if (!path) { 3048c2ecf20Sopenharmony_ci ret = -ENOMEM; 3058c2ecf20Sopenharmony_ci goto out; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci key.objectid = 0; 3098c2ecf20Sopenharmony_ci key.type = 0; 3108c2ecf20Sopenharmony_ci key.offset = 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciagain_search_slot: 3138c2ecf20Sopenharmony_ci ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION); 3148c2ecf20Sopenharmony_ci if (ret) { 3158c2ecf20Sopenharmony_ci if (ret > 0) 3168c2ecf20Sopenharmony_ci ret = 0; 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci while (1) { 3218c2ecf20Sopenharmony_ci if (btrfs_fs_closing(fs_info)) { 3228c2ecf20Sopenharmony_ci ret = -EINTR; 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci cond_resched(); 3268c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 3278c2ecf20Sopenharmony_ci slot = path->slots[0]; 3288c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(leaf, &key, slot); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (key.type != BTRFS_UUID_KEY_SUBVOL && 3318c2ecf20Sopenharmony_ci key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) 3328c2ecf20Sopenharmony_ci goto skip; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci offset = btrfs_item_ptr_offset(leaf, slot); 3358c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(leaf, slot); 3368c2ecf20Sopenharmony_ci if (!IS_ALIGNED(item_size, sizeof(u64))) { 3378c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 3388c2ecf20Sopenharmony_ci "uuid item with illegal size %lu!", 3398c2ecf20Sopenharmony_ci (unsigned long)item_size); 3408c2ecf20Sopenharmony_ci goto skip; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci while (item_size) { 3438c2ecf20Sopenharmony_ci u8 uuid[BTRFS_UUID_SIZE]; 3448c2ecf20Sopenharmony_ci __le64 subid_le; 3458c2ecf20Sopenharmony_ci u64 subid_cpu; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci put_unaligned_le64(key.objectid, uuid); 3488c2ecf20Sopenharmony_ci put_unaligned_le64(key.offset, uuid + sizeof(u64)); 3498c2ecf20Sopenharmony_ci read_extent_buffer(leaf, &subid_le, offset, 3508c2ecf20Sopenharmony_ci sizeof(subid_le)); 3518c2ecf20Sopenharmony_ci subid_cpu = le64_to_cpu(subid_le); 3528c2ecf20Sopenharmony_ci ret = btrfs_check_uuid_tree_entry(fs_info, uuid, 3538c2ecf20Sopenharmony_ci key.type, subid_cpu); 3548c2ecf20Sopenharmony_ci if (ret < 0) 3558c2ecf20Sopenharmony_ci goto out; 3568c2ecf20Sopenharmony_ci if (ret > 0) { 3578c2ecf20Sopenharmony_ci btrfs_release_path(path); 3588c2ecf20Sopenharmony_ci ret = btrfs_uuid_iter_rem(root, uuid, key.type, 3598c2ecf20Sopenharmony_ci subid_cpu); 3608c2ecf20Sopenharmony_ci if (ret == 0) { 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * this might look inefficient, but the 3638c2ecf20Sopenharmony_ci * justification is that it is an 3648c2ecf20Sopenharmony_ci * exception that check_func returns 1, 3658c2ecf20Sopenharmony_ci * and that in the regular case only one 3668c2ecf20Sopenharmony_ci * entry per UUID exists. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci goto again_search_slot; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ENOENT) 3718c2ecf20Sopenharmony_ci goto out; 3728c2ecf20Sopenharmony_ci key.offset++; 3738c2ecf20Sopenharmony_ci goto again_search_slot; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci item_size -= sizeof(subid_le); 3768c2ecf20Sopenharmony_ci offset += sizeof(subid_le); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciskip: 3808c2ecf20Sopenharmony_ci ret = btrfs_next_item(root, path); 3818c2ecf20Sopenharmony_ci if (ret == 0) 3828c2ecf20Sopenharmony_ci continue; 3838c2ecf20Sopenharmony_ci else if (ret > 0) 3848c2ecf20Sopenharmony_ci ret = 0; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciout: 3898c2ecf20Sopenharmony_ci btrfs_free_path(path); 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci} 392