[XFS] Block on unwritten extent conversion during synchronous direct I/O.
Currently we do not wait on extent conversion to occur, and hence we can return to userspace from a synchronous direct I/O write without having completed all the actions in the write. Hence a read after the write may see zeroes (unwritten extent) rather than the data that was written. Block the I/O completion by triggering a synchronous workqueue flush to ensure that the conversion has occurred before we return to userspace. SGI-PV: 964092 SGI-Modid: xfs-linux-melb:xfs-kern:28775a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
This commit is contained in:
parent
f4a9f28a90
commit
e927af90aa
|
@ -108,14 +108,19 @@ xfs_page_trace(
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Schedule IO completion handling on a xfsdatad if this was
|
* Schedule IO completion handling on a xfsdatad if this was
|
||||||
* the final hold on this ioend.
|
* the final hold on this ioend. If we are asked to wait,
|
||||||
|
* flush the workqueue.
|
||||||
*/
|
*/
|
||||||
STATIC void
|
STATIC void
|
||||||
xfs_finish_ioend(
|
xfs_finish_ioend(
|
||||||
xfs_ioend_t *ioend)
|
xfs_ioend_t *ioend,
|
||||||
|
int wait)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&ioend->io_remaining))
|
if (atomic_dec_and_test(&ioend->io_remaining)) {
|
||||||
queue_work(xfsdatad_workqueue, &ioend->io_work);
|
queue_work(xfsdatad_workqueue, &ioend->io_work);
|
||||||
|
if (wait)
|
||||||
|
flush_workqueue(xfsdatad_workqueue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -334,7 +339,7 @@ xfs_end_bio(
|
||||||
bio->bi_end_io = NULL;
|
bio->bi_end_io = NULL;
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
|
|
||||||
xfs_finish_ioend(ioend);
|
xfs_finish_ioend(ioend, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +475,7 @@ xfs_submit_ioend(
|
||||||
}
|
}
|
||||||
if (bio)
|
if (bio)
|
||||||
xfs_submit_ioend_bio(ioend, bio);
|
xfs_submit_ioend_bio(ioend, bio);
|
||||||
xfs_finish_ioend(ioend);
|
xfs_finish_ioend(ioend, 0);
|
||||||
} while ((ioend = next) != NULL);
|
} while ((ioend = next) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1416,6 +1421,13 @@ xfs_end_io_direct(
|
||||||
* This is not necessary for synchronous direct I/O, but we do
|
* This is not necessary for synchronous direct I/O, but we do
|
||||||
* it anyway to keep the code uniform and simpler.
|
* it anyway to keep the code uniform and simpler.
|
||||||
*
|
*
|
||||||
|
* Well, if only it were that simple. Because synchronous direct I/O
|
||||||
|
* requires extent conversion to occur *before* we return to userspace,
|
||||||
|
* we have to wait for extent conversion to complete. Look at the
|
||||||
|
* iocb that has been passed to us to determine if this is AIO or
|
||||||
|
* not. If it is synchronous, tell xfs_finish_ioend() to kick the
|
||||||
|
* workqueue and wait for it to complete.
|
||||||
|
*
|
||||||
* The core direct I/O code might be changed to always call the
|
* The core direct I/O code might be changed to always call the
|
||||||
* completion handler in the future, in which case all this can
|
* completion handler in the future, in which case all this can
|
||||||
* go away.
|
* go away.
|
||||||
|
@ -1423,9 +1435,9 @@ xfs_end_io_direct(
|
||||||
ioend->io_offset = offset;
|
ioend->io_offset = offset;
|
||||||
ioend->io_size = size;
|
ioend->io_size = size;
|
||||||
if (ioend->io_type == IOMAP_READ) {
|
if (ioend->io_type == IOMAP_READ) {
|
||||||
xfs_finish_ioend(ioend);
|
xfs_finish_ioend(ioend, 0);
|
||||||
} else if (private && size > 0) {
|
} else if (private && size > 0) {
|
||||||
xfs_finish_ioend(ioend);
|
xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* A direct I/O write ioend starts it's life in unwritten
|
* A direct I/O write ioend starts it's life in unwritten
|
||||||
|
@ -1434,7 +1446,7 @@ xfs_end_io_direct(
|
||||||
* handler.
|
* handler.
|
||||||
*/
|
*/
|
||||||
INIT_WORK(&ioend->io_work, xfs_end_bio_written);
|
INIT_WORK(&ioend->io_work, xfs_end_bio_written);
|
||||||
xfs_finish_ioend(ioend);
|
xfs_finish_ioend(ioend, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue