Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iomap: add a flag to bounce buffer direct I/O

Add a new flag that request bounce buffering for direct I/O. This is
needed to provide the stable pages requirement requested by devices
that need to calculate checksums or parity over the data and allows
file systems to properly work with things like T10 protection
information. The implementation just calls out to the new bio bounce
buffering helpers to allocate a bounce buffer, which is used for
I/O and to copy to/from it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Tested-by: Anuj Gupta <anuj20.g@samsung.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Christoph Hellwig and committed by
Jens Axboe
c9d11484 d969bd72

+29 -10
+20 -10
fs/iomap/direct-io.c
··· 215 215 { 216 216 struct iomap_dio *dio = bio->bi_private; 217 217 218 - if (dio->flags & IOMAP_DIO_USER_BACKED) { 218 + if (dio->flags & IOMAP_DIO_BOUNCE) { 219 + bio_iov_iter_unbounce(bio, !!dio->error, 220 + dio->flags & IOMAP_DIO_USER_BACKED); 221 + bio_put(bio); 222 + } else if (dio->flags & IOMAP_DIO_USER_BACKED) { 219 223 bio_check_pages_dirty(bio); 220 224 } else { 221 225 bio_release_pages(bio, false); ··· 307 303 struct iomap_dio *dio, loff_t pos, unsigned int alignment, 308 304 blk_opf_t op) 309 305 { 306 + unsigned int nr_vecs; 310 307 struct bio *bio; 311 308 ssize_t ret; 312 309 313 - bio = iomap_dio_alloc_bio(iter, dio, 314 - bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS), 315 - op); 310 + if (dio->flags & IOMAP_DIO_BOUNCE) 311 + nr_vecs = bio_iov_bounce_nr_vecs(dio->submit.iter, op); 312 + else 313 + nr_vecs = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); 314 + 315 + bio = iomap_dio_alloc_bio(iter, dio, nr_vecs, op); 316 316 fscrypt_set_bio_crypt_ctx(bio, iter->inode, 317 317 pos >> iter->inode->i_blkbits, GFP_KERNEL); 318 318 bio->bi_iter.bi_sector = iomap_sector(&iter->iomap, pos); ··· 325 317 bio->bi_private = dio; 326 318 bio->bi_end_io = iomap_dio_bio_end_io; 327 319 328 - ret = bio_iov_iter_get_pages(bio, dio->submit.iter, alignment - 1); 320 + if (dio->flags & IOMAP_DIO_BOUNCE) 321 + ret = bio_iov_iter_bounce(bio, dio->submit.iter); 322 + else 323 + ret = bio_iov_iter_get_pages(bio, dio->submit.iter, 324 + alignment - 1); 329 325 if (unlikely(ret)) 330 326 goto out_put_bio; 331 327 ret = bio->bi_iter.bi_size; ··· 345 333 346 334 if (dio->flags & IOMAP_DIO_WRITE) 347 335 task_io_account_write(ret); 348 - else if (dio->flags & IOMAP_DIO_USER_BACKED) 336 + else if ((dio->flags & IOMAP_DIO_USER_BACKED) && 337 + !(dio->flags & IOMAP_DIO_BOUNCE)) 349 338 bio_set_pages_dirty(bio); 350 339 351 340 /* ··· 675 662 dio->i_size = i_size_read(inode); 676 663 dio->dops = dops; 677 664 dio->error = 0; 678 - dio->flags = 0; 665 + dio->flags = dio_flags & (IOMAP_DIO_FSBLOCK_ALIGNED | IOMAP_DIO_BOUNCE); 679 666 dio->done_before = done_before; 680 667 681 668 dio->submit.iter = iter; ··· 683 670 684 671 if (iocb->ki_flags & IOCB_NOWAIT) 685 672 iomi.flags |= IOMAP_NOWAIT; 686 - 687 - if (dio_flags & IOMAP_DIO_FSBLOCK_ALIGNED) 688 - dio->flags |= IOMAP_DIO_FSBLOCK_ALIGNED; 689 673 690 674 if (iov_iter_rw(iter) == READ) { 691 675 if (iomi.pos >= dio->i_size)
+9
include/linux/iomap.h
··· 562 562 */ 563 563 #define IOMAP_DIO_FSBLOCK_ALIGNED (1 << 3) 564 564 565 + /* 566 + * Bounce buffer instead of using zero copy access. 567 + * 568 + * This is needed if the device needs stable data to checksum or generate 569 + * parity. The file system must hook into the I/O submission and offload 570 + * completions to user context for reads when this is set. 571 + */ 572 + #define IOMAP_DIO_BOUNCE (1 << 4) 573 + 565 574 ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, 566 575 const struct iomap_ops *ops, const struct iomap_dio_ops *dops, 567 576 unsigned int dio_flags, void *private, size_t done_before);