Btrfs-progs: Add chunk recover function - using old chunk items

Add chunk-recover program to check or rebuild chunk tree when the system
chunk array or chunk tree is broken.

Due to the importance of the system chunk array and chunk tree, if one of
them is broken, the whole btrfs will be broken even other data are OK.

But we have some hint(fsid, checksum...) to salvage the old metadata.
So this function will first scan the whole file system and collect the
needed data(chunk/block group/dev extent), and check for the references
between them. If the references are OK, the chunk tree can be rebuilt and
luckily the file system will be mountable.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
Miao Xie 2013-07-03 21:25:17 +08:00 committed by Chris Mason
parent 65534643f6
commit 30d5c8a49f
12 changed files with 1672 additions and 131 deletions

View File

@ -10,7 +10,7 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \
cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \
cmds-restore.o
cmds-restore.o cmds-chunk.o
libbtrfs_objects = send-stream.o send-utils.o rbtree.o btrfs-list.o crc32c.o
libbtrfs_headers = send-stream.h send-utils.h send.h rbtree.h btrfs-list.h \
crc32c.h list.h kerncompat.h radix-tree.h extent-cache.h \

View File

@ -247,6 +247,7 @@ const struct cmd_group btrfs_cmd_group = {
{ "device", cmd_device, NULL, &device_cmd_group, 0 },
{ "scrub", cmd_scrub, NULL, &scrub_cmd_group, 0 },
{ "check", cmd_check, cmd_check_usage, NULL, 0 },
{ "chunk-recover", cmd_chunk_recover, cmd_chunk_recover_usage, NULL, 0},
{ "restore", cmd_restore, cmd_restore_usage, NULL, 0 },
{ "inspect-internal", cmd_inspect, NULL, &inspect_cmd_group, 0 },
{ "send", cmd_send, cmd_send_usage, NULL, 0 },

View File

@ -35,6 +35,8 @@ struct block_group_record {
/* Used to identify the orphan block groups */
struct list_head list;
u64 generation;
u64 objectid;
u8 type;
u64 offset;
@ -51,6 +53,8 @@ struct device_record {
struct rb_node node;
u64 devid;
u64 generation;
u64 objectid;
u8 type;
u64 offset;
@ -64,19 +68,31 @@ struct device_record {
struct stripe {
u64 devid;
u64 offset;
u8 dev_uuid[BTRFS_UUID_SIZE];
};
struct chunk_record {
struct cache_extent cache;
struct list_head list;
struct list_head dextents;
struct block_group_record *bg_rec;
u64 generation;
u64 objectid;
u8 type;
u64 offset;
u64 owner;
u64 length;
u64 type_flags;
u64 stripe_len;
u16 num_stripes;
u16 sub_stripes;
u32 io_align;
u32 io_width;
u32 sector_size;
struct stripe stripes[0];
};
@ -89,6 +105,8 @@ struct device_extent_record {
struct list_head chunk_list;
struct list_head device_list;
u64 generation;
u64 objectid;
u8 type;
u64 offset;
@ -115,4 +133,50 @@ struct device_extent_tree {
struct list_head no_device_orphans;
};
static inline unsigned long btrfs_chunk_record_size(int num_stripes)
{
return sizeof(struct chunk_record) +
sizeof(struct stripe) * num_stripes;
}
void free_chunk_cache_tree(struct cache_tree *chunk_cache);
/* For block group tree */
static inline void block_group_tree_init(struct block_group_tree *tree)
{
cache_tree_init(&tree->tree);
INIT_LIST_HEAD(&tree->block_groups);
}
int insert_block_group_record(struct block_group_tree *tree,
struct block_group_record *bg_rec);
void free_block_group_tree(struct block_group_tree *tree);
/* For device extent tree */
static inline void device_extent_tree_init(struct device_extent_tree *tree)
{
cache_tree_init(&tree->tree);
INIT_LIST_HEAD(&tree->no_chunk_orphans);
INIT_LIST_HEAD(&tree->no_device_orphans);
}
int insert_device_extent_record(struct device_extent_tree *tree,
struct device_extent_record *de_rec);
void free_device_extent_tree(struct device_extent_tree *tree);
/* Create various in-memory record by on-disk data */
struct chunk_record *btrfs_new_chunk_record(struct extent_buffer *leaf,
struct btrfs_key *key,
int slot);
struct block_group_record *
btrfs_new_block_group_record(struct extent_buffer *leaf, struct btrfs_key *key,
int slot);
struct device_extent_record *
btrfs_new_device_extent_record(struct extent_buffer *leaf,
struct btrfs_key *key, int slot);
int check_chunks(struct cache_tree *chunk_cache,
struct block_group_tree *block_group_cache,
struct device_extent_tree *dev_extent_cache,
struct list_head *good, struct list_head *bad, int silent);
#endif

View File

@ -2625,7 +2625,10 @@ static void free_chunk_record(struct cache_extent *cache)
free(rec);
}
FREE_EXTENT_CACHE_BASED_TREE(chunk_cache, free_chunk_record);
void free_chunk_cache_tree(struct cache_tree *chunk_cache)
{
cache_tree_free_extents(chunk_cache, free_chunk_record);
}
static void free_device_record(struct rb_node *node)
{
@ -2637,13 +2640,7 @@ static void free_device_record(struct rb_node *node)
FREE_RB_BASED_TREE(device_cache, free_device_record);
static void block_group_tree_init(struct block_group_tree *tree)
{
cache_tree_init(&tree->tree);
INIT_LIST_HEAD(&tree->block_groups);
}
static int insert_block_group_record(struct block_group_tree *tree,
int insert_block_group_record(struct block_group_tree *tree,
struct block_group_record *bg_rec)
{
int ret;
@ -2664,19 +2661,12 @@ static void free_block_group_record(struct cache_extent *cache)
free(rec);
}
static void free_block_group_tree(struct block_group_tree *tree)
void free_block_group_tree(struct block_group_tree *tree)
{
cache_tree_free_extents(&tree->tree, free_block_group_record);
}
static void device_extent_tree_init(struct device_extent_tree *tree)
{
cache_tree_init(&tree->tree);
INIT_LIST_HEAD(&tree->no_chunk_orphans);
INIT_LIST_HEAD(&tree->no_device_orphans);
}
static int insert_device_extent_record(struct device_extent_tree *tree,
int insert_device_extent_record(struct device_extent_tree *tree,
struct device_extent_record *de_rec)
{
int ret;
@ -2704,7 +2694,7 @@ static void free_device_extent_record(struct cache_extent *cache)
free(rec);
}
static void free_device_extent_tree(struct device_extent_tree *tree)
void free_device_extent_tree(struct device_extent_tree *tree)
{
cache_tree_free_extents(&tree->tree, free_device_extent_record);
}
@ -2728,50 +2718,69 @@ static int process_extent_ref_v0(struct cache_tree *extent_cache,
}
#endif
static inline unsigned long chunk_record_size(int num_stripes)
{
return sizeof(struct chunk_record) +
sizeof(struct stripe) * num_stripes;
}
static int process_chunk_item(struct cache_tree *chunk_cache,
struct btrfs_key *key, struct extent_buffer *eb, int slot)
struct chunk_record *btrfs_new_chunk_record(struct extent_buffer *leaf,
struct btrfs_key *key,
int slot)
{
struct btrfs_chunk *ptr;
struct chunk_record *rec;
int num_stripes, i;
int ret = 0;
ptr = btrfs_item_ptr(eb,
slot, struct btrfs_chunk);
ptr = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
num_stripes = btrfs_chunk_num_stripes(leaf, ptr);
num_stripes = btrfs_chunk_num_stripes(eb, ptr);
rec = malloc(chunk_record_size(num_stripes));
rec = malloc(btrfs_chunk_record_size(num_stripes));
if (!rec) {
fprintf(stderr, "memory allocation failed\n");
return -ENOMEM;
exit(-1);
}
memset(rec, 0, btrfs_chunk_record_size(num_stripes));
INIT_LIST_HEAD(&rec->list);
INIT_LIST_HEAD(&rec->dextents);
rec->bg_rec = NULL;
rec->cache.start = key->offset;
rec->cache.size = btrfs_chunk_length(eb, ptr);
rec->cache.size = btrfs_chunk_length(leaf, ptr);
rec->generation = btrfs_header_generation(leaf);
rec->objectid = key->objectid;
rec->type = key->type;
rec->offset = key->offset;
rec->length = rec->cache.size;
rec->type_flags = btrfs_chunk_type(eb, ptr);
rec->owner = btrfs_chunk_owner(leaf, ptr);
rec->stripe_len = btrfs_chunk_stripe_len(leaf, ptr);
rec->type_flags = btrfs_chunk_type(leaf, ptr);
rec->io_width = btrfs_chunk_io_width(leaf, ptr);
rec->io_align = btrfs_chunk_io_align(leaf, ptr);
rec->sector_size = btrfs_chunk_sector_size(leaf, ptr);
rec->num_stripes = num_stripes;
rec->sub_stripes = btrfs_chunk_sub_stripes(eb, ptr);
rec->sub_stripes = btrfs_chunk_sub_stripes(leaf, ptr);
for (i = 0; i < rec->num_stripes; ++i) {
rec->stripes[i].devid =
btrfs_stripe_devid_nr(eb, ptr, i);
btrfs_stripe_devid_nr(leaf, ptr, i);
rec->stripes[i].offset =
btrfs_stripe_offset_nr(eb, ptr, i);
btrfs_stripe_offset_nr(leaf, ptr, i);
read_extent_buffer(leaf, rec->stripes[i].dev_uuid,
(unsigned long)btrfs_stripe_dev_uuid_nr(ptr, i),
BTRFS_UUID_SIZE);
}
return rec;
}
static int process_chunk_item(struct cache_tree *chunk_cache,
struct btrfs_key *key, struct extent_buffer *eb,
int slot)
{
struct chunk_record *rec;
int ret = 0;
rec = btrfs_new_chunk_record(eb, key, slot);
ret = insert_cache_extent(chunk_cache, &rec->cache);
if (ret) {
fprintf(stderr, "Chunk[%llu, %llu] existed.\n",
@ -2799,6 +2808,7 @@ static int process_device_item(struct rb_root *dev_cache,
}
rec->devid = key->offset;
rec->generation = btrfs_header_generation(eb);
rec->objectid = key->objectid;
rec->type = key->type;
@ -2817,30 +2827,45 @@ static int process_device_item(struct rb_root *dev_cache,
return ret;
}
static int process_block_group_item(struct block_group_tree *block_group_cache,
struct btrfs_key *key, struct extent_buffer *eb, int slot)
struct block_group_record *
btrfs_new_block_group_record(struct extent_buffer *leaf, struct btrfs_key *key,
int slot)
{
struct btrfs_block_group_item *ptr;
struct block_group_record *rec;
int ret = 0;
ptr = btrfs_item_ptr(eb, slot,
struct btrfs_block_group_item);
rec = malloc(sizeof(*rec));
if (!rec) {
fprintf(stderr, "memory allocation failed\n");
return -ENOMEM;
exit(-1);
}
memset(rec, 0, sizeof(*rec));
rec->cache.start = key->objectid;
rec->cache.size = key->offset;
rec->generation = btrfs_header_generation(leaf);
rec->objectid = key->objectid;
rec->type = key->type;
rec->offset = key->offset;
rec->flags = btrfs_disk_block_group_flags(eb, ptr);
ptr = btrfs_item_ptr(leaf, slot, struct btrfs_block_group_item);
rec->flags = btrfs_disk_block_group_flags(leaf, ptr);
INIT_LIST_HEAD(&rec->list);
return rec;
}
static int process_block_group_item(struct block_group_tree *block_group_cache,
struct btrfs_key *key,
struct extent_buffer *eb, int slot)
{
struct block_group_record *rec;
int ret = 0;
rec = btrfs_new_block_group_record(eb, key, slot);
ret = insert_block_group_record(block_group_cache, rec);
if (ret) {
fprintf(stderr, "Block Group[%llu, %llu] existed.\n",
@ -2851,42 +2876,56 @@ static int process_block_group_item(struct block_group_tree *block_group_cache,
return ret;
}
static int
process_device_extent_item(struct device_extent_tree *dev_extent_cache,
struct btrfs_key *key, struct extent_buffer *eb,
int slot)
struct device_extent_record *
btrfs_new_device_extent_record(struct extent_buffer *leaf,
struct btrfs_key *key, int slot)
{
int ret = 0;
struct btrfs_dev_extent *ptr;
struct device_extent_record *rec;
ptr = btrfs_item_ptr(eb,
slot, struct btrfs_dev_extent);
struct btrfs_dev_extent *ptr;
rec = malloc(sizeof(*rec));
if (!rec) {
fprintf(stderr, "memory allocation failed\n");
return -ENOMEM;
exit(-1);
}
memset(rec, 0, sizeof(*rec));
rec->cache.objectid = key->objectid;
rec->cache.start = key->offset;
rec->generation = btrfs_header_generation(leaf);
rec->objectid = key->objectid;
rec->type = key->type;
rec->offset = key->offset;
ptr = btrfs_item_ptr(leaf, slot, struct btrfs_dev_extent);
rec->chunk_objecteid =
btrfs_dev_extent_chunk_objectid(eb, ptr);
btrfs_dev_extent_chunk_objectid(leaf, ptr);
rec->chunk_offset =
btrfs_dev_extent_chunk_offset(eb, ptr);
rec->length = btrfs_dev_extent_length(eb, ptr);
btrfs_dev_extent_chunk_offset(leaf, ptr);
rec->length = btrfs_dev_extent_length(leaf, ptr);
rec->cache.size = rec->length;
INIT_LIST_HEAD(&rec->chunk_list);
INIT_LIST_HEAD(&rec->device_list);
return rec;
}
static int
process_device_extent_item(struct device_extent_tree *dev_extent_cache,
struct btrfs_key *key, struct extent_buffer *eb,
int slot)
{
struct device_extent_record *rec;
int ret;
rec = btrfs_new_device_extent_record(eb, key, slot);
ret = insert_device_extent_record(dev_extent_cache, rec);
if (ret) {
fprintf(stderr, "Device extent[%llu, %llu, %llu] existed.\n",
fprintf(stderr,
"Device extent[%llu, %llu, %llu] existed.\n",
rec->objectid, rec->offset, rec->length);
free(rec);
}
@ -4911,7 +4950,8 @@ static u64 calc_stripe_length(struct chunk_record *chunk_rec)
static int check_chunk_refs(struct chunk_record *chunk_rec,
struct block_group_tree *block_group_cache,
struct device_extent_tree *dev_extent_cache)
struct device_extent_tree *dev_extent_cache,
int silent)
{
struct cache_extent *block_group_item;
struct block_group_record *block_group_rec;
@ -4933,6 +4973,7 @@ static int check_chunk_refs(struct chunk_record *chunk_rec,
if (chunk_rec->length != block_group_rec->offset ||
chunk_rec->offset != block_group_rec->objectid ||
chunk_rec->type_flags != block_group_rec->flags) {
if (!silent)
fprintf(stderr,
"Chunk[%llu, %u, %llu]: length(%llu), offset(%llu), type(%llu) mismatch with block group[%llu, %u, %llu]: offset(%llu), objectid(%llu), flags(%llu)\n",
chunk_rec->objectid,
@ -4948,9 +4989,12 @@ static int check_chunk_refs(struct chunk_record *chunk_rec,
block_group_rec->objectid,
block_group_rec->flags);
ret = -1;
}
list_del(&block_group_rec->list);
} else {
list_del_init(&block_group_rec->list);
chunk_rec->bg_rec = block_group_rec;
}
} else {
if (!silent)
fprintf(stderr,
"Chunk[%llu, %u, %llu]: length(%llu), offset(%llu), type(%llu) is not found in block group\n",
chunk_rec->objectid,
@ -4976,6 +5020,7 @@ static int check_chunk_refs(struct chunk_record *chunk_rec,
dev_extent_rec->offset != offset ||
dev_extent_rec->chunk_offset != chunk_rec->offset ||
dev_extent_rec->length != length) {
if (!silent)
fprintf(stderr,
"Chunk[%llu, %u, %llu] stripe[%llu, %llu] dismatch dev extent[%llu, %llu, %llu]\n",
chunk_rec->objectid,
@ -4987,9 +5032,12 @@ static int check_chunk_refs(struct chunk_record *chunk_rec,
dev_extent_rec->offset,
dev_extent_rec->length);
ret = -1;
}
list_del(&dev_extent_rec->chunk_list);
} else {
list_move(&dev_extent_rec->chunk_list,
&chunk_rec->dextents);
}
} else {
if (!silent)
fprintf(stderr,
"Chunk[%llu, %u, %llu] stripe[%llu, %llu] is not found in dev extent\n",
chunk_rec->objectid,
@ -5004,9 +5052,10 @@ static int check_chunk_refs(struct chunk_record *chunk_rec,
}
/* check btrfs_chunk -> btrfs_dev_extent / btrfs_block_group_item */
static int check_chunks(struct cache_tree *chunk_cache,
int check_chunks(struct cache_tree *chunk_cache,
struct block_group_tree *block_group_cache,
struct device_extent_tree *dev_extent_cache)
struct device_extent_tree *dev_extent_cache,
struct list_head *good, struct list_head *bad, int silent)
{
struct cache_extent *chunk_item;
struct chunk_record *chunk_rec;
@ -5020,26 +5069,38 @@ static int check_chunks(struct cache_tree *chunk_cache,
chunk_rec = container_of(chunk_item, struct chunk_record,
cache);
err = check_chunk_refs(chunk_rec, block_group_cache,
dev_extent_cache);
if (err)
dev_extent_cache, silent);
if (err) {
ret = err;
if (bad)
list_add_tail(&chunk_rec->list, bad);
} else {
if (good)
list_add_tail(&chunk_rec->list, good);
}
chunk_item = next_cache_extent(chunk_item);
}
list_for_each_entry(bg_rec, &block_group_cache->block_groups, list) {
if (!silent)
fprintf(stderr,
"Block group[%llu, %llu] (flags = %llu) didn't find the relative chunk.\n",
bg_rec->objectid, bg_rec->offset, bg_rec->flags);
bg_rec->objectid,
bg_rec->offset,
bg_rec->flags);
if (!ret)
ret = 1;
}
list_for_each_entry(dext_rec, &dev_extent_cache->no_chunk_orphans,
chunk_list) {
if (!silent)
fprintf(stderr,
"Device extent[%llu, %llu, %llu] didn't find the relative chunk.\n",
dext_rec->objectid, dext_rec->offset, dext_rec->length);
dext_rec->objectid,
dext_rec->offset,
dext_rec->length);
if (!ret)
ret = 1;
}
@ -5237,7 +5298,7 @@ again:
}
err = check_chunks(&chunk_cache, &block_group_cache,
&dev_extent_cache);
&dev_extent_cache, NULL, NULL, 0);
if (err && !ret)
ret = err;

1399
cmds-chunk.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -94,6 +94,7 @@ extern const struct cmd_group replace_cmd_group;
extern const char * const cmd_send_usage[];
extern const char * const cmd_receive_usage[];
extern const char * const cmd_check_usage[];
extern const char * const cmd_chunk_recover_usage[];
extern const char * const cmd_restore_usage[];
int cmd_subvolume(int argc, char **argv);
@ -102,6 +103,7 @@ int cmd_balance(int argc, char **argv);
int cmd_device(int argc, char **argv);
int cmd_scrub(int argc, char **argv);
int cmd_check(int argc, char **argv);
int cmd_chunk_recover(int argc, char **argv);
int cmd_inspect(int argc, char **argv);
int cmd_send(int argc, char **argv);
int cmd_receive(int argc, char **argv);

View File

@ -70,8 +70,8 @@ void btrfs_csum_final(u32 crc, char *result)
*(__le32 *)result = ~cpu_to_le32(crc);
}
int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
int verify)
static int __csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
int verify, int silent)
{
char *result;
u32 len;
@ -87,9 +87,11 @@ int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
if (verify) {
if (memcmp_extent_buffer(buf, result, 0, csum_size)) {
printk("checksum verify failed on %llu found %08X "
"wanted %08X\n", (unsigned long long)buf->start,
*((u32 *)result), *((u32*)(char *)buf->data));
if (!silent)
printk("checksum verify failed on %llu found %08X wanted %08X\n",
(unsigned long long)buf->start,
*((u32 *)result),
*((u32*)(char *)buf->data));
free(result);
return 1;
}
@ -100,6 +102,16 @@ int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
return 0;
}
int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size, int verify)
{
return __csum_tree_block_size(buf, csum_size, verify, 0);
}
int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size)
{
return __csum_tree_block_size(buf, csum_size, 1, 1);
}
int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
int verify)
{

View File

@ -92,6 +92,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
int btrfs_open_device(struct btrfs_device *dev);
int csum_tree_block_size(struct extent_buffer *buf, u16 csum_sectorsize,
int verify);
int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size);
int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
int verify);
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);

View File

@ -28,12 +28,6 @@
#include "volumes.h"
#include "free-space-cache.h"
#define BLOCK_GROUP_DATA EXTENT_WRITEBACK
#define BLOCK_GROUP_METADATA EXTENT_UPTODATE
#define BLOCK_GROUP_SYSTEM EXTENT_NEW
#define BLOCK_GROUP_DIRTY EXTENT_DIRTY
#define PENDING_EXTENT_INSERT 0
#define PENDING_EXTENT_DELETE 1
#define PENDING_BACKREF_UPDATE 2

View File

@ -41,6 +41,12 @@
#define EXTENT_CSUM (1 << 9)
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
#define BLOCK_GROUP_DATA EXTENT_WRITEBACK
#define BLOCK_GROUP_METADATA EXTENT_UPTODATE
#define BLOCK_GROUP_SYSTEM EXTENT_NEW
#define BLOCK_GROUP_DIRTY EXTENT_DIRTY
struct btrfs_fs_info;
struct extent_io_tree {

View File

@ -52,9 +52,6 @@ static inline int nr_data_stripes(struct map_lookup *map)
#define is_parity_stripe(x) ( ((x) == BTRFS_RAID5_P_STRIPE) || ((x) == BTRFS_RAID6_Q_STRIPE) )
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
static LIST_HEAD(fs_uuids);
static struct btrfs_device *__find_device(struct list_head *head, u64 devid,
@ -823,7 +820,7 @@ again:
if (!chunk)
return -ENOMEM;
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS);
if (!map) {
kfree(chunk);
return -ENOMEM;
@ -935,7 +932,7 @@ int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
if (!chunk)
return -ENOMEM;
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS);
if (!map) {
kfree(chunk);
return -ENOMEM;
@ -1420,7 +1417,7 @@ int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
list_for_each(cur, &fs_devices->devices) {
num_stripes++;
}
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS);
if (!map)
return -ENOMEM;
@ -1517,7 +1514,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
}
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS);
if (!map)
return -ENOMEM;

View File

@ -103,6 +103,8 @@ struct map_lookup {
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
#define btrfs_map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
/*
* Restriper's general type filter
@ -190,4 +192,6 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
struct btrfs_device *btrfs_find_device_by_devid(struct btrfs_root *root,
u64 devid, int instance);
struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
u8 *uuid, u8 *fsid);
#endif