Commit 3373503d authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

xfs: use bounce buffering direct I/O when the device requires stable pages



Fix direct I/O on devices that require stable pages by asking iomap
to bounce buffer.  To support this, ioends are used for direct reads
in this case to provide a user context for copying data back from the
bounce buffer.

This fixes qemu when used on devices using T10 protection information
and probably other cases like iSCSI using data digests.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Tested-by: default avatarAnuj Gupta <anuj20.g@samsung.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent c9d11484
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ xfs_ioend_put_open_zones(
 * IO write completion.
 */
STATIC void
xfs_end_ioend(
xfs_end_ioend_write(
	struct iomap_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
@@ -202,7 +202,11 @@ xfs_end_io(
			io_list))) {
		list_del_init(&ioend->io_list);
		iomap_ioend_try_merge(ioend, &tmp);
		xfs_end_ioend(ioend);
		if (bio_op(&ioend->io_bio) == REQ_OP_READ)
			iomap_finish_ioends(ioend,
				blk_status_to_errno(ioend->io_bio.bi_status));
		else
			xfs_end_ioend_write(ioend);
		cond_resched();
	}
}
+38 −3
Original line number Diff line number Diff line
@@ -224,12 +224,34 @@ xfs_ilock_iocb_for_write(
	return 0;
}

/*
 * Bounce buffering dio reads need a user context to copy back the data.
 * Use an ioend to provide that.
 */
static void
xfs_dio_read_bounce_submit_io(
	const struct iomap_iter	*iter,
	struct bio		*bio,
	loff_t			file_offset)
{
	iomap_init_ioend(iter->inode, bio, file_offset, IOMAP_IOEND_DIRECT);
	bio->bi_end_io = xfs_end_bio;
	submit_bio(bio);
}

static const struct iomap_dio_ops xfs_dio_read_bounce_ops = {
	.submit_io	= xfs_dio_read_bounce_submit_io,
	.bio_set	= &iomap_ioend_bioset,
};

STATIC ssize_t
xfs_file_dio_read(
	struct kiocb		*iocb,
	struct iov_iter		*to)
{
	struct xfs_inode	*ip = XFS_I(file_inode(iocb->ki_filp));
	unsigned int		dio_flags = 0;
	const struct iomap_dio_ops *dio_ops = NULL;
	ssize_t			ret;

	trace_xfs_file_direct_read(iocb, to);
@@ -242,7 +264,12 @@ xfs_file_dio_read(
	ret = xfs_ilock_iocb(iocb, XFS_IOLOCK_SHARED);
	if (ret)
		return ret;
	ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL, 0, NULL, 0);
	if (mapping_stable_writes(iocb->ki_filp->f_mapping)) {
		dio_ops = &xfs_dio_read_bounce_ops;
		dio_flags |= IOMAP_DIO_BOUNCE;
	}
	ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, dio_ops, dio_flags,
			NULL, 0);
	xfs_iunlock(ip, XFS_IOLOCK_SHARED);

	return ret;
@@ -703,6 +730,8 @@ xfs_file_dio_write_aligned(
		xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
		iolock = XFS_IOLOCK_SHARED;
	}
	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
		dio_flags |= IOMAP_DIO_BOUNCE;
	trace_xfs_file_direct_write(iocb, from);
	ret = iomap_dio_rw(iocb, from, ops, dops, dio_flags, ac, 0);
out_unlock:
@@ -750,6 +779,7 @@ xfs_file_dio_write_atomic(
{
	unsigned int		iolock = XFS_IOLOCK_SHARED;
	ssize_t			ret, ocount = iov_iter_count(from);
	unsigned int		dio_flags = 0;
	const struct iomap_ops	*dops;

	/*
@@ -777,8 +807,10 @@ xfs_file_dio_write_atomic(
	}

	trace_xfs_file_direct_write(iocb, from);
	ret = iomap_dio_rw(iocb, from, dops, &xfs_dio_write_ops,
			0, NULL, 0);
	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
		dio_flags |= IOMAP_DIO_BOUNCE;
	ret = iomap_dio_rw(iocb, from, dops, &xfs_dio_write_ops, dio_flags,
			NULL, 0);

	/*
	 * The retry mechanism is based on the ->iomap_begin method returning
@@ -867,6 +899,9 @@ xfs_file_dio_write_unaligned(
	if (flags & IOMAP_DIO_FORCE_WAIT)
		inode_dio_wait(VFS_I(ip));

	if (mapping_stable_writes(iocb->ki_filp->f_mapping))
		flags |= IOMAP_DIO_BOUNCE;

	trace_xfs_file_direct_write(iocb, from);
	ret = iomap_dio_rw(iocb, from, &xfs_direct_write_iomap_ops,
			   &xfs_dio_write_ops, flags, NULL, 0);