aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-06-23 05:05:48 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:43:07 -0400
commite0f23603fb2607315ce52432cc4225df410828cf (patch)
tree7a32b42a64a64488aee0e91ab016d53c353f9482
parent57ae2508610d50893cb3e3bbb869ff70ff724a2a (diff)
[PATCH] Remove semi-softlockup from invalidate_mapping_pages
If invalidate_mapping_pages is called to invalidate a very large mapping (e.g. a very large block device) and if the only active page in that device is near the end (or at least, at a very large index), such as, say, the superblock of an md array, and if that page happens to be locked when invalidate_mapping_pages is called, then pagevec_lookup will return this page and as it is locked, 'next' will be incremented and pagevec_lookup will be called again. and again. and again. while we count from 0 upto a very large number. We should really always set 'next' to 'page->index+1' before going around the loop again, not just if the page isn't locked. Cc: "Steinar H. Gunderson" <sgunderson@bigfoot.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--mm/truncate.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/mm/truncate.c b/mm/truncate.c
index 6cb3fff25f67..cf1b015df4a7 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -230,14 +230,24 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
230 pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { 230 pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
231 for (i = 0; i < pagevec_count(&pvec); i++) { 231 for (i = 0; i < pagevec_count(&pvec); i++) {
232 struct page *page = pvec.pages[i]; 232 struct page *page = pvec.pages[i];
233 pgoff_t index;
234 int lock_failed;
233 235
234 if (TestSetPageLocked(page)) { 236 lock_failed = TestSetPageLocked(page);
235 next++; 237
236 continue; 238 /*
237 } 239 * We really shouldn't be looking at the ->index of an
238 if (page->index > next) 240 * unlocked page. But we're not allowed to lock these
239 next = page->index; 241 * pages. So we rely upon nobody altering the ->index
242 * of this (pinned-by-us) page.
243 */
244 index = page->index;
245 if (index > next)
246 next = index;
240 next++; 247 next++;
248 if (lock_failed)
249 continue;
250
241 if (PageDirty(page) || PageWriteback(page)) 251 if (PageDirty(page) || PageWriteback(page))
242 goto unlock; 252 goto unlock;
243 if (page_mapped(page)) 253 if (page_mapped(page))