Chuck Ebbert 6c58ce
From: Christoph Hellwig <hch@infradead.org>
Chuck Ebbert 6c58ce
Date: Sun, 18 Jul 2010 21:17:10 +0000 (+0000)
Chuck Ebbert 6c58ce
Subject: xfs: move aio completion after unwritten extent conversion
Chuck Ebbert 6c58ce
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=fb511f2150174b18b28ad54708c1adda0df39b17
Chuck Ebbert 6c58ce
Chuck Ebbert 6c58ce
xfs: move aio completion after unwritten extent conversion
Chuck Ebbert 6c58ce
Chuck Ebbert 6c58ce
If we write into an unwritten extent using AIO we need to complete the AIO
Chuck Ebbert 6c58ce
request after the extent conversion has finished.  Without that a read could
Chuck Ebbert 6c58ce
race to see see the extent still unwritten and return zeros.   For synchronous
Chuck Ebbert 6c58ce
I/O we already take care of that by flushing the xfsconvertd workqueue (which
Chuck Ebbert 6c58ce
might be a bit of overkill).
Chuck Ebbert 6c58ce
Chuck Ebbert 6c58ce
To do that add iocb and result fields to struct xfs_ioend, so that we can
Chuck Ebbert 6c58ce
call aio_complete from xfs_end_io after the extent conversion has happened.
Chuck Ebbert 6c58ce
Note that we need a new result field as io_error is used for positive errno
Chuck Ebbert 6c58ce
values, while the AIO code can return negative error values and positive
Chuck Ebbert 6c58ce
transfer sizes.
Chuck Ebbert 6c58ce
Chuck Ebbert 6c58ce
Signed-off-by: Christoph Hellwig <hch@lst.de>
Chuck Ebbert 6c58ce
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Chuck Ebbert 6c58ce
Signed-off-by: Alex Elder <aelder@sgi.com>
Chuck Ebbert 6c58ce
---
Chuck Ebbert 6c58ce
Chuck Ebbert 6c58ce
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce
index 95d1e26..13622d5 100644
Chuck Ebbert 6c58ce
--- a/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce
+++ b/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce
@@ -265,8 +265,11 @@ xfs_end_io(
Chuck Ebbert 6c58ce
 		xfs_finish_ioend(ioend, 0);
Chuck Ebbert 6c58ce
 		/* ensure we don't spin on blocked ioends */
Chuck Ebbert 6c58ce
 		delay(1);
Chuck Ebbert 6c58ce
-	} else
Chuck Ebbert 6c58ce
+	} else {
Chuck Ebbert 6c58ce
+		if (ioend->io_iocb)
Chuck Ebbert 6c58ce
+			aio_complete(ioend->io_iocb, ioend->io_result, 0);
Chuck Ebbert 6c58ce
 		xfs_destroy_ioend(ioend);
Chuck Ebbert 6c58ce
+	}
Chuck Ebbert 6c58ce
 }
Chuck Ebbert 6c58ce
 
Chuck Ebbert 6c58ce
 /*
Chuck Ebbert 6c58ce
@@ -299,6 +302,8 @@ xfs_alloc_ioend(
Chuck Ebbert 6c58ce
 	atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
Chuck Ebbert 6c58ce
 	ioend->io_offset = 0;
Chuck Ebbert 6c58ce
 	ioend->io_size = 0;
Chuck Ebbert 6c58ce
+	ioend->io_iocb = NULL;
Chuck Ebbert 6c58ce
+	ioend->io_result = 0;
Chuck Ebbert 6c58ce
 
Chuck Ebbert 6c58ce
 	INIT_WORK(&ioend->io_work, xfs_end_io);
Chuck Ebbert 6c58ce
 	return ioend;
Chuck Ebbert 6c58ce
@@ -1411,6 +1416,7 @@ xfs_end_io_direct(
Chuck Ebbert 6c58ce
 	bool		is_async)
Chuck Ebbert 6c58ce
 {
Chuck Ebbert 6c58ce
 	xfs_ioend_t	*ioend = iocb->private;
Chuck Ebbert 6c58ce
+	bool		complete_aio = is_async;
Chuck Ebbert 6c58ce
 
Chuck Ebbert 6c58ce
 	/*
Chuck Ebbert 6c58ce
 	 * Non-NULL private data means we need to issue a transaction to
Chuck Ebbert 6c58ce
@@ -1436,7 +1442,14 @@ xfs_end_io_direct(
Chuck Ebbert 6c58ce
 	if (ioend->io_type == IO_READ) {
Chuck Ebbert 6c58ce
 		xfs_finish_ioend(ioend, 0);
Chuck Ebbert 6c58ce
 	} else if (private && size > 0) {
Chuck Ebbert 6c58ce
-		xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
Chuck Ebbert 6c58ce
+		if (is_async) {
Chuck Ebbert 6c58ce
+			ioend->io_iocb = iocb;
Chuck Ebbert 6c58ce
+			ioend->io_result = ret;
Chuck Ebbert 6c58ce
+			complete_aio = false;
Chuck Ebbert 6c58ce
+			xfs_finish_ioend(ioend, 0);
Chuck Ebbert 6c58ce
+		} else {
Chuck Ebbert 6c58ce
+			xfs_finish_ioend(ioend, 1);
Chuck Ebbert 6c58ce
+		}
Chuck Ebbert 6c58ce
 	} else {
Chuck Ebbert 6c58ce
 		/*
Chuck Ebbert 6c58ce
 		 * A direct I/O write ioend starts it's life in unwritten
Chuck Ebbert 6c58ce
@@ -1455,7 +1468,7 @@ xfs_end_io_direct(
Chuck Ebbert 6c58ce
 	 */
Chuck Ebbert 6c58ce
 	iocb->private = NULL;
Chuck Ebbert 6c58ce
 
Chuck Ebbert 6c58ce
-	if (is_async)
Chuck Ebbert 6c58ce
+	if (complete_aio)
Chuck Ebbert 6c58ce
 		aio_complete(iocb, ret, 0);
Chuck Ebbert 6c58ce
 }
Chuck Ebbert 6c58ce