summaryrefslogtreecommitdiff
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-29 09:38:00 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commita236aed14ccb0661611d4416f6b573d892bdc60a (patch)
treeb275333ab5bfaa9ea68756aa0a5c6d5c6fef5405 /fs/btrfs
parent4235298e4fc3c1a09f659cfe2fd285024eeb2241 (diff)
Btrfs: Deal with failed writes in mirrored configurations
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/disk-io.c17
-rw-r--r--fs/btrfs/extent-tree.c4
-rw-r--r--fs/btrfs/volumes.c17
-rw-r--r--fs/btrfs/volumes.h3
4 files changed, 33 insertions, 8 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1c7d84aff864..e35e70165b53 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1385,7 +1385,10 @@ int write_all_supers(struct btrfs_root *root)
struct buffer_head *bh;
int ret;
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);
sb = root->fs_info->sb_buffer;
@@ -1433,8 +1436,14 @@ int write_all_supers(struct btrfs_root *root)
} else {
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) {
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);
BUG_ON(!buffer_uptodate(bh));
} else {
- BUG();
+ total_errors++;
}
}
dev->pending_io = NULL;
brelse(bh);
}
+ if (total_errors > max_errors) {
+ printk("btrfs: %d errors while writing supers\n", total_errors);
+ BUG();
+ }
return 0;
}
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 95aee5a29375..f94794a99329 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -315,8 +315,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
block_group_cache = &info->block_group_cache;
total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
- if (!owner)
- factor = 10;
+ if (data & BTRFS_BLOCK_GROUP_METADATA)
+ factor = 9;
bit = block_group_state_bits(data);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 9a7241134560..57ab755aca76 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1425,6 +1425,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int stripe_index;
int i;
int num_stripes;
+ int max_errors = 0;
struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & (1 << BIO_RW))) {
@@ -1436,6 +1437,8 @@ again:
GFP_NOFS);
if (!multi)
return -ENOMEM;
+
+ atomic_set(&multi->error, 0);
}
spin_lock(&em_tree->lock);
@@ -1462,8 +1465,10 @@ again:
if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_DUP)) {
stripes_required = map->num_stripes;
+ max_errors = 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
stripes_required = map->sub_stripes;
+ max_errors = 1;
}
}
if (multi_ret && rw == WRITE &&
@@ -1561,6 +1566,7 @@ again:
if (multi_ret) {
*multi_ret = multi;
multi->num_stripes = num_stripes;
+ multi->max_errors = max_errors;
}
out:
free_extent_map(em);
@@ -1598,14 +1604,19 @@ static int end_bio_multi_stripe(struct bio *bio,
return 1;
#endif
if (err)
- multi->error = err;
+ atomic_inc(&multi->error);
if (atomic_dec_and_test(&multi->stripes_pending)) {
bio->bi_private = multi->private;
bio->bi_end_io = multi->end_io;
- if (!err && multi->error)
- err = multi->error;
+ /* only send an error to the higher layers if it is
+ * beyond the tolerance of the multi-bio
+ */
+ if (atomic_read(&multi->error) > multi->max_errors)
+ err = -EIO;
+ else
+ err = 0;
kfree(multi);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 3f9a17f2e41b..a9663e92bb14 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -90,7 +90,8 @@ struct btrfs_multi_bio {
atomic_t stripes_pending;
bio_end_io_t *end_io;
void *private;
- int error;
+ atomic_t error;
+ int max_errors;
int num_stripes;
struct btrfs_bio_stripe stripes[];
};