Commit d88992f6 authored by David Chinner's avatar David Chinner Committed by Nathan Scott

[XFS] Fix a race in xfs_submit_ioend() where we can be completing I/O for

a page while we are still submitting other buffers on the same page for
I/O.

SGI-PV: 948197
SGI-Modid: xfs-linux-melb:xfs-kern:25004a
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent 2664b250
...@@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh) ...@@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
} }
/* /*
* Submit all of the bios for all of the ioends we have saved up, * Submit all of the bios for all of the ioends we have saved up, covering the
* covering the initial writepage page and also any probed pages. * initial writepage page and also any probed pages.
*
* Because we may have multiple ioends spanning a page, we need to start
* writeback on all the buffers before we submit them for I/O. If we mark the
* buffers as we got, then we can end up with a page that only has buffers
* marked async write and I/O complete on can occur before we mark the other
* buffers async write.
*
* The end result of this is that we trip a bug in end_page_writeback() because
* we call it twice for the one page as the code in end_buffer_async_write()
* assumes that all buffers on the page are started at the same time.
*
* The fix is two passes across the ioend list - one to start writeback on the
* bufferheads, and then the second one submit them for I/O.
*/ */
STATIC void STATIC void
xfs_submit_ioend( xfs_submit_ioend(
xfs_ioend_t *ioend) xfs_ioend_t *ioend)
{ {
xfs_ioend_t *head = ioend;
xfs_ioend_t *next; xfs_ioend_t *next;
struct buffer_head *bh; struct buffer_head *bh;
struct bio *bio; struct bio *bio;
sector_t lastblock = 0; sector_t lastblock = 0;
/* Pass 1 - start writeback */
do {
next = ioend->io_list;
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
xfs_start_buffer_writeback(bh);
}
} while ((ioend = next) != NULL);
/* Pass 2 - submit I/O */
ioend = head;
do { do {
next = ioend->io_list; next = ioend->io_list;
bio = NULL; bio = NULL;
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
xfs_start_buffer_writeback(bh);
if (!bio) { if (!bio) {
retry: retry:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment