aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/memory-failure.c45
1 files changed, 37 insertions, 8 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index dc47415a5511..9a285f8cdbe1 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -350,6 +350,30 @@ static const char *action_name[] = {
350}; 350};
351 351
352/* 352/*
353 * XXX: It is possible that a page is isolated from LRU cache,
354 * and then kept in swap cache or failed to remove from page cache.
355 * The page count will stop it from being freed by unpoison.
356 * Stress tests should be aware of this memory leak problem.
357 */
358static int delete_from_lru_cache(struct page *p)
359{
360 if (!isolate_lru_page(p)) {
361 /*
362 * Clear sensible page flags, so that the buddy system won't
363 * complain when the page is unpoison-and-freed.
364 */
365 ClearPageActive(p);
366 ClearPageUnevictable(p);
367 /*
368 * drop the page count elevated by isolate_lru_page()
369 */
370 page_cache_release(p);
371 return 0;
372 }
373 return -EIO;
374}
375
376/*
353 * Error hit kernel page. 377 * Error hit kernel page.
354 * Do nothing, try to be lucky and not touch this instead. For a few cases we 378 * Do nothing, try to be lucky and not touch this instead. For a few cases we
355 * could be more sophisticated. 379 * could be more sophisticated.
@@ -393,6 +417,8 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
393 int ret = FAILED; 417 int ret = FAILED;
394 struct address_space *mapping; 418 struct address_space *mapping;
395 419
420 delete_from_lru_cache(p);
421
396 /* 422 /*
397 * For anonymous pages we're done the only reference left 423 * For anonymous pages we're done the only reference left
398 * should be the one m_f() holds. 424 * should be the one m_f() holds.
@@ -522,14 +548,20 @@ static int me_swapcache_dirty(struct page *p, unsigned long pfn)
522 /* Trigger EIO in shmem: */ 548 /* Trigger EIO in shmem: */
523 ClearPageUptodate(p); 549 ClearPageUptodate(p);
524 550
525 return DELAYED; 551 if (!delete_from_lru_cache(p))
552 return DELAYED;
553 else
554 return FAILED;
526} 555}
527 556
528static int me_swapcache_clean(struct page *p, unsigned long pfn) 557static int me_swapcache_clean(struct page *p, unsigned long pfn)
529{ 558{
530 delete_from_swap_cache(p); 559 delete_from_swap_cache(p);
531 560
532 return RECOVERED; 561 if (!delete_from_lru_cache(p))
562 return RECOVERED;
563 else
564 return FAILED;
533} 565}
534 566
535/* 567/*
@@ -746,7 +778,6 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
746 778
747int __memory_failure(unsigned long pfn, int trapno, int flags) 779int __memory_failure(unsigned long pfn, int trapno, int flags)
748{ 780{
749 unsigned long lru_flag;
750 struct page_state *ps; 781 struct page_state *ps;
751 struct page *p; 782 struct page *p;
752 int res; 783 int res;
@@ -796,13 +827,11 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
796 */ 827 */
797 if (!PageLRU(p)) 828 if (!PageLRU(p))
798 lru_add_drain_all(); 829 lru_add_drain_all();
799 lru_flag = p->flags & lru; 830 if (!PageLRU(p)) {
800 if (isolate_lru_page(p)) {
801 action_result(pfn, "non LRU", IGNORED); 831 action_result(pfn, "non LRU", IGNORED);
802 put_page(p); 832 put_page(p);
803 return -EBUSY; 833 return -EBUSY;
804 } 834 }
805 page_cache_release(p);
806 835
807 /* 836 /*
808 * Lock the page and wait for writeback to finish. 837 * Lock the page and wait for writeback to finish.
@@ -825,7 +854,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
825 /* 854 /*
826 * Torn down by someone else? 855 * Torn down by someone else?
827 */ 856 */
828 if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) { 857 if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) {
829 action_result(pfn, "already truncated LRU", IGNORED); 858 action_result(pfn, "already truncated LRU", IGNORED);
830 res = 0; 859 res = 0;
831 goto out; 860 goto out;
@@ -833,7 +862,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
833 862
834 res = -EBUSY; 863 res = -EBUSY;
835 for (ps = error_states;; ps++) { 864 for (ps = error_states;; ps++) {
836 if (((p->flags | lru_flag)& ps->mask) == ps->res) { 865 if ((p->flags & ps->mask) == ps->res) {
837 res = page_action(ps, p, pfn); 866 res = page_action(ps, p, pfn);
838 break; 867 break;
839 } 868 }