mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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
					
				
					 1 changed files with 75 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -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 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)
 | 
			
		|||
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 @@ static int __btrfs_correct_data_nocsum(struct inode *inode,
 | 
			
		|||
 | 
			
		||||
		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 @@ static void btrfs_retry_endio(struct bio *bio)
 | 
			
		|||
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 @@ static int __btrfs_subio_endio_read(struct inode *inode,
 | 
			
		|||
		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 @@ static int __btrfs_subio_endio_read(struct inode *inode,
 | 
			
		|||
			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