anolis: mm: support unmapping zeropage of the same file offset

ANBZ: #2510

If a file is mapped by differnet processes, it can be shared and
private mapping simultaneously. When the vma with shared mapping
allocates a new page in the page cache, the zero page filled by the
private mapping needs to be unmapped to re-acquire the page in the
page cache.

Signed-off-by: Kaihao Bai <carlo.bai@linux.alibaba.com>
Reviewed-by: zhong jiang <zhongjiang-ali@linux.alibaba.com>
Link: https://gitee.com/anolis/cloud-kernel/pulls/785
Reviewed-by: Xu Yu <xuyu@linux.alibaba.com>
This commit is contained in:
Kaihao Bai 2022-08-15 12:30:17 +08:00 committed by 小龙
parent d0fe960f18
commit 002b186d8f
3 changed files with 54 additions and 0 deletions

View File

@ -99,6 +99,7 @@ enum ttu_flags {
TTU_RMAP_LOCKED = 0x80, /* do not grab rmap lock:
* caller holds it */
TTU_SPLIT_FREEZE = 0x100, /* freeze pte under splitting thp */
TTU_ZEROPAGE = 0x200, /* unmap zero pages of the same offset */
};
#ifdef CONFIG_MMU
@ -197,10 +198,14 @@ int page_referenced(struct page *, int is_locked,
bool try_to_unmap(struct page *, enum ttu_flags flags);
void try_to_unmap_zeropage(struct page *page, enum ttu_flags flags);
/* Avoid racy checks */
#define PVMW_SYNC (1 << 0)
/* Look for migarion entries rather than present PTEs */
#define PVMW_MIGRATION (1 << 1)
/* Avoid extra judgement of zeropage */
#define PVMW_ZEROPAGE (1 << 2)
struct page_vma_mapped_walk {
struct page *page;
@ -291,6 +296,7 @@ static inline int page_referenced(struct page *page, int is_locked,
}
#define try_to_unmap(page, refs) false
#define try_to_unmap_zeropage(page, refs) false
static inline int page_mkclean(struct page *page)
{

View File

@ -110,6 +110,9 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw)
return false;
pfn = pte_pfn(*pvmw->pte);
if (pvmw->flags & PVMW_ZEROPAGE)
return is_zero_pfn(pfn);
}
return pfn_is_match(pvmw->page, pfn);

View File

@ -1394,6 +1394,13 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
if (flags & TTU_SYNC)
pvmw.flags = PVMW_SYNC;
/*
* If the same mapping offset of a file is alreadly mapped with
* zeropage, the zeropage mapping needs to be unmapped.
*/
if (flags & TTU_ZEROPAGE)
pvmw.flags = PVMW_ZEROPAGE;
/* munlock has nothing to gain from examining un-locked vmas */
if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
return true;
@ -1440,6 +1447,18 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
}
#endif
/*
* If the page is zeropage, we just unmap it and return.
* Because currently compound page is not supported.
*/
if (flags & TTU_ZEROPAGE) {
ptep_clear_flush(vma, pvmw.address, pvmw.pte);
mmu_notifier_invalidate_range(mm, pvmw.address,
pvmw.address + PAGE_SIZE);
page_vma_mapped_walk_done(&pvmw);
break;
}
/*
* If the page is mlock()d, we cannot swap it out.
* If it's recently referenced (perhaps page_referenced
@ -1799,6 +1818,32 @@ bool try_to_unmap(struct page *page, enum ttu_flags flags)
return !page_mapcount(page);
}
/**
* try_to_unmap_zeropage - try to remove all page table mappings to a zero page
* with the same offset. If the flag doesn't contain TTU_ZEROPAGE, this function
* does no thing.
* @page: the page to get unmapped
* @flags: action and flags
*
* Tries to remove all the page table entries which are mapping zero
* page with the same offset, used in the pageout path. Caller must hold the page
* lock of the newly allocated page.
*
* During rmap_walk, it holds the i_mmap_sem to avoid modify VMA which not expected.
*/
void try_to_unmap_zeropage(struct page *page, enum ttu_flags flags)
{
struct rmap_walk_control rwc = {
.rmap_one = try_to_unmap_one,
.arg = (void *)flags,
};
if (!(flags & TTU_ZEROPAGE))
return;
rmap_walk(page, &rwc);
}
/**
* try_to_munlock - try to munlock a page
* @page: the page to be munlocked