aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2009-02-14 10:42:58 -0500
committerTheodore Ts'o <tytso@mit.edu>2009-02-14 10:42:58 -0500
commit2acf2c261b823d9d9ed954f348b97620297a36b5 (patch)
tree01bcc80ee26a9cc25df9b9a215081943f3fcbd6c
parentd794bf8e0936dce45104565cd48c571061f4c1e3 (diff)
ext4: Implement range_cyclic in ext4_da_writepages instead of write_cache_pages
With delayed allocation we lock the page in write_cache_pages() and try to build an in memory extent of contiguous blocks. This is needed so that we can get large contiguous blocks request. If range_cyclic mode is enabled, write_cache_pages() will loop back to the 0 index if no I/O has been done yet, and try to start writing from the beginning of the range. That causes an attempt to take the page lock of lower index page while holding the page lock of higher index page, which can cause a dead lock with another writeback thread. The solution is to implement the range_cyclic behavior in ext4_da_writepages() instead. http://bugzilla.kernel.org/show_bug.cgi?id=12579 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/inode.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 658c4a7f2578..cbd2ca99d113 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2439,6 +2439,7 @@ static int ext4_da_writepages(struct address_space *mapping,
2439 int no_nrwrite_index_update; 2439 int no_nrwrite_index_update;
2440 int pages_written = 0; 2440 int pages_written = 0;
2441 long pages_skipped; 2441 long pages_skipped;
2442 int range_cyclic, cycled = 1, io_done = 0;
2442 int needed_blocks, ret = 0, nr_to_writebump = 0; 2443 int needed_blocks, ret = 0, nr_to_writebump = 0;
2443 struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); 2444 struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
2444 2445
@@ -2490,9 +2491,15 @@ static int ext4_da_writepages(struct address_space *mapping,
2490 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) 2491 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
2491 range_whole = 1; 2492 range_whole = 1;
2492 2493
2493 if (wbc->range_cyclic) 2494 range_cyclic = wbc->range_cyclic;
2495 if (wbc->range_cyclic) {
2494 index = mapping->writeback_index; 2496 index = mapping->writeback_index;
2495 else 2497 if (index)
2498 cycled = 0;
2499 wbc->range_start = index << PAGE_CACHE_SHIFT;
2500 wbc->range_end = LLONG_MAX;
2501 wbc->range_cyclic = 0;
2502 } else
2496 index = wbc->range_start >> PAGE_CACHE_SHIFT; 2503 index = wbc->range_start >> PAGE_CACHE_SHIFT;
2497 2504
2498 mpd.wbc = wbc; 2505 mpd.wbc = wbc;
@@ -2506,6 +2513,7 @@ static int ext4_da_writepages(struct address_space *mapping,
2506 wbc->no_nrwrite_index_update = 1; 2513 wbc->no_nrwrite_index_update = 1;
2507 pages_skipped = wbc->pages_skipped; 2514 pages_skipped = wbc->pages_skipped;
2508 2515
2516retry:
2509 while (!ret && wbc->nr_to_write > 0) { 2517 while (!ret && wbc->nr_to_write > 0) {
2510 2518
2511 /* 2519 /*
@@ -2548,6 +2556,7 @@ static int ext4_da_writepages(struct address_space *mapping,
2548 pages_written += mpd.pages_written; 2556 pages_written += mpd.pages_written;
2549 wbc->pages_skipped = pages_skipped; 2557 wbc->pages_skipped = pages_skipped;
2550 ret = 0; 2558 ret = 0;
2559 io_done = 1;
2551 } else if (wbc->nr_to_write) 2560 } else if (wbc->nr_to_write)
2552 /* 2561 /*
2553 * There is no more writeout needed 2562 * There is no more writeout needed
@@ -2556,6 +2565,13 @@ static int ext4_da_writepages(struct address_space *mapping,
2556 */ 2565 */
2557 break; 2566 break;
2558 } 2567 }
2568 if (!io_done && !cycled) {
2569 cycled = 1;
2570 index = 0;
2571 wbc->range_start = index << PAGE_CACHE_SHIFT;
2572 wbc->range_end = mapping->writeback_index - 1;
2573 goto retry;
2574 }
2559 if (pages_skipped != wbc->pages_skipped) 2575 if (pages_skipped != wbc->pages_skipped)
2560 printk(KERN_EMERG "This should not happen leaving %s " 2576 printk(KERN_EMERG "This should not happen leaving %s "
2561 "with nr_to_write = %ld ret = %d\n", 2577 "with nr_to_write = %ld ret = %d\n",
@@ -2563,6 +2579,7 @@ static int ext4_da_writepages(struct address_space *mapping,
2563 2579
2564 /* Update index */ 2580 /* Update index */
2565 index += pages_written; 2581 index += pages_written;
2582 wbc->range_cyclic = range_cyclic;
2566 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) 2583 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
2567 /* 2584 /*
2568 * set the writeback_index so that range_cyclic 2585 * set the writeback_index so that range_cyclic