On 04/23/2015 11:03 PM, Kirill A. Shutemov wrote: > With new refcounting we will be able map the same compound page with > PTEs and PMDs. It requires adjustment to conditions when we can reuse > the page on write-protection fault. > > For PTE fault we can't reuse the page if it's part of huge page. > > For PMD we can only reuse the page if nobody else maps the huge page or > it's part. We can do it by checking page_mapcount() on each sub-page, > but it's expensive. > > The cheaper way is to check page_count() to be equal 1: every mapcount > takes page reference, so this way we can guarantee, that the PMD is the > only mapping. > > This approach can give false negative if somebody pinned the page, but > that doesn't affect correctness. > > Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> > Tested-by: Sasha Levin <sasha.levin@xxxxxxxxxx> Acked-by: Jerome Marchand <jmarchan@xxxxxxxxxx> > --- > include/linux/swap.h | 3 ++- > mm/huge_memory.c | 12 +++++++++++- > mm/swapfile.c | 3 +++ > 3 files changed, 16 insertions(+), 2 deletions(-) > > diff --git a/include/linux/swap.h b/include/linux/swap.h > index 0428e4c84e1d..17cdd6b9456b 100644 > --- a/include/linux/swap.h > +++ b/include/linux/swap.h > @@ -524,7 +524,8 @@ static inline int page_swapcount(struct page *page) > return 0; > } > > -#define reuse_swap_page(page) (page_mapcount(page) == 1) > +#define reuse_swap_page(page) \ > + (!PageTransCompound(page) && page_mapcount(page) == 1) > > static inline int try_to_free_swap(struct page *page) > { > diff --git a/mm/huge_memory.c b/mm/huge_memory.c > index 534f353e12bf..fd8af5b9917f 100644 > --- a/mm/huge_memory.c > +++ b/mm/huge_memory.c > @@ -1103,7 +1103,17 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, > > page = pmd_page(orig_pmd); > VM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page); > - if (page_mapcount(page) == 1) { > + /* > + * We can only reuse the page if nobody else maps the huge page or it's > + * part. We can do it by checking page_mapcount() on each sub-page, but > + * it's expensive. > + * The cheaper way is to check page_count() to be equal 1: every > + * mapcount takes page reference reference, so this way we can > + * guarantee, that the PMD is the only mapping. > + * This can give false negative if somebody pinned the page, but that's > + * fine. > + */ > + if (page_mapcount(page) == 1 && page_count(page) == 1) { > pmd_t entry; > entry = pmd_mkyoung(orig_pmd); > entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma); > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 6dd365d1c488..3cd5f188b996 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -887,6 +887,9 @@ int reuse_swap_page(struct page *page) > VM_BUG_ON_PAGE(!PageLocked(page), page); > if (unlikely(PageKsm(page))) > return 0; > + /* The page is part of THP and cannot be reused */ > + if (PageTransCompound(page)) > + return 0; > count = page_mapcount(page); > if (count <= 1 && PageSwapCache(page)) { > count += page_swapcount(page); >
Attachment:
signature.asc
Description: OpenPGP digital signature