diff options
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 | } |
