aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2015-12-24 01:48:13 -0200
committerPaulo Alcantara <pcacjr@zytor.com>2015-12-27 11:55:38 -0200
commit548386049cd41e887079cdb904d3954365eb28f3 (patch)
tree3b0c36b254ea2500c633afb1b3083438ec824b0f
parent721a0af2f0ba111c31685c5f6c5481eb25346971 (diff)
downloadsyslinux-btrfs-fixes-v2.tar.gz
syslinux-btrfs-fixes-v2.tar.xz
syslinux-btrfs-fixes-v2.zip
btrfs: Fix logical to physical block address mappingbtrfs-fixes-v2
The current btrfs support did not handled multiple stripes stored in chunk items, hence skipping the physical addresses that were needed to do the mapping. Besides, the chunk tree may contain DEV_ITEM keys which store information on all of the underlying block devices, so we must skip them instead of finishing lookup. The bug was reproduced with btrfs-progs v4.2.2. Cc: Gene Cumm <gene.cumm@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> --- v1 -> v2: * Do not set ignore_key multiple times. Set it before parsing chunk tree. v2 -> v3: * Replace an unnecessary goto with a continue statement.
-rw-r--r--core/fs/btrfs/btrfs.c49
-rw-r--r--core/fs/btrfs/btrfs.h2
2 files changed, 35 insertions, 16 deletions
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index 53e11050..58e1fe68 100644
--- a/core/fs/btrfs/btrfs.c
+++ b/core/fs/btrfs/btrfs.c
@@ -81,7 +81,8 @@ static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
}
/* insert a new chunk mapping item */
-static void insert_map(struct fs_info *fs, struct btrfs_chunk_map_item *item)
+static void insert_chunk_item(struct fs_info *fs,
+ struct btrfs_chunk_map_item *item)
{
struct btrfs_info * const bfs = fs->fs_info;
struct btrfs_chunk_map *chunk_map = &bfs->chunk_map;
@@ -113,6 +114,22 @@ static void insert_map(struct fs_info *fs, struct btrfs_chunk_map_item *item)
chunk_map->cur_length++;
}
+static inline void insert_map(struct fs_info *fs, struct btrfs_disk_key *key,
+ struct btrfs_chunk *chunk)
+{
+ struct btrfs_stripe *stripe = &chunk->stripe;
+ struct btrfs_stripe *stripe_end = stripe + chunk->num_stripes;
+ struct btrfs_chunk_map_item item;
+
+ item.logical = key->offset;
+ item.length = chunk->length;
+ for ( ; stripe < stripe_end; stripe++) {
+ item.devid = stripe->devid;
+ item.physical = stripe->offset;
+ insert_chunk_item(fs, &item);
+ }
+}
+
/*
* from sys_chunk_array or chunk_tree, we can convert a logical address to
* a physical address we can not support multi device case yet
@@ -330,7 +347,6 @@ static int next_slot(struct fs_info *fs, struct btrfs_disk_key *key,
static void btrfs_read_sys_chunk_array(struct fs_info *fs)
{
struct btrfs_info * const bfs = fs->fs_info;
- struct btrfs_chunk_map_item item;
struct btrfs_disk_key *key;
struct btrfs_chunk *chunk;
int cur;
@@ -342,12 +358,7 @@ static void btrfs_read_sys_chunk_array(struct fs_info *fs)
cur += sizeof(*key);
chunk = (struct btrfs_chunk *)(bfs->sb.sys_chunk_array + cur);
cur += btrfs_chunk_item_size(chunk->num_stripes);
- /* insert to mapping table, ignore multi stripes */
- item.logical = key->offset;
- item.length = chunk->length;
- item.devid = chunk->stripe.devid;
- item.physical = chunk->stripe.offset;/*ignore other stripes */
- insert_map(fs, &item);
+ insert_map(fs, key, chunk);
}
}
@@ -355,14 +366,18 @@ static void btrfs_read_sys_chunk_array(struct fs_info *fs)
static void btrfs_read_chunk_tree(struct fs_info *fs)
{
struct btrfs_info * const bfs = fs->fs_info;
+ struct btrfs_disk_key ignore_key;
struct btrfs_disk_key search_key;
struct btrfs_chunk *chunk;
- struct btrfs_chunk_map_item item;
struct btrfs_path path;
if (!(bfs->sb.flags & BTRFS_SUPER_FLAG_METADUMP)) {
if (bfs->sb.num_devices > 1)
printf("warning: only support single device btrfs\n");
+
+ ignore_key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
+ ignore_key.type = BTRFS_DEV_ITEM_KEY;
+
/* read chunk from chunk_tree */
search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
search_key.type = BTRFS_CHUNK_ITEM_KEY;
@@ -371,16 +386,18 @@ static void btrfs_read_chunk_tree(struct fs_info *fs)
search_tree(fs, bfs->sb.chunk_root, &search_key, &path);
do {
do {
+ /* skip information about underlying block
+ * devices.
+ */
+ if (!btrfs_comp_keys_type(&ignore_key,
+ &path.item.key))
+ continue;
if (btrfs_comp_keys_type(&search_key,
- &path.item.key))
+ &path.item.key))
break;
+
chunk = (struct btrfs_chunk *)(path.data);
- /* insert to mapping table, ignore stripes */
- item.logical = path.item.key.offset;
- item.length = chunk->length;
- item.devid = chunk->stripe.devid;
- item.physical = chunk->stripe.offset;
- insert_map(fs, &item);
+ insert_map(fs, &path.item.key, chunk);
} while (!next_slot(fs, &search_key, &path));
if (btrfs_comp_keys_type(&search_key, &path.item.key))
break;
diff --git a/core/fs/btrfs/btrfs.h b/core/fs/btrfs/btrfs.h
index 8f519a9c..32e7c703 100644
--- a/core/fs/btrfs/btrfs.h
+++ b/core/fs/btrfs/btrfs.h
@@ -56,6 +56,8 @@ typedef u64 __le64;
#define BTRFS_MAX_LEVEL 8
#define BTRFS_MAX_CHUNK_ENTRIES 256
+#define BTRFS_DEV_ITEMS_OBJECTID 1ULL
+
#define BTRFS_FT_REG_FILE 1
#define BTRFS_FT_DIR 2
#define BTRFS_FT_SYMLINK 7