Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1219

kernel-2.6.18-238.el5.src.rpm

From: Eric Sandeen <sandeen@redhat.com>
Date: Thu, 2 Sep 2010 17:45:49 -0400
Subject: [fs] xfs: move aio completion after unwritten extent conv
Message-id: <4C7FE2CD.9020104@redhat.com>
Patchwork-id: 28025
O-Subject: [RHEL5.6 PATCH 2/3] xfs: move aio completion after unwritten extent
	conversion
Bugzilla: 617690
RH-Acked-by: Dave Chinner <dchinner@redhat.com>

For Bug 617690 -
ext4 and xfs wrong data returned on read after write if file size was changed with ftruncate

See also kernel.org bz https://bugzilla.kernel.org/show_bug.cgi?id=16165

Backport of:

commit fb511f2150174b18b28ad54708c1adda0df39b17
Author: Christoph Hellwig <hch@infradead.org>
Date:   Sun Jul 18 21:17:10 2010 +0000

    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: Christoph Hellwig <hch@lst.de>
    Reviewed-by: Dave Chinner <dchinner@redhat.com>
    Signed-off-by: Alex Elder <aelder@sgi.com>

Signed-off-by: Jarod Wilson <jarod@redhat.com>

diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 0f334b5..b546a81 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -247,6 +247,8 @@ xfs_end_bio_unwritten(
 		}
 		xfs_setfilesize(ioend);
 	}
+	if (ioend->io_iocb)
+		aio_complete(ioend->io_iocb, ioend->io_result, 0);
 	xfs_destroy_ioend(ioend);
 }
 
@@ -292,6 +294,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;
 
 	if (type == IOMAP_UNWRITTEN)
 		INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend);
@@ -1438,6 +1442,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
@@ -1463,7 +1468,14 @@ xfs_end_io_direct(
 	if (ioend->io_type == IOMAP_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
@@ -1482,7 +1494,7 @@ xfs_end_io_direct(
 	 */
 	iocb->private = NULL;
 
-	if (is_async)
+	if (complete_aio)
 		aio_complete(iocb, ret, 0);
 }