Commit 2dabb324 authored by Chandan Rajendra's avatar Chandan Rajendra Committed by David Sterba

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