mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
57ae250861
commit
e0f23603fb
|
@ -230,14 +230,24 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|||
pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
pgoff_t index;
|
||||
int lock_failed;
|
||||
|
||||
if (TestSetPageLocked(page)) {
|
||||
next++;
|
||||
continue;
|
||||
}
|
||||
if (page->index > next)
|
||||
next = page->index;
|
||||
lock_failed = TestSetPageLocked(page);
|
||||
|
||||
/*
|
||||
* We really shouldn't be looking at the ->index of an
|
||||
* unlocked page. But we're not allowed to lock these
|
||||
* pages. So we rely upon nobody altering the ->index
|
||||
* of this (pinned-by-us) page.
|
||||
*/
|
||||
index = page->index;
|
||||
if (index > next)
|
||||
next = index;
|
||||
next++;
|
||||
if (lock_failed)
|
||||
continue;
|
||||
|
||||
if (PageDirty(page) || PageWriteback(page))
|
||||
goto unlock;
|
||||
if (page_mapped(page))
|
||||
|
|
Loading…
Reference in New Issue