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:
parent
d0fe960f18
commit
002b186d8f
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
45
mm/rmap.c
45
mm/rmap.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue