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/btrfs/volumes.c | |
parent | 4235298e4fc3c1a09f659cfe2fd285024eeb2241 (diff) |
Btrfs: Deal with failed writes in mirrored configurations
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 17 |
1 files changed, 14 insertions, 3 deletions
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) |