xref: /openbmc/u-boot/fs/btrfs/chunk-map.c (revision e0ed8332)
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