aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
parent4235298e4fc3c1a09f659cfe2fd285024eeb2241 (diff)
Btrfs: Deal with failed writes in mirrored configurations
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-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)
1385 struct buffer_head *bh; 1385 struct buffer_head *bh;
1386 int ret; 1386 int ret;
1387 int do_barriers; 1387 int do_barriers;
1388 int max_errors;
1389 int total_errors = 0;
1388 1390
1391 max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
1389 do_barriers = !btrfs_test_opt(root, NOBARRIER); 1392 do_barriers = !btrfs_test_opt(root, NOBARRIER);
1390 1393
1391 sb = root->fs_info->sb_buffer; 1394 sb = root->fs_info->sb_buffer;
@@ -1433,8 +1436,14 @@ int write_all_supers(struct btrfs_root *root)
1433 } else { 1436 } else {
1434 ret = submit_bh(WRITE, bh); 1437 ret = submit_bh(WRITE, bh);
1435 } 1438 }
1436 BUG_ON(ret); 1439 if (ret)
1440 total_errors++;
1437 } 1441 }
1442 if (total_errors > max_errors) {
1443 printk("btrfs: %d errors while writing supers\n", total_errors);
1444 BUG();
1445 }
1446 total_errors = 0;
1438 1447
1439 list_for_each(cur, head) { 1448 list_for_each(cur, head) {
1440 dev = list_entry(cur, struct btrfs_device, dev_list); 1449 dev = list_entry(cur, struct btrfs_device, dev_list);
@@ -1454,13 +1463,17 @@ int write_all_supers(struct btrfs_root *root)
1454 wait_on_buffer(bh); 1463 wait_on_buffer(bh);
1455 BUG_ON(!buffer_uptodate(bh)); 1464 BUG_ON(!buffer_uptodate(bh));
1456 } else { 1465 } else {
1457 BUG(); 1466 total_errors++;
1458 } 1467 }
1459 1468
1460 } 1469 }
1461 dev->pending_io = NULL; 1470 dev->pending_io = NULL;
1462 brelse(bh); 1471 brelse(bh);
1463 } 1472 }
1473 if (total_errors > max_errors) {
1474 printk("btrfs: %d errors while writing supers\n", total_errors);
1475 BUG();
1476 }
1464 return 0; 1477 return 0;
1465} 1478}
1466 1479
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,
315 block_group_cache = &info->block_group_cache; 315 block_group_cache = &info->block_group_cache;
316 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); 316 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
317 317
318 if (!owner) 318 if (data & BTRFS_BLOCK_GROUP_METADATA)
319 factor = 10; 319 factor = 9;
320 320
321 bit = block_group_state_bits(data); 321 bit = block_group_state_bits(data);
322 322
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,
1425 int stripe_index; 1425 int stripe_index;
1426 int i; 1426 int i;
1427 int num_stripes; 1427 int num_stripes;
1428 int max_errors = 0;
1428 struct btrfs_multi_bio *multi = NULL; 1429 struct btrfs_multi_bio *multi = NULL;
1429 1430
1430 if (multi_ret && !(rw & (1 << BIO_RW))) { 1431 if (multi_ret && !(rw & (1 << BIO_RW))) {
@@ -1436,6 +1437,8 @@ again:
1436 GFP_NOFS); 1437 GFP_NOFS);
1437 if (!multi) 1438 if (!multi)
1438 return -ENOMEM; 1439 return -ENOMEM;
1440
1441 atomic_set(&multi->error, 0);
1439 } 1442 }
1440 1443
1441 spin_lock(&em_tree->lock); 1444 spin_lock(&em_tree->lock);
@@ -1462,8 +1465,10 @@ again:
1462 if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | 1465 if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
1463 BTRFS_BLOCK_GROUP_DUP)) { 1466 BTRFS_BLOCK_GROUP_DUP)) {
1464 stripes_required = map->num_stripes; 1467 stripes_required = map->num_stripes;
1468 max_errors = 1;
1465 } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { 1469 } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
1466 stripes_required = map->sub_stripes; 1470 stripes_required = map->sub_stripes;
1471 max_errors = 1;
1467 } 1472 }
1468 } 1473 }
1469 if (multi_ret && rw == WRITE && 1474 if (multi_ret && rw == WRITE &&
@@ -1561,6 +1566,7 @@ again:
1561 if (multi_ret) { 1566 if (multi_ret) {
1562 *multi_ret = multi; 1567 *multi_ret = multi;
1563 multi->num_stripes = num_stripes; 1568 multi->num_stripes = num_stripes;
1569 multi->max_errors = max_errors;
1564 } 1570 }
1565out: 1571out:
1566 free_extent_map(em); 1572 free_extent_map(em);
@@ -1598,14 +1604,19 @@ static int end_bio_multi_stripe(struct bio *bio,
1598 return 1; 1604 return 1;
1599#endif 1605#endif
1600 if (err) 1606 if (err)
1601 multi->error = err; 1607 atomic_inc(&multi->error);
1602 1608
1603 if (atomic_dec_and_test(&multi->stripes_pending)) { 1609 if (atomic_dec_and_test(&multi->stripes_pending)) {
1604 bio->bi_private = multi->private; 1610 bio->bi_private = multi->private;
1605 bio->bi_end_io = multi->end_io; 1611 bio->bi_end_io = multi->end_io;
1606 1612
1607 if (!err && multi->error) 1613 /* only send an error to the higher layers if it is
1608 err = multi->error; 1614 * beyond the tolerance of the multi-bio
1615 */
1616 if (atomic_read(&multi->error) > multi->max_errors)
1617 err = -EIO;
1618 else
1619 err = 0;
1609 kfree(multi); 1620 kfree(multi);
1610 1621
1611#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) 1622#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 {
90 atomic_t stripes_pending; 90 atomic_t stripes_pending;
91 bio_end_io_t *end_io; 91 bio_end_io_t *end_io;
92 void *private; 92 void *private;
93 int error; 93 atomic_t error;
94 int max_errors;
94 int num_stripes; 95 int num_stripes;
95 struct btrfs_bio_stripe stripes[]; 96 struct btrfs_bio_stripe stripes[];
96}; 97};