|
@@ -7751,9 +7751,9 @@ static int btrfs_check_dio_repairable(struct inode *inode,
|
|
|
}
|
|
|
|
|
|
static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
- struct page *page, u64 start, u64 end,
|
|
|
- int failed_mirror, bio_end_io_t *repair_endio,
|
|
|
- void *repair_arg)
|
|
|
+ struct page *page, unsigned int pgoff,
|
|
|
+ u64 start, u64 end, int failed_mirror,
|
|
|
+ bio_end_io_t *repair_endio, void *repair_arg)
|
|
|
{
|
|
|
struct io_failure_record *failrec;
|
|
|
struct bio *bio;
|
|
@@ -7774,7 +7774,9 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
- if (failed_bio->bi_vcnt > 1)
|
|
|
+ if ((failed_bio->bi_vcnt > 1)
|
|
|
+ || (failed_bio->bi_io_vec->bv_len
|
|
|
+ > BTRFS_I(inode)->root->sectorsize))
|
|
|
read_mode = READ_SYNC | REQ_FAILFAST_DEV;
|
|
|
else
|
|
|
read_mode = READ_SYNC;
|
|
@@ -7782,7 +7784,7 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
isector = start - btrfs_io_bio(failed_bio)->logical;
|
|
|
isector >>= inode->i_sb->s_blocksize_bits;
|
|
|
bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
|
|
|
- 0, isector, repair_endio, repair_arg);
|
|
|
+ pgoff, isector, repair_endio, repair_arg);
|
|
|
if (!bio) {
|
|
|
free_io_failure(inode, failrec);
|
|
|
return -EIO;
|
|
@@ -7812,12 +7814,17 @@ struct btrfs_retry_complete {
|
|
|
static void btrfs_retry_endio_nocsum(struct bio *bio)
|
|
|
{
|
|
|
struct btrfs_retry_complete *done = bio->bi_private;
|
|
|
+ struct inode *inode;
|
|
|
struct bio_vec *bvec;
|
|
|
int i;
|
|
|
|
|
|
if (bio->bi_error)
|
|
|
goto end;
|
|
|
|
|
|
+ ASSERT(bio->bi_vcnt == 1);
|
|
|
+ inode = bio->bi_io_vec->bv_page->mapping->host;
|
|
|
+ ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize);
|
|
|
+
|
|
|
done->uptodate = 1;
|
|
|
bio_for_each_segment_all(bvec, bio, i)
|
|
|
clean_io_failure(done->inode, done->start, bvec->bv_page, 0);
|
|
@@ -7829,25 +7836,35 @@ end:
|
|
|
static int __btrfs_correct_data_nocsum(struct inode *inode,
|
|
|
struct btrfs_io_bio *io_bio)
|
|
|
{
|
|
|
+ struct btrfs_fs_info *fs_info;
|
|
|
struct bio_vec *bvec;
|
|
|
struct btrfs_retry_complete done;
|
|
|
u64 start;
|
|
|
+ unsigned int pgoff;
|
|
|
+ u32 sectorsize;
|
|
|
+ int nr_sectors;
|
|
|
int i;
|
|
|
int ret;
|
|
|
|
|
|
+ fs_info = BTRFS_I(inode)->root->fs_info;
|
|
|
+ sectorsize = BTRFS_I(inode)->root->sectorsize;
|
|
|
+
|
|
|
start = io_bio->logical;
|
|
|
done.inode = inode;
|
|
|
|
|
|
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
|
|
-try_again:
|
|
|
+ nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
|
|
+ pgoff = bvec->bv_offset;
|
|
|
+
|
|
|
+next_block_or_try_again:
|
|
|
done.uptodate = 0;
|
|
|
done.start = start;
|
|
|
init_completion(&done.done);
|
|
|
|
|
|
- ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
|
|
- start + bvec->bv_len - 1,
|
|
|
- io_bio->mirror_num,
|
|
|
- btrfs_retry_endio_nocsum, &done);
|
|
|
+ ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
|
|
+ pgoff, start, start + sectorsize - 1,
|
|
|
+ io_bio->mirror_num,
|
|
|
+ btrfs_retry_endio_nocsum, &done);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -7855,10 +7872,15 @@ try_again:
|
|
|
|
|
|
if (!done.uptodate) {
|
|
|
/* We might have another mirror, so try again */
|
|
|
- goto try_again;
|
|
|
+ goto next_block_or_try_again;
|
|
|
}
|
|
|
|
|
|
- start += bvec->bv_len;
|
|
|
+ start += sectorsize;
|
|
|
+
|
|
|
+ if (nr_sectors--) {
|
|
|
+ pgoff += sectorsize;
|
|
|
+ goto next_block_or_try_again;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -7868,7 +7890,9 @@ static void btrfs_retry_endio(struct bio *bio)
|
|
|
{
|
|
|
struct btrfs_retry_complete *done = bio->bi_private;
|
|
|
struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
|
|
|
+ struct inode *inode;
|
|
|
struct bio_vec *bvec;
|
|
|
+ u64 start;
|
|
|
int uptodate;
|
|
|
int ret;
|
|
|
int i;
|
|
@@ -7877,13 +7901,20 @@ static void btrfs_retry_endio(struct bio *bio)
|
|
|
goto end;
|
|
|
|
|
|
uptodate = 1;
|
|
|
+
|
|
|
+ start = done->start;
|
|
|
+
|
|
|
+ ASSERT(bio->bi_vcnt == 1);
|
|
|
+ inode = bio->bi_io_vec->bv_page->mapping->host;
|
|
|
+ ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize);
|
|
|
+
|
|
|
bio_for_each_segment_all(bvec, bio, i) {
|
|
|
ret = __readpage_endio_check(done->inode, io_bio, i,
|
|
|
- bvec->bv_page, 0,
|
|
|
- done->start, bvec->bv_len);
|
|
|
+ bvec->bv_page, bvec->bv_offset,
|
|
|
+ done->start, bvec->bv_len);
|
|
|
if (!ret)
|
|
|
clean_io_failure(done->inode, done->start,
|
|
|
- bvec->bv_page, 0);
|
|
|
+ bvec->bv_page, bvec->bv_offset);
|
|
|
else
|
|
|
uptodate = 0;
|
|
|
}
|
|
@@ -7897,20 +7928,34 @@ end:
|
|
|
static int __btrfs_subio_endio_read(struct inode *inode,
|
|
|
struct btrfs_io_bio *io_bio, int err)
|
|
|
{
|
|
|
+ struct btrfs_fs_info *fs_info;
|
|
|
struct bio_vec *bvec;
|
|
|
struct btrfs_retry_complete done;
|
|
|
u64 start;
|
|
|
u64 offset = 0;
|
|
|
+ u32 sectorsize;
|
|
|
+ int nr_sectors;
|
|
|
+ unsigned int pgoff;
|
|
|
+ int csum_pos;
|
|
|
int i;
|
|
|
int ret;
|
|
|
|
|
|
+ fs_info = BTRFS_I(inode)->root->fs_info;
|
|
|
+ sectorsize = BTRFS_I(inode)->root->sectorsize;
|
|
|
+
|
|
|
err = 0;
|
|
|
start = io_bio->logical;
|
|
|
done.inode = inode;
|
|
|
|
|
|
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
|
|
- ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
|
|
|
- 0, start, bvec->bv_len);
|
|
|
+ nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
|
|
+
|
|
|
+ pgoff = bvec->bv_offset;
|
|
|
+next_block:
|
|
|
+ csum_pos = BTRFS_BYTES_TO_BLKS(fs_info, offset);
|
|
|
+ ret = __readpage_endio_check(inode, io_bio, csum_pos,
|
|
|
+ bvec->bv_page, pgoff, start,
|
|
|
+ sectorsize);
|
|
|
if (likely(!ret))
|
|
|
goto next;
|
|
|
try_again:
|
|
@@ -7918,10 +7963,10 @@ try_again:
|
|
|
done.start = start;
|
|
|
init_completion(&done.done);
|
|
|
|
|
|
- ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
|
|
- start + bvec->bv_len - 1,
|
|
|
- io_bio->mirror_num,
|
|
|
- btrfs_retry_endio, &done);
|
|
|
+ ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
|
|
+ pgoff, start, start + sectorsize - 1,
|
|
|
+ io_bio->mirror_num,
|
|
|
+ btrfs_retry_endio, &done);
|
|
|
if (ret) {
|
|
|
err = ret;
|
|
|
goto next;
|
|
@@ -7934,8 +7979,15 @@ try_again:
|
|
|
goto try_again;
|
|
|
}
|
|
|
next:
|
|
|
- offset += bvec->bv_len;
|
|
|
- start += bvec->bv_len;
|
|
|
+ offset += sectorsize;
|
|
|
+ start += sectorsize;
|
|
|
+
|
|
|
+ ASSERT(nr_sectors);
|
|
|
+
|
|
|
+ if (--nr_sectors) {
|
|
|
+ pgoff += sectorsize;
|
|
|
+ goto next_block;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return err;
|