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 b86d1cc..e45874f 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);