xfs: defer AIO/DIO completions
authorChristoph Hellwig <hch@infradead.org>
Tue, 23 Aug 2011 08:28:10 +0000 (08:28 +0000)
committerAlex Elder <aelder@sgi.com>
Wed, 12 Oct 2011 02:15:00 +0000 (21:15 -0500)
We really shouldn't complete AIO or DIO requests until we have finished
the unwritten extent conversion and size update.  This means fsync never
has to pick up any ioends as all work has been completed when signalling
I/O completion.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h

index d91564404abfa945a9d223f3b683ad9c5e626ced..10660c3641058ac9c5fee41c83814e2c06954e53 100644 (file)
@@ -122,6 +122,11 @@ xfs_destroy_ioend(
                bh->b_end_io(bh, !ioend->io_error);
        }
 
+       if (ioend->io_iocb) {
+               if (ioend->io_isasync)
+                       aio_complete(ioend->io_iocb, ioend->io_result, 0);
+               inode_dio_done(ioend->io_inode);
+       }
        xfs_ioend_wake(ip);
        mempool_free(ioend, xfs_ioend_pool);
 }
@@ -236,8 +241,6 @@ xfs_end_io(
                /* ensure we don't spin on blocked ioends */
                delay(1);
        } else {
-               if (ioend->io_iocb)
-                       aio_complete(ioend->io_iocb, ioend->io_result, 0);
                xfs_destroy_ioend(ioend);
        }
 }
@@ -274,6 +277,7 @@ xfs_alloc_ioend(
         * all the I/O from calling the completion routine too early.
         */
        atomic_set(&ioend->io_remaining, 1);
+       ioend->io_isasync = 0;
        ioend->io_error = 0;
        ioend->io_list = NULL;
        ioend->io_type = type;
@@ -1289,7 +1293,6 @@ xfs_end_io_direct_write(
        bool                    is_async)
 {
        struct xfs_ioend        *ioend = iocb->private;
-       struct inode            *inode = ioend->io_inode;
 
        /*
         * blockdev_direct_IO can return an error even after the I/O
@@ -1300,28 +1303,17 @@ xfs_end_io_direct_write(
 
        ioend->io_offset = offset;
        ioend->io_size = size;
+       ioend->io_iocb = iocb;
+       ioend->io_result = ret;
        if (private && size > 0)
                ioend->io_type = IO_UNWRITTEN;
 
        if (is_async) {
-               /*
-                * If we are converting an unwritten extent we need to delay
-                * the AIO completion until after the unwrittent extent
-                * conversion has completed, otherwise do it ASAP.
-                */
-               if (ioend->io_type == IO_UNWRITTEN) {
-                       ioend->io_iocb = iocb;
-                       ioend->io_result = ret;
-               } else {
-                       aio_complete(iocb, ret, 0);
-               }
+               ioend->io_isasync = 1;
                xfs_finish_ioend(ioend);
        } else {
                xfs_finish_ioend_sync(ioend);
        }
-
-       /* XXX: probably should move into the real I/O completion handler */
-       inode_dio_done(inode);
 }
 
 STATIC ssize_t
index 71f721e1a71f9b82a09a3fd298c739a76a419851..ce3dcb50762e3de89733097f6043ac787f31c340 100644 (file)
@@ -47,6 +47,7 @@ typedef struct xfs_ioend {
        unsigned int            io_type;        /* delalloc / unwritten */
        int                     io_error;       /* I/O error code */
        atomic_t                io_remaining;   /* hold count */
+       unsigned int            io_isasync : 1; /* needs aio_complete */
        struct inode            *io_inode;      /* file being written to */
        struct buffer_head      *io_buffer_head;/* buffer linked list head */
        struct buffer_head      *io_buffer_tail;/* buffer linked list tail */