lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <8c4c158d-8cbc-479e-8561-de9ce961c9cd@redhat.com>
Date: Thu, 8 May 2025 21:18:55 +1000
From: Gavin Shan <gshan@...hat.com>
To: Ryan Roberts <ryan.roberts@....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 5/8/25 7:22 PM, Ryan Roberts wrote:
> 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>
> 

Thanks.

> 
> 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.
> 

Right, pmd_trans_huge() is the superset of pmd_sect() and pmd_leaf(). The later
two macros are equivalent in logic. I had a quick check on the sites where
pmd_sect() and pmd_leaf() are called, there seems no PRESENT_INVALID case. So
I think it would be safe to sync up pmd_leaf() to pmd_trans_huges(), and then
make the later one as an alias to pmd_leaf(). Besides, pmd_sect() needs to be
replaced by pmd_leaf() as you're suggesting.

Hopefully, I don't miss anything before I'm going to prepare the patches, which
will be stacked up on current one. I'm understanding you want something (for
PMD) like below.

----

static inline int pmd_leaf(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_present(pmd) && !pmd_table(__pmd(pmd_val(pmd) | PTE_VALID));
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd)	pmd_leaf(pmd)
#endif

With above changes, replace pmd_sect() with pmd_leaf() so that pmd_sect() can be
completely dropped.

Thanks,
Gavin



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ