aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-10-29 11:20:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-10-29 11:20:00 -0400
commit3242f9804ba992c867360e2b57efc268b8e4e175 (patch)
tree96fbdbc1344aa67588ce26765f308c674b91a75f /mm
parent23756692147c5dfd3328afd42e16e9d943ff756c (diff)
parent7456b0405d8fc063c49628f969cdb23be060fc80 (diff)
Merge branch 'hwpoison-2.6.32' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6
* 'hwpoison-2.6.32' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6: HWPOISON: fix invalid page count in printk output HWPOISON: Allow schedule_on_each_cpu() from keventd HWPOISON: fix/proc/meminfo alignment HWPOISON: fix oops on ksm pages HWPOISON: Fix page count leak in hwpoison late kill in do_swap_page HWPOISON: return early on non-LRU pages HWPOISON: Add brief hwpoison description to Documentation HWPOISON: Clean up PR_MCE_KILL interface
Diffstat (limited to 'mm')
-rw-r--r--mm/memory-failure.c56
-rw-r--r--mm/memory.c3
2 files changed, 31 insertions, 28 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 7fc2130d2737..dacc64183874 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -371,9 +371,6 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
371 int ret = FAILED; 371 int ret = FAILED;
372 struct address_space *mapping; 372 struct address_space *mapping;
373 373
374 if (!isolate_lru_page(p))
375 page_cache_release(p);
376
377 /* 374 /*
378 * For anonymous pages we're done the only reference left 375 * For anonymous pages we're done the only reference left
379 * should be the one m_f() holds. 376 * should be the one m_f() holds.
@@ -499,30 +496,18 @@ static int me_pagecache_dirty(struct page *p, unsigned long pfn)
499 */ 496 */
500static int me_swapcache_dirty(struct page *p, unsigned long pfn) 497static int me_swapcache_dirty(struct page *p, unsigned long pfn)
501{ 498{
502 int ret = FAILED;
503
504 ClearPageDirty(p); 499 ClearPageDirty(p);
505 /* Trigger EIO in shmem: */ 500 /* Trigger EIO in shmem: */
506 ClearPageUptodate(p); 501 ClearPageUptodate(p);
507 502
508 if (!isolate_lru_page(p)) { 503 return DELAYED;
509 page_cache_release(p);
510 ret = DELAYED;
511 }
512
513 return ret;
514} 504}
515 505
516static int me_swapcache_clean(struct page *p, unsigned long pfn) 506static int me_swapcache_clean(struct page *p, unsigned long pfn)
517{ 507{
518 int ret = FAILED;
519
520 if (!isolate_lru_page(p)) {
521 page_cache_release(p);
522 ret = RECOVERED;
523 }
524 delete_from_swap_cache(p); 508 delete_from_swap_cache(p);
525 return ret; 509
510 return RECOVERED;
526} 511}
527 512
528/* 513/*
@@ -612,8 +597,6 @@ static struct page_state {
612 { 0, 0, "unknown page state", me_unknown }, 597 { 0, 0, "unknown page state", me_unknown },
613}; 598};
614 599
615#undef lru
616
617static void action_result(unsigned long pfn, char *msg, int result) 600static void action_result(unsigned long pfn, char *msg, int result)
618{ 601{
619 struct page *page = NULL; 602 struct page *page = NULL;
@@ -630,13 +613,16 @@ static int page_action(struct page_state *ps, struct page *p,
630 unsigned long pfn, int ref) 613 unsigned long pfn, int ref)
631{ 614{
632 int result; 615 int result;
616 int count;
633 617
634 result = ps->action(p, pfn); 618 result = ps->action(p, pfn);
635 action_result(pfn, ps->msg, result); 619 action_result(pfn, ps->msg, result);
636 if (page_count(p) != 1 + ref) 620
621 count = page_count(p) - 1 - ref;
622 if (count != 0)
637 printk(KERN_ERR 623 printk(KERN_ERR
638 "MCE %#lx: %s page still referenced by %d users\n", 624 "MCE %#lx: %s page still referenced by %d users\n",
639 pfn, ps->msg, page_count(p) - 1); 625 pfn, ps->msg, count);
640 626
641 /* Could do more checks here if page looks ok */ 627 /* Could do more checks here if page looks ok */
642 /* 628 /*
@@ -665,9 +651,6 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn,
665 if (PageReserved(p) || PageCompound(p) || PageSlab(p) || PageKsm(p)) 651 if (PageReserved(p) || PageCompound(p) || PageSlab(p) || PageKsm(p))
666 return; 652 return;
667 653
668 if (!PageLRU(p))
669 lru_add_drain_all();
670
671 /* 654 /*
672 * This check implies we don't kill processes if their pages 655 * This check implies we don't kill processes if their pages
673 * are in the swap cache early. Those are always late kills. 656 * are in the swap cache early. Those are always late kills.
@@ -739,6 +722,7 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn,
739 722
740int __memory_failure(unsigned long pfn, int trapno, int ref) 723int __memory_failure(unsigned long pfn, int trapno, int ref)
741{ 724{
725 unsigned long lru_flag;
742 struct page_state *ps; 726 struct page_state *ps;
743 struct page *p; 727 struct page *p;
744 int res; 728 int res;
@@ -776,6 +760,24 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
776 } 760 }
777 761
778 /* 762 /*
763 * We ignore non-LRU pages for good reasons.
764 * - PG_locked is only well defined for LRU pages and a few others
765 * - to avoid races with __set_page_locked()
766 * - to avoid races with __SetPageSlab*() (and more non-atomic ops)
767 * The check (unnecessarily) ignores LRU pages being isolated and
768 * walked by the page reclaim code, however that's not a big loss.
769 */
770 if (!PageLRU(p))
771 lru_add_drain_all();
772 lru_flag = p->flags & lru;
773 if (isolate_lru_page(p)) {
774 action_result(pfn, "non LRU", IGNORED);
775 put_page(p);
776 return -EBUSY;
777 }
778 page_cache_release(p);
779
780 /*
779 * Lock the page and wait for writeback to finish. 781 * Lock the page and wait for writeback to finish.
780 * It's very difficult to mess with pages currently under IO 782 * It's very difficult to mess with pages currently under IO
781 * and in many cases impossible, so we just avoid it here. 783 * and in many cases impossible, so we just avoid it here.
@@ -791,7 +793,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
791 /* 793 /*
792 * Torn down by someone else? 794 * Torn down by someone else?
793 */ 795 */
794 if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) { 796 if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) {
795 action_result(pfn, "already truncated LRU", IGNORED); 797 action_result(pfn, "already truncated LRU", IGNORED);
796 res = 0; 798 res = 0;
797 goto out; 799 goto out;
@@ -799,7 +801,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
799 801
800 res = -EBUSY; 802 res = -EBUSY;
801 for (ps = error_states;; ps++) { 803 for (ps = error_states;; ps++) {
802 if ((p->flags & ps->mask) == ps->res) { 804 if (((p->flags | lru_flag)& ps->mask) == ps->res) {
803 res = page_action(ps, p, pfn, ref); 805 res = page_action(ps, p, pfn, ref);
804 break; 806 break;
805 } 807 }
diff --git a/mm/memory.c b/mm/memory.c
index 60ea601e03ea..6ab19dd4a199 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2542,7 +2542,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
2542 } else if (PageHWPoison(page)) { 2542 } else if (PageHWPoison(page)) {
2543 ret = VM_FAULT_HWPOISON; 2543 ret = VM_FAULT_HWPOISON;
2544 delayacct_clear_flag(DELAYACCT_PF_SWAPIN); 2544 delayacct_clear_flag(DELAYACCT_PF_SWAPIN);
2545 goto out; 2545 goto out_release;
2546 } 2546 }
2547 2547
2548 lock_page(page); 2548 lock_page(page);
@@ -2614,6 +2614,7 @@ out_nomap:
2614 pte_unmap_unlock(page_table, ptl); 2614 pte_unmap_unlock(page_table, ptl);
2615out_page: 2615out_page:
2616 unlock_page(page); 2616 unlock_page(page);
2617out_release:
2617 page_cache_release(page); 2618 page_cache_release(page);
2618 return ret; 2619 return ret;
2619} 2620}