All of lore.kernel.org
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org, fstests@vger.kernel.org,
	u-boot@lists.denx.de
Cc: marek.behun@nic.cz
Subject: [PATCH U-BOOT 14/26] fs: btrfs: Crossport btrfs_read_sys_array() and btrfs_read_chunk_tree()
Date: Wed, 22 Apr 2020 14:49:57 +0800	[thread overview]
Message-ID: <20200422065009.69392-15-wqu@suse.com> (raw)
In-Reply-To: <20200422065009.69392-1-wqu@suse.com>

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>
---
 fs/btrfs/btrfs.c     |   2 +-
 fs/btrfs/btrfs.h     |   2 +-
 fs/btrfs/chunk-map.c |   2 +-
 fs/btrfs/volumes.c   | 301 +++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/volumes.h   |   2 +
 5 files changed, 306 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c
index 1cb56ea0124d..4f2fa2fe6c9f 100644
--- a/fs/btrfs/btrfs.c
+++ b/fs/btrfs/btrfs.c
@@ -98,7 +98,7 @@ int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition)
 	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;
 	}
diff --git a/fs/btrfs/btrfs.h b/fs/btrfs/btrfs.h
index 57cdb5aad58c..037492fa06a8 100644
--- a/fs/btrfs/btrfs.h
+++ b/fs/btrfs/btrfs.h
@@ -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);
diff --git a/fs/btrfs/chunk-map.c b/fs/btrfs/chunk-map.c
index 85c3efc63e16..49d8835e14e9 100644
--- a/fs/btrfs/chunk-map.c
+++ b/fs/btrfs/chunk-map.c
@@ -141,7 +141,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;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 63853cb2a1dd..56cf7ac8c631 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -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
  *
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 4383b4f9c034..d0c09d831c74 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -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);
-- 
2.26.0


WARNING: multiple messages have this Message-ID (diff)
From: Qu Wenruo <wqu@suse.com>
To: u-boot@lists.denx.de
Subject: [PATCH U-BOOT 14/26] fs: btrfs: Crossport btrfs_read_sys_array() and btrfs_read_chunk_tree()
Date: Wed, 22 Apr 2020 14:49:57 +0800	[thread overview]
Message-ID: <20200422065009.69392-15-wqu@suse.com> (raw)
In-Reply-To: <20200422065009.69392-1-wqu@suse.com>

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>
---
 fs/btrfs/btrfs.c     |   2 +-
 fs/btrfs/btrfs.h     |   2 +-
 fs/btrfs/chunk-map.c |   2 +-
 fs/btrfs/volumes.c   | 301 +++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/volumes.h   |   2 +
 5 files changed, 306 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c
index 1cb56ea0124d..4f2fa2fe6c9f 100644
--- a/fs/btrfs/btrfs.c
+++ b/fs/btrfs/btrfs.c
@@ -98,7 +98,7 @@ int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition)
 	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;
 	}
diff --git a/fs/btrfs/btrfs.h b/fs/btrfs/btrfs.h
index 57cdb5aad58c..037492fa06a8 100644
--- a/fs/btrfs/btrfs.h
+++ b/fs/btrfs/btrfs.h
@@ -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);
diff --git a/fs/btrfs/chunk-map.c b/fs/btrfs/chunk-map.c
index 85c3efc63e16..49d8835e14e9 100644
--- a/fs/btrfs/chunk-map.c
+++ b/fs/btrfs/chunk-map.c
@@ -141,7 +141,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;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 63853cb2a1dd..56cf7ac8c631 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -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
  *
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 4383b4f9c034..d0c09d831c74 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -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);
-- 
2.26.0

  parent reply	other threads:[~2020-04-22  6:51 UTC|newest]

Thread overview: 85+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-22  6:49 [PATCH U-BOOT 00/26] fs: btrfs: Re-implement btrfs support using the more widely used extent buffer base code Qu Wenruo
2020-04-22  6:49 ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 01/26] fs: btrfs: Sync btrfs_btree.h from kernel Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 02/26] fs: btrfs: Add More checksum algorithm support to btrfs Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 03/26] fs: btrfs: Cross-port btrfs_read_dev_super() from btrfs-progs Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  8:26   ` Marek Behun
2020-04-22  8:26     ` Marek Behun
2020-04-22  8:34     ` Qu Wenruo
2020-04-22  8:34       ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 04/26] fs: btrfs: Cross-port rbtree-utils " Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 05/26] fs: btrfs: Cross-port extent-cache.[ch] " Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 06/26] fs: btrfs: Cross-port extent-io.[ch] " Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 07/26] fs: btrfs: Cross port structure accessor into ctree.h Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 08/26] fs: btrfs: Cross port volumes.[ch] from btrfs-progs Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 09/26] fs: btrfs: Crossport read_tree_block() " Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 10/26] fs: btrfs: Rename struct btrfs_path to struct __btrfs_path Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 11/26] fs: btrfs: Rename btrfs_root to __btrfs_root Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 12/26] fs: btrfs: Cross port struct btrfs_root to ctree.h Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 13/26] fs: btrfs: Crossport btrfs_search_slot() from btrfs-progs Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` Qu Wenruo [this message]
2020-04-22  6:49   ` [PATCH U-BOOT 14/26] fs: btrfs: Crossport btrfs_read_sys_array() and btrfs_read_chunk_tree() Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 15/26] fs: btrfs: Crossport open_ctree_fs_info() Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:49 ` [PATCH U-BOOT 16/26] fs: btrfs: Rename path resolve related functions to avoid name conflicts Qu Wenruo
2020-04-22  6:49   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 17/26] fs: btrfs: Use btrfs_readlink() to implement __btrfs_readlink() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 18/26] fs: btrfs: Implement btrfs_lookup_path() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  9:37   ` Su Yue
2020-04-22  9:46   ` Su Yue
2020-04-22  9:46     ` Su Yue
2020-04-22 10:04     ` Marek Behun
2020-04-22 10:04       ` Marek Behun
2020-04-22 14:17       ` Su Yue
2020-04-22 14:17         ` Su Yue
2020-04-22 14:44   ` Su Yue
2020-04-22 14:44     ` Su Yue
2020-04-22 14:49     ` Marek Behun
2020-04-22 14:49       ` Marek Behun
2020-04-22  6:50 ` [PATCH U-BOOT 19/26] fs: btrfs: Use btrfs_iter_dir() to replace btrfs_readdir() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 20/26] fs: btrfs: Use btrfs_lookup_path() to implement btrfs_exists() and btrfs_size() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 21/26] fs: btrfs: Rename btrfs_file_read() and its callees to avoid name conflicts Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 22/26] fs: btrfs: Introduce btrfs_read_extent_inline() and btrfs_read_extent_reg() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 23/26] fs: btrfs: Introduce lookup_data_extent() for later use Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 24/26] fs: btrfs: Implement btrfs_file_read() Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 25/26] fs: btrfs: Cleanup the old implementation Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  6:50 ` [PATCH U-BOOT 26/26] MAINTAINERS: Add btrfs mail list Qu Wenruo
2020-04-22  6:50   ` Qu Wenruo
2020-04-22  7:46 ` [PATCH U-BOOT 00/26] fs: btrfs: Re-implement btrfs support using the more widely used extent buffer base code Marek Behun
2020-04-22  7:46   ` Marek Behun
2020-04-22  7:52   ` Qu Wenruo
2020-04-22  7:52     ` Qu Wenruo
2020-04-22  7:56     ` Qu Wenruo
2020-04-22  7:56       ` Qu Wenruo
2020-04-22  9:33     ` Marek Behun
2020-04-22  9:33       ` Marek Behun
2020-04-22  7:52 ` Marek Behun
2020-04-22  7:52   ` Marek Behun
2020-04-22  7:59 ` Marek Behun
2020-04-22  7:59   ` Marek Behun
2020-04-22  8:12   ` Qu Wenruo
2020-04-22  8:12     ` Qu Wenruo
2020-04-22  8:13 ` Marek Behun
2020-04-22  8:13   ` Marek Behun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200422065009.69392-15-wqu@suse.com \
    --to=wqu@suse.com \
    --cc=fstests@vger.kernel.org \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=marek.behun@nic.cz \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.