]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/rmap.c
scsi: qedf: Cleanup the type of io_log->op
[karo-tx-linux.git] / mm / rmap.c
index 91619fd709399a428a5a65fff6367d14cbef3db3..3ff241f714ebc066ce34a4d68381efcb303f4043 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -46,6 +46,8 @@
  */
 
 #include <linux/mm.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/task.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
@@ -607,8 +609,7 @@ void try_to_unmap_flush_dirty(void)
                try_to_unmap_flush();
 }
 
-static void set_tlb_ubc_flush_pending(struct mm_struct *mm,
-               struct page *page, bool writable)
+static void set_tlb_ubc_flush_pending(struct mm_struct *mm, bool writable)
 {
        struct tlbflush_unmap_batch *tlb_ubc = &current->tlb_ubc;
 
@@ -643,8 +644,7 @@ static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags)
        return should_defer;
 }
 #else
-static void set_tlb_ubc_flush_pending(struct mm_struct *mm,
-               struct page *page, bool writable)
+static void set_tlb_ubc_flush_pending(struct mm_struct *mm, bool writable)
 {
 }
 
@@ -684,6 +684,7 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
 pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
 {
        pgd_t *pgd;
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd = NULL;
        pmd_t pmde;
@@ -692,7 +693,11 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
        if (!pgd_present(*pgd))
                goto out;
 
-       pud = pud_offset(pgd, address);
+       p4d = p4d_offset(pgd, address);
+       if (!p4d_present(*p4d))
+               goto out;
+
+       pud = pud_offset(p4d, address);
        if (!pud_present(*pud))
                goto out;
 
@@ -710,170 +715,6 @@ out:
        return pmd;
 }
 
-/*
- * Check that @page is mapped at @address into @mm.
- *
- * If @sync is false, page_check_address may perform a racy check to avoid
- * the page table lock when the pte is not present (helpful when reclaiming
- * highly shared pages).
- *
- * On success returns with pte mapped and locked.
- */
-pte_t *__page_check_address(struct page *page, struct mm_struct *mm,
-                         unsigned long address, spinlock_t **ptlp, int sync)
-{
-       pmd_t *pmd;
-       pte_t *pte;
-       spinlock_t *ptl;
-
-       if (unlikely(PageHuge(page))) {
-               /* when pud is not present, pte will be NULL */
-               pte = huge_pte_offset(mm, address);
-               if (!pte)
-                       return NULL;
-
-               ptl = huge_pte_lockptr(page_hstate(page), mm, pte);
-               goto check;
-       }
-
-       pmd = mm_find_pmd(mm, address);
-       if (!pmd)
-               return NULL;
-
-       pte = pte_offset_map(pmd, address);
-       /* Make a quick check before getting the lock */
-       if (!sync && !pte_present(*pte)) {
-               pte_unmap(pte);
-               return NULL;
-       }
-
-       ptl = pte_lockptr(mm, pmd);
-check:
-       spin_lock(ptl);
-       if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) {
-               *ptlp = ptl;
-               return pte;
-       }
-       pte_unmap_unlock(pte, ptl);
-       return NULL;
-}
-
-/**
- * page_mapped_in_vma - check whether a page is really mapped in a VMA
- * @page: the page to test
- * @vma: the VMA to test
- *
- * Returns 1 if the page is mapped into the page tables of the VMA, 0
- * if the page is not mapped into the page tables of this VMA.  Only
- * valid for normal file or anonymous VMAs.
- */
-int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma)
-{
-       unsigned long address;
-       pte_t *pte;
-       spinlock_t *ptl;
-
-       address = __vma_address(page, vma);
-       if (unlikely(address < vma->vm_start || address >= vma->vm_end))
-               return 0;
-       pte = page_check_address(page, vma->vm_mm, address, &ptl, 1);
-       if (!pte)                       /* the page is not in this mm */
-               return 0;
-       pte_unmap_unlock(pte, ptl);
-
-       return 1;
-}
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-/*
- * Check that @page is mapped at @address into @mm. In contrast to
- * page_check_address(), this function can handle transparent huge pages.
- *
- * On success returns true with pte mapped and locked. For PMD-mapped
- * transparent huge pages *@ptep is set to NULL.
- */
-bool page_check_address_transhuge(struct page *page, struct mm_struct *mm,
-                                 unsigned long address, pmd_t **pmdp,
-                                 pte_t **ptep, spinlock_t **ptlp)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       spinlock_t *ptl;
-
-       if (unlikely(PageHuge(page))) {
-               /* when pud is not present, pte will be NULL */
-               pte = huge_pte_offset(mm, address);
-               if (!pte)
-                       return false;
-
-               ptl = huge_pte_lockptr(page_hstate(page), mm, pte);
-               pmd = NULL;
-               goto check_pte;
-       }
-
-       pgd = pgd_offset(mm, address);
-       if (!pgd_present(*pgd))
-               return false;
-       pud = pud_offset(pgd, address);
-       if (!pud_present(*pud))
-               return false;
-       pmd = pmd_offset(pud, address);
-
-       if (pmd_trans_huge(*pmd)) {
-               ptl = pmd_lock(mm, pmd);
-               if (!pmd_present(*pmd))
-                       goto unlock_pmd;
-               if (unlikely(!pmd_trans_huge(*pmd))) {
-                       spin_unlock(ptl);
-                       goto map_pte;
-               }
-
-               if (pmd_page(*pmd) != page)
-                       goto unlock_pmd;
-
-               pte = NULL;
-               goto found;
-unlock_pmd:
-               spin_unlock(ptl);
-               return false;
-       } else {
-               pmd_t pmde = *pmd;
-
-               barrier();
-               if (!pmd_present(pmde) || pmd_trans_huge(pmde))
-                       return false;
-       }
-map_pte:
-       pte = pte_offset_map(pmd, address);
-       if (!pte_present(*pte)) {
-               pte_unmap(pte);
-               return false;
-       }
-
-       ptl = pte_lockptr(mm, pmd);
-check_pte:
-       spin_lock(ptl);
-
-       if (!pte_present(*pte)) {
-               pte_unmap_unlock(pte, ptl);
-               return false;
-       }
-
-       /* THP can be referenced by any subpage */
-       if (pte_pfn(*pte) - page_to_pfn(page) >= hpage_nr_pages(page)) {
-               pte_unmap_unlock(pte, ptl);
-               return false;
-       }
-found:
-       *ptep = pte;
-       *pmdp = pmd;
-       *ptlp = ptl;
-       return true;
-}
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-
 struct page_referenced_arg {
        int mapcount;
        int referenced;
@@ -883,48 +724,51 @@ struct page_referenced_arg {
 /*
  * arg: page_referenced_arg will be passed
  */
-static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
+static bool page_referenced_one(struct page *page, struct vm_area_struct *vma,
                        unsigned long address, void *arg)
 {
-       struct mm_struct *mm = vma->vm_mm;
        struct page_referenced_arg *pra = arg;
-       pmd_t *pmd;
-       pte_t *pte;
-       spinlock_t *ptl;
+       struct page_vma_mapped_walk pvmw = {
+               .page = page,
+               .vma = vma,
+               .address = address,
+       };
        int referenced = 0;
 
-       if (!page_check_address_transhuge(page, mm, address, &pmd, &pte, &ptl))
-               return SWAP_AGAIN;
+       while (page_vma_mapped_walk(&pvmw)) {
+               address = pvmw.address;
 
-       if (vma->vm_flags & VM_LOCKED) {
-               if (pte)
-                       pte_unmap(pte);
-               spin_unlock(ptl);
-               pra->vm_flags |= VM_LOCKED;
-               return SWAP_FAIL; /* To break the loop */
-       }
+               if (vma->vm_flags & VM_LOCKED) {
+                       page_vma_mapped_walk_done(&pvmw);
+                       pra->vm_flags |= VM_LOCKED;
+                       return false; /* To break the loop */
+               }
 
-       if (pte) {
-               if (ptep_clear_flush_young_notify(vma, address, pte)) {
-                       /*
-                        * Don't treat a reference through a sequentially read
-                        * mapping as such.  If the page has been used in
-                        * another mapping, we will catch it; if this other
-                        * mapping is already gone, the unmap path will have
-                        * set PG_referenced or activated the page.
-                        */
-                       if (likely(!(vma->vm_flags & VM_SEQ_READ)))
+               if (pvmw.pte) {
+                       if (ptep_clear_flush_young_notify(vma, address,
+                                               pvmw.pte)) {
+                               /*
+                                * Don't treat a reference through
+                                * a sequentially read mapping as such.
+                                * If the page has been used in another mapping,
+                                * we will catch it; if this other mapping is
+                                * already gone, the unmap path will have set
+                                * PG_referenced or activated the page.
+                                */
+                               if (likely(!(vma->vm_flags & VM_SEQ_READ)))
+                                       referenced++;
+                       }
+               } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
+                       if (pmdp_clear_flush_young_notify(vma, address,
+                                               pvmw.pmd))
                                referenced++;
+               } else {
+                       /* unexpected pmd-mapped page? */
+                       WARN_ON_ONCE(1);
                }
-               pte_unmap(pte);
-       } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
-               if (pmdp_clear_flush_young_notify(vma, address, pmd))
-                       referenced++;
-       } else {
-               /* unexpected pmd-mapped page? */
-               WARN_ON_ONCE(1);
+
+               pra->mapcount--;
        }
-       spin_unlock(ptl);
 
        if (referenced)
                clear_page_idle(page);
@@ -936,11 +780,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
                pra->vm_flags |= vma->vm_flags;
        }
 
-       pra->mapcount--;
        if (!pra->mapcount)
-               return SWAP_SUCCESS; /* To break the loop */
+               return false; /* To break the loop */
 
-       return SWAP_AGAIN;
+       return true;
 }
 
 static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)
@@ -969,7 +812,6 @@ int page_referenced(struct page *page,
                    struct mem_cgroup *memcg,
                    unsigned long *vm_flags)
 {
-       int ret;
        int we_locked = 0;
        struct page_referenced_arg pra = {
                .mapcount = total_mapcount(page),
@@ -1003,7 +845,7 @@ int page_referenced(struct page *page,
                rwc.invalid_vma = invalid_page_referenced_vma;
        }
 
-       ret = rmap_walk(page, &rwc);
+       rmap_walk(page, &rwc);
        *vm_flags = pra.vm_flags;
 
        if (we_locked)
@@ -1012,38 +854,60 @@ int page_referenced(struct page *page,
        return pra.referenced;
 }
 
-static int page_mkclean_one(struct page *page, struct vm_area_struct *vma,
+static bool page_mkclean_one(struct page *page, struct vm_area_struct *vma,
                            unsigned long address, void *arg)
 {
-       struct mm_struct *mm = vma->vm_mm;
-       pte_t *pte;
-       spinlock_t *ptl;
-       int ret = 0;
+       struct page_vma_mapped_walk pvmw = {
+               .page = page,
+               .vma = vma,
+               .address = address,
+               .flags = PVMW_SYNC,
+       };
        int *cleaned = arg;
 
-       pte = page_check_address(page, mm, address, &ptl, 1);
-       if (!pte)
-               goto out;
-
-       if (pte_dirty(*pte) || pte_write(*pte)) {
-               pte_t entry;
+       while (page_vma_mapped_walk(&pvmw)) {
+               int ret = 0;
+               address = pvmw.address;
+               if (pvmw.pte) {
+                       pte_t entry;
+                       pte_t *pte = pvmw.pte;
+
+                       if (!pte_dirty(*pte) && !pte_write(*pte))
+                               continue;
+
+                       flush_cache_page(vma, address, pte_pfn(*pte));
+                       entry = ptep_clear_flush(vma, address, pte);
+                       entry = pte_wrprotect(entry);
+                       entry = pte_mkclean(entry);
+                       set_pte_at(vma->vm_mm, address, pte, entry);
+                       ret = 1;
+               } else {
+#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
+                       pmd_t *pmd = pvmw.pmd;
+                       pmd_t entry;
+
+                       if (!pmd_dirty(*pmd) && !pmd_write(*pmd))
+                               continue;
+
+                       flush_cache_page(vma, address, page_to_pfn(page));
+                       entry = pmdp_huge_clear_flush(vma, address, pmd);
+                       entry = pmd_wrprotect(entry);
+                       entry = pmd_mkclean(entry);
+                       set_pmd_at(vma->vm_mm, address, pmd, entry);
+                       ret = 1;
+#else
+                       /* unexpected pmd-mapped page? */
+                       WARN_ON_ONCE(1);
+#endif
+               }
 
-               flush_cache_page(vma, address, pte_pfn(*pte));
-               entry = ptep_clear_flush(vma, address, pte);
-               entry = pte_wrprotect(entry);
-               entry = pte_mkclean(entry);
-               set_pte_at(mm, address, pte, entry);
-               ret = 1;
+               if (ret) {
+                       mmu_notifier_invalidate_page(vma->vm_mm, address);
+                       (*cleaned)++;
+               }
        }
 
-       pte_unmap_unlock(pte, ptl);
-
-       if (ret) {
-               mmu_notifier_invalidate_page(mm, address);
-               (*cleaned)++;
-       }
-out:
-       return SWAP_AGAIN;
+       return true;
 }
 
 static bool invalid_mkclean_vma(struct vm_area_struct *vma, void *arg)
@@ -1294,7 +1158,7 @@ void page_add_file_rmap(struct page *page, bool compound)
                        goto out;
        }
        __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, nr);
-       mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
+       mod_memcg_page_state(page, NR_FILE_MAPPED, nr);
 out:
        unlock_page_memcg(page);
 }
@@ -1334,7 +1198,7 @@ static void page_remove_file_rmap(struct page *page, bool compound)
         * pte lock(a spinlock) is held, which implies preemption disabled.
         */
        __mod_node_page_state(page_pgdat(page), NR_FILE_MAPPED, -nr);
-       mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
+       mod_memcg_page_state(page, NR_FILE_MAPPED, -nr);
 
        if (unlikely(PageMlocked(page)))
                clear_page_mlock(page);
@@ -1423,167 +1287,186 @@ void page_remove_rmap(struct page *page, bool compound)
         */
 }
 
-struct rmap_private {
-       enum ttu_flags flags;
-       int lazyfreed;
-};
-
 /*
  * @arg: enum ttu_flags will be passed to this argument
  */
-static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
+static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                     unsigned long address, void *arg)
 {
        struct mm_struct *mm = vma->vm_mm;
-       pte_t *pte;
+       struct page_vma_mapped_walk pvmw = {
+               .page = page,
+               .vma = vma,
+               .address = address,
+       };
        pte_t pteval;
-       spinlock_t *ptl;
-       int ret = SWAP_AGAIN;
-       struct rmap_private *rp = arg;
-       enum ttu_flags flags = rp->flags;
+       struct page *subpage;
+       bool ret = true;
+       enum ttu_flags flags = (enum ttu_flags)arg;
 
        /* munlock has nothing to gain from examining un-locked vmas */
        if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
-               goto out;
+               return true;
 
        if (flags & TTU_SPLIT_HUGE_PMD) {
                split_huge_pmd_address(vma, address,
                                flags & TTU_MIGRATION, page);
-               /* check if we have anything to do after split */
-               if (page_mapcount(page) == 0)
-                       goto out;
        }
 
-       pte = page_check_address(page, mm, address, &ptl,
-                                PageTransCompound(page));
-       if (!pte)
-               goto out;
-
-       /*
-        * If the page is mlock()d, we cannot swap it out.
-        * If it's recently referenced (perhaps page_referenced
-        * skipped over this mm) then we should reactivate it.
-        */
-       if (!(flags & TTU_IGNORE_MLOCK)) {
-               if (vma->vm_flags & VM_LOCKED) {
-                       /* PTE-mapped THP are never mlocked */
-                       if (!PageTransCompound(page)) {
-                               /*
-                                * Holding pte lock, we do *not* need
-                                * mmap_sem here
-                                */
-                               mlock_vma_page(page);
+       while (page_vma_mapped_walk(&pvmw)) {
+               /*
+                * If the page is mlock()d, we cannot swap it out.
+                * If it's recently referenced (perhaps page_referenced
+                * skipped over this mm) then we should reactivate it.
+                */
+               if (!(flags & TTU_IGNORE_MLOCK)) {
+                       if (vma->vm_flags & VM_LOCKED) {
+                               /* PTE-mapped THP are never mlocked */
+                               if (!PageTransCompound(page)) {
+                                       /*
+                                        * Holding pte lock, we do *not* need
+                                        * mmap_sem here
+                                        */
+                                       mlock_vma_page(page);
+                               }
+                               ret = false;
+                               page_vma_mapped_walk_done(&pvmw);
+                               break;
                        }
-                       ret = SWAP_MLOCK;
-                       goto out_unmap;
+                       if (flags & TTU_MUNLOCK)
+                               continue;
                }
-               if (flags & TTU_MUNLOCK)
-                       goto out_unmap;
-       }
-       if (!(flags & TTU_IGNORE_ACCESS)) {
-               if (ptep_clear_flush_young_notify(vma, address, pte)) {
-                       ret = SWAP_FAIL;
-                       goto out_unmap;
-               }
-       }
 
-       /* Nuke the page table entry. */
-       flush_cache_page(vma, address, page_to_pfn(page));
-       if (should_defer_flush(mm, flags)) {
-               /*
-                * We clear the PTE but do not flush so potentially a remote
-                * CPU could still be writing to the page. If the entry was
-                * previously clean then the architecture must guarantee that
-                * a clear->dirty transition on a cached TLB entry is written
-                * through and traps if the PTE is unmapped.
-                */
-               pteval = ptep_get_and_clear(mm, address, pte);
+               /* Unexpected PMD-mapped THP? */
+               VM_BUG_ON_PAGE(!pvmw.pte, page);
+
+               subpage = page - page_to_pfn(page) + pte_pfn(*pvmw.pte);
+               address = pvmw.address;
 
-               set_tlb_ubc_flush_pending(mm, page, pte_dirty(pteval));
-       } else {
-               pteval = ptep_clear_flush(vma, address, pte);
-       }
 
-       /* Move the dirty bit to the physical page now the pte is gone. */
-       if (pte_dirty(pteval))
-               set_page_dirty(page);
+               if (!(flags & TTU_IGNORE_ACCESS)) {
+                       if (ptep_clear_flush_young_notify(vma, address,
+                                               pvmw.pte)) {
+                               ret = false;
+                               page_vma_mapped_walk_done(&pvmw);
+                               break;
+                       }
+               }
 
-       /* Update high watermark before we lower rss */
-       update_hiwater_rss(mm);
+               /* Nuke the page table entry. */
+               flush_cache_page(vma, address, pte_pfn(*pvmw.pte));
+               if (should_defer_flush(mm, flags)) {
+                       /*
+                        * We clear the PTE but do not flush so potentially
+                        * a remote CPU could still be writing to the page.
+                        * If the entry was previously clean then the
+                        * architecture must guarantee that a clear->dirty
+                        * transition on a cached TLB entry is written through
+                        * and traps if the PTE is unmapped.
+                        */
+                       pteval = ptep_get_and_clear(mm, address, pvmw.pte);
 
-       if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) {
-               if (PageHuge(page)) {
-                       hugetlb_count_sub(1 << compound_order(page), mm);
+                       set_tlb_ubc_flush_pending(mm, pte_dirty(pteval));
                } else {
-                       dec_mm_counter(mm, mm_counter(page));
+                       pteval = ptep_clear_flush(vma, address, pvmw.pte);
                }
-               set_pte_at(mm, address, pte,
-                          swp_entry_to_pte(make_hwpoison_entry(page)));
-       } else if (pte_unused(pteval)) {
-               /*
-                * The guest indicated that the page content is of no
-                * interest anymore. Simply discard the pte, vmscan
-                * will take care of the rest.
-                */
-               dec_mm_counter(mm, mm_counter(page));
-       } else if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION)) {
-               swp_entry_t entry;
-               pte_t swp_pte;
-               /*
-                * Store the pfn of the page in a special migration
-                * pte. do_swap_page() will wait until the migration
-                * pte is removed and then restart fault handling.
-                */
-               entry = make_migration_entry(page, pte_write(pteval));
-               swp_pte = swp_entry_to_pte(entry);
-               if (pte_soft_dirty(pteval))
-                       swp_pte = pte_swp_mksoft_dirty(swp_pte);
-               set_pte_at(mm, address, pte, swp_pte);
-       } else if (PageAnon(page)) {
-               swp_entry_t entry = { .val = page_private(page) };
-               pte_t swp_pte;
-               /*
-                * Store the swap location in the pte.
-                * See handle_pte_fault() ...
-                */
-               VM_BUG_ON_PAGE(!PageSwapCache(page), page);
 
-               if (!PageDirty(page) && (flags & TTU_LZFREE)) {
-                       /* It's a freeable page by MADV_FREE */
-                       dec_mm_counter(mm, MM_ANONPAGES);
-                       rp->lazyfreed++;
-                       goto discard;
-               }
+               /* Move the dirty bit to the page. Now the pte is gone. */
+               if (pte_dirty(pteval))
+                       set_page_dirty(page);
 
-               if (swap_duplicate(entry) < 0) {
-                       set_pte_at(mm, address, pte, pteval);
-                       ret = SWAP_FAIL;
-                       goto out_unmap;
-               }
-               if (list_empty(&mm->mmlist)) {
-                       spin_lock(&mmlist_lock);
-                       if (list_empty(&mm->mmlist))
-                               list_add(&mm->mmlist, &init_mm.mmlist);
-                       spin_unlock(&mmlist_lock);
-               }
-               dec_mm_counter(mm, MM_ANONPAGES);
-               inc_mm_counter(mm, MM_SWAPENTS);
-               swp_pte = swp_entry_to_pte(entry);
-               if (pte_soft_dirty(pteval))
-                       swp_pte = pte_swp_mksoft_dirty(swp_pte);
-               set_pte_at(mm, address, pte, swp_pte);
-       } else
-               dec_mm_counter(mm, mm_counter_file(page));
+               /* Update high watermark before we lower rss */
+               update_hiwater_rss(mm);
 
-discard:
-       page_remove_rmap(page, PageHuge(page));
-       put_page(page);
+               if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) {
+                       if (PageHuge(page)) {
+                               int nr = 1 << compound_order(page);
+                               hugetlb_count_sub(nr, mm);
+                       } else {
+                               dec_mm_counter(mm, mm_counter(page));
+                       }
+
+                       pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
+                       set_pte_at(mm, address, pvmw.pte, pteval);
+               } else if (pte_unused(pteval)) {
+                       /*
+                        * The guest indicated that the page content is of no
+                        * interest anymore. Simply discard the pte, vmscan
+                        * will take care of the rest.
+                        */
+                       dec_mm_counter(mm, mm_counter(page));
+               } else if (IS_ENABLED(CONFIG_MIGRATION) &&
+                               (flags & TTU_MIGRATION)) {
+                       swp_entry_t entry;
+                       pte_t swp_pte;
+                       /*
+                        * Store the pfn of the page in a special migration
+                        * pte. do_swap_page() will wait until the migration
+                        * pte is removed and then restart fault handling.
+                        */
+                       entry = make_migration_entry(subpage,
+                                       pte_write(pteval));
+                       swp_pte = swp_entry_to_pte(entry);
+                       if (pte_soft_dirty(pteval))
+                               swp_pte = pte_swp_mksoft_dirty(swp_pte);
+                       set_pte_at(mm, address, pvmw.pte, swp_pte);
+               } else if (PageAnon(page)) {
+                       swp_entry_t entry = { .val = page_private(subpage) };
+                       pte_t swp_pte;
+                       /*
+                        * Store the swap location in the pte.
+                        * See handle_pte_fault() ...
+                        */
+                       if (unlikely(PageSwapBacked(page) != PageSwapCache(page))) {
+                               WARN_ON_ONCE(1);
+                               ret = false;
+                               page_vma_mapped_walk_done(&pvmw);
+                               break;
+                       }
+
+                       /* MADV_FREE page check */
+                       if (!PageSwapBacked(page)) {
+                               if (!PageDirty(page)) {
+                                       dec_mm_counter(mm, MM_ANONPAGES);
+                                       goto discard;
+                               }
+
+                               /*
+                                * If the page was redirtied, it cannot be
+                                * discarded. Remap the page to page table.
+                                */
+                               set_pte_at(mm, address, pvmw.pte, pteval);
+                               SetPageSwapBacked(page);
+                               ret = false;
+                               page_vma_mapped_walk_done(&pvmw);
+                               break;
+                       }
 
-out_unmap:
-       pte_unmap_unlock(pte, ptl);
-       if (ret != SWAP_FAIL && ret != SWAP_MLOCK && !(flags & TTU_MUNLOCK))
+                       if (swap_duplicate(entry) < 0) {
+                               set_pte_at(mm, address, pvmw.pte, pteval);
+                               ret = false;
+                               page_vma_mapped_walk_done(&pvmw);
+                               break;
+                       }
+                       if (list_empty(&mm->mmlist)) {
+                               spin_lock(&mmlist_lock);
+                               if (list_empty(&mm->mmlist))
+                                       list_add(&mm->mmlist, &init_mm.mmlist);
+                               spin_unlock(&mmlist_lock);
+                       }
+                       dec_mm_counter(mm, MM_ANONPAGES);
+                       inc_mm_counter(mm, MM_SWAPENTS);
+                       swp_pte = swp_entry_to_pte(entry);
+                       if (pte_soft_dirty(pteval))
+                               swp_pte = pte_swp_mksoft_dirty(swp_pte);
+                       set_pte_at(mm, address, pvmw.pte, swp_pte);
+               } else
+                       dec_mm_counter(mm, mm_counter_file(page));
+discard:
+               page_remove_rmap(subpage, PageHuge(page));
+               put_page(page);
                mmu_notifier_invalidate_page(mm, address);
-out:
+       }
        return ret;
 }
 
@@ -1608,7 +1491,7 @@ static bool invalid_migration_vma(struct vm_area_struct *vma, void *arg)
 
 static int page_mapcount_is_zero(struct page *page)
 {
-       return !page_mapcount(page);
+       return !total_mapcount(page);
 }
 
 /**
@@ -1618,24 +1501,14 @@ static int page_mapcount_is_zero(struct page *page)
  *
  * Tries to remove all the page table entries which are mapping this
  * page, used in the pageout path.  Caller must hold the page lock.
- * Return values are:
  *
- * SWAP_SUCCESS        - we succeeded in removing all mappings
- * SWAP_AGAIN  - we missed a mapping, try again later
- * SWAP_FAIL   - the page is unswappable
- * SWAP_MLOCK  - page is mlocked.
+ * If unmap is successful, return true. Otherwise, false.
  */
-int try_to_unmap(struct page *page, enum ttu_flags flags)
+bool try_to_unmap(struct page *page, enum ttu_flags flags)
 {
-       int ret;
-       struct rmap_private rp = {
-               .flags = flags,
-               .lazyfreed = 0,
-       };
-
        struct rmap_walk_control rwc = {
                .rmap_one = try_to_unmap_one,
-               .arg = &rp,
+               .arg = (void *)flags,
                .done = page_mapcount_is_zero,
                .anon_lock = page_lock_anon_vma_read,
        };
@@ -1652,16 +1525,11 @@ int try_to_unmap(struct page *page, enum ttu_flags flags)
                rwc.invalid_vma = invalid_migration_vma;
 
        if (flags & TTU_RMAP_LOCKED)
-               ret = rmap_walk_locked(page, &rwc);
+               rmap_walk_locked(page, &rwc);
        else
-               ret = rmap_walk(page, &rwc);
+               rmap_walk(page, &rwc);
 
-       if (ret != SWAP_MLOCK && !page_mapcount(page)) {
-               ret = SWAP_SUCCESS;
-               if (rp.lazyfreed && !PageDirty(page))
-                       ret = SWAP_LZFREE;
-       }
-       return ret;
+       return !page_mapcount(page) ? true : false;
 }
 
 static int page_not_mapped(struct page *page)
@@ -1676,34 +1544,22 @@ static int page_not_mapped(struct page *page)
  * Called from munlock code.  Checks all of the VMAs mapping the page
  * to make sure nobody else has this page mlocked. The page will be
  * returned with PG_mlocked cleared if no other vmas have it mlocked.
- *
- * Return values are:
- *
- * SWAP_AGAIN  - no vma is holding page mlocked, or,
- * SWAP_AGAIN  - page mapped in mlocked vma -- couldn't acquire mmap sem
- * SWAP_FAIL   - page cannot be located at present
- * SWAP_MLOCK  - page is now mlocked.
  */
-int try_to_munlock(struct page *page)
-{
-       int ret;
-       struct rmap_private rp = {
-               .flags = TTU_MUNLOCK,
-               .lazyfreed = 0,
-       };
 
+void try_to_munlock(struct page *page)
+{
        struct rmap_walk_control rwc = {
                .rmap_one = try_to_unmap_one,
-               .arg = &rp,
+               .arg = (void *)TTU_MUNLOCK,
                .done = page_not_mapped,
                .anon_lock = page_lock_anon_vma_read,
 
        };
 
        VM_BUG_ON_PAGE(!PageLocked(page) || PageLRU(page), page);
+       VM_BUG_ON_PAGE(PageCompound(page) && PageDoubleMap(page), page);
 
-       ret = rmap_walk(page, &rwc);
-       return ret;
+       rmap_walk(page, &rwc);
 }
 
 void __put_anon_vma(struct anon_vma *anon_vma)
@@ -1751,13 +1607,12 @@ static struct anon_vma *rmap_walk_anon_lock(struct page *page,
  * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
  * LOCKED.
  */
-static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
+static void rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
                bool locked)
 {
        struct anon_vma *anon_vma;
-       pgoff_t pgoff;
+       pgoff_t pgoff_start, pgoff_end;
        struct anon_vma_chain *avc;
-       int ret = SWAP_AGAIN;
 
        if (locked) {
                anon_vma = page_anon_vma(page);
@@ -1767,10 +1622,12 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
                anon_vma = rmap_walk_anon_lock(page, rwc);
        }
        if (!anon_vma)
-               return ret;
+               return;
 
-       pgoff = page_to_pgoff(page);
-       anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
+       pgoff_start = page_to_pgoff(page);
+       pgoff_end = pgoff_start + hpage_nr_pages(page) - 1;
+       anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root,
+                       pgoff_start, pgoff_end) {
                struct vm_area_struct *vma = avc->vma;
                unsigned long address = vma_address(page, vma);
 
@@ -1779,8 +1636,7 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
                if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
                        continue;
 
-               ret = rwc->rmap_one(page, vma, address, rwc->arg);
-               if (ret != SWAP_AGAIN)
+               if (!rwc->rmap_one(page, vma, address, rwc->arg))
                        break;
                if (rwc->done && rwc->done(page))
                        break;
@@ -1788,7 +1644,6 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
 
        if (!locked)
                anon_vma_unlock_read(anon_vma);
-       return ret;
 }
 
 /*
@@ -1804,13 +1659,12 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
  * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
  * LOCKED.
  */
-static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
+static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
                bool locked)
 {
        struct address_space *mapping = page_mapping(page);
-       pgoff_t pgoff;
+       pgoff_t pgoff_start, pgoff_end;
        struct vm_area_struct *vma;
-       int ret = SWAP_AGAIN;
 
        /*
         * The page lock not only makes sure that page->mapping cannot
@@ -1821,12 +1675,14 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
        VM_BUG_ON_PAGE(!PageLocked(page), page);
 
        if (!mapping)
-               return ret;
+               return;
 
-       pgoff = page_to_pgoff(page);
+       pgoff_start = page_to_pgoff(page);
+       pgoff_end = pgoff_start + hpage_nr_pages(page) - 1;
        if (!locked)
                i_mmap_lock_read(mapping);
-       vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
+       vma_interval_tree_foreach(vma, &mapping->i_mmap,
+                       pgoff_start, pgoff_end) {
                unsigned long address = vma_address(page, vma);
 
                cond_resched();
@@ -1834,8 +1690,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
                if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
                        continue;
 
-               ret = rwc->rmap_one(page, vma, address, rwc->arg);
-               if (ret != SWAP_AGAIN)
+               if (!rwc->rmap_one(page, vma, address, rwc->arg))
                        goto done;
                if (rwc->done && rwc->done(page))
                        goto done;
@@ -1844,28 +1699,27 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
 done:
        if (!locked)
                i_mmap_unlock_read(mapping);
-       return ret;
 }
 
-int rmap_walk(struct page *page, struct rmap_walk_control *rwc)
+void rmap_walk(struct page *page, struct rmap_walk_control *rwc)
 {
        if (unlikely(PageKsm(page)))
-               return rmap_walk_ksm(page, rwc);
+               rmap_walk_ksm(page, rwc);
        else if (PageAnon(page))
-               return rmap_walk_anon(page, rwc, false);
+               rmap_walk_anon(page, rwc, false);
        else
-               return rmap_walk_file(page, rwc, false);
+               rmap_walk_file(page, rwc, false);
 }
 
 /* Like rmap_walk, but caller holds relevant rmap lock */
-int rmap_walk_locked(struct page *page, struct rmap_walk_control *rwc)
+void rmap_walk_locked(struct page *page, struct rmap_walk_control *rwc)
 {
        /* no ksm support for now */
        VM_BUG_ON_PAGE(PageKsm(page), page);
        if (PageAnon(page))
-               return rmap_walk_anon(page, rwc, true);
+               rmap_walk_anon(page, rwc, true);
        else
-               return rmap_walk_file(page, rwc, true);
+               rmap_walk_file(page, rwc, true);
 }
 
 #ifdef CONFIG_HUGETLB_PAGE