Re: [RFC PATCH v2 5/9] mm, pgtable: Add a refcount to PTE table
From: Nadav Amit
Date: Tue Sep 27 2022 - 13:59:35 EST
On Sep 27, 2022, at 9:29 AM, Chih-En Lin <shiyn.lin@xxxxxxxxx> wrote:
> Reuse the _refcount in struct page for the page table to maintain the
> number of process references to COWed PTE table. Before decreasing the
> refcount, it will check whether refcount is one or not for reusing
> shared PTE table.
>
> Signed-off-by: Chih-En Lin <shiyn.lin@xxxxxxxxx>
> ---
> include/linux/mm.h | 1 +
> include/linux/pgtable.h | 28 ++++++++++++++++++++++++++++
> mm/memory.c | 1 +
> 3 files changed, 30 insertions(+)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 965523dcca3b8..bfe6a8c7ab9ed 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2290,6 +2290,7 @@ static inline bool pgtable_pte_page_ctor(struct page *page)
> __SetPageTable(page);
> inc_lruvec_page_state(page, NR_PAGETABLE);
> page->cow_pte_owner = NULL;
> + set_page_count(page, 1);
> return true;
> }
>
> diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
> index 25c1e5c42fdf3..8b497d7d800ed 100644
> --- a/include/linux/pgtable.h
> +++ b/include/linux/pgtable.h
> @@ -9,6 +9,7 @@
> #ifdef CONFIG_MMU
>
> #include <linux/mm_types.h>
> +#include <linux/page_ref.h>
> #include <linux/bug.h>
> #include <linux/errno.h>
> #include <asm-generic/pgtable_uffd.h>
> @@ -628,6 +629,33 @@ static inline bool cow_pte_owner_is_same(pmd_t *pmd, pmd_t *owner)
> return smp_load_acquire(&pmd_page(*pmd)->cow_pte_owner) == owner;
> }
>
> +static inline int pmd_get_pte(pmd_t *pmd)
> +{
> + return page_ref_inc_return(pmd_page(*pmd));
> +}
> +
> +/*
> + * If the COW PTE refcount is 1, instead of decreasing the counter,
> + * clear write protection of the corresponding PMD entry and reset
> + * the COW PTE owner to reuse the table.
> + * But if the reuse parameter is false, do not thing. This help us
> + * to handle the situation that PTE table we already handled.
> + */
> +static inline int pmd_put_pte(struct vm_area_struct *vma, pmd_t *pmd,
> + unsigned long addr, bool reuse)
> +{
> + if (!page_ref_add_unless(pmd_page(*pmd), -1, 1) && reuse) {
> + cow_pte_fallback(vma, pmd, addr);
Is there some assumption that pmd_get_pte() would not be called between the
page_ref_add_unless() and cow_pte_fallback()?
Hard to know without comments or context.