Commit a236aed1 authored by Chris Mason's avatar Chris Mason

Btrfs: Deal with failed writes in mirrored configurations

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 4235298e
...@@ -1385,7 +1385,10 @@ int write_all_supers(struct btrfs_root *root) ...@@ -1385,7 +1385,10 @@ int write_all_supers(struct btrfs_root *root)
struct buffer_head *bh; struct buffer_head *bh;
int ret; int ret;
int do_barriers; int do_barriers;
int max_errors;
int total_errors = 0;
max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
do_barriers = !btrfs_test_opt(root, NOBARRIER); do_barriers = !btrfs_test_opt(root, NOBARRIER);
sb = root->fs_info->sb_buffer; sb = root->fs_info->sb_buffer;
...@@ -1433,8 +1436,14 @@ int write_all_supers(struct btrfs_root *root) ...@@ -1433,8 +1436,14 @@ int write_all_supers(struct btrfs_root *root)
} else { } else {
ret = submit_bh(WRITE, bh); ret = submit_bh(WRITE, bh);
} }
BUG_ON(ret); if (ret)
total_errors++;
} }
if (total_errors > max_errors) {
printk("btrfs: %d errors while writing supers\n", total_errors);
BUG();
}
total_errors = 0;
list_for_each(cur, head) { list_for_each(cur, head) {
dev = list_entry(cur, struct btrfs_device, dev_list); dev = list_entry(cur, struct btrfs_device, dev_list);
...@@ -1454,13 +1463,17 @@ int write_all_supers(struct btrfs_root *root) ...@@ -1454,13 +1463,17 @@ int write_all_supers(struct btrfs_root *root)
wait_on_buffer(bh); wait_on_buffer(bh);
BUG_ON(!buffer_uptodate(bh)); BUG_ON(!buffer_uptodate(bh));
} else { } else {
BUG(); total_errors++;
} }
} }
dev->pending_io = NULL; dev->pending_io = NULL;
brelse(bh); brelse(bh);
} }
if (total_errors > max_errors) {
printk("btrfs: %d errors while writing supers\n", total_errors);
BUG();
}
return 0; return 0;
} }
......
...@@ -315,8 +315,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -315,8 +315,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
block_group_cache = &info->block_group_cache; block_group_cache = &info->block_group_cache;
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
if (!owner) if (data & BTRFS_BLOCK_GROUP_METADATA)
factor = 10; factor = 9;
bit = block_group_state_bits(data); bit = block_group_state_bits(data);
......
...@@ -1425,6 +1425,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -1425,6 +1425,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int stripe_index; int stripe_index;
int i; int i;
int num_stripes; int num_stripes;
int max_errors = 0;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & (1 << BIO_RW))) { if (multi_ret && !(rw & (1 << BIO_RW))) {
...@@ -1436,6 +1437,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -1436,6 +1437,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
GFP_NOFS); GFP_NOFS);
if (!multi) if (!multi)
return -ENOMEM; return -ENOMEM;
atomic_set(&multi->error, 0);
} }
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
...@@ -1462,8 +1465,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -1462,8 +1465,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_DUP)) { BTRFS_BLOCK_GROUP_DUP)) {
stripes_required = map->num_stripes; stripes_required = map->num_stripes;
max_errors = 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
stripes_required = map->sub_stripes; stripes_required = map->sub_stripes;
max_errors = 1;
} }
} }
if (multi_ret && rw == WRITE && if (multi_ret && rw == WRITE &&
...@@ -1561,6 +1566,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -1561,6 +1566,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
if (multi_ret) { if (multi_ret) {
*multi_ret = multi; *multi_ret = multi;
multi->num_stripes = num_stripes; multi->num_stripes = num_stripes;
multi->max_errors = max_errors;
} }
out: out:
free_extent_map(em); free_extent_map(em);
...@@ -1598,14 +1604,19 @@ static int end_bio_multi_stripe(struct bio *bio, ...@@ -1598,14 +1604,19 @@ static int end_bio_multi_stripe(struct bio *bio,
return 1; return 1;
#endif #endif
if (err) if (err)
multi->error = err; atomic_inc(&multi->error);
if (atomic_dec_and_test(&multi->stripes_pending)) { if (atomic_dec_and_test(&multi->stripes_pending)) {
bio->bi_private = multi->private; bio->bi_private = multi->private;
bio->bi_end_io = multi->end_io; bio->bi_end_io = multi->end_io;
if (!err && multi->error) /* only send an error to the higher layers if it is
err = multi->error; * beyond the tolerance of the multi-bio
*/
if (atomic_read(&multi->error) > multi->max_errors)
err = -EIO;
else
err = 0;
kfree(multi); kfree(multi);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
......
...@@ -90,7 +90,8 @@ struct btrfs_multi_bio { ...@@ -90,7 +90,8 @@ struct btrfs_multi_bio {
atomic_t stripes_pending; atomic_t stripes_pending;
bio_end_io_t *end_io; bio_end_io_t *end_io;
void *private; void *private;
int error; atomic_t error;
int max_errors;
int num_stripes; int num_stripes;
struct btrfs_bio_stripe stripes[]; struct btrfs_bio_stripe stripes[];
}; };
......
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