diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-29 11:20:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-29 11:20:00 -0400 |
commit | 3242f9804ba992c867360e2b57efc268b8e4e175 (patch) | |
tree | 96fbdbc1344aa67588ce26765f308c674b91a75f /mm | |
parent | 23756692147c5dfd3328afd42e16e9d943ff756c (diff) | |
parent | 7456b0405d8fc063c49628f969cdb23be060fc80 (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.c | 56 | ||||
-rw-r--r-- | mm/memory.c | 3 |
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 | */ |
500 | static int me_swapcache_dirty(struct page *p, unsigned long pfn) | 497 | static 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 | ||
516 | static int me_swapcache_clean(struct page *p, unsigned long pfn) | 506 | static 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 | |||
617 | static void action_result(unsigned long pfn, char *msg, int result) | 600 | static 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 | ||
740 | int __memory_failure(unsigned long pfn, int trapno, int ref) | 723 | int __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); |
2615 | out_page: | 2615 | out_page: |
2616 | unlock_page(page); | 2616 | unlock_page(page); |
2617 | out_release: | ||
2617 | page_cache_release(page); | 2618 | page_cache_release(page); |
2618 | return ret; | 2619 | return ret; |
2619 | } | 2620 | } |