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