mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-11-04 10:21:25 +01:00 
			
		
		
		
	This causes errors when translating logical addresses to physical: btrfs_map_logical_to_physical: Cannot map logical address <addr> to physical btrfs_file_read: Error reading extent The behavior of btrfs_map_logical_to_physical() is to stop traversing CHUNK_TREE when it encounters first non-CHUNK_ITEM, which makes only some portion of CHUNK_ITEMs being read. Change it to skip over non-chunk items. Signed-off-by: Yevgeny Popovych <yevgenyp@pointgrab.com> Cc: Marek Behun <marek.behun@nic.cz> Cc: Sergey Struzh <sergeys@pointgrab.com> Reviewed-by: Marek Behun <marek.behun@nic.cz>
		
			
				
	
	
		
			178 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0+
 | 
						|
/*
 | 
						|
 * BTRFS filesystem implementation for U-Boot
 | 
						|
 *
 | 
						|
 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
 | 
						|
 */
 | 
						|
 | 
						|
#include "btrfs.h"
 | 
						|
#include <malloc.h>
 | 
						|
 | 
						|
struct chunk_map_item {
 | 
						|
	struct rb_node node;
 | 
						|
	u64 logical;
 | 
						|
	u64 length;
 | 
						|
	u64 physical;
 | 
						|
};
 | 
						|
 | 
						|
static int add_chunk_mapping(struct btrfs_key *key, struct btrfs_chunk *chunk)
 | 
						|
{
 | 
						|
	struct btrfs_stripe *stripe;
 | 
						|
	u64 block_profile = chunk->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
 | 
						|
	struct rb_node **new = &(btrfs_info.chunks_root.rb_node), *prnt = NULL;
 | 
						|
	struct chunk_map_item *map_item;
 | 
						|
 | 
						|
	if (block_profile && block_profile != BTRFS_BLOCK_GROUP_DUP) {
 | 
						|
		printf("%s: unsupported chunk profile %llu\n", __func__,
 | 
						|
		       block_profile);
 | 
						|
		return -1;
 | 
						|
	} else if (!chunk->length) {
 | 
						|
		printf("%s: zero length chunk\n", __func__);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	stripe = &chunk->stripe;
 | 
						|
	btrfs_stripe_to_cpu(stripe);
 | 
						|
 | 
						|
	while (*new) {
 | 
						|
		struct chunk_map_item *this;
 | 
						|
 | 
						|
		this = rb_entry(*new, struct chunk_map_item, node);
 | 
						|
 | 
						|
		prnt = *new;
 | 
						|
		if (key->offset < this->logical) {
 | 
						|
			new = &((*new)->rb_left);
 | 
						|
		} else if (key->offset > this->logical) {
 | 
						|
			new = &((*new)->rb_right);
 | 
						|
		} else {
 | 
						|
			debug("%s: Logical address %llu already in map!\n",
 | 
						|
			      __func__, key->offset);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	map_item = malloc(sizeof(struct chunk_map_item));
 | 
						|
	if (!map_item)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	map_item->logical = key->offset;
 | 
						|
	map_item->length = chunk->length;
 | 
						|
	map_item->physical = le64_to_cpu(chunk->stripe.offset);
 | 
						|
	rb_link_node(&map_item->node, prnt, new);
 | 
						|
	rb_insert_color(&map_item->node, &btrfs_info.chunks_root);
 | 
						|
 | 
						|
	debug("%s: Mapping %llu to %llu\n", __func__, map_item->logical,
 | 
						|
	      map_item->physical);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
u64 btrfs_map_logical_to_physical(u64 logical)
 | 
						|
{
 | 
						|
	struct rb_node *node = btrfs_info.chunks_root.rb_node;
 | 
						|
 | 
						|
	while (node) {
 | 
						|
		struct chunk_map_item *item;
 | 
						|
 | 
						|
		item = rb_entry(node, struct chunk_map_item, node);
 | 
						|
 | 
						|
		if (item->logical > logical)
 | 
						|
			node = node->rb_left;
 | 
						|
		else if (logical > item->logical + item->length)
 | 
						|
			node = node->rb_right;
 | 
						|
		else
 | 
						|
			return item->physical + logical - item->logical;
 | 
						|
	}
 | 
						|
 | 
						|
	printf("%s: Cannot map logical address %llu to physical\n", __func__,
 | 
						|
	       logical);
 | 
						|
 | 
						|
	return -1ULL;
 | 
						|
}
 | 
						|
 | 
						|
void btrfs_chunk_map_exit(void)
 | 
						|
{
 | 
						|
	struct rb_node *now, *next;
 | 
						|
	struct chunk_map_item *item;
 | 
						|
 | 
						|
	for (now = rb_first_postorder(&btrfs_info.chunks_root); now; now = next)
 | 
						|
	{
 | 
						|
		item = rb_entry(now, struct chunk_map_item, node);
 | 
						|
		next = rb_next_postorder(now);
 | 
						|
		free(item);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int btrfs_chunk_map_init(void)
 | 
						|
{
 | 
						|
	u8 sys_chunk_array_copy[sizeof(btrfs_info.sb.sys_chunk_array)];
 | 
						|
	u8 * const start = sys_chunk_array_copy;
 | 
						|
	u8 * const end = start + btrfs_info.sb.sys_chunk_array_size;
 | 
						|
	u8 *cur;
 | 
						|
	struct btrfs_key *key;
 | 
						|
	struct btrfs_chunk *chunk;
 | 
						|
 | 
						|
	btrfs_info.chunks_root = RB_ROOT;
 | 
						|
 | 
						|
	memcpy(sys_chunk_array_copy, btrfs_info.sb.sys_chunk_array,
 | 
						|
	       sizeof(sys_chunk_array_copy));
 | 
						|
 | 
						|
	for (cur = start; cur < end;) {
 | 
						|
		key = (struct btrfs_key *) cur;
 | 
						|
		cur += sizeof(struct btrfs_key);
 | 
						|
		chunk = (struct btrfs_chunk *) cur;
 | 
						|
 | 
						|
		btrfs_key_to_cpu(key);
 | 
						|
		btrfs_chunk_to_cpu(chunk);
 | 
						|
 | 
						|
		if (key->type != BTRFS_CHUNK_ITEM_KEY) {
 | 
						|
			printf("%s: invalid key type %u\n", __func__,
 | 
						|
			       key->type);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
 | 
						|
		if (add_chunk_mapping(key, chunk))
 | 
						|
			return -1;
 | 
						|
 | 
						|
		cur += sizeof(struct btrfs_chunk);
 | 
						|
		cur += sizeof(struct btrfs_stripe) * (chunk->num_stripes - 1);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int btrfs_read_chunk_tree(void)
 | 
						|
{
 | 
						|
	struct btrfs_path path;
 | 
						|
	struct btrfs_key key, *found_key;
 | 
						|
	struct btrfs_chunk *chunk;
 | 
						|
	int res = 0;
 | 
						|
 | 
						|
	key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
 | 
						|
	key.type = BTRFS_CHUNK_ITEM_KEY;
 | 
						|
	key.offset = 0;
 | 
						|
 | 
						|
	if (btrfs_search_tree(&btrfs_info.chunk_root, &key, &path))
 | 
						|
		return -1;
 | 
						|
 | 
						|
	do {
 | 
						|
		found_key = btrfs_path_leaf_key(&path);
 | 
						|
		if (btrfs_comp_keys_type(&key, found_key))
 | 
						|
			continue;
 | 
						|
 | 
						|
		chunk = btrfs_path_item_ptr(&path, struct btrfs_chunk);
 | 
						|
		btrfs_chunk_to_cpu(chunk);
 | 
						|
		if (add_chunk_mapping(found_key, chunk)) {
 | 
						|
			res = -1;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	} while (!(res = btrfs_next_slot(&path)));
 | 
						|
 | 
						|
	btrfs_free_path(&path);
 | 
						|
 | 
						|
	if (res < 0)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |