Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 725130ba authored by Liu Bo's avatar Liu Bo Committed by David Sterba
Browse files

Btrfs: use bio_clone_bioset_partial to simplify DIO submit



Currently when mapping bio to limit bio to a single stripe length, we
split bio by adding page to bio one by one, but later we don't modify
the vector of bio at all, thus we can use bio_clone_fast to use the
original bio vector directly.

Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 2f8e9140
Loading
Loading
Loading
Loading
+45 −74
Original line number Original line Diff line number Diff line
@@ -8380,16 +8380,6 @@ static void btrfs_end_dio_bio(struct bio *bio)
	bio_put(bio);
	bio_put(bio);
}
}


static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
				       u64 first_sector, gfp_t gfp_flags)
{
	struct bio *bio;
	bio = btrfs_bio_alloc(bdev, first_sector, BIO_MAX_PAGES, gfp_flags);
	if (bio)
		bio_associate_current(bio);
	return bio;
}

static inline int btrfs_lookup_and_bind_dio_csum(struct inode *inode,
static inline int btrfs_lookup_and_bind_dio_csum(struct inode *inode,
						 struct btrfs_dio_private *dip,
						 struct btrfs_dio_private *dip,
						 struct bio *bio,
						 struct bio *bio,
@@ -8479,24 +8469,23 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct bio *bio;
	struct bio *bio;
	struct bio *orig_bio = dip->orig_bio;
	struct bio *orig_bio = dip->orig_bio;
	struct bio_vec *bvec;
	u64 start_sector = orig_bio->bi_iter.bi_sector;
	u64 start_sector = orig_bio->bi_iter.bi_sector;
	u64 file_offset = dip->logical_offset;
	u64 file_offset = dip->logical_offset;
	u64 submit_len = 0;
	u64 map_length;
	u64 map_length;
	u32 blocksize = fs_info->sectorsize;
	int async_submit = 0;
	int async_submit = 0;
	int nr_sectors;
	u64 submit_len;
	int clone_offset = 0;
	int clone_len;
	int ret;
	int ret;
	int i, j;


	map_length = orig_bio->bi_iter.bi_size;
	map_length = orig_bio->bi_iter.bi_size;
	submit_len = map_length;
	ret = btrfs_map_block(fs_info, btrfs_op(orig_bio), start_sector << 9,
	ret = btrfs_map_block(fs_info, btrfs_op(orig_bio), start_sector << 9,
			      &map_length, NULL, 0);
			      &map_length, NULL, 0);
	if (ret)
	if (ret)
		return -EIO;
		return -EIO;


	if (map_length >= orig_bio->bi_iter.bi_size) {
	if (map_length >= submit_len) {
		bio = orig_bio;
		bio = orig_bio;
		dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
		dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
		goto submit;
		goto submit;
@@ -8508,32 +8497,36 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
	else
	else
		async_submit = 1;
		async_submit = 1;


	bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
	/* bio split */
	if (!bio)
	ASSERT(map_length <= INT_MAX);
		return -ENOMEM;
	atomic_inc(&dip->pending_bios);
	while (submit_len > 0) {
		clone_len = min_t(int, submit_len, map_length);


	bio->bi_opf = orig_bio->bi_opf;
		/*
		 * This will never fail as it's passing GPF_NOFS and
		 * the allocation is backed by btrfs_bioset.
		 */
		bio = btrfs_bio_clone_partial(orig_bio, GFP_NOFS, clone_offset,
					      clone_len);
		bio->bi_private = dip;
		bio->bi_private = dip;
		bio->bi_end_io = btrfs_end_dio_bio;
		bio->bi_end_io = btrfs_end_dio_bio;
		btrfs_io_bio(bio)->logical = file_offset;
		btrfs_io_bio(bio)->logical = file_offset;
	atomic_inc(&dip->pending_bios);


	bio_for_each_segment_all(bvec, orig_bio, j) {
		ASSERT(submit_len >= clone_len);
		nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
		submit_len -= clone_len;
		i = 0;
		if (submit_len == 0)
next_block:
			break;
		if (unlikely(map_length < submit_len + blocksize ||

		    bio_add_page(bio, bvec->bv_page, blocksize,
			    bvec->bv_offset + (i * blocksize)) < blocksize)) {
		/*
		/*
			 * inc the count before we submit the bio so
		 * Increase the count before we submit the bio so we know
			 * we know the end IO handler won't happen before
		 * the end IO handler won't happen before we increase the
			 * we inc the count. Otherwise, the dip might get freed
		 * count. Otherwise, the dip might get freed before we're
			 * before we're done setting it up
		 * done setting it up.
		 */
		 */
		atomic_inc(&dip->pending_bios);
		atomic_inc(&dip->pending_bios);
			ret = __btrfs_submit_dio_bio(bio, inode,

						     file_offset, skip_sum,
		ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
					     async_submit);
					     async_submit);
		if (ret) {
		if (ret) {
			bio_put(bio);
			bio_put(bio);
@@ -8541,39 +8534,17 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
			goto out_err;
			goto out_err;
		}
		}


			start_sector += submit_len >> 9;
		clone_offset += clone_len;
			file_offset += submit_len;
		start_sector += clone_len >> 9;

		file_offset += clone_len;
			submit_len = 0;


			bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
		map_length = submit_len;
						  start_sector, GFP_NOFS);
			if (!bio)
				goto out_err;
			bio->bi_opf = orig_bio->bi_opf;
			bio->bi_private = dip;
			bio->bi_end_io = btrfs_end_dio_bio;
			btrfs_io_bio(bio)->logical = file_offset;

			map_length = orig_bio->bi_iter.bi_size;
		ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
		ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
					      start_sector << 9,
				      start_sector << 9, &map_length, NULL, 0);
					      &map_length, NULL, 0);
		if (ret)
			if (ret) {
				bio_put(bio);
			goto out_err;
			goto out_err;
	}
	}


			goto next_block;
		} else {
			submit_len += blocksize;
			if (--nr_sectors) {
				i++;
				goto next_block;
			}
		}
	}

submit:
submit:
	ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
	ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
				     async_submit);
				     async_submit);