Skip to content

Commit

Permalink
xfs: move aio completion after unwritten extent conversion
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christoph Hellwig authored and Alex Elder committed Jul 26, 2010
1 parent 40e2e97 commit fb511f2
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions fs/xfs/linux-2.6/xfs_aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,11 @@ 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);
}
}

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -1455,7 +1468,7 @@ xfs_end_io_direct(
*/
iocb->private = NULL;

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

Expand Down

0 comments on commit fb511f2

Please sign in to comment.