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:
|
TTU_RMAP_LOCKED = 0x80, /* do not grab rmap lock:
|
||||||
* caller holds it */
|
* caller holds it */
|
||||||
TTU_SPLIT_FREEZE = 0x100, /* freeze pte under splitting thp */
|
TTU_SPLIT_FREEZE = 0x100, /* freeze pte under splitting thp */
|
||||||
|
TTU_ZEROPAGE = 0x200, /* unmap zero pages of the same offset */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#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);
|
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 */
|
/* Avoid racy checks */
|
||||||
#define PVMW_SYNC (1 << 0)
|
#define PVMW_SYNC (1 << 0)
|
||||||
/* Look for migarion entries rather than present PTEs */
|
/* Look for migarion entries rather than present PTEs */
|
||||||
#define PVMW_MIGRATION (1 << 1)
|
#define PVMW_MIGRATION (1 << 1)
|
||||||
|
/* Avoid extra judgement of zeropage */
|
||||||
|
#define PVMW_ZEROPAGE (1 << 2)
|
||||||
|
|
||||||
struct page_vma_mapped_walk {
|
struct page_vma_mapped_walk {
|
||||||
struct page *page;
|
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(page, refs) false
|
||||||
|
#define try_to_unmap_zeropage(page, refs) false
|
||||||
|
|
||||||
static inline int page_mkclean(struct page *page)
|
static inline int page_mkclean(struct page *page)
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,6 +110,9 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pfn = pte_pfn(*pvmw->pte);
|
pfn = pte_pfn(*pvmw->pte);
|
||||||
|
|
||||||
|
if (pvmw->flags & PVMW_ZEROPAGE)
|
||||||
|
return is_zero_pfn(pfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pfn_is_match(pvmw->page, 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)
|
if (flags & TTU_SYNC)
|
||||||
pvmw.flags = PVMW_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 */
|
/* munlock has nothing to gain from examining un-locked vmas */
|
||||||
if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
|
if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1440,6 +1447,18 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
|
||||||
}
|
}
|
||||||
#endif
|
#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 the page is mlock()d, we cannot swap it out.
|
||||||
* If it's recently referenced (perhaps page_referenced
|
* 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);
|
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
|
* try_to_munlock - try to munlock a page
|
||||||
* @page: the page to be munlocked
|
* @page: the page to be munlocked
|
||||||
|
|
Loading…
Reference in New Issue