151 lines
5.0 KiB
Diff
151 lines
5.0 KiB
Diff
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
|
|
|