mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-30 16:35:37 +00: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
5 changed files with 306 additions and 3 deletions
|
@ -100,7 +100,7 @@ int btrfs_probe(struct blk_desc *fs_dev_desc,
|
||||||
btrfs_info.chunk_root.objectid = 0;
|
btrfs_info.chunk_root.objectid = 0;
|
||||||
btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
|
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__);
|
printf("%s: failed to read chunk tree\n", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ int btrfs_devread(u64, int, void *);
|
||||||
u64 btrfs_map_logical_to_physical(u64);
|
u64 btrfs_map_logical_to_physical(u64);
|
||||||
int btrfs_chunk_map_init(void);
|
int btrfs_chunk_map_init(void);
|
||||||
void btrfs_chunk_map_exit(void);
|
void btrfs_chunk_map_exit(void);
|
||||||
int btrfs_read_chunk_tree(void);
|
int __btrfs_read_chunk_tree(void);
|
||||||
|
|
||||||
/* compression.c */
|
/* compression.c */
|
||||||
u32 btrfs_decompress(u8 type, const char *, u32, char *, u32);
|
u32 btrfs_decompress(u8 type, const char *, u32, char *, u32);
|
||||||
|
|
|
@ -142,7 +142,7 @@ int btrfs_chunk_map_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_read_chunk_tree(void)
|
int __btrfs_read_chunk_tree(void)
|
||||||
{
|
{
|
||||||
struct __btrfs_path path;
|
struct __btrfs_path path;
|
||||||
struct btrfs_key key, *found_key;
|
struct btrfs_key key, *found_key;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
|
#include "extent-io.h"
|
||||||
|
|
||||||
const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
|
const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
|
||||||
[BTRFS_RAID_RAID10] = {
|
[BTRFS_RAID_RAID10] = {
|
||||||
|
@ -369,6 +370,14 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
|
||||||
return NULL;
|
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
|
* slot == -1: SYSTEM chunk
|
||||||
* return -EIO on error, otherwise return 0
|
* return -EIO on error, otherwise return 0
|
||||||
|
@ -498,6 +507,298 @@ int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info,
|
||||||
return 0;
|
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
|
* 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,
|
return btrfs_next_bg(fs_info, logical, size,
|
||||||
BTRFS_BLOCK_GROUP_SYSTEM);
|
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_open_devices(struct btrfs_fs_devices *fs_devices);
|
||||||
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
|
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
|
||||||
void btrfs_close_all_devices(void);
|
void btrfs_close_all_devices(void);
|
||||||
|
|
Loading…
Add table
Reference in a new issue