Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Hugh Dickins and committed by
Linus Torvalds
88784396 7c1cfacc

+23 -7
+23 -7
mm/fremap.c
··· 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); 42 - update_hiwater_rss(mm); 43 - dec_mm_counter(mm, MM_FILEPAGES); 44 49 } 45 - } else { 46 - if (!pte_file(pte)) 47 - free_swap_and_cache(pte_to_swp_entry(pte)); 50 + } else { /* zap_pte() is not called when pte_none() */ 51 + if (!pte_file(pte)) { 52 + update_hiwater_rss(mm); 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 + } 63 + } 48 64 pte_clear_not_present_full(mm, addr, ptep, 0); 49 65 } 50 66 }