mm/swapfile: fix lost swap bits in unuse_pte()
authorMiaohe Lin <linmiaohe@huawei.com>
Thu, 19 May 2022 12:50:27 +0000 (20:50 +0800)
committerakpm <akpm@linux-foundation.org>
Fri, 27 May 2022 16:33:46 +0000 (09:33 -0700)
This is observed by code review only but not any real report.

When we turn off swapping we could have lost the bits stored in the swap
ptes.  The new rmap-exclusive bit is fine since that turned into a page
flag, but not for soft-dirty and uffd-wp.  Add them.

Link: https://lkml.kernel.org/r/20220519125030.21486-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Suggested-by: Peter Xu <peterx@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
Cc: NeilBrown <neilb@suse.de>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/swapfile.c

index b86d1cc8d00b46b41ff47ca65e157b88895f1077..e45874fb2ec7e3a0133425b0fe070d9db42fd41f 100644 (file)
@@ -1774,7 +1774,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 {
        struct page *swapcache;
        spinlock_t *ptl;
-       pte_t *pte;
+       pte_t *pte, new_pte;
        int ret = 1;
 
        swapcache = page;
@@ -1823,8 +1823,12 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                page_add_new_anon_rmap(page, vma, addr);
                lru_cache_add_inactive_or_unevictable(page, vma);
        }
-       set_pte_at(vma->vm_mm, addr, pte,
-                  pte_mkold(mk_pte(page, vma->vm_page_prot)));
+       new_pte = pte_mkold(mk_pte(page, vma->vm_page_prot));
+       if (pte_swp_soft_dirty(*pte))
+               new_pte = pte_mksoft_dirty(new_pte);
+       if (pte_swp_uffd_wp(*pte))
+               new_pte = pte_mkuffd_wp(new_pte);
+       set_pte_at(vma->vm_mm, addr, pte, new_pte);
        swap_free(entry);
 out:
        pte_unmap_unlock(pte, ptl);