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,
|
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,
|
|||||||
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,
|
|||||||
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 {
|
|||||||
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,23 +7836,33 @@ end:
|
|||||||
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)
|
||||||
@ -7855,10 +7872,15 @@ try_again:
|
|||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@ end:
|
|||||||
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,8 +7963,8 @@ try_again:
|
|||||||
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) {
|
||||||
@ -7934,8 +7979,15 @@ try_again:
|
|||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user