mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-23 20:24:26 +08:00
fs: btrfs: Crossport btrfs_read_sys_array() and btrfs_read_chunk_tree()
These two functions play a big role in btrfs bootstrap. The following function is removed: - Seed device support Although in theory we can still support multiple devices, we don't have a facility in U-Boot to do device scan without opening them. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Marek Behún <marek.behun@nic.cz>
This commit is contained in:
parent
29c26ae8bc
commit
57f24f1073
@ -100,7 +100,7 @@ int btrfs_probe(struct blk_desc *fs_dev_desc,
|
||||
btrfs_info.chunk_root.objectid = 0;
|
||||
btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
|
||||
|
||||
if (btrfs_read_chunk_tree()) {
|
||||
if (__btrfs_read_chunk_tree()) {
|
||||
printf("%s: failed to read chunk tree\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ int btrfs_devread(u64, int, void *);
|
||||
u64 btrfs_map_logical_to_physical(u64);
|
||||
int btrfs_chunk_map_init(void);
|
||||
void btrfs_chunk_map_exit(void);
|
||||
int btrfs_read_chunk_tree(void);
|
||||
int __btrfs_read_chunk_tree(void);
|
||||
|
||||
/* compression.c */
|
||||
u32 btrfs_decompress(u8 type, const char *, u32, char *, u32);
|
||||
|
@ -142,7 +142,7 @@ int btrfs_chunk_map_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_read_chunk_tree(void)
|
||||
int __btrfs_read_chunk_tree(void)
|
||||
{
|
||||
struct __btrfs_path path;
|
||||
struct btrfs_key key, *found_key;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "volumes.h"
|
||||
#include "extent-io.h"
|
||||
|
||||
const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
|
||||
[BTRFS_RAID_RAID10] = {
|
||||
@ -369,6 +370,14 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct btrfs_device *fill_missing_device(u64 devid)
|
||||
{
|
||||
struct btrfs_device *device;
|
||||
|
||||
device = kzalloc(sizeof(*device), GFP_NOFS);
|
||||
return device;
|
||||
}
|
||||
|
||||
/*
|
||||
* slot == -1: SYSTEM chunk
|
||||
* return -EIO on error, otherwise return 0
|
||||
@ -498,6 +507,298 @@ int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slot is used to verify the chunk item is valid
|
||||
*
|
||||
* For sys chunk in superblock, pass -1 to indicate sys chunk.
|
||||
*/
|
||||
static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
|
||||
struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk, int slot)
|
||||
{
|
||||
struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
|
||||
struct map_lookup *map;
|
||||
struct cache_extent *ce;
|
||||
u64 logical;
|
||||
u64 length;
|
||||
u64 devid;
|
||||
u8 uuid[BTRFS_UUID_SIZE];
|
||||
int num_stripes;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
logical = key->offset;
|
||||
length = btrfs_chunk_length(leaf, chunk);
|
||||
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
|
||||
/* Validation check */
|
||||
ret = btrfs_check_chunk_valid(fs_info, leaf, chunk, slot, logical);
|
||||
if (ret) {
|
||||
error("%s checksums match, but it has an invalid chunk, %s",
|
||||
(slot == -1) ? "Superblock" : "Metadata",
|
||||
(slot == -1) ? "try btrfsck --repair -s <superblock> ie, 0,1,2" : "");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ce = search_cache_extent(&map_tree->cache_tree, logical);
|
||||
|
||||
/* already mapped? */
|
||||
if (ce && ce->start <= logical && ce->start + ce->size > logical) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->ce.start = logical;
|
||||
map->ce.size = length;
|
||||
map->num_stripes = num_stripes;
|
||||
map->io_width = btrfs_chunk_io_width(leaf, chunk);
|
||||
map->io_align = btrfs_chunk_io_align(leaf, chunk);
|
||||
map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
|
||||
map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
|
||||
map->type = btrfs_chunk_type(leaf, chunk);
|
||||
map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
|
||||
|
||||
for (i = 0; i < num_stripes; i++) {
|
||||
map->stripes[i].physical =
|
||||
btrfs_stripe_offset_nr(leaf, chunk, i);
|
||||
devid = btrfs_stripe_devid_nr(leaf, chunk, i);
|
||||
read_extent_buffer(leaf, uuid, (unsigned long)
|
||||
btrfs_stripe_dev_uuid_nr(chunk, i),
|
||||
BTRFS_UUID_SIZE);
|
||||
map->stripes[i].dev = btrfs_find_device(fs_info, devid, uuid,
|
||||
NULL);
|
||||
if (!map->stripes[i].dev) {
|
||||
map->stripes[i].dev = fill_missing_device(devid);
|
||||
printf("warning, device %llu is missing\n",
|
||||
(unsigned long long)devid);
|
||||
list_add(&map->stripes[i].dev->dev_list,
|
||||
&fs_info->fs_devices->devices);
|
||||
}
|
||||
|
||||
}
|
||||
ret = insert_cache_extent(&map_tree->cache_tree, &map->ce);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
error("failed to add chunk map start=%llu len=%llu: %d (%m)",
|
||||
map->ce.start, map->ce.size, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_device_from_item(struct extent_buffer *leaf,
|
||||
struct btrfs_dev_item *dev_item,
|
||||
struct btrfs_device *device)
|
||||
{
|
||||
unsigned long ptr;
|
||||
|
||||
device->devid = btrfs_device_id(leaf, dev_item);
|
||||
device->total_bytes = btrfs_device_total_bytes(leaf, dev_item);
|
||||
device->bytes_used = btrfs_device_bytes_used(leaf, dev_item);
|
||||
device->type = btrfs_device_type(leaf, dev_item);
|
||||
device->io_align = btrfs_device_io_align(leaf, dev_item);
|
||||
device->io_width = btrfs_device_io_width(leaf, dev_item);
|
||||
device->sector_size = btrfs_device_sector_size(leaf, dev_item);
|
||||
|
||||
ptr = (unsigned long)btrfs_device_uuid(dev_item);
|
||||
read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_one_dev(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *leaf,
|
||||
struct btrfs_dev_item *dev_item)
|
||||
{
|
||||
struct btrfs_device *device;
|
||||
u64 devid;
|
||||
int ret = 0;
|
||||
u8 fs_uuid[BTRFS_UUID_SIZE];
|
||||
u8 dev_uuid[BTRFS_UUID_SIZE];
|
||||
|
||||
devid = btrfs_device_id(leaf, dev_item);
|
||||
read_extent_buffer(leaf, dev_uuid,
|
||||
(unsigned long)btrfs_device_uuid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
read_extent_buffer(leaf, fs_uuid,
|
||||
(unsigned long)btrfs_device_fsid(dev_item),
|
||||
BTRFS_FSID_SIZE);
|
||||
|
||||
if (memcmp(fs_uuid, fs_info->fs_devices->fsid, BTRFS_UUID_SIZE)) {
|
||||
error("Seed device is not yet supported\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid);
|
||||
if (!device) {
|
||||
device = kzalloc(sizeof(*device), GFP_NOFS);
|
||||
if (!device)
|
||||
return -ENOMEM;
|
||||
list_add(&device->dev_list,
|
||||
&fs_info->fs_devices->devices);
|
||||
}
|
||||
|
||||
fill_device_from_item(leaf, dev_item, device);
|
||||
fs_info->fs_devices->total_rw_bytes +=
|
||||
btrfs_device_total_bytes(leaf, dev_item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_read_sys_array(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
struct btrfs_super_block *super_copy = fs_info->super_copy;
|
||||
struct extent_buffer *sb;
|
||||
struct btrfs_disk_key *disk_key;
|
||||
struct btrfs_chunk *chunk;
|
||||
u8 *array_ptr;
|
||||
unsigned long sb_array_offset;
|
||||
int ret = 0;
|
||||
u32 num_stripes;
|
||||
u32 array_size;
|
||||
u32 len = 0;
|
||||
u32 cur_offset;
|
||||
struct btrfs_key key;
|
||||
|
||||
if (fs_info->nodesize < BTRFS_SUPER_INFO_SIZE) {
|
||||
printf("ERROR: nodesize %u too small to read superblock\n",
|
||||
fs_info->nodesize);
|
||||
return -EINVAL;
|
||||
}
|
||||
sb = alloc_dummy_extent_buffer(fs_info, BTRFS_SUPER_INFO_OFFSET,
|
||||
BTRFS_SUPER_INFO_SIZE);
|
||||
if (!sb)
|
||||
return -ENOMEM;
|
||||
btrfs_set_buffer_uptodate(sb);
|
||||
write_extent_buffer(sb, super_copy, 0, sizeof(*super_copy));
|
||||
array_size = btrfs_super_sys_array_size(super_copy);
|
||||
|
||||
array_ptr = super_copy->sys_chunk_array;
|
||||
sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array);
|
||||
cur_offset = 0;
|
||||
|
||||
while (cur_offset < array_size) {
|
||||
disk_key = (struct btrfs_disk_key *)array_ptr;
|
||||
len = sizeof(*disk_key);
|
||||
if (cur_offset + len > array_size)
|
||||
goto out_short_read;
|
||||
|
||||
btrfs_disk_key_to_cpu(&key, disk_key);
|
||||
|
||||
array_ptr += len;
|
||||
sb_array_offset += len;
|
||||
cur_offset += len;
|
||||
|
||||
if (key.type == BTRFS_CHUNK_ITEM_KEY) {
|
||||
chunk = (struct btrfs_chunk *)sb_array_offset;
|
||||
/*
|
||||
* At least one btrfs_chunk with one stripe must be
|
||||
* present, exact stripe count check comes afterwards
|
||||
*/
|
||||
len = btrfs_chunk_item_size(1);
|
||||
if (cur_offset + len > array_size)
|
||||
goto out_short_read;
|
||||
|
||||
num_stripes = btrfs_chunk_num_stripes(sb, chunk);
|
||||
if (!num_stripes) {
|
||||
printk(
|
||||
"ERROR: invalid number of stripes %u in sys_array at offset %u\n",
|
||||
num_stripes, cur_offset);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
len = btrfs_chunk_item_size(num_stripes);
|
||||
if (cur_offset + len > array_size)
|
||||
goto out_short_read;
|
||||
|
||||
ret = read_one_chunk(fs_info, &key, sb, chunk, -1);
|
||||
if (ret)
|
||||
break;
|
||||
} else {
|
||||
printk(
|
||||
"ERROR: unexpected item type %u in sys_array at offset %u\n",
|
||||
(u32)key.type, cur_offset);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
array_ptr += len;
|
||||
sb_array_offset += len;
|
||||
cur_offset += len;
|
||||
}
|
||||
free_extent_buffer(sb);
|
||||
return ret;
|
||||
|
||||
out_short_read:
|
||||
printk("ERROR: sys_array too short to read %u bytes at offset %u\n",
|
||||
len, cur_offset);
|
||||
free_extent_buffer(sb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_root *root = fs_info->chunk_root;
|
||||
int ret;
|
||||
int slot;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Read all device items, and then all the chunk items. All
|
||||
* device items are found before any chunk item (their object id
|
||||
* is smaller than the lowest possible object id for a chunk
|
||||
* item - BTRFS_FIRST_CHUNK_TREE_OBJECTID).
|
||||
*/
|
||||
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
|
||||
key.offset = 0;
|
||||
key.type = 0;
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
while(1) {
|
||||
leaf = path->nodes[0];
|
||||
slot = path->slots[0];
|
||||
if (slot >= btrfs_header_nritems(leaf)) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret == 0)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
||||
if (found_key.type == BTRFS_DEV_ITEM_KEY) {
|
||||
struct btrfs_dev_item *dev_item;
|
||||
dev_item = btrfs_item_ptr(leaf, slot,
|
||||
struct btrfs_dev_item);
|
||||
ret = read_one_dev(fs_info, leaf, dev_item);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
} else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) {
|
||||
struct btrfs_chunk *chunk;
|
||||
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
|
||||
ret = read_one_chunk(fs_info, &found_key, leaf, chunk,
|
||||
slot);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
path->slots[0]++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get stripe length from chunk item and its stripe items
|
||||
*
|
||||
|
@ -182,6 +182,8 @@ static inline int btrfs_next_bg_system(struct btrfs_fs_info *fs_info,
|
||||
return btrfs_next_bg(fs_info, logical, size,
|
||||
BTRFS_BLOCK_GROUP_SYSTEM);
|
||||
}
|
||||
int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices);
|
||||
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
|
||||
void btrfs_close_all_devices(void);
|
||||
|
Loading…
Reference in New Issue
Block a user