aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-11-05 12:51:52 -0500
committerJosef Bacik <jbacik@fusionio.com>2012-12-12 17:15:40 -0500
commit618919236ba54361e93106f4951d233a7ade63cd (patch)
tree4ab4c62432550e7ed32aa19a07609fbca0b9de52
parent63a212abc2315972b245f93cb11ae3acf3c0b513 (diff)
Btrfs: handle errors from btrfs_map_bio() everywhere
With the addition of the device replace procedure, it is possible for btrfs_map_bio(READ) to report an error. This happens when the specific mirror is requested which is located on the target disk, and the copy operation has not yet copied this block. Hence the block cannot be read and this error state is indicated by returning EIO. Some background information follows now. A new mirror is added while the device replace procedure is running. btrfs_get_num_copies() returns one more, and btrfs_map_bio(GET_READ_MIRROR) adds one more mirror if a disk location is involved that was already handled by the device replace copy operation. The assigned mirror num is the highest mirror number, e.g. the value 3 in case of RAID1. If btrfs_map_bio() is invoked with mirror_num == 0 (i.e., select any mirror), the copy on the target drive is never selected because that disk shall be able to perform the write requests as quickly as possible. The parallel execution of read requests would only slow down the disk copy procedure. Second case is that btrfs_map_bio() is called with mirror_num > 0. This is done from the repair code only. In this case, the highest mirror num is assigned to the target disk, since it is used last. And when this mirror is not available because the copy procedure has not yet handled this area, an error is returned. Everywhere in the code the handling of such errors is added now. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--fs/btrfs/check-integrity.c15
-rw-r--r--fs/btrfs/compression.c6
-rw-r--r--fs/btrfs/disk-io.c44
-rw-r--r--fs/btrfs/extent_io.c4
-rw-r--r--fs/btrfs/inode.c27
-rw-r--r--fs/btrfs/volumes.c2
6 files changed, 65 insertions, 33 deletions
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 8f9abedae2c3..badc6f141b6f 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -1585,6 +1585,18 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
1585 ret = btrfs_map_block(state->root->fs_info, READ, 1585 ret = btrfs_map_block(state->root->fs_info, READ,
1586 bytenr, &length, &multi, mirror_num); 1586 bytenr, &length, &multi, mirror_num);
1587 1587
1588 if (ret) {
1589 block_ctx_out->start = 0;
1590 block_ctx_out->dev_bytenr = 0;
1591 block_ctx_out->len = 0;
1592 block_ctx_out->dev = NULL;
1593 block_ctx_out->datav = NULL;
1594 block_ctx_out->pagev = NULL;
1595 block_ctx_out->mem_to_free = NULL;
1596
1597 return ret;
1598 }
1599
1588 device = multi->stripes[0].dev; 1600 device = multi->stripes[0].dev;
1589 block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev); 1601 block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev);
1590 block_ctx_out->dev_bytenr = multi->stripes[0].physical; 1602 block_ctx_out->dev_bytenr = multi->stripes[0].physical;
@@ -1594,8 +1606,7 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
1594 block_ctx_out->pagev = NULL; 1606 block_ctx_out->pagev = NULL;
1595 block_ctx_out->mem_to_free = NULL; 1607 block_ctx_out->mem_to_free = NULL;
1596 1608
1597 if (0 == ret) 1609 kfree(multi);
1598 kfree(multi);
1599 if (NULL == block_ctx_out->dev) { 1610 if (NULL == block_ctx_out->dev) {
1600 ret = -ENXIO; 1611 ret = -ENXIO;
1601 printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n"); 1612 printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n");
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index c6467aa88bee..94ab2f80e7e3 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -687,7 +687,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
687 687
688 ret = btrfs_map_bio(root, READ, comp_bio, 688 ret = btrfs_map_bio(root, READ, comp_bio,
689 mirror_num, 0); 689 mirror_num, 0);
690 BUG_ON(ret); /* -ENOMEM */ 690 if (ret)
691 bio_endio(comp_bio, ret);
691 692
692 bio_put(comp_bio); 693 bio_put(comp_bio);
693 694
@@ -712,7 +713,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
712 } 713 }
713 714
714 ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); 715 ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
715 BUG_ON(ret); /* -ENOMEM */ 716 if (ret)
717 bio_endio(comp_bio, ret);
716 718
717 bio_put(comp_bio); 719 bio_put(comp_bio);
718 return 0; 720 return 0;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9d1b71060813..0e410478ad27 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -852,11 +852,16 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
852 int mirror_num, unsigned long bio_flags, 852 int mirror_num, unsigned long bio_flags,
853 u64 bio_offset) 853 u64 bio_offset)
854{ 854{
855 int ret;
856
855 /* 857 /*
856 * when we're called for a write, we're already in the async 858 * when we're called for a write, we're already in the async
857 * submission context. Just jump into btrfs_map_bio 859 * submission context. Just jump into btrfs_map_bio
858 */ 860 */
859 return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); 861 ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
862 if (ret)
863 bio_endio(bio, ret);
864 return ret;
860} 865}
861 866
862static int check_async_write(struct inode *inode, unsigned long bio_flags) 867static int check_async_write(struct inode *inode, unsigned long bio_flags)
@@ -878,7 +883,6 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
878 int ret; 883 int ret;
879 884
880 if (!(rw & REQ_WRITE)) { 885 if (!(rw & REQ_WRITE)) {
881
882 /* 886 /*
883 * called for a read, do the setup so that checksum validation 887 * called for a read, do the setup so that checksum validation
884 * can happen in the async kernel threads 888 * can happen in the async kernel threads
@@ -886,26 +890,32 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
886 ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, 890 ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
887 bio, 1); 891 bio, 1);
888 if (ret) 892 if (ret)
889 return ret; 893 goto out_w_error;
890 return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, 894 ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
891 mirror_num, 0); 895 mirror_num, 0);
892 } else if (!async) { 896 } else if (!async) {
893 ret = btree_csum_one_bio(bio); 897 ret = btree_csum_one_bio(bio);
894 if (ret) 898 if (ret)
895 return ret; 899 goto out_w_error;
896 return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, 900 ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
897 mirror_num, 0); 901 mirror_num, 0);
902 } else {
903 /*
904 * kthread helpers are used to submit writes so that
905 * checksumming can happen in parallel across all CPUs
906 */
907 ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
908 inode, rw, bio, mirror_num, 0,
909 bio_offset,
910 __btree_submit_bio_start,
911 __btree_submit_bio_done);
898 } 912 }
899 913
900 /* 914 if (ret) {
901 * kthread helpers are used to submit writes so that checksumming 915out_w_error:
902 * can happen in parallel across all CPUs 916 bio_endio(bio, ret);
903 */ 917 }
904 return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, 918 return ret;
905 inode, rw, bio, mirror_num, 0,
906 bio_offset,
907 __btree_submit_bio_start,
908 __btree_submit_bio_done);
909} 919}
910 920
911#ifdef CONFIG_MIGRATION 921#ifdef CONFIG_MIGRATION
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 62ec6e45f705..1b319df29eee 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2462,10 +2462,6 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
2462 return bio; 2462 return bio;
2463} 2463}
2464 2464
2465/*
2466 * Since writes are async, they will only return -ENOMEM.
2467 * Reads can return the full range of I/O error conditions.
2468 */
2469static int __must_check submit_one_bio(int rw, struct bio *bio, 2465static int __must_check submit_one_bio(int rw, struct bio *bio,
2470 int mirror_num, unsigned long bio_flags) 2466 int mirror_num, unsigned long bio_flags)
2471{ 2467{
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 5d1675a8c9e2..d7bf2e7ee8a0 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1602,7 +1602,12 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
1602 u64 bio_offset) 1602 u64 bio_offset)
1603{ 1603{
1604 struct btrfs_root *root = BTRFS_I(inode)->root; 1604 struct btrfs_root *root = BTRFS_I(inode)->root;
1605 return btrfs_map_bio(root, rw, bio, mirror_num, 1); 1605 int ret;
1606
1607 ret = btrfs_map_bio(root, rw, bio, mirror_num, 1);
1608 if (ret)
1609 bio_endio(bio, ret);
1610 return ret;
1606} 1611}
1607 1612
1608/* 1613/*
@@ -1626,15 +1631,17 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
1626 if (!(rw & REQ_WRITE)) { 1631 if (!(rw & REQ_WRITE)) {
1627 ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata); 1632 ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
1628 if (ret) 1633 if (ret)
1629 return ret; 1634 goto out;
1630 1635
1631 if (bio_flags & EXTENT_BIO_COMPRESSED) { 1636 if (bio_flags & EXTENT_BIO_COMPRESSED) {
1632 return btrfs_submit_compressed_read(inode, bio, 1637 ret = btrfs_submit_compressed_read(inode, bio,
1633 mirror_num, bio_flags); 1638 mirror_num,
1639 bio_flags);
1640 goto out;
1634 } else if (!skip_sum) { 1641 } else if (!skip_sum) {
1635 ret = btrfs_lookup_bio_sums(root, inode, bio, NULL); 1642 ret = btrfs_lookup_bio_sums(root, inode, bio, NULL);
1636 if (ret) 1643 if (ret)
1637 return ret; 1644 goto out;
1638 } 1645 }
1639 goto mapit; 1646 goto mapit;
1640 } else if (!skip_sum) { 1647 } else if (!skip_sum) {
@@ -1642,15 +1649,21 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
1642 if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) 1649 if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
1643 goto mapit; 1650 goto mapit;
1644 /* we're doing a write, do the async checksumming */ 1651 /* we're doing a write, do the async checksumming */
1645 return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, 1652 ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
1646 inode, rw, bio, mirror_num, 1653 inode, rw, bio, mirror_num,
1647 bio_flags, bio_offset, 1654 bio_flags, bio_offset,
1648 __btrfs_submit_bio_start, 1655 __btrfs_submit_bio_start,
1649 __btrfs_submit_bio_done); 1656 __btrfs_submit_bio_done);
1657 goto out;
1650 } 1658 }
1651 1659
1652mapit: 1660mapit:
1653 return btrfs_map_bio(root, rw, bio, mirror_num, 0); 1661 ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
1662
1663out:
1664 if (ret < 0)
1665 bio_endio(bio, ret);
1666 return ret;
1654} 1667}
1655 1668
1656/* 1669/*
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 31f7af878d96..415862885b67 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4435,7 +4435,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
4435 4435
4436 ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, 4436 ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio,
4437 mirror_num); 4437 mirror_num);
4438 if (ret) /* -ENOMEM */ 4438 if (ret)
4439 return ret; 4439 return ret;
4440 4440
4441 total_devs = bbio->num_stripes; 4441 total_devs = bbio->num_stripes;