diff options
author | NeilBrown <neilb@suse.de> | 2006-06-23 05:05:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-23 10:43:07 -0400 |
commit | e0f23603fb2607315ce52432cc4225df410828cf (patch) | |
tree | 7a32b42a64a64488aee0e91ab016d53c353f9482 /mm/truncate.c | |
parent | 57ae2508610d50893cb3e3bbb869ff70ff724a2a (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>
Diffstat (limited to 'mm/truncate.c')
-rw-r--r-- | mm/truncate.c | 22 |
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)) |