Skip to content

Commit

Permalink
[XFS] Fix a race in xfs_submit_ioend() where we can be completing I/O…
Browse files Browse the repository at this point in the history
… 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: David Chinner <dgc@sgi.com>
Signed-off-by: Nathan Scott <nathans@sgi.com>
  • Loading branch information
David Chinner authored and Nathan Scott committed Jan 18, 2006
1 parent 2664b25 commit d88992f
Showing 1 changed file with 26 additions and 3 deletions.
29 changes: 26 additions & 3 deletions fs/xfs/linux-2.6/xfs_aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
* covering the initial writepage page and also any probed pages.
* Submit all of the bios for all of the ioends we have saved up, covering the
* 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
xfs_submit_ioend(
xfs_ioend_t *ioend)
{
xfs_ioend_t *head = ioend;
xfs_ioend_t *next;
struct buffer_head *bh;
struct bio *bio;
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 {
next = ioend->io_list;
bio = NULL;

for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
xfs_start_buffer_writeback(bh);

if (!bio) {
retry:
Expand Down

0 comments on commit d88992f

Please sign in to comment.