All of lore.kernel.org
 help / color / mirror / Atom feed
From: Catalin Marinas <catalin.marinas@arm.com>
To: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: mark.rutland@arm.com, Suzuki Poulose <suzuki.poulose@arm.com>,
	Marc Zyngier <maz@kernel.org>,
	linux-kernel@vger.kernel.org, linux-mm@kvack.org, ziy@nvidia.com,
	will@kernel.org, linux-arm-kernel@lists.infradead.org
Subject: Re: [RFC V2 1/2] arm64/mm: Change THP helpers per generic memory semantics
Date: Thu, 2 Jul 2020 13:11:35 +0100	[thread overview]
Message-ID: <20200702121135.GD22241@gaia> (raw)
In-Reply-To: <1592226918-26378-2-git-send-email-anshuman.khandual@arm.com>

Hi Anshuman,

On Mon, Jun 15, 2020 at 06:45:17PM +0530, Anshuman Khandual wrote:
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -353,15 +353,92 @@ static inline int pmd_protnone(pmd_t pmd)
>  }
>  #endif
>  
> +#define pmd_table(pmd)	((pmd_val(pmd) & PMD_TYPE_MASK) ==  PMD_TYPE_TABLE)
> +#define pmd_sect(pmd)	((pmd_val(pmd) & PMD_TYPE_MASK) ==  PMD_TYPE_SECT)
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>  /*
> - * THP definitions.
> + * PMD Level Encoding (THP Enabled)
> + *
> + * 0b00 - Not valid	Not present	NA
> + * 0b10 - Not valid	Present		Huge  (Splitting)
> + * 0b01 - Valid		Present		Huge  (Mapped)
> + * 0b11 - Valid		Present		Table (Mapped)
>   */

I wonder whether it would be easier to read if we add a dedicated
PMD_SPLITTING bit, only when bit 0 is cleared. This bit can be high (say
59), it doesn't really matter as the entry is not valid.

The only doubt I have is that pmd_mkinvalid() is used in other contexts
when it's not necessarily splitting a pmd (search for the
pmdp_invalidate() calls). So maybe a better name like PMD_PRESENT with a
comment that pmd_to_page() is valid (i.e. no migration or swap entry).
Feel free to suggest a better name.

> +static inline pmd_t pmd_mksplitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
>  
> -#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> -#define pmd_trans_huge(pmd)	(pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
> +	return __pmd((val & ~PMD_TYPE_MASK) | PMD_TABLE_BIT);
> +}
> +
> +static inline pmd_t pmd_clrsplitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
> +
> +	return __pmd((val & ~PMD_TYPE_MASK) | PMD_TYPE_SECT);
> +}
> +
> +static inline bool pmd_splitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
> +
> +	if ((val & PMD_TYPE_MASK) == PMD_TABLE_BIT)
> +		return true;
> +	return false;
> +}
> +
> +static inline bool pmd_mapped(pmd_t pmd)
> +{
> +	return pmd_sect(pmd);
> +}
> +
> +static inline pmd_t pmd_mkinvalid(pmd_t pmd)
> +{
> +	/*
> +	 * Invalidation should not have been invoked on
> +	 * a PMD table entry. Just warn here otherwise.
> +	 */
> +	WARN_ON(pmd_table(pmd));
> +	return pmd_mksplitting(pmd);
> +}

And here we wouldn't need t worry about table checks.

> +static inline int pmd_present(pmd_t pmd);
> +
> +static inline int pmd_trans_huge(pmd_t pmd)
> +{
> +	if (!pmd_present(pmd))
> +		return 0;
> +
> +	if (!pmd_val(pmd))
> +		return 0;
> +
> +	if (pmd_mapped(pmd))
> +		return 1;
> +
> +	if (pmd_splitting(pmd))
> +		return 1;
> +	return 0;

Doesn't your new pmd_present() already check for splitting? I think
checking for bit 0 and the new PMD_PRESENT. That would be similar to
what we do with PTE_PROT_NONE. Actually, you could use the same bit for
both.

> +}
> +
> +void set_pmd_at(struct mm_struct *mm, unsigned long addr,
> +		pmd_t *pmdp, pmd_t pmd);
>  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>  
> -#define pmd_present(pmd)	pte_present(pmd_pte(pmd))
> +static inline int pmd_present(pmd_t pmd)
> +{
> +	pte_t pte = pmd_pte(pmd);
> +
> +	if (pte_present(pte))
> +		return 1;
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +	if (pmd_splitting(pmd))
> +		return 1;
> +#endif
> +	return 0;
> +}

[...]

> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 990929c8837e..337519031115 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -22,6 +22,8 @@
>  #include <linux/io.h>
>  #include <linux/mm.h>
>  #include <linux/vmalloc.h>
> +#include <linux/swap.h>
> +#include <linux/swapops.h>
>  
>  #include <asm/barrier.h>
>  #include <asm/cputype.h>
> @@ -1483,3 +1485,21 @@ static int __init prevent_bootmem_remove_init(void)
>  }
>  device_initcall(prevent_bootmem_remove_init);
>  #endif
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +void set_pmd_at(struct mm_struct *mm, unsigned long addr,
> +		pmd_t *pmdp, pmd_t pmd)
> +{
> +	/*
> +	 * PMD migration entries need to retain splitting PMD
> +	 * representation created with pmdp_invalidate(). But
> +	 * any non-migration entry which just might have been
> +	 * invalidated previously, still need be a normal huge
> +	 * page. Hence selectively clear splitting entries.
> +	 */
> +	if (!is_migration_entry(pmd_to_swp_entry(pmd)))
> +		pmd = pmd_clrsplitting(pmd);
> +
> +	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd));
> +}
> +#endif

So a pmdp_invalidate() returns the old pmd. Do we ever need to rebuild a
pmd based on the actual bits in the new invalidated pmdp? Wondering how
the table bit ends up here that we need to pmd_clrsplitting().

-- 
Catalin

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Catalin Marinas <catalin.marinas@arm.com>
To: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: linux-mm@kvack.org, linux-arm-kernel@lists.infradead.org,
	will@kernel.org, mark.rutland@arm.com, ziy@nvidia.com,
	Marc Zyngier <maz@kernel.org>,
	Suzuki Poulose <suzuki.poulose@arm.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC V2 1/2] arm64/mm: Change THP helpers per generic memory semantics
Date: Thu, 2 Jul 2020 13:11:35 +0100	[thread overview]
Message-ID: <20200702121135.GD22241@gaia> (raw)
In-Reply-To: <1592226918-26378-2-git-send-email-anshuman.khandual@arm.com>

Hi Anshuman,

On Mon, Jun 15, 2020 at 06:45:17PM +0530, Anshuman Khandual wrote:
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -353,15 +353,92 @@ static inline int pmd_protnone(pmd_t pmd)
>  }
>  #endif
>  
> +#define pmd_table(pmd)	((pmd_val(pmd) & PMD_TYPE_MASK) ==  PMD_TYPE_TABLE)
> +#define pmd_sect(pmd)	((pmd_val(pmd) & PMD_TYPE_MASK) ==  PMD_TYPE_SECT)
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>  /*
> - * THP definitions.
> + * PMD Level Encoding (THP Enabled)
> + *
> + * 0b00 - Not valid	Not present	NA
> + * 0b10 - Not valid	Present		Huge  (Splitting)
> + * 0b01 - Valid		Present		Huge  (Mapped)
> + * 0b11 - Valid		Present		Table (Mapped)
>   */

I wonder whether it would be easier to read if we add a dedicated
PMD_SPLITTING bit, only when bit 0 is cleared. This bit can be high (say
59), it doesn't really matter as the entry is not valid.

The only doubt I have is that pmd_mkinvalid() is used in other contexts
when it's not necessarily splitting a pmd (search for the
pmdp_invalidate() calls). So maybe a better name like PMD_PRESENT with a
comment that pmd_to_page() is valid (i.e. no migration or swap entry).
Feel free to suggest a better name.

> +static inline pmd_t pmd_mksplitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
>  
> -#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> -#define pmd_trans_huge(pmd)	(pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
> +	return __pmd((val & ~PMD_TYPE_MASK) | PMD_TABLE_BIT);
> +}
> +
> +static inline pmd_t pmd_clrsplitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
> +
> +	return __pmd((val & ~PMD_TYPE_MASK) | PMD_TYPE_SECT);
> +}
> +
> +static inline bool pmd_splitting(pmd_t pmd)
> +{
> +	unsigned long val = pmd_val(pmd);
> +
> +	if ((val & PMD_TYPE_MASK) == PMD_TABLE_BIT)
> +		return true;
> +	return false;
> +}
> +
> +static inline bool pmd_mapped(pmd_t pmd)
> +{
> +	return pmd_sect(pmd);
> +}
> +
> +static inline pmd_t pmd_mkinvalid(pmd_t pmd)
> +{
> +	/*
> +	 * Invalidation should not have been invoked on
> +	 * a PMD table entry. Just warn here otherwise.
> +	 */
> +	WARN_ON(pmd_table(pmd));
> +	return pmd_mksplitting(pmd);
> +}

And here we wouldn't need t worry about table checks.

> +static inline int pmd_present(pmd_t pmd);
> +
> +static inline int pmd_trans_huge(pmd_t pmd)
> +{
> +	if (!pmd_present(pmd))
> +		return 0;
> +
> +	if (!pmd_val(pmd))
> +		return 0;
> +
> +	if (pmd_mapped(pmd))
> +		return 1;
> +
> +	if (pmd_splitting(pmd))
> +		return 1;
> +	return 0;

Doesn't your new pmd_present() already check for splitting? I think
checking for bit 0 and the new PMD_PRESENT. That would be similar to
what we do with PTE_PROT_NONE. Actually, you could use the same bit for
both.

> +}
> +
> +void set_pmd_at(struct mm_struct *mm, unsigned long addr,
> +		pmd_t *pmdp, pmd_t pmd);
>  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>  
> -#define pmd_present(pmd)	pte_present(pmd_pte(pmd))
> +static inline int pmd_present(pmd_t pmd)
> +{
> +	pte_t pte = pmd_pte(pmd);
> +
> +	if (pte_present(pte))
> +		return 1;
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +	if (pmd_splitting(pmd))
> +		return 1;
> +#endif
> +	return 0;
> +}

[...]

> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 990929c8837e..337519031115 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -22,6 +22,8 @@
>  #include <linux/io.h>
>  #include <linux/mm.h>
>  #include <linux/vmalloc.h>
> +#include <linux/swap.h>
> +#include <linux/swapops.h>
>  
>  #include <asm/barrier.h>
>  #include <asm/cputype.h>
> @@ -1483,3 +1485,21 @@ static int __init prevent_bootmem_remove_init(void)
>  }
>  device_initcall(prevent_bootmem_remove_init);
>  #endif
> +
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +void set_pmd_at(struct mm_struct *mm, unsigned long addr,
> +		pmd_t *pmdp, pmd_t pmd)
> +{
> +	/*
> +	 * PMD migration entries need to retain splitting PMD
> +	 * representation created with pmdp_invalidate(). But
> +	 * any non-migration entry which just might have been
> +	 * invalidated previously, still need be a normal huge
> +	 * page. Hence selectively clear splitting entries.
> +	 */
> +	if (!is_migration_entry(pmd_to_swp_entry(pmd)))
> +		pmd = pmd_clrsplitting(pmd);
> +
> +	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd));
> +}
> +#endif

So a pmdp_invalidate() returns the old pmd. Do we ever need to rebuild a
pmd based on the actual bits in the new invalidated pmdp? Wondering how
the table bit ends up here that we need to pmd_clrsplitting().

-- 
Catalin


  reply	other threads:[~2020-07-02 12:13 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-15 13:15 [RFC V2 0/2] arm64/mm: Enable THP migration Anshuman Khandual
2020-06-15 13:15 ` Anshuman Khandual
2020-06-15 13:15 ` [RFC V2 1/2] arm64/mm: Change THP helpers per generic memory semantics Anshuman Khandual
2020-06-15 13:15   ` Anshuman Khandual
2020-07-02 12:11   ` Catalin Marinas [this message]
2020-07-02 12:11     ` Catalin Marinas
2020-07-06  3:57     ` Anshuman Khandual
2020-07-06  3:57       ` Anshuman Khandual
2020-07-07 17:44       ` Catalin Marinas
2020-07-07 17:44         ` Catalin Marinas
2020-08-17  5:43         ` Anshuman Khandual
2020-08-17  5:43           ` Anshuman Khandual
2020-06-15 13:15 ` [RFC V2 2/2] arm64/mm: Enable THP migration Anshuman Khandual
2020-06-15 13:15   ` Anshuman Khandual

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200702121135.GD22241@gaia \
    --to=catalin.marinas@arm.com \
    --cc=anshuman.khandual@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=suzuki.poulose@arm.com \
    --cc=will@kernel.org \
    --cc=ziy@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.