Commit c725328c authored by Liu Bo's avatar Liu Bo Committed by David Sterba

Btrfs: enable repair during read for raid56 profile

Now that scrub can fix data errors with the help of parity for raid56
profile, repair during read is able to as well.

Although the mirror num in raid56 scenario has different meanings, i.e.
0 or 1: read data directly
> 1:    do recover with parity,
it could be fit into how we repair bad block during read.

The trick is to use BTRFS_MAP_READ instead of BTRFS_MAP_WRITE to get the
device and position on it.

Cc: David Sterba <dsterba@suse.cz>
Tested-by: default avatarQu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 619a9742
...@@ -2009,10 +2009,6 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length, ...@@ -2009,10 +2009,6 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length,
ASSERT(!(fs_info->sb->s_flags & MS_RDONLY)); ASSERT(!(fs_info->sb->s_flags & MS_RDONLY));
BUG_ON(!mirror_num); BUG_ON(!mirror_num);
/* we can't repair anything in raid56 yet */
if (btrfs_is_parity_mirror(fs_info, logical, length, mirror_num))
return 0;
bio = btrfs_io_bio_alloc(GFP_NOFS, 1); bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
if (!bio) if (!bio)
return -EIO; return -EIO;
...@@ -2025,17 +2021,35 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length, ...@@ -2025,17 +2021,35 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length,
* read repair operation. * read repair operation.
*/ */
btrfs_bio_counter_inc_blocked(fs_info); btrfs_bio_counter_inc_blocked(fs_info);
ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical, if (btrfs_is_parity_mirror(fs_info, logical, length, mirror_num)) {
&map_length, &bbio, mirror_num); /*
if (ret) { * Note that we don't use BTRFS_MAP_WRITE because it's supposed
btrfs_bio_counter_dec(fs_info); * to update all raid stripes, but here we just want to correct
bio_put(bio); * bad stripe, thus BTRFS_MAP_READ is abused to only get the bad
return -EIO; * stripe's dev and sector.
*/
ret = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
&map_length, &bbio, 0);
if (ret) {
btrfs_bio_counter_dec(fs_info);
bio_put(bio);
return -EIO;
}
ASSERT(bbio->mirror_num == 1);
} else {
ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical,
&map_length, &bbio, mirror_num);
if (ret) {
btrfs_bio_counter_dec(fs_info);
bio_put(bio);
return -EIO;
}
BUG_ON(mirror_num != bbio->mirror_num);
} }
BUG_ON(mirror_num != bbio->mirror_num);
sector = bbio->stripes[mirror_num-1].physical >> 9; sector = bbio->stripes[bbio->mirror_num - 1].physical >> 9;
bio->bi_iter.bi_sector = sector; bio->bi_iter.bi_sector = sector;
dev = bbio->stripes[mirror_num-1].dev; dev = bbio->stripes[bbio->mirror_num - 1].dev;
btrfs_put_bbio(bbio); btrfs_put_bbio(bbio);
if (!dev || !dev->bdev || !dev->writeable) { if (!dev || !dev->bdev || !dev->writeable) {
btrfs_bio_counter_dec(fs_info); btrfs_bio_counter_dec(fs_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment