btrfs-progs: add btrfs_uuid_tree_remove

It will be used to clear received data on RW snapshots that were
received. The function is copied from kernel sources.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Nikolay Borisov 2021-09-14 12:05:55 +03:00 committed by David Sterba
parent 97640a5b81
commit 39c6e0b79c
2 changed files with 83 additions and 0 deletions

View file

@ -2865,6 +2865,8 @@ int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid,
/* uuid-tree.c, interface for unmounte filesystem */
int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
u64 subvol_id_cpu);
int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
u64 subid);
static inline int is_fstree(u64 rootid)
{

View file

@ -110,3 +110,84 @@ int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid,
BTRFS_UUID_KEY_RECEIVED_SUBVOL,
subvol_id);
}
int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
u64 subid)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *uuid_root = fs_info->uuid_root;
int ret;
struct btrfs_path *path = NULL;
struct btrfs_key key;
struct extent_buffer *eb;
int slot;
unsigned long offset;
u32 item_size;
unsigned long move_dst;
unsigned long move_src;
unsigned long move_len;
if (!uuid_root) {
ret = -EINVAL;
goto out;
}
btrfs_uuid_to_key(uuid, &key);
key.type = type;
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto out;
}
ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
if (ret < 0) {
warning("error %d while searching for uuid item!", ret);
goto out;
}
if (ret > 0) {
ret = -ENOENT;
goto out;
}
eb = path->nodes[0];
slot = path->slots[0];
offset = btrfs_item_ptr_offset(eb, slot);
item_size = btrfs_item_size_nr(eb, slot);
if (!IS_ALIGNED(item_size, sizeof(u64))) {
warning("uuid item with illegal size %u!", item_size);
ret = -ENOENT;
goto out;
}
while (item_size) {
__le64 read_subid;
read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
if (le64_to_cpu(read_subid) == subid)
break;
offset += sizeof(read_subid);
item_size -= sizeof(read_subid);
}
if (!item_size) {
ret = -ENOENT;
goto out;
}
item_size = btrfs_item_size_nr(eb, slot);
if (item_size == sizeof(subid)) {
ret = btrfs_del_item(trans, uuid_root, path);
goto out;
}
move_dst = offset;
move_src = offset + sizeof(subid);
move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
memmove_extent_buffer(eb, move_dst, move_src, move_len);
btrfs_truncate_item(path, item_size - sizeof(subid), 1);
out:
btrfs_free_path(path);
return ret;
}