You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
mm: save soft-dirty bits on file pages
Andy reported that if file page get reclaimed we lose the soft-dirty bit if it was there, so save _PAGE_BIT_SOFT_DIRTY bit when page address get encoded into pte entry. Thus when #pf happens on such non-present pte we can restore it back. Reported-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Acked-by: Pavel Emelyanov <xemul@parallels.com> Cc: Matt Mackall <mpm@selenic.com> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Peter Zijlstra <peterz@infradead.org> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Cc: Minchan Kim <minchan@kernel.org> Cc: Wanpeng Li <liwanp@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
179ef71cbc
commit
41bb3476b3
+9
-4
@@ -57,17 +57,22 @@ static int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
unsigned long addr, unsigned long pgoff, pgprot_t prot)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
pte_t *pte;
|
||||
pte_t *pte, ptfile;
|
||||
spinlock_t *ptl;
|
||||
|
||||
pte = get_locked_pte(mm, addr, &ptl);
|
||||
if (!pte)
|
||||
goto out;
|
||||
|
||||
if (!pte_none(*pte))
|
||||
zap_pte(mm, vma, addr, pte);
|
||||
ptfile = pgoff_to_pte(pgoff);
|
||||
|
||||
set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
|
||||
if (!pte_none(*pte)) {
|
||||
if (pte_present(*pte) && pte_soft_dirty(*pte))
|
||||
pte_file_mksoft_dirty(ptfile);
|
||||
zap_pte(mm, vma, addr, pte);
|
||||
}
|
||||
|
||||
set_pte_at(mm, addr, pte, ptfile);
|
||||
/*
|
||||
* We don't need to run update_mmu_cache() here because the "file pte"
|
||||
* being installed by install_file_pte() is not a real pte - it's a
|
||||
|
||||
+8
-3
@@ -1141,9 +1141,12 @@ again:
|
||||
continue;
|
||||
if (unlikely(details) && details->nonlinear_vma
|
||||
&& linear_page_index(details->nonlinear_vma,
|
||||
addr) != page->index)
|
||||
set_pte_at(mm, addr, pte,
|
||||
pgoff_to_pte(page->index));
|
||||
addr) != page->index) {
|
||||
pte_t ptfile = pgoff_to_pte(page->index);
|
||||
if (pte_soft_dirty(ptent))
|
||||
pte_file_mksoft_dirty(ptfile);
|
||||
set_pte_at(mm, addr, pte, ptfile);
|
||||
}
|
||||
if (PageAnon(page))
|
||||
rss[MM_ANONPAGES]--;
|
||||
else {
|
||||
@@ -3410,6 +3413,8 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
entry = mk_pte(page, vma->vm_page_prot);
|
||||
if (flags & FAULT_FLAG_WRITE)
|
||||
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
|
||||
else if (pte_file(orig_pte) && pte_file_soft_dirty(orig_pte))
|
||||
pte_mksoft_dirty(entry);
|
||||
if (anon) {
|
||||
inc_mm_counter_fast(mm, MM_ANONPAGES);
|
||||
page_add_new_anon_rmap(page, vma, address);
|
||||
|
||||
@@ -1405,8 +1405,12 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
|
||||
pteval = ptep_clear_flush(vma, address, pte);
|
||||
|
||||
/* If nonlinear, store the file page offset in the pte. */
|
||||
if (page->index != linear_page_index(vma, address))
|
||||
set_pte_at(mm, address, pte, pgoff_to_pte(page->index));
|
||||
if (page->index != linear_page_index(vma, address)) {
|
||||
pte_t ptfile = pgoff_to_pte(page->index);
|
||||
if (pte_soft_dirty(pteval))
|
||||
pte_file_mksoft_dirty(ptfile);
|
||||
set_pte_at(mm, address, pte, ptfile);
|
||||
}
|
||||
|
||||
/* Move the dirty bit to the physical page now the pte is gone. */
|
||||
if (pte_dirty(pteval))
|
||||
|
||||
Reference in New Issue
Block a user