forked from Minki/linux
Btrfs: Deal with failed writes in mirrored configurations
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
4235298e4f
commit
a236aed14c
@ -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)
|
|||||||
} 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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ again:
|
|||||||
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 @@ again:
|
|||||||
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 @@ again:
|
|||||||
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,
|
|||||||
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 {
|
|||||||
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[];
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user