Commit 887843961c4b4681ee993c36d4997bf4b4aa8253
Committed by
Linus Torvalds
1 parent
7c1cfacca2
Exists in
master
and in
16 other branches
mm: fix bad rss-counter if remap_file_pages raced migration
Fix some "Bad rss-counter state" reports on exit, arising from the interaction between page migration and remap_file_pages(): zap_pte() must count a migration entry when zapping it. And yes, it is possible (though very unusual) to find an anon page or swap entry in a VM_SHARED nonlinear mapping: coming from that horrid get_user_pages(write, force) case which COWs even in a shared mapping. Signed-off-by: Hugh Dickins <hughd@google.com> Tested-by: Sasha Levin sasha.levin@oracle.com> Tested-by: Dave Jones davej@redhat.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 22 additions and 6 deletions Side-by-side Diff
mm/fremap.c
... | ... | @@ -23,28 +23,44 @@ |
23 | 23 | |
24 | 24 | #include "internal.h" |
25 | 25 | |
26 | +static int mm_counter(struct page *page) | |
27 | +{ | |
28 | + return PageAnon(page) ? MM_ANONPAGES : MM_FILEPAGES; | |
29 | +} | |
30 | + | |
26 | 31 | static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma, |
27 | 32 | unsigned long addr, pte_t *ptep) |
28 | 33 | { |
29 | 34 | pte_t pte = *ptep; |
35 | + struct page *page; | |
36 | + swp_entry_t entry; | |
30 | 37 | |
31 | 38 | if (pte_present(pte)) { |
32 | - struct page *page; | |
33 | - | |
34 | 39 | flush_cache_page(vma, addr, pte_pfn(pte)); |
35 | 40 | pte = ptep_clear_flush(vma, addr, ptep); |
36 | 41 | page = vm_normal_page(vma, addr, pte); |
37 | 42 | if (page) { |
38 | 43 | if (pte_dirty(pte)) |
39 | 44 | set_page_dirty(page); |
45 | + update_hiwater_rss(mm); | |
46 | + dec_mm_counter(mm, mm_counter(page)); | |
40 | 47 | page_remove_rmap(page); |
41 | 48 | page_cache_release(page); |
49 | + } | |
50 | + } else { /* zap_pte() is not called when pte_none() */ | |
51 | + if (!pte_file(pte)) { | |
42 | 52 | update_hiwater_rss(mm); |
43 | - dec_mm_counter(mm, MM_FILEPAGES); | |
53 | + entry = pte_to_swp_entry(pte); | |
54 | + if (non_swap_entry(entry)) { | |
55 | + if (is_migration_entry(entry)) { | |
56 | + page = migration_entry_to_page(entry); | |
57 | + dec_mm_counter(mm, mm_counter(page)); | |
58 | + } | |
59 | + } else { | |
60 | + free_swap_and_cache(entry); | |
61 | + dec_mm_counter(mm, MM_SWAPENTS); | |
62 | + } | |
44 | 63 | } |
45 | - } else { | |
46 | - if (!pte_file(pte)) | |
47 | - free_swap_and_cache(pte_to_swp_entry(pte)); | |
48 | 64 | pte_clear_not_present_full(mm, addr, ptep, 0); |
49 | 65 | } |
50 | 66 | } |