Commit 31a12666 authored by Nick Piggin's avatar Nick Piggin Committed by Linus Torvalds

mm: write_cache_pages cyclic fix

In write_cache_pages, scanned == 1 is supposed to mean that cyclic
writeback has circled through zero, thus we should not circle again.
However it gets set to 1 after the first successful pagevec lookup.  This
leads to cases where not enough data gets written.

Counterexample: file with first 10 pages dirty, writeback_index == 5,
nr_to_write == 10.  Then the 5 last pages will be found, and scanned will
be set to 1, after writing those out, we will not cycle back to get the
first 5.

Rework this logic, now we'll always cycle unless we started off from index
0.  When cycling, only write out as far as 1 page before the start page
from the first cycle (so we don't write parts of the file twice).
Signed-off-by: default avatarNick Piggin <npiggin@suse.de>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 38c8e618
...@@ -868,9 +868,10 @@ int write_cache_pages(struct address_space *mapping, ...@@ -868,9 +868,10 @@ int write_cache_pages(struct address_space *mapping,
int done = 0; int done = 0;
struct pagevec pvec; struct pagevec pvec;
int nr_pages; int nr_pages;
pgoff_t uninitialized_var(writeback_index);
pgoff_t index; pgoff_t index;
pgoff_t end; /* Inclusive */ pgoff_t end; /* Inclusive */
int scanned = 0; int cycled;
int range_whole = 0; int range_whole = 0;
long nr_to_write = wbc->nr_to_write; long nr_to_write = wbc->nr_to_write;
...@@ -881,14 +882,19 @@ int write_cache_pages(struct address_space *mapping, ...@@ -881,14 +882,19 @@ int write_cache_pages(struct address_space *mapping,
pagevec_init(&pvec, 0); pagevec_init(&pvec, 0);
if (wbc->range_cyclic) { if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */ writeback_index = mapping->writeback_index; /* prev offset */
index = writeback_index;
if (index == 0)
cycled = 1;
else
cycled = 0;
end = -1; end = -1;
} else { } else {
index = wbc->range_start >> PAGE_CACHE_SHIFT; index = wbc->range_start >> PAGE_CACHE_SHIFT;
end = wbc->range_end >> PAGE_CACHE_SHIFT; end = wbc->range_end >> PAGE_CACHE_SHIFT;
if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
range_whole = 1; range_whole = 1;
scanned = 1; cycled = 1; /* ignore range_cyclic tests */
} }
retry: retry:
while (!done && (index <= end) && while (!done && (index <= end) &&
...@@ -897,7 +903,6 @@ int write_cache_pages(struct address_space *mapping, ...@@ -897,7 +903,6 @@ int write_cache_pages(struct address_space *mapping,
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
unsigned i; unsigned i;
scanned = 1;
for (i = 0; i < nr_pages; i++) { for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i]; struct page *page = pvec.pages[i];
...@@ -915,7 +920,11 @@ int write_cache_pages(struct address_space *mapping, ...@@ -915,7 +920,11 @@ int write_cache_pages(struct address_space *mapping,
continue; continue;
} }
if (!wbc->range_cyclic && page->index > end) { if (page->index > end) {
/*
* can't be range_cyclic (1st pass) because
* end == -1 in that case.
*/
done = 1; done = 1;
unlock_page(page); unlock_page(page);
continue; continue;
...@@ -946,13 +955,15 @@ int write_cache_pages(struct address_space *mapping, ...@@ -946,13 +955,15 @@ int write_cache_pages(struct address_space *mapping,
pagevec_release(&pvec); pagevec_release(&pvec);
cond_resched(); cond_resched();
} }
if (!scanned && !done) { if (!cycled) {
/* /*
* range_cyclic:
* We hit the last page and there is more work to be done: wrap * We hit the last page and there is more work to be done: wrap
* back to the start of the file * back to the start of the file
*/ */
scanned = 1; cycled = 1;
index = 0; index = 0;
end = writeback_index - 1;
goto retry; goto retry;
} }
if (!wbc->no_nrwrite_index_update) { if (!wbc->no_nrwrite_index_update) {
......
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