|
@@ -8380,16 +8380,6 @@ out:
|
|
|
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,
|
|
|
struct btrfs_dio_private *dip,
|
|
|
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 bio *bio;
|
|
|
struct bio *orig_bio = dip->orig_bio;
|
|
|
- struct bio_vec *bvec;
|
|
|
u64 start_sector = orig_bio->bi_iter.bi_sector;
|
|
|
u64 file_offset = dip->logical_offset;
|
|
|
- u64 submit_len = 0;
|
|
|
u64 map_length;
|
|
|
- u32 blocksize = fs_info->sectorsize;
|
|
|
int async_submit = 0;
|
|
|
- int nr_sectors;
|
|
|
+ u64 submit_len;
|
|
|
+ int clone_offset = 0;
|
|
|
+ int clone_len;
|
|
|
int ret;
|
|
|
- int i, j;
|
|
|
|
|
|
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,
|
|
|
&map_length, NULL, 0);
|
|
|
if (ret)
|
|
|
return -EIO;
|
|
|
|
|
|
- if (map_length >= orig_bio->bi_iter.bi_size) {
|
|
|
+ if (map_length >= submit_len) {
|
|
|
bio = orig_bio;
|
|
|
dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
|
|
|
goto submit;
|
|
@@ -8508,70 +8497,52 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
|
|
|
else
|
|
|
async_submit = 1;
|
|
|
|
|
|
- bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
|
|
|
- if (!bio)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- 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;
|
|
|
+ /* bio split */
|
|
|
+ ASSERT(map_length <= INT_MAX);
|
|
|
atomic_inc(&dip->pending_bios);
|
|
|
+ while (submit_len > 0) {
|
|
|
+ clone_len = min_t(int, submit_len, map_length);
|
|
|
|
|
|
- bio_for_each_segment_all(bvec, orig_bio, j) {
|
|
|
- nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
|
|
- i = 0;
|
|
|
-next_block:
|
|
|
- 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
|
|
|
- * we know the end IO handler won't happen before
|
|
|
- * we inc the count. Otherwise, the dip might get freed
|
|
|
- * before we're done setting it up
|
|
|
- */
|
|
|
- atomic_inc(&dip->pending_bios);
|
|
|
- ret = __btrfs_submit_dio_bio(bio, inode,
|
|
|
- file_offset, skip_sum,
|
|
|
- async_submit);
|
|
|
- if (ret) {
|
|
|
- bio_put(bio);
|
|
|
- atomic_dec(&dip->pending_bios);
|
|
|
- goto out_err;
|
|
|
- }
|
|
|
-
|
|
|
- start_sector += submit_len >> 9;
|
|
|
- file_offset += submit_len;
|
|
|
+ /*
|
|
|
+ * 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_end_io = btrfs_end_dio_bio;
|
|
|
+ btrfs_io_bio(bio)->logical = file_offset;
|
|
|
+
|
|
|
+ ASSERT(submit_len >= clone_len);
|
|
|
+ submit_len -= clone_len;
|
|
|
+ if (submit_len == 0)
|
|
|
+ break;
|
|
|
|
|
|
- submit_len = 0;
|
|
|
+ /*
|
|
|
+ * Increase the count before we submit the bio so we know
|
|
|
+ * the end IO handler won't happen before we increase the
|
|
|
+ * count. Otherwise, the dip might get freed before we're
|
|
|
+ * done setting it up.
|
|
|
+ */
|
|
|
+ atomic_inc(&dip->pending_bios);
|
|
|
|
|
|
- bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
|
|
|
- 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;
|
|
|
+ ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
|
|
|
+ async_submit);
|
|
|
+ if (ret) {
|
|
|
+ bio_put(bio);
|
|
|
+ atomic_dec(&dip->pending_bios);
|
|
|
+ goto out_err;
|
|
|
+ }
|
|
|
|
|
|
- map_length = orig_bio->bi_iter.bi_size;
|
|
|
- ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
|
|
|
- start_sector << 9,
|
|
|
- &map_length, NULL, 0);
|
|
|
- if (ret) {
|
|
|
- bio_put(bio);
|
|
|
- goto out_err;
|
|
|
- }
|
|
|
+ clone_offset += clone_len;
|
|
|
+ start_sector += clone_len >> 9;
|
|
|
+ file_offset += clone_len;
|
|
|
|
|
|
- goto next_block;
|
|
|
- } else {
|
|
|
- submit_len += blocksize;
|
|
|
- if (--nr_sectors) {
|
|
|
- i++;
|
|
|
- goto next_block;
|
|
|
- }
|
|
|
- }
|
|
|
+ map_length = submit_len;
|
|
|
+ ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
|
|
|
+ start_sector << 9, &map_length, NULL, 0);
|
|
|
+ if (ret)
|
|
|
+ goto out_err;
|
|
|
}
|
|
|
|
|
|
submit:
|