123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- From 548386049cd41e887079cdb904d3954365eb28f3 Mon Sep 17 00:00:00 2001
- From: Paulo Alcantara <pcacjr@zytor.com>
- Date: Thu, 24 Dec 2015 01:48:13 -0200
- Subject: [PATCH 1/1] btrfs: Fix logical to physical block address mapping
- 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.
- ---
- core/fs/btrfs/btrfs.c | 49 +++++++++++++++++++++++++++++++++----------------
- core/fs/btrfs/btrfs.h | 2 ++
- 2 files changed, 35 insertions(+), 16 deletions(-)
- diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
- index 53e1105..58e1fe6 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 8f519a9..32e7c70 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
- --
- 2.5.5.GIT
|