Commit e06baab4 authored by Stefan Behrens's avatar Stefan Behrens Committed by Josef Bacik

Btrfs: change integrity checker to support big blocks

The integrity checker used to be coded for nodesize == leafsize ==
sectorsize == PAGE_CACHE_SIZE.
This is now changed to support sizes for nodesize and leafsize which are
N * PAGE_CACHE_SIZE.
Signed-off-by: default avatarStefan Behrens <sbehrens@giantdisaster.de>
parent fd5e62a3
...@@ -103,8 +103,6 @@ ...@@ -103,8 +103,6 @@
#define BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER 20111300 #define BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER 20111300
#define BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL (200 - 6) /* in characters, #define BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL (200 - 6) /* in characters,
* excluding " [...]" */ * excluding " [...]" */
#define BTRFSIC_BLOCK_SIZE PAGE_SIZE
#define BTRFSIC_GENERATION_UNKNOWN ((u64)-1) #define BTRFSIC_GENERATION_UNKNOWN ((u64)-1)
/* /*
...@@ -210,8 +208,9 @@ struct btrfsic_block_data_ctx { ...@@ -210,8 +208,9 @@ struct btrfsic_block_data_ctx {
u64 dev_bytenr; /* physical bytenr on device */ u64 dev_bytenr; /* physical bytenr on device */
u32 len; u32 len;
struct btrfsic_dev_state *dev; struct btrfsic_dev_state *dev;
char *data; char **datav;
struct buffer_head *bh; /* do not use if set to NULL */ struct page **pagev;
void *mem_to_free;
}; };
/* This structure is used to implement recursion without occupying /* This structure is used to implement recursion without occupying
...@@ -243,6 +242,8 @@ struct btrfsic_state { ...@@ -243,6 +242,8 @@ struct btrfsic_state {
struct btrfs_root *root; struct btrfs_root *root;
u64 max_superblock_generation; u64 max_superblock_generation;
struct btrfsic_block *latest_superblock; struct btrfsic_block *latest_superblock;
u32 metablock_size;
u32 datablock_size;
}; };
static void btrfsic_block_init(struct btrfsic_block *b); static void btrfsic_block_init(struct btrfsic_block *b);
...@@ -290,8 +291,10 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -290,8 +291,10 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
static int btrfsic_process_metablock(struct btrfsic_state *state, static int btrfsic_process_metablock(struct btrfsic_state *state,
struct btrfsic_block *block, struct btrfsic_block *block,
struct btrfsic_block_data_ctx *block_ctx, struct btrfsic_block_data_ctx *block_ctx,
struct btrfs_header *hdr,
int limit_nesting, int force_iodone_flag); int limit_nesting, int force_iodone_flag);
static void btrfsic_read_from_block_data(
struct btrfsic_block_data_ctx *block_ctx,
void *dst, u32 offset, size_t len);
static int btrfsic_create_link_to_next_block( static int btrfsic_create_link_to_next_block(
struct btrfsic_state *state, struct btrfsic_state *state,
struct btrfsic_block *block, struct btrfsic_block *block,
...@@ -318,12 +321,13 @@ static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx); ...@@ -318,12 +321,13 @@ static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx);
static int btrfsic_read_block(struct btrfsic_state *state, static int btrfsic_read_block(struct btrfsic_state *state,
struct btrfsic_block_data_ctx *block_ctx); struct btrfsic_block_data_ctx *block_ctx);
static void btrfsic_dump_database(struct btrfsic_state *state); static void btrfsic_dump_database(struct btrfsic_state *state);
static void btrfsic_complete_bio_end_io(struct bio *bio, int err);
static int btrfsic_test_for_metadata(struct btrfsic_state *state, static int btrfsic_test_for_metadata(struct btrfsic_state *state,
const u8 *data, unsigned int size); char **datav, unsigned int num_pages);
static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
u64 dev_bytenr, u8 *mapped_data, u64 dev_bytenr, char **mapped_datav,
unsigned int len, struct bio *bio, unsigned int num_pages,
int *bio_is_patched, struct bio *bio, int *bio_is_patched,
struct buffer_head *bh, struct buffer_head *bh,
int submit_bio_bh_rw); int submit_bio_bh_rw);
static int btrfsic_process_written_superblock( static int btrfsic_process_written_superblock(
...@@ -375,7 +379,7 @@ static struct btrfsic_dev_state *btrfsic_dev_state_lookup( ...@@ -375,7 +379,7 @@ static struct btrfsic_dev_state *btrfsic_dev_state_lookup(
static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
u64 bytenr, u64 bytenr,
struct btrfsic_dev_state *dev_state, struct btrfsic_dev_state *dev_state,
u64 dev_bytenr, char *data); u64 dev_bytenr);
static struct mutex btrfsic_mutex; static struct mutex btrfsic_mutex;
static int btrfsic_is_initialized; static int btrfsic_is_initialized;
...@@ -651,7 +655,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -651,7 +655,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
int pass; int pass;
BUG_ON(NULL == state); BUG_ON(NULL == state);
selected_super = kmalloc(sizeof(*selected_super), GFP_NOFS); selected_super = kzalloc(sizeof(*selected_super), GFP_NOFS);
if (NULL == selected_super) { if (NULL == selected_super) {
printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
return -1; return -1;
...@@ -718,7 +722,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -718,7 +722,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
num_copies = num_copies =
btrfs_num_copies(&state->root->fs_info->mapping_tree, btrfs_num_copies(&state->root->fs_info->mapping_tree,
next_bytenr, PAGE_SIZE); next_bytenr, state->metablock_size);
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
(unsigned long long)next_bytenr, num_copies); (unsigned long long)next_bytenr, num_copies);
...@@ -727,9 +731,9 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -727,9 +731,9 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
struct btrfsic_block *next_block; struct btrfsic_block *next_block;
struct btrfsic_block_data_ctx tmp_next_block_ctx; struct btrfsic_block_data_ctx tmp_next_block_ctx;
struct btrfsic_block_link *l; struct btrfsic_block_link *l;
struct btrfs_header *hdr;
ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE, ret = btrfsic_map_block(state, next_bytenr,
state->metablock_size,
&tmp_next_block_ctx, &tmp_next_block_ctx,
mirror_num); mirror_num);
if (ret) { if (ret) {
...@@ -758,7 +762,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -758,7 +762,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
BUG_ON(NULL == l); BUG_ON(NULL == l);
ret = btrfsic_read_block(state, &tmp_next_block_ctx); ret = btrfsic_read_block(state, &tmp_next_block_ctx);
if (ret < (int)BTRFSIC_BLOCK_SIZE) { if (ret < (int)PAGE_CACHE_SIZE) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: read @logical %llu failed!\n", "btrfsic: read @logical %llu failed!\n",
(unsigned long long) (unsigned long long)
...@@ -768,11 +772,9 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, ...@@ -768,11 +772,9 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
return -1; return -1;
} }
hdr = (struct btrfs_header *)tmp_next_block_ctx.data;
ret = btrfsic_process_metablock(state, ret = btrfsic_process_metablock(state,
next_block, next_block,
&tmp_next_block_ctx, &tmp_next_block_ctx,
hdr,
BTRFS_MAX_LEVEL + 3, 1); BTRFS_MAX_LEVEL + 3, 1);
btrfsic_release_block_ctx(&tmp_next_block_ctx); btrfsic_release_block_ctx(&tmp_next_block_ctx);
} }
...@@ -799,7 +801,10 @@ static int btrfsic_process_superblock_dev_mirror( ...@@ -799,7 +801,10 @@ static int btrfsic_process_superblock_dev_mirror(
/* super block bytenr is always the unmapped device bytenr */ /* super block bytenr is always the unmapped device bytenr */
dev_bytenr = btrfs_sb_offset(superblock_mirror_num); dev_bytenr = btrfs_sb_offset(superblock_mirror_num);
bh = __bread(superblock_bdev, dev_bytenr / 4096, 4096); if (dev_bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes)
return -1;
bh = __bread(superblock_bdev, dev_bytenr / 4096,
BTRFS_SUPER_INFO_SIZE);
if (NULL == bh) if (NULL == bh)
return -1; return -1;
super_tmp = (struct btrfs_super_block *) super_tmp = (struct btrfs_super_block *)
...@@ -808,7 +813,10 @@ static int btrfsic_process_superblock_dev_mirror( ...@@ -808,7 +813,10 @@ static int btrfsic_process_superblock_dev_mirror(
if (btrfs_super_bytenr(super_tmp) != dev_bytenr || if (btrfs_super_bytenr(super_tmp) != dev_bytenr ||
strncmp((char *)(&(super_tmp->magic)), BTRFS_MAGIC, strncmp((char *)(&(super_tmp->magic)), BTRFS_MAGIC,
sizeof(super_tmp->magic)) || sizeof(super_tmp->magic)) ||
memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE)) { memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE) ||
btrfs_super_nodesize(super_tmp) != state->metablock_size ||
btrfs_super_leafsize(super_tmp) != state->metablock_size ||
btrfs_super_sectorsize(super_tmp) != state->datablock_size) {
brelse(bh); brelse(bh);
return 0; return 0;
} }
...@@ -893,7 +901,7 @@ static int btrfsic_process_superblock_dev_mirror( ...@@ -893,7 +901,7 @@ static int btrfsic_process_superblock_dev_mirror(
num_copies = num_copies =
btrfs_num_copies(&state->root->fs_info->mapping_tree, btrfs_num_copies(&state->root->fs_info->mapping_tree,
next_bytenr, PAGE_SIZE); next_bytenr, state->metablock_size);
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
(unsigned long long)next_bytenr, num_copies); (unsigned long long)next_bytenr, num_copies);
...@@ -902,7 +910,8 @@ static int btrfsic_process_superblock_dev_mirror( ...@@ -902,7 +910,8 @@ static int btrfsic_process_superblock_dev_mirror(
struct btrfsic_block_data_ctx tmp_next_block_ctx; struct btrfsic_block_data_ctx tmp_next_block_ctx;
struct btrfsic_block_link *l; struct btrfsic_block_link *l;
if (btrfsic_map_block(state, next_bytenr, PAGE_SIZE, if (btrfsic_map_block(state, next_bytenr,
state->metablock_size,
&tmp_next_block_ctx, &tmp_next_block_ctx,
mirror_num)) { mirror_num)) {
printk(KERN_INFO "btrfsic: btrfsic_map_block(" printk(KERN_INFO "btrfsic: btrfsic_map_block("
...@@ -966,13 +975,15 @@ static int btrfsic_process_metablock( ...@@ -966,13 +975,15 @@ static int btrfsic_process_metablock(
struct btrfsic_state *state, struct btrfsic_state *state,
struct btrfsic_block *const first_block, struct btrfsic_block *const first_block,
struct btrfsic_block_data_ctx *const first_block_ctx, struct btrfsic_block_data_ctx *const first_block_ctx,
struct btrfs_header *const first_hdr,
int first_limit_nesting, int force_iodone_flag) int first_limit_nesting, int force_iodone_flag)
{ {
struct btrfsic_stack_frame initial_stack_frame = { 0 }; struct btrfsic_stack_frame initial_stack_frame = { 0 };
struct btrfsic_stack_frame *sf; struct btrfsic_stack_frame *sf;
struct btrfsic_stack_frame *next_stack; struct btrfsic_stack_frame *next_stack;
struct btrfs_header *const first_hdr =
(struct btrfs_header *)first_block_ctx->datav[0];
BUG_ON(!first_hdr);
sf = &initial_stack_frame; sf = &initial_stack_frame;
sf->error = 0; sf->error = 0;
sf->i = -1; sf->i = -1;
...@@ -1012,21 +1023,47 @@ static int btrfsic_process_metablock( ...@@ -1012,21 +1023,47 @@ static int btrfsic_process_metablock(
} }
if (sf->i < sf->nr) { if (sf->i < sf->nr) {
struct btrfs_item *disk_item = leafhdr->items + sf->i; struct btrfs_item disk_item;
struct btrfs_disk_key *disk_key = &disk_item->key; u32 disk_item_offset =
(uintptr_t)(leafhdr->items + sf->i) -
(uintptr_t)leafhdr;
struct btrfs_disk_key *disk_key;
u8 type; u8 type;
const u32 item_offset = le32_to_cpu(disk_item->offset); u32 item_offset;
if (disk_item_offset + sizeof(struct btrfs_item) >
sf->block_ctx->len) {
leaf_item_out_of_bounce_error:
printk(KERN_INFO
"btrfsic: leaf item out of bounce at logical %llu, dev %s\n",
sf->block_ctx->start,
sf->block_ctx->dev->name);
goto one_stack_frame_backwards;
}
btrfsic_read_from_block_data(sf->block_ctx,
&disk_item,
disk_item_offset,
sizeof(struct btrfs_item));
item_offset = le32_to_cpu(disk_item.offset);
disk_key = &disk_item.key;
type = disk_key->type; type = disk_key->type;
if (BTRFS_ROOT_ITEM_KEY == type) { if (BTRFS_ROOT_ITEM_KEY == type) {
const struct btrfs_root_item *const root_item = struct btrfs_root_item root_item;
(struct btrfs_root_item *) u32 root_item_offset;
(sf->block_ctx->data + u64 next_bytenr;
offsetof(struct btrfs_leaf, items) +
item_offset); root_item_offset = item_offset +
const u64 next_bytenr = offsetof(struct btrfs_leaf, items);
le64_to_cpu(root_item->bytenr); if (root_item_offset +
sizeof(struct btrfs_root_item) >
sf->block_ctx->len)
goto leaf_item_out_of_bounce_error;
btrfsic_read_from_block_data(
sf->block_ctx, &root_item,
root_item_offset,
sizeof(struct btrfs_root_item));
next_bytenr = le64_to_cpu(root_item.bytenr);
sf->error = sf->error =
btrfsic_create_link_to_next_block( btrfsic_create_link_to_next_block(
...@@ -1041,7 +1078,7 @@ static int btrfsic_process_metablock( ...@@ -1041,7 +1078,7 @@ static int btrfsic_process_metablock(
&sf->num_copies, &sf->num_copies,
&sf->mirror_num, &sf->mirror_num,
disk_key, disk_key,
le64_to_cpu(root_item-> le64_to_cpu(root_item.
generation)); generation));
if (sf->error) if (sf->error)
goto one_stack_frame_backwards; goto one_stack_frame_backwards;
...@@ -1049,7 +1086,7 @@ static int btrfsic_process_metablock( ...@@ -1049,7 +1086,7 @@ static int btrfsic_process_metablock(
if (NULL != sf->next_block) { if (NULL != sf->next_block) {
struct btrfs_header *const next_hdr = struct btrfs_header *const next_hdr =
(struct btrfs_header *) (struct btrfs_header *)
sf->next_block_ctx.data; sf->next_block_ctx.datav[0];
next_stack = next_stack =
btrfsic_stack_frame_alloc(); btrfsic_stack_frame_alloc();
...@@ -1111,10 +1148,24 @@ static int btrfsic_process_metablock( ...@@ -1111,10 +1148,24 @@ static int btrfsic_process_metablock(
} }
if (sf->i < sf->nr) { if (sf->i < sf->nr) {
struct btrfs_key_ptr *disk_key_ptr = struct btrfs_key_ptr key_ptr;
nodehdr->ptrs + sf->i; u32 key_ptr_offset;
const u64 next_bytenr = u64 next_bytenr;
le64_to_cpu(disk_key_ptr->blockptr);
key_ptr_offset = (uintptr_t)(nodehdr->ptrs + sf->i) -
(uintptr_t)nodehdr;
if (key_ptr_offset + sizeof(struct btrfs_key_ptr) >
sf->block_ctx->len) {
printk(KERN_INFO
"btrfsic: node item out of bounce at logical %llu, dev %s\n",
sf->block_ctx->start,
sf->block_ctx->dev->name);
goto one_stack_frame_backwards;
}
btrfsic_read_from_block_data(
sf->block_ctx, &key_ptr, key_ptr_offset,
sizeof(struct btrfs_key_ptr));
next_bytenr = le64_to_cpu(key_ptr.blockptr);
sf->error = btrfsic_create_link_to_next_block( sf->error = btrfsic_create_link_to_next_block(
state, state,
...@@ -1127,15 +1178,15 @@ static int btrfsic_process_metablock( ...@@ -1127,15 +1178,15 @@ static int btrfsic_process_metablock(
force_iodone_flag, force_iodone_flag,
&sf->num_copies, &sf->num_copies,
&sf->mirror_num, &sf->mirror_num,
&disk_key_ptr->key, &key_ptr.key,
le64_to_cpu(disk_key_ptr->generation)); le64_to_cpu(key_ptr.generation));
if (sf->error) if (sf->error)
goto one_stack_frame_backwards; goto one_stack_frame_backwards;
if (NULL != sf->next_block) { if (NULL != sf->next_block) {
struct btrfs_header *const next_hdr = struct btrfs_header *const next_hdr =
(struct btrfs_header *) (struct btrfs_header *)
sf->next_block_ctx.data; sf->next_block_ctx.datav[0];
next_stack = btrfsic_stack_frame_alloc(); next_stack = btrfsic_stack_frame_alloc();
if (NULL == next_stack) if (NULL == next_stack)
...@@ -1181,6 +1232,35 @@ static int btrfsic_process_metablock( ...@@ -1181,6 +1232,35 @@ static int btrfsic_process_metablock(
return sf->error; return sf->error;
} }
static void btrfsic_read_from_block_data(
struct btrfsic_block_data_ctx *block_ctx,
void *dstv, u32 offset, size_t len)
{
size_t cur;
size_t offset_in_page;
char *kaddr;
char *dst = (char *)dstv;
size_t start_offset = block_ctx->start & ((u64)PAGE_CACHE_SIZE - 1);
unsigned long i = (start_offset + offset) >> PAGE_CACHE_SHIFT;
WARN_ON(offset + len > block_ctx->len);
offset_in_page = (start_offset + offset) &
((unsigned long)PAGE_CACHE_SIZE - 1);
while (len > 0) {
cur = min(len, ((size_t)PAGE_CACHE_SIZE - offset_in_page));
BUG_ON(i >= (block_ctx->len + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT);
kaddr = block_ctx->datav[i];
memcpy(dst, kaddr + offset_in_page, cur);
dst += cur;
len -= cur;
offset_in_page = 0;
i++;
}
}
static int btrfsic_create_link_to_next_block( static int btrfsic_create_link_to_next_block(
struct btrfsic_state *state, struct btrfsic_state *state,
struct btrfsic_block *block, struct btrfsic_block *block,
...@@ -1204,7 +1284,7 @@ static int btrfsic_create_link_to_next_block( ...@@ -1204,7 +1284,7 @@ static int btrfsic_create_link_to_next_block(
if (0 == *num_copiesp) { if (0 == *num_copiesp) {
*num_copiesp = *num_copiesp =
btrfs_num_copies(&state->root->fs_info->mapping_tree, btrfs_num_copies(&state->root->fs_info->mapping_tree,
next_bytenr, PAGE_SIZE); next_bytenr, state->metablock_size);
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
(unsigned long long)next_bytenr, *num_copiesp); (unsigned long long)next_bytenr, *num_copiesp);
...@@ -1219,7 +1299,7 @@ static int btrfsic_create_link_to_next_block( ...@@ -1219,7 +1299,7 @@ static int btrfsic_create_link_to_next_block(
"btrfsic_create_link_to_next_block(mirror_num=%d)\n", "btrfsic_create_link_to_next_block(mirror_num=%d)\n",
*mirror_nump); *mirror_nump);
ret = btrfsic_map_block(state, next_bytenr, ret = btrfsic_map_block(state, next_bytenr,
BTRFSIC_BLOCK_SIZE, state->metablock_size,
next_block_ctx, *mirror_nump); next_block_ctx, *mirror_nump);
if (ret) { if (ret) {
printk(KERN_INFO printk(KERN_INFO
...@@ -1314,7 +1394,7 @@ static int btrfsic_create_link_to_next_block( ...@@ -1314,7 +1394,7 @@ static int btrfsic_create_link_to_next_block(
if (limit_nesting > 0 && did_alloc_block_link) { if (limit_nesting > 0 && did_alloc_block_link) {
ret = btrfsic_read_block(state, next_block_ctx); ret = btrfsic_read_block(state, next_block_ctx);
if (ret < (int)BTRFSIC_BLOCK_SIZE) { if (ret < (int)next_block_ctx->len) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: read block @logical %llu failed!\n", "btrfsic: read block @logical %llu failed!\n",
(unsigned long long)next_bytenr); (unsigned long long)next_bytenr);
...@@ -1339,43 +1419,55 @@ static int btrfsic_handle_extent_data( ...@@ -1339,43 +1419,55 @@ static int btrfsic_handle_extent_data(
u32 item_offset, int force_iodone_flag) u32 item_offset, int force_iodone_flag)
{ {
int ret; int ret;
struct btrfs_file_extent_item *file_extent_item = struct btrfs_file_extent_item file_extent_item;
(struct btrfs_file_extent_item *)(block_ctx->data + u64 file_extent_item_offset;
offsetof(struct btrfs_leaf, u64 next_bytenr;
items) + item_offset); u64 num_bytes;
u64 next_bytenr = u64 generation;
le64_to_cpu(file_extent_item->disk_bytenr) +
le64_to_cpu(file_extent_item->offset);
u64 num_bytes = le64_to_cpu(file_extent_item->num_bytes);
u64 generation = le64_to_cpu(file_extent_item->generation);
struct btrfsic_block_link *l; struct btrfsic_block_link *l;
file_extent_item_offset = offsetof(struct btrfs_leaf, items) +
item_offset;
if (file_extent_item_offset + sizeof(struct btrfs_file_extent_item) >
block_ctx->len) {
printk(KERN_INFO
"btrfsic: file item out of bounce at logical %llu, dev %s\n",
block_ctx->start, block_ctx->dev->name);
return -1;
}
btrfsic_read_from_block_data(block_ctx, &file_extent_item,
file_extent_item_offset,
sizeof(struct btrfs_file_extent_item));
next_bytenr = le64_to_cpu(file_extent_item.disk_bytenr) +
le64_to_cpu(file_extent_item.offset);
generation = le64_to_cpu(file_extent_item.generation);
num_bytes = le64_to_cpu(file_extent_item.num_bytes);
generation = le64_to_cpu(file_extent_item.generation);
if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE) if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu," printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu,"
" offset = %llu, num_bytes = %llu\n", " offset = %llu, num_bytes = %llu\n",
file_extent_item->type, file_extent_item.type,
(unsigned long long) (unsigned long long)
le64_to_cpu(file_extent_item->disk_bytenr), le64_to_cpu(file_extent_item.disk_bytenr),
(unsigned long long) (unsigned long long)le64_to_cpu(file_extent_item.offset),
le64_to_cpu(file_extent_item->offset), (unsigned long long)num_bytes);
(unsigned long long) if (BTRFS_FILE_EXTENT_REG != file_extent_item.type ||
le64_to_cpu(file_extent_item->num_bytes)); ((u64)0) == le64_to_cpu(file_extent_item.disk_bytenr))
if (BTRFS_FILE_EXTENT_REG != file_extent_item->type ||
((u64)0) == le64_to_cpu(file_extent_item->disk_bytenr))
return 0; return 0;
while (num_bytes > 0) { while (num_bytes > 0) {
u32 chunk_len; u32 chunk_len;
int num_copies; int num_copies;
int mirror_num; int mirror_num;
if (num_bytes > BTRFSIC_BLOCK_SIZE) if (num_bytes > state->datablock_size)
chunk_len = BTRFSIC_BLOCK_SIZE; chunk_len = state->datablock_size;
else else
chunk_len = num_bytes; chunk_len = num_bytes;
num_copies = num_copies =
btrfs_num_copies(&state->root->fs_info->mapping_tree, btrfs_num_copies(&state->root->fs_info->mapping_tree,
next_bytenr, PAGE_SIZE); next_bytenr, state->datablock_size);
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
(unsigned long long)next_bytenr, num_copies); (unsigned long long)next_bytenr, num_copies);
...@@ -1475,8 +1567,9 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, ...@@ -1475,8 +1567,9 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
block_ctx_out->dev_bytenr = multi->stripes[0].physical; block_ctx_out->dev_bytenr = multi->stripes[0].physical;
block_ctx_out->start = bytenr; block_ctx_out->start = bytenr;
block_ctx_out->len = len; block_ctx_out->len = len;
block_ctx_out->data = NULL; block_ctx_out->datav = NULL;
block_ctx_out->bh = NULL; block_ctx_out->pagev = NULL;
block_ctx_out->mem_to_free = NULL;
if (0 == ret) if (0 == ret)
kfree(multi); kfree(multi);
...@@ -1496,8 +1589,9 @@ static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr, ...@@ -1496,8 +1589,9 @@ static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
block_ctx_out->dev_bytenr = bytenr; block_ctx_out->dev_bytenr = bytenr;
block_ctx_out->start = bytenr; block_ctx_out->start = bytenr;
block_ctx_out->len = len; block_ctx_out->len = len;
block_ctx_out->data = NULL; block_ctx_out->datav = NULL;
block_ctx_out->bh = NULL; block_ctx_out->pagev = NULL;
block_ctx_out->mem_to_free = NULL;
if (NULL != block_ctx_out->dev) { if (NULL != block_ctx_out->dev) {
return 0; return 0;
} else { } else {
...@@ -1508,38 +1602,127 @@ static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr, ...@@ -1508,38 +1602,127 @@ static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx) static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx)
{ {
if (NULL != block_ctx->bh) { if (block_ctx->mem_to_free) {
brelse(block_ctx->bh); unsigned int num_pages;
block_ctx->bh = NULL;
BUG_ON(!block_ctx->datav);
BUG_ON(!block_ctx->pagev);
num_pages = (block_ctx->len + (u64)PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
while (num_pages > 0) {
num_pages--;
if (block_ctx->datav[num_pages]) {
kunmap(block_ctx->pagev[num_pages]);
block_ctx->datav[num_pages] = NULL;
}
if (block_ctx->pagev[num_pages]) {
__free_page(block_ctx->pagev[num_pages]);
block_ctx->pagev[num_pages] = NULL;
}
}
kfree(block_ctx->mem_to_free);
block_ctx->mem_to_free = NULL;
block_ctx->pagev = NULL;
block_ctx->datav = NULL;
} }
} }
static int btrfsic_read_block(struct btrfsic_state *state, static int btrfsic_read_block(struct btrfsic_state *state,
struct btrfsic_block_data_ctx *block_ctx) struct btrfsic_block_data_ctx *block_ctx)
{ {
block_ctx->bh = NULL; unsigned int num_pages;
if (block_ctx->dev_bytenr & 4095) { unsigned int i;
u64 dev_bytenr;
int ret;
BUG_ON(block_ctx->datav);
BUG_ON(block_ctx->pagev);
BUG_ON(block_ctx->mem_to_free);
if (block_ctx->dev_bytenr & ((u64)PAGE_CACHE_SIZE - 1)) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: read_block() with unaligned bytenr %llu\n", "btrfsic: read_block() with unaligned bytenr %llu\n",
(unsigned long long)block_ctx->dev_bytenr); (unsigned long long)block_ctx->dev_bytenr);
return -1; return -1;
} }
if (block_ctx->len > 4096) {
num_pages = (block_ctx->len + (u64)PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
block_ctx->mem_to_free = kzalloc((sizeof(*block_ctx->datav) +
sizeof(*block_ctx->pagev)) *
num_pages, GFP_NOFS);
if (!block_ctx->mem_to_free)
return -1;
block_ctx->datav = block_ctx->mem_to_free;
block_ctx->pagev = (struct page **)(block_ctx->datav + num_pages);
for (i = 0; i < num_pages; i++) {
block_ctx->pagev[i] = alloc_page(GFP_NOFS);
if (!block_ctx->pagev[i])
return -1;
}
dev_bytenr = block_ctx->dev_bytenr;
for (i = 0; i < num_pages;) {
struct bio *bio;
unsigned int j;
DECLARE_COMPLETION_ONSTACK(complete);
bio = bio_alloc(GFP_NOFS, num_pages - i);
if (!bio) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: read_block() with too huge size %d\n", "btrfsic: bio_alloc() for %u pages failed!\n",
block_ctx->len); num_pages - i);
return -1; return -1;
} }
bio->bi_bdev = block_ctx->dev->bdev;
bio->bi_sector = dev_bytenr >> 9;
bio->bi_end_io = btrfsic_complete_bio_end_io;
bio->bi_private = &complete;
block_ctx->bh = __bread(block_ctx->dev->bdev, for (j = i; j < num_pages; j++) {
block_ctx->dev_bytenr >> 12, 4096); ret = bio_add_page(bio, block_ctx->pagev[j],
if (NULL == block_ctx->bh) PAGE_CACHE_SIZE, 0);
if (PAGE_CACHE_SIZE != ret)
break;
}
if (j == i) {
printk(KERN_INFO
"btrfsic: error, failed to add a single page!\n");
return -1;
}
submit_bio(READ, bio);
/* this will also unplug the queue */
wait_for_completion(&complete);
if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
printk(KERN_INFO
"btrfsic: read error at logical %llu dev %s!\n",
block_ctx->start, block_ctx->dev->name);
bio_put(bio);
return -1;
}
bio_put(bio);
dev_bytenr += (j - i) * PAGE_CACHE_SIZE;
i = j;
}
for (i = 0; i < num_pages; i++) {
block_ctx->datav[i] = kmap(block_ctx->pagev[i]);
if (!block_ctx->datav[i]) {
printk(KERN_INFO "btrfsic: kmap() failed (dev %s)!\n",
block_ctx->dev->name);
return -1; return -1;
block_ctx->data = block_ctx->bh->b_data; }
}
return block_ctx->len; return block_ctx->len;
} }
static void btrfsic_complete_bio_end_io(struct bio *bio, int err)
{
complete((struct completion *)bio->bi_private);
}
static void btrfsic_dump_database(struct btrfsic_state *state) static void btrfsic_dump_database(struct btrfsic_state *state)
{ {
struct list_head *elem_all; struct list_head *elem_all;
...@@ -1617,32 +1800,39 @@ static void btrfsic_dump_database(struct btrfsic_state *state) ...@@ -1617,32 +1800,39 @@ static void btrfsic_dump_database(struct btrfsic_state *state)
* (note that this test fails for the super block) * (note that this test fails for the super block)
*/ */
static int btrfsic_test_for_metadata(struct btrfsic_state *state, static int btrfsic_test_for_metadata(struct btrfsic_state *state,
const u8 *data, unsigned int size) char **datav, unsigned int num_pages)
{ {
struct btrfs_header *h; struct btrfs_header *h;
u8 csum[BTRFS_CSUM_SIZE]; u8 csum[BTRFS_CSUM_SIZE];
u32 crc = ~(u32)0; u32 crc = ~(u32)0;
int fail = 0; unsigned int i;
int crc_fail = 0;
h = (struct btrfs_header *)data; if (num_pages * PAGE_CACHE_SIZE < state->metablock_size)
return 1; /* not metadata */
num_pages = state->metablock_size >> PAGE_CACHE_SHIFT;
h = (struct btrfs_header *)datav[0];
if (memcmp(h->fsid, state->root->fs_info->fsid, BTRFS_UUID_SIZE)) if (memcmp(h->fsid, state->root->fs_info->fsid, BTRFS_UUID_SIZE))
fail++; return 1;
for (i = 0; i < num_pages; i++) {
u8 *data = i ? datav[i] : (datav[i] + BTRFS_CSUM_SIZE);
size_t sublen = i ? PAGE_CACHE_SIZE :
(PAGE_CACHE_SIZE - BTRFS_CSUM_SIZE);
crc = crc32c(crc, data + BTRFS_CSUM_SIZE, PAGE_SIZE - BTRFS_CSUM_SIZE); crc = crc32c(crc, data, sublen);
}
btrfs_csum_final(crc, csum); btrfs_csum_final(crc, csum);
if (memcmp(csum, h->csum, state->csum_size)) if (memcmp(csum, h->csum, state->csum_size))
crc_fail++; return 1;
return fail || crc_fail; return 0; /* is metadata */
} }
static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
u64 dev_bytenr, u64 dev_bytenr, char **mapped_datav,
u8 *mapped_data, unsigned int len, unsigned int num_pages,
struct bio *bio, struct bio *bio, int *bio_is_patched,
int *bio_is_patched,
struct buffer_head *bh, struct buffer_head *bh,
int submit_bio_bh_rw) int submit_bio_bh_rw)
{ {
...@@ -1652,12 +1842,19 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1652,12 +1842,19 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
int ret; int ret;
struct btrfsic_state *state = dev_state->state; struct btrfsic_state *state = dev_state->state;
struct block_device *bdev = dev_state->bdev; struct block_device *bdev = dev_state->bdev;
unsigned int processed_len;
WARN_ON(len > PAGE_SIZE);
is_metadata = (0 == btrfsic_test_for_metadata(state, mapped_data, len));
if (NULL != bio_is_patched) if (NULL != bio_is_patched)
*bio_is_patched = 0; *bio_is_patched = 0;
again:
if (num_pages == 0)
return;
processed_len = 0;
is_metadata = (0 == btrfsic_test_for_metadata(state, mapped_datav,
num_pages));
block = btrfsic_block_hashtable_lookup(bdev, dev_bytenr, block = btrfsic_block_hashtable_lookup(bdev, dev_bytenr,
&state->block_hashtable); &state->block_hashtable);
if (NULL != block) { if (NULL != block) {
...@@ -1667,8 +1864,16 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1667,8 +1864,16 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
if (block->is_superblock) { if (block->is_superblock) {
bytenr = le64_to_cpu(((struct btrfs_super_block *) bytenr = le64_to_cpu(((struct btrfs_super_block *)
mapped_data)->bytenr); mapped_datav[0])->bytenr);
if (num_pages * PAGE_CACHE_SIZE <
BTRFS_SUPER_INFO_SIZE) {
printk(KERN_INFO
"btrfsic: cannot work with too short bios!\n");
return;
}
is_metadata = 1; is_metadata = 1;
BUG_ON(BTRFS_SUPER_INFO_SIZE & (PAGE_CACHE_SIZE - 1));
processed_len = BTRFS_SUPER_INFO_SIZE;
if (state->print_mask & if (state->print_mask &
BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE) { BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE) {
printk(KERN_INFO printk(KERN_INFO
...@@ -1678,12 +1883,18 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1678,12 +1883,18 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
} }
if (is_metadata) { if (is_metadata) {
if (!block->is_superblock) { if (!block->is_superblock) {
if (num_pages * PAGE_CACHE_SIZE <
state->metablock_size) {
printk(KERN_INFO
"btrfsic: cannot work with too short bios!\n");
return;
}
processed_len = state->metablock_size;
bytenr = le64_to_cpu(((struct btrfs_header *) bytenr = le64_to_cpu(((struct btrfs_header *)
mapped_data)->bytenr); mapped_datav[0])->bytenr);
btrfsic_cmp_log_and_dev_bytenr(state, bytenr, btrfsic_cmp_log_and_dev_bytenr(state, bytenr,
dev_state, dev_state,
dev_bytenr, dev_bytenr);
mapped_data);
} }
if (block->logical_bytenr != bytenr) { if (block->logical_bytenr != bytenr) {
printk(KERN_INFO printk(KERN_INFO
...@@ -1710,6 +1921,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1710,6 +1921,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
block->mirror_num, block->mirror_num,
btrfsic_get_block_type(state, block)); btrfsic_get_block_type(state, block));
} else { } else {
if (num_pages * PAGE_CACHE_SIZE <
state->datablock_size) {
printk(KERN_INFO
"btrfsic: cannot work with too short bios!\n");
return;
}
processed_len = state->datablock_size;
bytenr = block->logical_bytenr; bytenr = block->logical_bytenr;
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO printk(KERN_INFO
...@@ -1747,7 +1965,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1747,7 +1965,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
le64_to_cpu(block->disk_key.offset), le64_to_cpu(block->disk_key.offset),
(unsigned long long) (unsigned long long)
le64_to_cpu(((struct btrfs_header *) le64_to_cpu(((struct btrfs_header *)
mapped_data)->generation), mapped_datav[0])->generation),
(unsigned long long) (unsigned long long)
state->max_superblock_generation); state->max_superblock_generation);
btrfsic_dump_tree(state); btrfsic_dump_tree(state);
...@@ -1765,10 +1983,10 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1765,10 +1983,10 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
(unsigned long long)block->generation, (unsigned long long)block->generation,
(unsigned long long) (unsigned long long)
le64_to_cpu(((struct btrfs_header *) le64_to_cpu(((struct btrfs_header *)
mapped_data)->generation)); mapped_datav[0])->generation));
/* it would not be safe to go on */ /* it would not be safe to go on */
btrfsic_dump_tree(state); btrfsic_dump_tree(state);
return; goto continue_loop;
} }
/* /*
...@@ -1796,18 +2014,19 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1796,18 +2014,19 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
} }
if (block->is_superblock) if (block->is_superblock)
ret = btrfsic_map_superblock(state, bytenr, len, ret = btrfsic_map_superblock(state, bytenr,
processed_len,
bdev, &block_ctx); bdev, &block_ctx);
else else
ret = btrfsic_map_block(state, bytenr, len, ret = btrfsic_map_block(state, bytenr, processed_len,
&block_ctx, 0); &block_ctx, 0);
if (ret) { if (ret) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: btrfsic_map_block(root @%llu)" "btrfsic: btrfsic_map_block(root @%llu)"
" failed!\n", (unsigned long long)bytenr); " failed!\n", (unsigned long long)bytenr);
return; goto continue_loop;
} }
block_ctx.data = mapped_data; block_ctx.datav = mapped_datav;
/* the following is required in case of writes to mirrors, /* the following is required in case of writes to mirrors,
* use the same that was used for the lookup */ * use the same that was used for the lookup */
block_ctx.dev = dev_state; block_ctx.dev = dev_state;
...@@ -1863,11 +2082,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1863,11 +2082,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
block->logical_bytenr = bytenr; block->logical_bytenr = bytenr;
block->is_metadata = 1; block->is_metadata = 1;
if (block->is_superblock) { if (block->is_superblock) {
BUG_ON(PAGE_CACHE_SIZE !=
BTRFS_SUPER_INFO_SIZE);
ret = btrfsic_process_written_superblock( ret = btrfsic_process_written_superblock(
state, state,
block, block,
(struct btrfs_super_block *) (struct btrfs_super_block *)
mapped_data); mapped_datav[0]);
if (state->print_mask & if (state->print_mask &
BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE) { BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE) {
printk(KERN_INFO printk(KERN_INFO
...@@ -1880,8 +2101,6 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1880,8 +2101,6 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
state, state,
block, block,
&block_ctx, &block_ctx,
(struct btrfs_header *)
block_ctx.data,
0, 0); 0, 0);
} }
if (ret) if (ret)
...@@ -1912,26 +2131,30 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1912,26 +2131,30 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
u64 bytenr; u64 bytenr;
if (!is_metadata) { if (!is_metadata) {
processed_len = state->datablock_size;
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO "Written block (%s/%llu/?)" printk(KERN_INFO "Written block (%s/%llu/?)"
" !found in hash table, D.\n", " !found in hash table, D.\n",
dev_state->name, dev_state->name,
(unsigned long long)dev_bytenr); (unsigned long long)dev_bytenr);
if (!state->include_extent_data) if (!state->include_extent_data) {
return; /* ignore that written D block */ /* ignore that written D block */
goto continue_loop;
}
/* this is getting ugly for the /* this is getting ugly for the
* include_extent_data case... */ * include_extent_data case... */
bytenr = 0; /* unknown */ bytenr = 0; /* unknown */
block_ctx.start = bytenr; block_ctx.start = bytenr;
block_ctx.len = len; block_ctx.len = processed_len;
block_ctx.bh = NULL; block_ctx.mem_to_free = NULL;
block_ctx.pagev = NULL;
} else { } else {
processed_len = state->metablock_size;
bytenr = le64_to_cpu(((struct btrfs_header *) bytenr = le64_to_cpu(((struct btrfs_header *)
mapped_data)->bytenr); mapped_datav[0])->bytenr);
btrfsic_cmp_log_and_dev_bytenr(state, bytenr, dev_state, btrfsic_cmp_log_and_dev_bytenr(state, bytenr, dev_state,
dev_bytenr, dev_bytenr);
mapped_data);
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO printk(KERN_INFO
"Written block @%llu (%s/%llu/?)" "Written block @%llu (%s/%llu/?)"
...@@ -1940,17 +2163,17 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1940,17 +2163,17 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
dev_state->name, dev_state->name,
(unsigned long long)dev_bytenr); (unsigned long long)dev_bytenr);
ret = btrfsic_map_block(state, bytenr, len, &block_ctx, ret = btrfsic_map_block(state, bytenr, processed_len,
0); &block_ctx, 0);
if (ret) { if (ret) {
printk(KERN_INFO printk(KERN_INFO
"btrfsic: btrfsic_map_block(root @%llu)" "btrfsic: btrfsic_map_block(root @%llu)"
" failed!\n", " failed!\n",
(unsigned long long)dev_bytenr); (unsigned long long)dev_bytenr);
return; goto continue_loop;
} }
} }
block_ctx.data = mapped_data; block_ctx.datav = mapped_datav;
/* the following is required in case of writes to mirrors, /* the following is required in case of writes to mirrors,
* use the same that was used for the lookup */ * use the same that was used for the lookup */
block_ctx.dev = dev_state; block_ctx.dev = dev_state;
...@@ -1960,7 +2183,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -1960,7 +2183,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
if (NULL == block) { if (NULL == block) {
printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
btrfsic_release_block_ctx(&block_ctx); btrfsic_release_block_ctx(&block_ctx);
return; goto continue_loop;
} }
block->dev_state = dev_state; block->dev_state = dev_state;
block->dev_bytenr = dev_bytenr; block->dev_bytenr = dev_bytenr;
...@@ -2020,9 +2243,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -2020,9 +2243,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
if (is_metadata) { if (is_metadata) {
ret = btrfsic_process_metablock(state, block, ret = btrfsic_process_metablock(state, block,
&block_ctx, &block_ctx, 0, 0);
(struct btrfs_header *)
block_ctx.data, 0, 0);
if (ret) if (ret)
printk(KERN_INFO printk(KERN_INFO
"btrfsic: process_metablock(root @%llu)" "btrfsic: process_metablock(root @%llu)"
...@@ -2031,6 +2252,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, ...@@ -2031,6 +2252,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
} }
btrfsic_release_block_ctx(&block_ctx); btrfsic_release_block_ctx(&block_ctx);
} }
continue_loop:
BUG_ON(!processed_len);
dev_bytenr += processed_len;
mapped_datav += processed_len >> PAGE_CACHE_SHIFT;
num_pages -= processed_len >> PAGE_CACHE_SHIFT;
goto again;
} }
static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
...@@ -2213,7 +2441,7 @@ static int btrfsic_process_written_superblock( ...@@ -2213,7 +2441,7 @@ static int btrfsic_process_written_superblock(
num_copies = num_copies =
btrfs_num_copies(&state->root->fs_info->mapping_tree, btrfs_num_copies(&state->root->fs_info->mapping_tree,
next_bytenr, PAGE_SIZE); next_bytenr, BTRFS_SUPER_INFO_SIZE);
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
(unsigned long long)next_bytenr, num_copies); (unsigned long long)next_bytenr, num_copies);
...@@ -2224,7 +2452,8 @@ static int btrfsic_process_written_superblock( ...@@ -2224,7 +2452,8 @@ static int btrfsic_process_written_superblock(
printk(KERN_INFO printk(KERN_INFO
"btrfsic_process_written_superblock(" "btrfsic_process_written_superblock("
"mirror_num=%d)\n", mirror_num); "mirror_num=%d)\n", mirror_num);
ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE, ret = btrfsic_map_block(state, next_bytenr,
BTRFS_SUPER_INFO_SIZE,
&tmp_next_block_ctx, &tmp_next_block_ctx,
mirror_num); mirror_num);
if (ret) { if (ret) {
...@@ -2689,7 +2918,7 @@ static struct btrfsic_block *btrfsic_block_lookup_or_add( ...@@ -2689,7 +2918,7 @@ static struct btrfsic_block *btrfsic_block_lookup_or_add(
static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
u64 bytenr, u64 bytenr,
struct btrfsic_dev_state *dev_state, struct btrfsic_dev_state *dev_state,
u64 dev_bytenr, char *data) u64 dev_bytenr)
{ {
int num_copies; int num_copies;
int mirror_num; int mirror_num;
...@@ -2698,10 +2927,10 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, ...@@ -2698,10 +2927,10 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
int match = 0; int match = 0;
num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree, num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree,
bytenr, PAGE_SIZE); bytenr, state->metablock_size);
for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
ret = btrfsic_map_block(state, bytenr, PAGE_SIZE, ret = btrfsic_map_block(state, bytenr, state->metablock_size,
&block_ctx, mirror_num); &block_ctx, mirror_num);
if (ret) { if (ret) {
printk(KERN_INFO "btrfsic:" printk(KERN_INFO "btrfsic:"
...@@ -2727,7 +2956,8 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, ...@@ -2727,7 +2956,8 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
(unsigned long long)bytenr, dev_state->name, (unsigned long long)bytenr, dev_state->name,
(unsigned long long)dev_bytenr); (unsigned long long)dev_bytenr);
for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
ret = btrfsic_map_block(state, bytenr, PAGE_SIZE, ret = btrfsic_map_block(state, bytenr,
state->metablock_size,
&block_ctx, mirror_num); &block_ctx, mirror_num);
if (ret) if (ret)
continue; continue;
...@@ -2781,13 +3011,13 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) ...@@ -2781,13 +3011,13 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh)
(unsigned long)bh->b_size, bh->b_data, (unsigned long)bh->b_size, bh->b_data,
bh->b_bdev); bh->b_bdev);
btrfsic_process_written_block(dev_state, dev_bytenr, btrfsic_process_written_block(dev_state, dev_bytenr,
bh->b_data, bh->b_size, NULL, &bh->b_data, 1, NULL,
NULL, bh, rw); NULL, bh, rw);
} else if (NULL != dev_state && (rw & REQ_FLUSH)) { } else if (NULL != dev_state && (rw & REQ_FLUSH)) {
if (dev_state->state->print_mask & if (dev_state->state->print_mask &
BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
printk(KERN_INFO printk(KERN_INFO
"submit_bh(rw=0x%x) FLUSH, bdev=%p)\n", "submit_bh(rw=0x%x FLUSH, bdev=%p)\n",
rw, bh->b_bdev); rw, bh->b_bdev);
if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) {
if ((dev_state->state->print_mask & if ((dev_state->state->print_mask &
...@@ -2836,6 +3066,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio) ...@@ -2836,6 +3066,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio)
unsigned int i; unsigned int i;
u64 dev_bytenr; u64 dev_bytenr;
int bio_is_patched; int bio_is_patched;
char **mapped_datav;
dev_bytenr = 512 * bio->bi_sector; dev_bytenr = 512 * bio->bi_sector;
bio_is_patched = 0; bio_is_patched = 0;
...@@ -2848,35 +3079,46 @@ void btrfsic_submit_bio(int rw, struct bio *bio) ...@@ -2848,35 +3079,46 @@ void btrfsic_submit_bio(int rw, struct bio *bio)
(unsigned long long)dev_bytenr, (unsigned long long)dev_bytenr,
bio->bi_bdev); bio->bi_bdev);
mapped_datav = kmalloc(sizeof(*mapped_datav) * bio->bi_vcnt,
GFP_NOFS);
if (!mapped_datav)
goto leave;
for (i = 0; i < bio->bi_vcnt; i++) { for (i = 0; i < bio->bi_vcnt; i++) {
u8 *mapped_data; BUG_ON(bio->bi_io_vec[i].bv_len != PAGE_CACHE_SIZE);
mapped_datav[i] = kmap(bio->bi_io_vec[i].bv_page);
mapped_data = kmap(bio->bi_io_vec[i].bv_page); if (!mapped_datav[i]) {
while (i > 0) {
i--;
kunmap(bio->bi_io_vec[i].bv_page);
}
kfree(mapped_datav);
goto leave;
}
if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
BTRFSIC_PRINT_MASK_VERBOSE) == BTRFSIC_PRINT_MASK_VERBOSE) ==
(dev_state->state->print_mask & (dev_state->state->print_mask &
(BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
BTRFSIC_PRINT_MASK_VERBOSE))) BTRFSIC_PRINT_MASK_VERBOSE)))
printk(KERN_INFO printk(KERN_INFO
"#%u: page=%p, mapped=%p, len=%u," "#%u: page=%p, len=%u, offset=%u\n",
" offset=%u\n",
i, bio->bi_io_vec[i].bv_page, i, bio->bi_io_vec[i].bv_page,
mapped_data,
bio->bi_io_vec[i].bv_len, bio->bi_io_vec[i].bv_len,
bio->bi_io_vec[i].bv_offset); bio->bi_io_vec[i].bv_offset);
}
btrfsic_process_written_block(dev_state, dev_bytenr, btrfsic_process_written_block(dev_state, dev_bytenr,
mapped_data, mapped_datav, bio->bi_vcnt,
bio->bi_io_vec[i].bv_len,
bio, &bio_is_patched, bio, &bio_is_patched,
NULL, rw); NULL, rw);
while (i > 0) {
i--;
kunmap(bio->bi_io_vec[i].bv_page); kunmap(bio->bi_io_vec[i].bv_page);
dev_bytenr += bio->bi_io_vec[i].bv_len;
} }
kfree(mapped_datav);
} else if (NULL != dev_state && (rw & REQ_FLUSH)) { } else if (NULL != dev_state && (rw & REQ_FLUSH)) {
if (dev_state->state->print_mask & if (dev_state->state->print_mask &
BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
printk(KERN_INFO printk(KERN_INFO
"submit_bio(rw=0x%x) FLUSH, bdev=%p)\n", "submit_bio(rw=0x%x FLUSH, bdev=%p)\n",
rw, bio->bi_bdev); rw, bio->bi_bdev);
if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) {
if ((dev_state->state->print_mask & if ((dev_state->state->print_mask &
...@@ -2903,6 +3145,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio) ...@@ -2903,6 +3145,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio)
bio->bi_end_io = btrfsic_bio_end_io; bio->bi_end_io = btrfsic_bio_end_io;
} }
} }
leave:
mutex_unlock(&btrfsic_mutex); mutex_unlock(&btrfsic_mutex);
submit_bio(rw, bio); submit_bio(rw, bio);
...@@ -2917,6 +3160,30 @@ int btrfsic_mount(struct btrfs_root *root, ...@@ -2917,6 +3160,30 @@ int btrfsic_mount(struct btrfs_root *root,
struct list_head *dev_head = &fs_devices->devices; struct list_head *dev_head = &fs_devices->devices;
struct btrfs_device *device; struct btrfs_device *device;
if (root->nodesize != root->leafsize) {
printk(KERN_INFO
"btrfsic: cannot handle nodesize %d != leafsize %d!\n",
root->nodesize, root->leafsize);
return -1;
}
if (root->nodesize & ((u64)PAGE_CACHE_SIZE - 1)) {
printk(KERN_INFO
"btrfsic: cannot handle nodesize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
root->nodesize, (unsigned long)PAGE_CACHE_SIZE);
return -1;
}
if (root->leafsize & ((u64)PAGE_CACHE_SIZE - 1)) {
printk(KERN_INFO
"btrfsic: cannot handle leafsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
root->leafsize, (unsigned long)PAGE_CACHE_SIZE);
return -1;
}
if (root->sectorsize & ((u64)PAGE_CACHE_SIZE - 1)) {
printk(KERN_INFO
"btrfsic: cannot handle sectorsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
root->sectorsize, (unsigned long)PAGE_CACHE_SIZE);
return -1;
}
state = kzalloc(sizeof(*state), GFP_NOFS); state = kzalloc(sizeof(*state), GFP_NOFS);
if (NULL == state) { if (NULL == state) {
printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n"); printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n");
...@@ -2933,6 +3200,8 @@ int btrfsic_mount(struct btrfs_root *root, ...@@ -2933,6 +3200,8 @@ int btrfsic_mount(struct btrfs_root *root,
state->print_mask = print_mask; state->print_mask = print_mask;
state->include_extent_data = including_extent_data; state->include_extent_data = including_extent_data;
state->csum_size = 0; state->csum_size = 0;
state->metablock_size = root->nodesize;
state->datablock_size = root->sectorsize;
INIT_LIST_HEAD(&state->all_blocks_list); INIT_LIST_HEAD(&state->all_blocks_list);
btrfsic_block_hashtable_init(&state->block_hashtable); btrfsic_block_hashtable_init(&state->block_hashtable);
btrfsic_block_link_hashtable_init(&state->block_link_hashtable); btrfsic_block_link_hashtable_init(&state->block_link_hashtable);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment