diff options
Diffstat (limited to 'fs/btrfs/root.c')
-rw-r--r-- | fs/btrfs/root.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/fs/btrfs/root.c b/fs/btrfs/root.c new file mode 100644 index 0000000000..c405813b69 --- /dev/null +++ b/fs/btrfs/root.c @@ -0,0 +1,93 @@ +/* + * BTRFS filesystem implementation for U-Boot + * + * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "btrfs.h" + +static void read_root_item(struct btrfs_path *p, struct btrfs_root_item *item) +{ + u32 len; + int reset = 0; + + len = btrfs_path_item_size(p); + memcpy(item, btrfs_path_item_ptr(p, struct btrfs_root_item), len); + btrfs_root_item_to_cpu(item); + + if (len < sizeof(*item)) + reset = 1; + if (!reset && item->generation != item->generation_v2) { + if (item->generation_v2 != 0) + printf("%s: generation != generation_v2 in root item", + __func__); + reset = 1; + } + if (reset) { + memset(&item->generation_v2, 0, + sizeof(*item) - offsetof(struct btrfs_root_item, + generation_v2)); + } +} + +int btrfs_find_root(u64 objectid, struct btrfs_root *root, + struct btrfs_root_item *root_item) +{ + struct btrfs_path path; + struct btrfs_root_item my_root_item; + + if (!btrfs_search_tree_key_type(&btrfs_info.tree_root, objectid, + BTRFS_ROOT_ITEM_KEY, &path)) + return -1; + + if (!root_item) + root_item = &my_root_item; + read_root_item(&path, root_item); + + if (root) { + root->objectid = objectid; + root->bytenr = root_item->bytenr; + root->root_dirid = root_item->root_dirid; + } + + btrfs_free_path(&path); + return 0; +} + +u64 btrfs_lookup_root_ref(u64 subvolid, struct btrfs_root_ref *refp, char *name) +{ + struct btrfs_path path; + struct btrfs_key *key; + struct btrfs_root_ref *ref; + u64 res = -1ULL; + + key = btrfs_search_tree_key_type(&btrfs_info.tree_root, subvolid, + BTRFS_ROOT_BACKREF_KEY, &path); + + if (!key) + return -1ULL; + + ref = btrfs_path_item_ptr(&path, struct btrfs_root_ref); + btrfs_root_ref_to_cpu(ref); + + if (refp) + *refp = *ref; + + if (name) { + if (ref->name_len > BTRFS_VOL_NAME_MAX) { + printf("%s: volume name too long: %u\n", __func__, + ref->name_len); + goto out; + } + + memcpy(name, ref + 1, ref->name_len); + } + + res = key->offset; +out: + btrfs_free_path(&path); + return res; +} + |