diff options
-rw-r--r-- | fs/iomap.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/fs/iomap.c b/fs/iomap.c index 071880fee018..596a10f09cde 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -1569,7 +1569,7 @@ static inline void iomap_dio_set_error(struct iomap_dio *dio, int ret) cmpxchg(&dio->error, 0, ret); } -static void iomap_dio_bio_end_io(struct bio *bio) +static void _iomap_dio_bio_end_io(struct bio *bio, bool from_gup) { struct iomap_dio *dio = bio->bi_private; bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY); @@ -1593,19 +1593,24 @@ static void iomap_dio_bio_end_io(struct bio *bio) } if (should_dirty) { - bio_check_pages_dirty(bio, false); + bio_check_pages_dirty(bio, from_gup); } else { - if (!bio_flagged(bio, BIO_NO_PAGE_REF)) { - struct bvec_iter_all iter_all; - struct bio_vec *bvec; - - bio_for_each_segment_all(bvec, bio, iter_all) - put_page(bvec->bv_page); - } + if (!bio_flagged(bio, BIO_NO_PAGE_REF)) + bio_release_pages(bio, from_gup); bio_put(bio); } } +static void iomap_dio_bio_end_io(struct bio *bio) +{ + _iomap_dio_bio_end_io(bio, false); +} + +static void iomap_dio_gup_bio_end_io(struct bio *bio) +{ + _iomap_dio_bio_end_io(bio, true); +} + static void iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos, unsigned len) @@ -1698,7 +1703,9 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length, bio->bi_write_hint = dio->iocb->ki_hint; bio->bi_ioprio = dio->iocb->ki_ioprio; bio->bi_private = dio; - bio->bi_end_io = iomap_dio_bio_end_io; + bio->bi_end_io = iov_iter_get_pages_use_gup(&iter) ? + iomap_dio_gup_bio_end_io : + iomap_dio_bio_end_io; ret = bio_iov_iter_get_pages(bio, &iter); if (unlikely(ret)) { |