Skip to content

Commit 6189192

Browse files
Stefan BehrensJosef Bacik
authored andcommitted
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 <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 63a212a commit 6189192

File tree

6 files changed

+65
-33
lines changed

6 files changed

+65
-33
lines changed

fs/btrfs/check-integrity.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,18 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
15851585
ret = btrfs_map_block(state->root->fs_info, READ,
15861586
bytenr, &length, &multi, mirror_num);
15871587

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+
15881600
device = multi->stripes[0].dev;
15891601
block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev);
15901602
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,
15941606
block_ctx_out->pagev = NULL;
15951607
block_ctx_out->mem_to_free = NULL;
15961608

1597-
if (0 == ret)
1598-
kfree(multi);
1609+
kfree(multi);
15991610
if (NULL == block_ctx_out->dev) {
16001611
ret = -ENXIO;
16011612
printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n");

fs/btrfs/compression.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
687687

688688
ret = btrfs_map_bio(root, READ, comp_bio,
689689
mirror_num, 0);
690-
BUG_ON(ret); /* -ENOMEM */
690+
if (ret)
691+
bio_endio(comp_bio, ret);
691692

692693
bio_put(comp_bio);
693694

@@ -712,7 +713,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
712713
}
713714

714715
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);
716718

717719
bio_put(comp_bio);
718720
return 0;

fs/btrfs/disk-io.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -852,11 +852,16 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
852852
int mirror_num, unsigned long bio_flags,
853853
u64 bio_offset)
854854
{
855+
int ret;
856+
855857
/*
856858
* when we're called for a write, we're already in the async
857859
* submission context. Just jump into btrfs_map_bio
858860
*/
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;
860865
}
861866

862867
static int check_async_write(struct inode *inode, unsigned long bio_flags)
@@ -878,34 +883,39 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
878883
int ret;
879884

880885
if (!(rw & REQ_WRITE)) {
881-
882886
/*
883887
* called for a read, do the setup so that checksum validation
884888
* can happen in the async kernel threads
885889
*/
886890
ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
887891
bio, 1);
888892
if (ret)
889-
return ret;
890-
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
891-
mirror_num, 0);
893+
goto out_w_error;
894+
ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
895+
mirror_num, 0);
892896
} else if (!async) {
893897
ret = btree_csum_one_bio(bio);
894898
if (ret)
895-
return ret;
896-
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
897-
mirror_num, 0);
899+
goto out_w_error;
900+
ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
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);
898912
}
899913

900-
/*
901-
* kthread helpers are used to submit writes so that checksumming
902-
* can happen in parallel across all CPUs
903-
*/
904-
return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
905-
inode, rw, bio, mirror_num, 0,
906-
bio_offset,
907-
__btree_submit_bio_start,
908-
__btree_submit_bio_done);
914+
if (ret) {
915+
out_w_error:
916+
bio_endio(bio, ret);
917+
}
918+
return ret;
909919
}
910920

911921
#ifdef CONFIG_MIGRATION

fs/btrfs/extent_io.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,10 +2462,6 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
24622462
return bio;
24632463
}
24642464

2465-
/*
2466-
* Since writes are async, they will only return -ENOMEM.
2467-
* Reads can return the full range of I/O error conditions.
2468-
*/
24692465
static int __must_check submit_one_bio(int rw, struct bio *bio,
24702466
int mirror_num, unsigned long bio_flags)
24712467
{

fs/btrfs/inode.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,7 +1602,12 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
16021602
u64 bio_offset)
16031603
{
16041604
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;
16061611
}
16071612

16081613
/*
@@ -1626,31 +1631,39 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
16261631
if (!(rw & REQ_WRITE)) {
16271632
ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
16281633
if (ret)
1629-
return ret;
1634+
goto out;
16301635

16311636
if (bio_flags & EXTENT_BIO_COMPRESSED) {
1632-
return btrfs_submit_compressed_read(inode, bio,
1633-
mirror_num, bio_flags);
1637+
ret = btrfs_submit_compressed_read(inode, bio,
1638+
mirror_num,
1639+
bio_flags);
1640+
goto out;
16341641
} else if (!skip_sum) {
16351642
ret = btrfs_lookup_bio_sums(root, inode, bio, NULL);
16361643
if (ret)
1637-
return ret;
1644+
goto out;
16381645
}
16391646
goto mapit;
16401647
} else if (!skip_sum) {
16411648
/* csum items have already been cloned */
16421649
if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
16431650
goto mapit;
16441651
/* 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,
16461653
inode, rw, bio, mirror_num,
16471654
bio_flags, bio_offset,
16481655
__btrfs_submit_bio_start,
16491656
__btrfs_submit_bio_done);
1657+
goto out;
16501658
}
16511659

16521660
mapit:
1653-
return btrfs_map_bio(root, rw, bio, mirror_num, 0);
1661+
ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
1662+
1663+
out:
1664+
if (ret < 0)
1665+
bio_endio(bio, ret);
1666+
return ret;
16541667
}
16551668

16561669
/*

fs/btrfs/volumes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4435,7 +4435,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
44354435

44364436
ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio,
44374437
mirror_num);
4438-
if (ret) /* -ENOMEM */
4438+
if (ret)
44394439
return ret;
44404440

44414441
total_devs = bbio->num_stripes;

0 commit comments

Comments
 (0)