diff --git a/block/bio.c b/block/bio.c index 00f99d03ac91..898b2f5ef8c8 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1181,8 +1181,11 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty) } EXPORT_SYMBOL_GPL(__bio_release_pages); -void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter) +bool bio_iov_iter_set(struct bio *bio, const struct iov_iter *iter) { + if (!iov_iter_is_bvec(iter)) + return false; + WARN_ON_ONCE(bio->bi_max_vecs); bio->bi_io_vec = (struct bio_vec *)iter->bvec; @@ -1190,6 +1193,7 @@ void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter) bio->bi_iter.bi_offset = iter->iov_offset; bio->bi_iter.bi_size = iov_iter_count(iter); bio_set_flag(bio, BIO_CLONED); + return true; } /* @@ -1284,10 +1288,9 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter, if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) return -EIO; - if (iov_iter_is_bvec(iter)) { - bio_iov_bvec_set(bio, iter); - - if (!bio_iov_bvec_aligned(bio, mem_align_mask)) + if (bio_iov_iter_set(bio, iter)) { + if (iov_iter_is_bvec(iter) && + !bio_iov_bvec_aligned(bio, mem_align_mask)) return -EINVAL; iov_iter_advance(iter, bio->bi_iter.bi_size); diff --git a/block/blk-map.c b/block/blk-map.c index 615d29bb840e..9cb9605d1f62 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -473,7 +473,7 @@ static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter) bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL); if (!bio) return -ENOMEM; - bio_iov_bvec_set(bio, iter); + bio_iov_iter_set(bio, iter); ret = blk_rq_append_bio(rq, bio); if (ret) diff --git a/block/fops.c b/block/fops.c index 3c2099dfef1d..d11923053afe 100644 --- a/block/fops.c +++ b/block/fops.c @@ -342,15 +342,13 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb, bio->bi_end_io = blkdev_bio_end_io_async; bio->bi_ioprio = iocb->ki_ioprio; - if (iov_iter_is_bvec(iter)) { - /* - * Users don't rely on the iterator being in any particular - * state for async I/O returning -EIOCBQUEUED, hence we can - * avoid expensive iov_iter_advance(). Bypass - * bio_iov_iter_get_pages() and set the bvec directly. - */ - bio_iov_bvec_set(bio, iter); - } else { + /* + * Users don't rely on the iterator being in any particular + * state for async I/O returning -EIOCBQUEUED, hence we can + * avoid expensive iov_iter_advance(). Bypass + * bio_iov_iter_get_pages() and set the bvec directly. + */ + if (!bio_iov_iter_set(bio, iter)) { ret = blkdev_iov_iter_get_pages(bio, iter, bdev); if (unlikely(ret)) goto out_bio_put; diff --git a/include/linux/bio.h b/include/linux/bio.h index 0445ecba3b24..bb3235497e67 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -518,7 +518,7 @@ int bdev_rw_virt(struct block_device *bdev, sector_t sector, void *data, int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter, unsigned mem_align_mask, unsigned len_align_mask); -void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter); +bool bio_iov_iter_set(struct bio *bio, const struct iov_iter *iter); void __bio_release_pages(struct bio *bio, bool mark_dirty); extern void bio_set_pages_dirty(struct bio *bio); extern void bio_check_pages_dirty(struct bio *bio);