183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
221a14facSMarek Behún /*
321a14facSMarek Behún * BTRFS filesystem implementation for U-Boot
421a14facSMarek Behún *
521a14facSMarek Behún * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
621a14facSMarek Behún */
721a14facSMarek Behún
821a14facSMarek Behún #include "btrfs.h"
921a14facSMarek Behún #include <malloc.h>
1021a14facSMarek Behún
1121a14facSMarek Behún struct chunk_map_item {
1221a14facSMarek Behún struct rb_node node;
1321a14facSMarek Behún u64 logical;
1421a14facSMarek Behún u64 length;
1521a14facSMarek Behún u64 physical;
1621a14facSMarek Behún };
1721a14facSMarek Behún
add_chunk_mapping(struct btrfs_key * key,struct btrfs_chunk * chunk)1821a14facSMarek Behún static int add_chunk_mapping(struct btrfs_key *key, struct btrfs_chunk *chunk)
1921a14facSMarek Behún {
2021a14facSMarek Behún struct btrfs_stripe *stripe;
2121a14facSMarek Behún u64 block_profile = chunk->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
2221a14facSMarek Behún struct rb_node **new = &(btrfs_info.chunks_root.rb_node), *prnt = NULL;
2321a14facSMarek Behún struct chunk_map_item *map_item;
2421a14facSMarek Behún
2521a14facSMarek Behún if (block_profile && block_profile != BTRFS_BLOCK_GROUP_DUP) {
2621a14facSMarek Behún printf("%s: unsupported chunk profile %llu\n", __func__,
2721a14facSMarek Behún block_profile);
2821a14facSMarek Behún return -1;
2921a14facSMarek Behún } else if (!chunk->length) {
3021a14facSMarek Behún printf("%s: zero length chunk\n", __func__);
3121a14facSMarek Behún return -1;
3221a14facSMarek Behún }
3321a14facSMarek Behún
3421a14facSMarek Behún stripe = &chunk->stripe;
3521a14facSMarek Behún btrfs_stripe_to_cpu(stripe);
3621a14facSMarek Behún
3721a14facSMarek Behún while (*new) {
3821a14facSMarek Behún struct chunk_map_item *this;
3921a14facSMarek Behún
4021a14facSMarek Behún this = rb_entry(*new, struct chunk_map_item, node);
4121a14facSMarek Behún
4221a14facSMarek Behún prnt = *new;
4321a14facSMarek Behún if (key->offset < this->logical) {
4421a14facSMarek Behún new = &((*new)->rb_left);
4521a14facSMarek Behún } else if (key->offset > this->logical) {
4621a14facSMarek Behún new = &((*new)->rb_right);
4721a14facSMarek Behún } else {
4821a14facSMarek Behún debug("%s: Logical address %llu already in map!\n",
4921a14facSMarek Behún __func__, key->offset);
5021a14facSMarek Behún return 0;
5121a14facSMarek Behún }
5221a14facSMarek Behún }
5321a14facSMarek Behún
5421a14facSMarek Behún map_item = malloc(sizeof(struct chunk_map_item));
5521a14facSMarek Behún if (!map_item)
5621a14facSMarek Behún return -1;
5721a14facSMarek Behún
5821a14facSMarek Behún map_item->logical = key->offset;
5921a14facSMarek Behún map_item->length = chunk->length;
6021a14facSMarek Behún map_item->physical = le64_to_cpu(chunk->stripe.offset);
6121a14facSMarek Behún rb_link_node(&map_item->node, prnt, new);
6221a14facSMarek Behún rb_insert_color(&map_item->node, &btrfs_info.chunks_root);
6321a14facSMarek Behún
6421a14facSMarek Behún debug("%s: Mapping %llu to %llu\n", __func__, map_item->logical,
6521a14facSMarek Behún map_item->physical);
6621a14facSMarek Behún
6721a14facSMarek Behún return 0;
6821a14facSMarek Behún }
6921a14facSMarek Behún
btrfs_map_logical_to_physical(u64 logical)7021a14facSMarek Behún u64 btrfs_map_logical_to_physical(u64 logical)
7121a14facSMarek Behún {
7221a14facSMarek Behún struct rb_node *node = btrfs_info.chunks_root.rb_node;
7321a14facSMarek Behún
7421a14facSMarek Behún while (node) {
7521a14facSMarek Behún struct chunk_map_item *item;
7621a14facSMarek Behún
7721a14facSMarek Behún item = rb_entry(node, struct chunk_map_item, node);
7821a14facSMarek Behún
7921a14facSMarek Behún if (item->logical > logical)
8021a14facSMarek Behún node = node->rb_left;
81*f8c173b6SMarek Behún else if (logical >= item->logical + item->length)
8221a14facSMarek Behún node = node->rb_right;
8321a14facSMarek Behún else
8421a14facSMarek Behún return item->physical + logical - item->logical;
8521a14facSMarek Behún }
8621a14facSMarek Behún
8721a14facSMarek Behún printf("%s: Cannot map logical address %llu to physical\n", __func__,
8821a14facSMarek Behún logical);
8921a14facSMarek Behún
9021a14facSMarek Behún return -1ULL;
9121a14facSMarek Behún }
9221a14facSMarek Behún
btrfs_chunk_map_exit(void)9321a14facSMarek Behún void btrfs_chunk_map_exit(void)
9421a14facSMarek Behún {
9521a14facSMarek Behún struct rb_node *now, *next;
9621a14facSMarek Behún struct chunk_map_item *item;
9721a14facSMarek Behún
9821a14facSMarek Behún for (now = rb_first_postorder(&btrfs_info.chunks_root); now; now = next)
9921a14facSMarek Behún {
10021a14facSMarek Behún item = rb_entry(now, struct chunk_map_item, node);
10121a14facSMarek Behún next = rb_next_postorder(now);
10221a14facSMarek Behún free(item);
10321a14facSMarek Behún }
10421a14facSMarek Behún }
10521a14facSMarek Behún
btrfs_chunk_map_init(void)10621a14facSMarek Behún int btrfs_chunk_map_init(void)
10721a14facSMarek Behún {
10821a14facSMarek Behún u8 sys_chunk_array_copy[sizeof(btrfs_info.sb.sys_chunk_array)];
10921a14facSMarek Behún u8 * const start = sys_chunk_array_copy;
11021a14facSMarek Behún u8 * const end = start + btrfs_info.sb.sys_chunk_array_size;
11121a14facSMarek Behún u8 *cur;
11221a14facSMarek Behún struct btrfs_key *key;
11321a14facSMarek Behún struct btrfs_chunk *chunk;
11421a14facSMarek Behún
11521a14facSMarek Behún btrfs_info.chunks_root = RB_ROOT;
11621a14facSMarek Behún
11721a14facSMarek Behún memcpy(sys_chunk_array_copy, btrfs_info.sb.sys_chunk_array,
11821a14facSMarek Behún sizeof(sys_chunk_array_copy));
11921a14facSMarek Behún
12021a14facSMarek Behún for (cur = start; cur < end;) {
12121a14facSMarek Behún key = (struct btrfs_key *) cur;
12221a14facSMarek Behún cur += sizeof(struct btrfs_key);
12321a14facSMarek Behún chunk = (struct btrfs_chunk *) cur;
12421a14facSMarek Behún
12521a14facSMarek Behún btrfs_key_to_cpu(key);
12621a14facSMarek Behún btrfs_chunk_to_cpu(chunk);
12721a14facSMarek Behún
12821a14facSMarek Behún if (key->type != BTRFS_CHUNK_ITEM_KEY) {
12921a14facSMarek Behún printf("%s: invalid key type %u\n", __func__,
13021a14facSMarek Behún key->type);
13121a14facSMarek Behún return -1;
13221a14facSMarek Behún }
13321a14facSMarek Behún
13421a14facSMarek Behún if (add_chunk_mapping(key, chunk))
13521a14facSMarek Behún return -1;
13621a14facSMarek Behún
13721a14facSMarek Behún cur += sizeof(struct btrfs_chunk);
13821a14facSMarek Behún cur += sizeof(struct btrfs_stripe) * (chunk->num_stripes - 1);
13921a14facSMarek Behún }
14021a14facSMarek Behún
14121a14facSMarek Behún return 0;
14221a14facSMarek Behún }
14321a14facSMarek Behún
btrfs_read_chunk_tree(void)14421a14facSMarek Behún int btrfs_read_chunk_tree(void)
14521a14facSMarek Behún {
14621a14facSMarek Behún struct btrfs_path path;
14721a14facSMarek Behún struct btrfs_key key, *found_key;
14821a14facSMarek Behún struct btrfs_chunk *chunk;
149ecab881cSMarek Behún int res = 0;
15021a14facSMarek Behún
15121a14facSMarek Behún key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
15221a14facSMarek Behún key.type = BTRFS_CHUNK_ITEM_KEY;
15321a14facSMarek Behún key.offset = 0;
15421a14facSMarek Behún
15521a14facSMarek Behún if (btrfs_search_tree(&btrfs_info.chunk_root, &key, &path))
15621a14facSMarek Behún return -1;
15721a14facSMarek Behún
15821a14facSMarek Behún do {
15921a14facSMarek Behún found_key = btrfs_path_leaf_key(&path);
16021a14facSMarek Behún if (btrfs_comp_keys_type(&key, found_key))
161f5591801SYevgeny Popovych continue;
16221a14facSMarek Behún
16321a14facSMarek Behún chunk = btrfs_path_item_ptr(&path, struct btrfs_chunk);
16421a14facSMarek Behún btrfs_chunk_to_cpu(chunk);
16521a14facSMarek Behún if (add_chunk_mapping(found_key, chunk)) {
16621a14facSMarek Behún res = -1;
16721a14facSMarek Behún break;
16821a14facSMarek Behún }
16921a14facSMarek Behún } while (!(res = btrfs_next_slot(&path)));
17021a14facSMarek Behún
17121a14facSMarek Behún btrfs_free_path(&path);
17221a14facSMarek Behún
17321a14facSMarek Behún if (res < 0)
17421a14facSMarek Behún return -1;
17521a14facSMarek Behún
17621a14facSMarek Behún return 0;
17721a14facSMarek Behún }
178