Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb511f21 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Alex Elder
Browse files

xfs: move aio completion after unwritten extent conversion



If we write into an unwritten extent using AIO we need to complete the AIO
request after the extent conversion has finished.  Without that a read could
race to see see the extent still unwritten and return zeros.   For synchronous
I/O we already take care of that by flushing the xfsconvertd workqueue (which
might be a bit of overkill).

To do that add iocb and result fields to struct xfs_ioend, so that we can
call aio_complete from xfs_end_io after the extent conversion has happened.
Note that we need a new result field as io_error is used for positive errno
values, while the AIO code can return negative error values and positive
transfer sizes.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarAlex Elder <aelder@sgi.com>
parent 40e2e973
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -265,9 +265,12 @@ xfs_end_io(
		xfs_finish_ioend(ioend, 0);
		/* ensure we don't spin on blocked ioends */
		delay(1);
	} else
	} else {
		if (ioend->io_iocb)
			aio_complete(ioend->io_iocb, ioend->io_result, 0);
		xfs_destroy_ioend(ioend);
	}
}

/*
 * Allocate and initialise an IO completion structure.
@@ -299,6 +302,8 @@ xfs_alloc_ioend(
	atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
	ioend->io_offset = 0;
	ioend->io_size = 0;
	ioend->io_iocb = NULL;
	ioend->io_result = 0;

	INIT_WORK(&ioend->io_work, xfs_end_io);
	return ioend;
@@ -1411,6 +1416,7 @@ xfs_end_io_direct(
	bool		is_async)
{
	xfs_ioend_t	*ioend = iocb->private;
	bool		complete_aio = is_async;

	/*
	 * Non-NULL private data means we need to issue a transaction to
@@ -1436,7 +1442,14 @@ xfs_end_io_direct(
	if (ioend->io_type == IO_READ) {
		xfs_finish_ioend(ioend, 0);
	} else if (private && size > 0) {
		xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
		if (is_async) {
			ioend->io_iocb = iocb;
			ioend->io_result = ret;
			complete_aio = false;
			xfs_finish_ioend(ioend, 0);
		} else {
			xfs_finish_ioend(ioend, 1);
		}
	} else {
		/*
		 * A direct I/O write ioend starts it's life in unwritten
@@ -1455,7 +1468,7 @@ xfs_end_io_direct(
	 */
	iocb->private = NULL;

	if (is_async)
	if (complete_aio)
		aio_complete(iocb, ret, 0);
}