aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_aops.c
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2006-01-17 21:38:12 -0500
committerNathan Scott <nathans@sgi.com>2006-01-17 21:38:12 -0500
commitd88992f660936049f5f38d74ea5a86b5c1491a48 (patch)
tree3c3ac2e25d33e4bd59193b9d4ecf7a1bee3e4d0e /fs/xfs/linux-2.6/xfs_aops.c
parent2664b25051f7ab96b22b199aa2f5ef6a949a4296 (diff)
[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: David Chinner <dgc@sgi.com> Signed-off-by: Nathan Scott <nathans@sgi.com>
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_aops.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index d1db8c17a74e..120626789406 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
336} 336}
337 337
338/* 338/*
339 * Submit all of the bios for all of the ioends we have saved up, 339 * Submit all of the bios for all of the ioends we have saved up, covering the
340 * covering the initial writepage page and also any probed pages. 340 * initial writepage page and also any probed pages.
341 *
342 * Because we may have multiple ioends spanning a page, we need to start
343 * writeback on all the buffers before we submit them for I/O. If we mark the
344 * buffers as we got, then we can end up with a page that only has buffers
345 * marked async write and I/O complete on can occur before we mark the other
346 * buffers async write.
347 *
348 * The end result of this is that we trip a bug in end_page_writeback() because
349 * we call it twice for the one page as the code in end_buffer_async_write()
350 * assumes that all buffers on the page are started at the same time.
351 *
352 * The fix is two passes across the ioend list - one to start writeback on the
353 * bufferheads, and then the second one submit them for I/O.
341 */ 354 */
342STATIC void 355STATIC void
343xfs_submit_ioend( 356xfs_submit_ioend(
344 xfs_ioend_t *ioend) 357 xfs_ioend_t *ioend)
345{ 358{
359 xfs_ioend_t *head = ioend;
346 xfs_ioend_t *next; 360 xfs_ioend_t *next;
347 struct buffer_head *bh; 361 struct buffer_head *bh;
348 struct bio *bio; 362 struct bio *bio;
349 sector_t lastblock = 0; 363 sector_t lastblock = 0;
350 364
365 /* Pass 1 - start writeback */
366 do {
367 next = ioend->io_list;
368 for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
369 xfs_start_buffer_writeback(bh);
370 }
371 } while ((ioend = next) != NULL);
372
373 /* Pass 2 - submit I/O */
374 ioend = head;
351 do { 375 do {
352 next = ioend->io_list; 376 next = ioend->io_list;
353 bio = NULL; 377 bio = NULL;
354 378
355 for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) { 379 for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
356 xfs_start_buffer_writeback(bh);
357 380
358 if (!bio) { 381 if (!bio) {
359 retry: 382 retry: