--- b/mm/madvise.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff -puN mm/madvise.c~madv-pageout-find-swap-cache mm/madvise.c --- a/mm/madvise.c~madv-pageout-find-swap-cache 2020-03-12 14:24:45.178775035 -0700 +++ b/mm/madvise.c 2020-03-12 14:35:49.706773378 -0700 @@ -248,6 +248,36 @@ static void force_shm_swapin_readahead(s #endif /* CONFIG_SWAP */ /* + * Given a PTE, find the corresponding 'struct page'. Also handles + * non-present swap PTEs. + */ +struct page *pte_to_reclaim_page(struct vm_area_struct *vma, + unsigned long addr, pte_t ptent) +{ + swp_entry_t entry; + + /* Totally empty PTE: */ + if (pte_none(ptent)) + return NULL; + + /* A normal, present page is mapped: */ + if (pte_present(ptent)) + return vm_normal_page(vma, addr, ptent); + + entry = pte_to_swp_entry(vmf->orig_pte); + /* Is it one of the "swap PTEs" that's not really swap? */ + if (non_swap_entry(entry)) + return false; + + /* + * The PTE was a true swap entry. The page may be in the + * swap cache. If so, find it and return it so it may be + * reclaimed. + */ + return lookup_swap_cache(entry, vma, addr); +} + +/* * Schedule all required I/O operations. Do not wait for completion. */ static long madvise_willneed(struct vm_area_struct *vma, @@ -389,13 +419,7 @@ regular_page: for (; addr < end; pte++, addr += PAGE_SIZE) { ptent = *pte; - if (pte_none(ptent)) - continue; - - if (!pte_present(ptent)) - continue; - - page = vm_normal_page(vma, addr, ptent); + page = pte_to_reclaim_page(vma, addr, ptent); if (!page) continue; _