Commit 887843961c4b4681ee993c36d4997bf4b4aa8253

Authored by Hugh Dickins
Committed by Linus Torvalds
1 parent 7c1cfacca2

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

... ... @@ -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 }