Btrfs: Direct I/O read: Work on sectorsized blocks
The direct I/O read's endio and corresponding repair functions work on page sized blocks. This commit adds the ability for direct I/O read to work on subpagesized blocks. Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
c40a3d38af
commit
2dabb32484
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue