aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2009-09-29 01:16:20 -0400
committerAndi Kleen <ak@linux.intel.com>2009-10-19 01:28:24 -0400
commite43c3afb367112a5b357f9adfac7817255129c88 (patch)
treeb85f21b23ab3a3c38a37cb192bd9a845e964c501 /mm
parentf58ee00f1547ceb17b610ecfce2aa9097f1f9737 (diff)
HWPOISON: return early on non-LRU pages
Right now we have some trouble with non atomic access to page flags when locking the page. To plug this hole for now, limit error recovery to LRU pages for now. This could be better fixed by defining a suitable protocol, but let's go this simple way for now This avoids unnecessary races with __set_page_locked() and __SetPageSlab*() and maybe more non-atomic page flag operations. This loses isolated pages which are currently in page reclaim, but these are relatively limited compared to the total memory. Signed-off-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> [AK: new description, bug fixes, cleanups]
Diffstat (limited to 'mm')
-rw-r--r--mm/memory-failure.c49
1 files changed, 24 insertions, 25 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 729d4b15b645..e17ec3f1c637 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -370,9 +370,6 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
370 int ret = FAILED; 370 int ret = FAILED;
371 struct address_space *mapping; 371 struct address_space *mapping;
372 372
373 if (!isolate_lru_page(p))
374 page_cache_release(p);
375
376 /* 373 /*
377 * For anonymous pages we're done the only reference left 374 * For anonymous pages we're done the only reference left
378 * should be the one m_f() holds. 375 * should be the one m_f() holds.
@@ -498,30 +495,18 @@ static int me_pagecache_dirty(struct page *p, unsigned long pfn)
498 */ 495 */
499static int me_swapcache_dirty(struct page *p, unsigned long pfn) 496static int me_swapcache_dirty(struct page *p, unsigned long pfn)
500{ 497{
501 int ret = FAILED;
502
503 ClearPageDirty(p); 498 ClearPageDirty(p);
504 /* Trigger EIO in shmem: */ 499 /* Trigger EIO in shmem: */
505 ClearPageUptodate(p); 500 ClearPageUptodate(p);
506 501
507 if (!isolate_lru_page(p)) { 502 return DELAYED;
508 page_cache_release(p);
509 ret = DELAYED;
510 }
511
512 return ret;
513} 503}
514 504
515static int me_swapcache_clean(struct page *p, unsigned long pfn) 505static int me_swapcache_clean(struct page *p, unsigned long pfn)
516{ 506{
517 int ret = FAILED;
518
519 if (!isolate_lru_page(p)) {
520 page_cache_release(p);
521 ret = RECOVERED;
522 }
523 delete_from_swap_cache(p); 507 delete_from_swap_cache(p);
524 return ret; 508
509 return RECOVERED;
525} 510}
526 511
527/* 512/*
@@ -611,8 +596,6 @@ static struct page_state {
611 { 0, 0, "unknown page state", me_unknown }, 596 { 0, 0, "unknown page state", me_unknown },
612}; 597};
613 598
614#undef lru
615
616static void action_result(unsigned long pfn, char *msg, int result) 599static void action_result(unsigned long pfn, char *msg, int result)
617{ 600{
618 struct page *page = NULL; 601 struct page *page = NULL;
@@ -664,9 +647,6 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn,
664 if (PageReserved(p) || PageCompound(p) || PageSlab(p)) 647 if (PageReserved(p) || PageCompound(p) || PageSlab(p))
665 return; 648 return;
666 649
667 if (!PageLRU(p))
668 lru_add_drain_all();
669
670 /* 650 /*
671 * This check implies we don't kill processes if their pages 651 * This check implies we don't kill processes if their pages
672 * are in the swap cache early. Those are always late kills. 652 * are in the swap cache early. Those are always late kills.
@@ -738,6 +718,7 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn,
738 718
739int __memory_failure(unsigned long pfn, int trapno, int ref) 719int __memory_failure(unsigned long pfn, int trapno, int ref)
740{ 720{
721 unsigned long lru_flag;
741 struct page_state *ps; 722 struct page_state *ps;
742 struct page *p; 723 struct page *p;
743 int res; 724 int res;
@@ -775,6 +756,24 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
775 } 756 }
776 757
777 /* 758 /*
759 * We ignore non-LRU pages for good reasons.
760 * - PG_locked is only well defined for LRU pages and a few others
761 * - to avoid races with __set_page_locked()
762 * - to avoid races with __SetPageSlab*() (and more non-atomic ops)
763 * The check (unnecessarily) ignores LRU pages being isolated and
764 * walked by the page reclaim code, however that's not a big loss.
765 */
766 if (!PageLRU(p))
767 lru_add_drain_all();
768 lru_flag = p->flags & lru;
769 if (isolate_lru_page(p)) {
770 action_result(pfn, "non LRU", IGNORED);
771 put_page(p);
772 return -EBUSY;
773 }
774 page_cache_release(p);
775
776 /*
778 * Lock the page and wait for writeback to finish. 777 * Lock the page and wait for writeback to finish.
779 * It's very difficult to mess with pages currently under IO 778 * It's very difficult to mess with pages currently under IO
780 * and in many cases impossible, so we just avoid it here. 779 * and in many cases impossible, so we just avoid it here.
@@ -790,7 +789,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
790 /* 789 /*
791 * Torn down by someone else? 790 * Torn down by someone else?
792 */ 791 */
793 if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) { 792 if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) {
794 action_result(pfn, "already truncated LRU", IGNORED); 793 action_result(pfn, "already truncated LRU", IGNORED);
795 res = 0; 794 res = 0;
796 goto out; 795 goto out;
@@ -798,7 +797,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
798 797
799 res = -EBUSY; 798 res = -EBUSY;
800 for (ps = error_states;; ps++) { 799 for (ps = error_states;; ps++) {
801 if ((p->flags & ps->mask) == ps->res) { 800 if (((p->flags | lru_flag)& ps->mask) == ps->res) {
802 res = page_action(ps, p, pfn, ref); 801 res = page_action(ps, p, pfn, ref);
803 break; 802 break;
804 } 803 }