diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-29 09:38:00 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | a236aed14ccb0661611d4416f6b573d892bdc60a (patch) | |
tree | b275333ab5bfaa9ea68756aa0a5c6d5c6fef5405 /fs | |
parent | 4235298e4fc3c1a09f659cfe2fd285024eeb2241 (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.c | 17 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 17 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
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 | } |
1565 | out: | 1571 | out: |
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 | }; |