mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.0 KiB
177 lines
4.0 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
/* |
|
* BTRFS filesystem implementation for U-Boot |
|
* |
|
* 2017 Marek Behun, CZ.NIC, [email protected] |
|
*/ |
|
|
|
#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; |
|
}
|
|
|