diff options
author | David Chinner <dgc@sgi.com> | 2007-06-05 02:24:36 -0400 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-07-14 01:30:52 -0400 |
commit | e927af90aaa7d75543edbbd9c2810e6963d0443f (patch) | |
tree | 56da842111210cd39bd45365a42f52f3c50eaf14 | |
parent | f4a9f28a909debe97cd3f6ca30e82e5811125bff (diff) |
[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>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 7361861e3aac..80a321462315 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -108,14 +108,19 @@ xfs_page_trace( | |||
108 | 108 | ||
109 | /* | 109 | /* |
110 | * Schedule IO completion handling on a xfsdatad if this was | 110 | * Schedule IO completion handling on a xfsdatad if this was |
111 | * the final hold on this ioend. | 111 | * the final hold on this ioend. If we are asked to wait, |
112 | * flush the workqueue. | ||
112 | */ | 113 | */ |
113 | STATIC void | 114 | STATIC void |
114 | xfs_finish_ioend( | 115 | xfs_finish_ioend( |
115 | xfs_ioend_t *ioend) | 116 | xfs_ioend_t *ioend, |
117 | int wait) | ||
116 | { | 118 | { |
117 | if (atomic_dec_and_test(&ioend->io_remaining)) | 119 | if (atomic_dec_and_test(&ioend->io_remaining)) { |
118 | queue_work(xfsdatad_workqueue, &ioend->io_work); | 120 | queue_work(xfsdatad_workqueue, &ioend->io_work); |
121 | if (wait) | ||
122 | flush_workqueue(xfsdatad_workqueue); | ||
123 | } | ||
119 | } | 124 | } |
120 | 125 | ||
121 | /* | 126 | /* |
@@ -334,7 +339,7 @@ xfs_end_bio( | |||
334 | bio->bi_end_io = NULL; | 339 | bio->bi_end_io = NULL; |
335 | bio_put(bio); | 340 | bio_put(bio); |
336 | 341 | ||
337 | xfs_finish_ioend(ioend); | 342 | xfs_finish_ioend(ioend, 0); |
338 | return 0; | 343 | return 0; |
339 | } | 344 | } |
340 | 345 | ||
@@ -470,7 +475,7 @@ xfs_submit_ioend( | |||
470 | } | 475 | } |
471 | if (bio) | 476 | if (bio) |
472 | xfs_submit_ioend_bio(ioend, bio); | 477 | xfs_submit_ioend_bio(ioend, bio); |
473 | xfs_finish_ioend(ioend); | 478 | xfs_finish_ioend(ioend, 0); |
474 | } while ((ioend = next) != NULL); | 479 | } while ((ioend = next) != NULL); |
475 | } | 480 | } |
476 | 481 | ||
@@ -1416,6 +1421,13 @@ xfs_end_io_direct( | |||
1416 | * This is not necessary for synchronous direct I/O, but we do | 1421 | * This is not necessary for synchronous direct I/O, but we do |
1417 | * it anyway to keep the code uniform and simpler. | 1422 | * it anyway to keep the code uniform and simpler. |
1418 | * | 1423 | * |
1424 | * Well, if only it were that simple. Because synchronous direct I/O | ||
1425 | * requires extent conversion to occur *before* we return to userspace, | ||
1426 | * we have to wait for extent conversion to complete. Look at the | ||
1427 | * iocb that has been passed to us to determine if this is AIO or | ||
1428 | * not. If it is synchronous, tell xfs_finish_ioend() to kick the | ||
1429 | * workqueue and wait for it to complete. | ||
1430 | * | ||
1419 | * The core direct I/O code might be changed to always call the | 1431 | * The core direct I/O code might be changed to always call the |
1420 | * completion handler in the future, in which case all this can | 1432 | * completion handler in the future, in which case all this can |
1421 | * go away. | 1433 | * go away. |
@@ -1423,9 +1435,9 @@ xfs_end_io_direct( | |||
1423 | ioend->io_offset = offset; | 1435 | ioend->io_offset = offset; |
1424 | ioend->io_size = size; | 1436 | ioend->io_size = size; |
1425 | if (ioend->io_type == IOMAP_READ) { | 1437 | if (ioend->io_type == IOMAP_READ) { |
1426 | xfs_finish_ioend(ioend); | 1438 | xfs_finish_ioend(ioend, 0); |
1427 | } else if (private && size > 0) { | 1439 | } else if (private && size > 0) { |
1428 | xfs_finish_ioend(ioend); | 1440 | xfs_finish_ioend(ioend, is_sync_kiocb(iocb)); |
1429 | } else { | 1441 | } else { |
1430 | /* | 1442 | /* |
1431 | * A direct I/O write ioend starts it's life in unwritten | 1443 | * A direct I/O write ioend starts it's life in unwritten |
@@ -1434,7 +1446,7 @@ xfs_end_io_direct( | |||
1434 | * handler. | 1446 | * handler. |
1435 | */ | 1447 | */ |
1436 | INIT_WORK(&ioend->io_work, xfs_end_bio_written); | 1448 | INIT_WORK(&ioend->io_work, xfs_end_bio_written); |
1437 | xfs_finish_ioend(ioend); | 1449 | xfs_finish_ioend(ioend, 0); |
1438 | } | 1450 | } |
1439 | 1451 | ||
1440 | /* | 1452 | /* |