diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/Kconfig | 4 | ||||
-rw-r--r-- | mm/memory-failure.c | 59 | ||||
-rw-r--r-- | mm/memory.c | 14 | ||||
-rw-r--r-- | mm/mempolicy.c | 13 | ||||
-rw-r--r-- | mm/page_alloc.c | 3 | ||||
-rw-r--r-- | mm/vmscan.c | 14 |
6 files changed, 62 insertions, 45 deletions
diff --git a/mm/Kconfig b/mm/Kconfig index 57963c6063d1..fd3386242cf0 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -67,7 +67,7 @@ config DISCONTIGMEM | |||
67 | 67 | ||
68 | config SPARSEMEM | 68 | config SPARSEMEM |
69 | def_bool y | 69 | def_bool y |
70 | depends on SPARSEMEM_MANUAL | 70 | depends on (!SELECT_MEMORY_MODEL && ARCH_SPARSEMEM_ENABLE) || SPARSEMEM_MANUAL |
71 | 71 | ||
72 | config FLATMEM | 72 | config FLATMEM |
73 | def_bool y | 73 | def_bool y |
@@ -129,7 +129,7 @@ config MEMORY_HOTPLUG | |||
129 | bool "Allow for memory hot-add" | 129 | bool "Allow for memory hot-add" |
130 | depends on SPARSEMEM || X86_64_ACPI_NUMA | 130 | depends on SPARSEMEM || X86_64_ACPI_NUMA |
131 | depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG | 131 | depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG |
132 | depends on (IA64 || X86 || PPC64 || SUPERH || S390) | 132 | depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390) |
133 | 133 | ||
134 | comment "Memory hotplug is currently incompatible with Software Suspend" | 134 | comment "Memory hotplug is currently incompatible with Software Suspend" |
135 | depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390 | 135 | depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390 |
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 729d4b15b645..dacc64183874 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/mm.h> | 35 | #include <linux/mm.h> |
36 | #include <linux/page-flags.h> | 36 | #include <linux/page-flags.h> |
37 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
38 | #include <linux/ksm.h> | ||
38 | #include <linux/rmap.h> | 39 | #include <linux/rmap.h> |
39 | #include <linux/pagemap.h> | 40 | #include <linux/pagemap.h> |
40 | #include <linux/swap.h> | 41 | #include <linux/swap.h> |
@@ -370,9 +371,6 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn) | |||
370 | int ret = FAILED; | 371 | int ret = FAILED; |
371 | struct address_space *mapping; | 372 | struct address_space *mapping; |
372 | 373 | ||
373 | if (!isolate_lru_page(p)) | ||
374 | page_cache_release(p); | ||
375 | |||
376 | /* | 374 | /* |
377 | * For anonymous pages we're done the only reference left | 375 | * For anonymous pages we're done the only reference left |
378 | * should be the one m_f() holds. | 376 | * should be the one m_f() holds. |
@@ -498,30 +496,18 @@ static int me_pagecache_dirty(struct page *p, unsigned long pfn) | |||
498 | */ | 496 | */ |
499 | static int me_swapcache_dirty(struct page *p, unsigned long pfn) | 497 | static int me_swapcache_dirty(struct page *p, unsigned long pfn) |
500 | { | 498 | { |
501 | int ret = FAILED; | ||
502 | |||
503 | ClearPageDirty(p); | 499 | ClearPageDirty(p); |
504 | /* Trigger EIO in shmem: */ | 500 | /* Trigger EIO in shmem: */ |
505 | ClearPageUptodate(p); | 501 | ClearPageUptodate(p); |
506 | 502 | ||
507 | if (!isolate_lru_page(p)) { | 503 | return DELAYED; |
508 | page_cache_release(p); | ||
509 | ret = DELAYED; | ||
510 | } | ||
511 | |||
512 | return ret; | ||
513 | } | 504 | } |
514 | 505 | ||
515 | static int me_swapcache_clean(struct page *p, unsigned long pfn) | 506 | static int me_swapcache_clean(struct page *p, unsigned long pfn) |
516 | { | 507 | { |
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); | 508 | delete_from_swap_cache(p); |
524 | return ret; | 509 | |
510 | return RECOVERED; | ||
525 | } | 511 | } |
526 | 512 | ||
527 | /* | 513 | /* |
@@ -611,8 +597,6 @@ static struct page_state { | |||
611 | { 0, 0, "unknown page state", me_unknown }, | 597 | { 0, 0, "unknown page state", me_unknown }, |
612 | }; | 598 | }; |
613 | 599 | ||
614 | #undef lru | ||
615 | |||
616 | static void action_result(unsigned long pfn, char *msg, int result) | 600 | static void action_result(unsigned long pfn, char *msg, int result) |
617 | { | 601 | { |
618 | struct page *page = NULL; | 602 | struct page *page = NULL; |
@@ -629,13 +613,16 @@ static int page_action(struct page_state *ps, struct page *p, | |||
629 | unsigned long pfn, int ref) | 613 | unsigned long pfn, int ref) |
630 | { | 614 | { |
631 | int result; | 615 | int result; |
616 | int count; | ||
632 | 617 | ||
633 | result = ps->action(p, pfn); | 618 | result = ps->action(p, pfn); |
634 | action_result(pfn, ps->msg, result); | 619 | action_result(pfn, ps->msg, result); |
635 | if (page_count(p) != 1 + ref) | 620 | |
621 | count = page_count(p) - 1 - ref; | ||
622 | if (count != 0) | ||
636 | printk(KERN_ERR | 623 | printk(KERN_ERR |
637 | "MCE %#lx: %s page still referenced by %d users\n", | 624 | "MCE %#lx: %s page still referenced by %d users\n", |
638 | pfn, ps->msg, page_count(p) - 1); | 625 | pfn, ps->msg, count); |
639 | 626 | ||
640 | /* Could do more checks here if page looks ok */ | 627 | /* Could do more checks here if page looks ok */ |
641 | /* | 628 | /* |
@@ -661,12 +648,9 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
661 | int i; | 648 | int i; |
662 | int kill = 1; | 649 | int kill = 1; |
663 | 650 | ||
664 | if (PageReserved(p) || PageCompound(p) || PageSlab(p)) | 651 | if (PageReserved(p) || PageCompound(p) || PageSlab(p) || PageKsm(p)) |
665 | return; | 652 | return; |
666 | 653 | ||
667 | if (!PageLRU(p)) | ||
668 | lru_add_drain_all(); | ||
669 | |||
670 | /* | 654 | /* |
671 | * This check implies we don't kill processes if their pages | 655 | * This check implies we don't kill processes if their pages |
672 | * are in the swap cache early. Those are always late kills. | 656 | * are in the swap cache early. Those are always late kills. |
@@ -738,6 +722,7 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
738 | 722 | ||
739 | int __memory_failure(unsigned long pfn, int trapno, int ref) | 723 | int __memory_failure(unsigned long pfn, int trapno, int ref) |
740 | { | 724 | { |
725 | unsigned long lru_flag; | ||
741 | struct page_state *ps; | 726 | struct page_state *ps; |
742 | struct page *p; | 727 | struct page *p; |
743 | int res; | 728 | int res; |
@@ -775,6 +760,24 @@ int __memory_failure(unsigned long pfn, int trapno, int ref) | |||
775 | } | 760 | } |
776 | 761 | ||
777 | /* | 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 | /* | ||
778 | * Lock the page and wait for writeback to finish. | 781 | * Lock the page and wait for writeback to finish. |
779 | * It's very difficult to mess with pages currently under IO | 782 | * It's very difficult to mess with pages currently under IO |
780 | * and in many cases impossible, so we just avoid it here. | 783 | * and in many cases impossible, so we just avoid it here. |
@@ -790,7 +793,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref) | |||
790 | /* | 793 | /* |
791 | * Torn down by someone else? | 794 | * Torn down by someone else? |
792 | */ | 795 | */ |
793 | if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) { | 796 | if ((lru_flag & lru) && !PageSwapCache(p) && p->mapping == NULL) { |
794 | action_result(pfn, "already truncated LRU", IGNORED); | 797 | action_result(pfn, "already truncated LRU", IGNORED); |
795 | res = 0; | 798 | res = 0; |
796 | goto out; | 799 | goto out; |
@@ -798,7 +801,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref) | |||
798 | 801 | ||
799 | res = -EBUSY; | 802 | res = -EBUSY; |
800 | for (ps = error_states;; ps++) { | 803 | for (ps = error_states;; ps++) { |
801 | if ((p->flags & ps->mask) == ps->res) { | 804 | if (((p->flags | lru_flag)& ps->mask) == ps->res) { |
802 | res = page_action(ps, p, pfn, ref); | 805 | res = page_action(ps, p, pfn, ref); |
803 | break; | 806 | break; |
804 | } | 807 | } |
diff --git a/mm/memory.c b/mm/memory.c index 7e91b5f9f690..6ab19dd4a199 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -641,6 +641,7 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
641 | pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma, | 641 | pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma, |
642 | unsigned long addr, unsigned long end) | 642 | unsigned long addr, unsigned long end) |
643 | { | 643 | { |
644 | pte_t *orig_src_pte, *orig_dst_pte; | ||
644 | pte_t *src_pte, *dst_pte; | 645 | pte_t *src_pte, *dst_pte; |
645 | spinlock_t *src_ptl, *dst_ptl; | 646 | spinlock_t *src_ptl, *dst_ptl; |
646 | int progress = 0; | 647 | int progress = 0; |
@@ -654,6 +655,8 @@ again: | |||
654 | src_pte = pte_offset_map_nested(src_pmd, addr); | 655 | src_pte = pte_offset_map_nested(src_pmd, addr); |
655 | src_ptl = pte_lockptr(src_mm, src_pmd); | 656 | src_ptl = pte_lockptr(src_mm, src_pmd); |
656 | spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); | 657 | spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); |
658 | orig_src_pte = src_pte; | ||
659 | orig_dst_pte = dst_pte; | ||
657 | arch_enter_lazy_mmu_mode(); | 660 | arch_enter_lazy_mmu_mode(); |
658 | 661 | ||
659 | do { | 662 | do { |
@@ -677,9 +680,9 @@ again: | |||
677 | 680 | ||
678 | arch_leave_lazy_mmu_mode(); | 681 | arch_leave_lazy_mmu_mode(); |
679 | spin_unlock(src_ptl); | 682 | spin_unlock(src_ptl); |
680 | pte_unmap_nested(src_pte - 1); | 683 | pte_unmap_nested(orig_src_pte); |
681 | add_mm_rss(dst_mm, rss[0], rss[1]); | 684 | add_mm_rss(dst_mm, rss[0], rss[1]); |
682 | pte_unmap_unlock(dst_pte - 1, dst_ptl); | 685 | pte_unmap_unlock(orig_dst_pte, dst_ptl); |
683 | cond_resched(); | 686 | cond_resched(); |
684 | if (addr != end) | 687 | if (addr != end) |
685 | goto again; | 688 | goto again; |
@@ -1820,10 +1823,10 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, | |||
1820 | token = pmd_pgtable(*pmd); | 1823 | token = pmd_pgtable(*pmd); |
1821 | 1824 | ||
1822 | do { | 1825 | do { |
1823 | err = fn(pte, token, addr, data); | 1826 | err = fn(pte++, token, addr, data); |
1824 | if (err) | 1827 | if (err) |
1825 | break; | 1828 | break; |
1826 | } while (pte++, addr += PAGE_SIZE, addr != end); | 1829 | } while (addr += PAGE_SIZE, addr != end); |
1827 | 1830 | ||
1828 | arch_leave_lazy_mmu_mode(); | 1831 | arch_leave_lazy_mmu_mode(); |
1829 | 1832 | ||
@@ -2539,7 +2542,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2539 | } else if (PageHWPoison(page)) { | 2542 | } else if (PageHWPoison(page)) { |
2540 | ret = VM_FAULT_HWPOISON; | 2543 | ret = VM_FAULT_HWPOISON; |
2541 | delayacct_clear_flag(DELAYACCT_PF_SWAPIN); | 2544 | delayacct_clear_flag(DELAYACCT_PF_SWAPIN); |
2542 | goto out; | 2545 | goto out_release; |
2543 | } | 2546 | } |
2544 | 2547 | ||
2545 | lock_page(page); | 2548 | lock_page(page); |
@@ -2611,6 +2614,7 @@ out_nomap: | |||
2611 | pte_unmap_unlock(page_table, ptl); | 2614 | pte_unmap_unlock(page_table, ptl); |
2612 | out_page: | 2615 | out_page: |
2613 | unlock_page(page); | 2616 | unlock_page(page); |
2617 | out_release: | ||
2614 | page_cache_release(page); | 2618 | page_cache_release(page); |
2615 | return ret; | 2619 | return ret; |
2616 | } | 2620 | } |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 7dd9d9f80694..4545d5944243 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -1024,7 +1024,7 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1024 | 1024 | ||
1025 | err = migrate_prep(); | 1025 | err = migrate_prep(); |
1026 | if (err) | 1026 | if (err) |
1027 | return err; | 1027 | goto mpol_out; |
1028 | } | 1028 | } |
1029 | { | 1029 | { |
1030 | NODEMASK_SCRATCH(scratch); | 1030 | NODEMASK_SCRATCH(scratch); |
@@ -1039,10 +1039,9 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1039 | err = -ENOMEM; | 1039 | err = -ENOMEM; |
1040 | NODEMASK_SCRATCH_FREE(scratch); | 1040 | NODEMASK_SCRATCH_FREE(scratch); |
1041 | } | 1041 | } |
1042 | if (err) { | 1042 | if (err) |
1043 | mpol_put(new); | 1043 | goto mpol_out; |
1044 | return err; | 1044 | |
1045 | } | ||
1046 | vma = check_range(mm, start, end, nmask, | 1045 | vma = check_range(mm, start, end, nmask, |
1047 | flags | MPOL_MF_INVERT, &pagelist); | 1046 | flags | MPOL_MF_INVERT, &pagelist); |
1048 | 1047 | ||
@@ -1058,9 +1057,11 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1058 | 1057 | ||
1059 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) | 1058 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) |
1060 | err = -EIO; | 1059 | err = -EIO; |
1061 | } | 1060 | } else |
1061 | putback_lru_pages(&pagelist); | ||
1062 | 1062 | ||
1063 | up_write(&mm->mmap_sem); | 1063 | up_write(&mm->mmap_sem); |
1064 | mpol_out: | ||
1064 | mpol_put(new); | 1065 | mpol_put(new); |
1065 | return err; | 1066 | return err; |
1066 | } | 1067 | } |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bf720550b44d..cdcedf661616 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2183,7 +2183,7 @@ void show_free_areas(void) | |||
2183 | printk("active_anon:%lu inactive_anon:%lu isolated_anon:%lu\n" | 2183 | printk("active_anon:%lu inactive_anon:%lu isolated_anon:%lu\n" |
2184 | " active_file:%lu inactive_file:%lu isolated_file:%lu\n" | 2184 | " active_file:%lu inactive_file:%lu isolated_file:%lu\n" |
2185 | " unevictable:%lu" | 2185 | " unevictable:%lu" |
2186 | " dirty:%lu writeback:%lu unstable:%lu buffer:%lu\n" | 2186 | " dirty:%lu writeback:%lu unstable:%lu\n" |
2187 | " free:%lu slab_reclaimable:%lu slab_unreclaimable:%lu\n" | 2187 | " free:%lu slab_reclaimable:%lu slab_unreclaimable:%lu\n" |
2188 | " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n", | 2188 | " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n", |
2189 | global_page_state(NR_ACTIVE_ANON), | 2189 | global_page_state(NR_ACTIVE_ANON), |
@@ -2196,7 +2196,6 @@ void show_free_areas(void) | |||
2196 | global_page_state(NR_FILE_DIRTY), | 2196 | global_page_state(NR_FILE_DIRTY), |
2197 | global_page_state(NR_WRITEBACK), | 2197 | global_page_state(NR_WRITEBACK), |
2198 | global_page_state(NR_UNSTABLE_NFS), | 2198 | global_page_state(NR_UNSTABLE_NFS), |
2199 | nr_blockdev_pages(), | ||
2200 | global_page_state(NR_FREE_PAGES), | 2199 | global_page_state(NR_FREE_PAGES), |
2201 | global_page_state(NR_SLAB_RECLAIMABLE), | 2200 | global_page_state(NR_SLAB_RECLAIMABLE), |
2202 | global_page_state(NR_SLAB_UNRECLAIMABLE), | 2201 | global_page_state(NR_SLAB_UNRECLAIMABLE), |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 64e438898832..777af57fd8c8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -544,6 +544,16 @@ redo: | |||
544 | */ | 544 | */ |
545 | lru = LRU_UNEVICTABLE; | 545 | lru = LRU_UNEVICTABLE; |
546 | add_page_to_unevictable_list(page); | 546 | add_page_to_unevictable_list(page); |
547 | /* | ||
548 | * When racing with an mlock clearing (page is | ||
549 | * unlocked), make sure that if the other thread does | ||
550 | * not observe our setting of PG_lru and fails | ||
551 | * isolation, we see PG_mlocked cleared below and move | ||
552 | * the page back to the evictable list. | ||
553 | * | ||
554 | * The other side is TestClearPageMlocked(). | ||
555 | */ | ||
556 | smp_mb(); | ||
547 | } | 557 | } |
548 | 558 | ||
549 | /* | 559 | /* |
@@ -1088,7 +1098,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan, | |||
1088 | int lumpy_reclaim = 0; | 1098 | int lumpy_reclaim = 0; |
1089 | 1099 | ||
1090 | while (unlikely(too_many_isolated(zone, file, sc))) { | 1100 | while (unlikely(too_many_isolated(zone, file, sc))) { |
1091 | congestion_wait(WRITE, HZ/10); | 1101 | congestion_wait(BLK_RW_ASYNC, HZ/10); |
1092 | 1102 | ||
1093 | /* We are about to die and free our memory. Return now. */ | 1103 | /* We are about to die and free our memory. Return now. */ |
1094 | if (fatal_signal_pending(current)) | 1104 | if (fatal_signal_pending(current)) |
@@ -1356,7 +1366,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone, | |||
1356 | * IO, plus JVM can create lots of anon VM_EXEC pages, | 1366 | * IO, plus JVM can create lots of anon VM_EXEC pages, |
1357 | * so we ignore them here. | 1367 | * so we ignore them here. |
1358 | */ | 1368 | */ |
1359 | if ((vm_flags & VM_EXEC) && !PageAnon(page)) { | 1369 | if ((vm_flags & VM_EXEC) && page_is_file_cache(page)) { |
1360 | list_add(&page->lru, &l_active); | 1370 | list_add(&page->lru, &l_active); |
1361 | continue; | 1371 | continue; |
1362 | } | 1372 | } |