[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0c6455f1-5a7b-4ae3-b7f8-7f163b6abc9a@arm.com>
Date: Thu, 8 May 2025 10:22:13 +0100
From: Ryan Roberts <ryan.roberts@....com>
To: Gavin Shan <gshan@...hat.com>, linux-arm-kernel@...ts.infradead.org
Cc: linux-kernel@...r.kernel.org, catalin.marinas@....com, will@...nel.org,
anshuman.khandual@....com, dev.jain@....com, peterx@...hat.com,
joey.gouly@....com, yangyicong@...ilicon.com, shan.gavin@...il.com
Subject: Re: [PATCH v2] arm64: mm: Drop redundant check in pmd_trans_huge()
On 08/05/2025 09:52, Gavin Shan wrote:
> pmd_val(pmd) is redundant because a positive pmd_present(pmd) ensures
> a positive pmd_val(pmd) according to their definitions like below.
>
> #define pmd_val(x) ((x).pmd)
> #define pmd_present(pmd) pte_present(pmd_pte(pmd))
> #define pte_present(pte) (pte_valid(pte) || pte_present_invalid(pte))
> #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
> #define pte_present_invalid(pte) \
> ((pte_val(pte) & (PTE_VALID | PTE_PRESENT_INVALID)) == PTE_PRESENT_INVALID)
>
> pte_present() can't be positive unless either of the flag PTE_VALID or
> PTE_PRESENT_INVALID is set. In this case, pmd_val(pmd) should be positive
> either.
>
> So lets drop the redundant check pmd_val(pmd) and no functional changes
> intended.
>
> Signed-off-by: Gavin Shan <gshan@...hat.com>
> Reviewed-by: Dev Jain <dev.jain@....com>
> Reviewed-by: Anshuman Khandual <anshuman.khandual@....com>
> ---
> v1: https://lore.kernel.org/linux-arm-kernel/4e5941f8-7e61-4a63-a669-bee1601093a6@arm.com/T/#u
> v2: Improved commit log per Anshuman
> ---
> arch/arm64/include/asm/pgtable.h | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index d3b538be1500..2599b9b8666f 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -739,8 +739,7 @@ static inline int pmd_trans_huge(pmd_t pmd)
> * If pmd is present-invalid, pmd_table() won't detect it
> * as a table, so force the valid bit for the comparison.
> */
> - return pmd_val(pmd) && pmd_present(pmd) &&
> - !pmd_table(__pmd(pmd_val(pmd) | PTE_VALID));
> + return pmd_present(pmd) && !pmd_table(__pmd(pmd_val(pmd) | PTE_VALID));
> }
> #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>
I agree the cleanup is useful and correct, so:
Reviewed-by: Ryan Roberts <ryan.roberts@....com>
But personally I find it maddening that we have:
#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)
#define pmd_leaf(pmd) (pmd_present(pmd) && !pmd_table(pmd))
static inline int pmd_trans_huge(pmd_t pmd)
{
/*
* If pmd is present-invalid, pmd_table() won't detect it
* as a table, so force the valid bit for the comparison.
*/
return pmd_val(pmd) && pmd_present(pmd) &&
!pmd_table(__pmd(pmd_val(pmd) | PTE_VALID));
}
Which all do basically the same thing, but with some very subtle differences.
Surely we should really only need 2 basic functions; is it a table? is it a
leaf? Then pmd_sect() and pmd_trans_huge() should just be aliases of pmd_leaf().
I *think* pmd_sect() and pmd_leaf() are really just 2 different ways of
expressing the same thing? Which is "Is this a *VALID* leaf?"
And pmd_trans_huge() is asking "Is this either a *VALID* or *PRESENT_INVALID* leaf?"
I'm not sure if we can relax pmd_sect()/pmd_leaf() to give the same semantics as
pmd_trans_huge()? I would guess we can. In which case it would be nice to clean
this all up to a single implementation and make the others wrappers. Or better
yet, fix the callers to consistently use pmd_leaf(). And do the same for pud.
Thanks,
Ryan
Powered by blists - more mailing lists