[PATCH 2/3] powerpc/64s: make HPTE lock and native_tlbie_lock irq-safe

Guenter Roeck linux at roeck-us.net
Fri Oct 14 11:18:26 AEDT 2022


On Fri, Oct 14, 2022 at 09:07:09AM +1000, Nicholas Piggin wrote:
> With kfence enabled, there are several cases where HPTE and TLBIE locks
> are called from softirq context, for example:
> 
>   WARNING: inconsistent lock state
>   6.0.0-11845-g0cbbc95b12ac #1 Tainted: G                 N
>   --------------------------------
>   inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
>   swapper/0/1 [HC0[0]:SC0[0]:HE1:SE1] takes:
>   c000000002734de8 (native_tlbie_lock){+.?.}-{2:2}, at: .native_hpte_updateboltedpp+0x1a4/0x600
>   {IN-SOFTIRQ-W} state was registered at:
>     .lock_acquire+0x20c/0x520
>     ._raw_spin_lock+0x4c/0x70
>     .native_hpte_invalidate+0x62c/0x840
>     .hash__kernel_map_pages+0x450/0x640
>     .kfence_protect+0x58/0xc0
>     .kfence_guarded_free+0x374/0x5a0
>     .__slab_free+0x3d0/0x630
>     .put_cred_rcu+0xcc/0x120
>     .rcu_core+0x3c4/0x14e0
>     .__do_softirq+0x1dc/0x7dc
>     .do_softirq_own_stack+0x40/0x60
> 
> Fix this by consistently disabling irqs while taking either of these
> locks. Don't just disable bh because several of the more common cases
> already disable irqs, so this just makes the locks always irq-safe.
> 
> Reported-by: Guenter Roeck <linux at roeck-us.net>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>

Tested-by: Guenter Roeck <linux at roeck-us.net>

> ---
>  arch/powerpc/mm/book3s64/hash_native.c | 27 ++++++++++++++++++++++++--
>  1 file changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/mm/book3s64/hash_native.c b/arch/powerpc/mm/book3s64/hash_native.c
> index 02d0c210a1ce..065f9c542a63 100644
> --- a/arch/powerpc/mm/book3s64/hash_native.c
> +++ b/arch/powerpc/mm/book3s64/hash_native.c
> @@ -268,8 +268,11 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
>  {
>  	struct hash_pte *hptep = htab_address + hpte_group;
>  	unsigned long hpte_v, hpte_r;
> +	unsigned long flags;
>  	int i;
>  
> +	local_irq_save(flags);
> +
>  	if (!(vflags & HPTE_V_BOLTED)) {
>  		DBG_LOW("    insert(group=%lx, vpn=%016lx, pa=%016lx,"
>  			" rflags=%lx, vflags=%lx, psize=%d)\n",
> @@ -288,8 +291,10 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
>  		hptep++;
>  	}
>  
> -	if (i == HPTES_PER_GROUP)
> +	if (i == HPTES_PER_GROUP) {
> +		local_irq_restore(flags);
>  		return -1;
> +	}
>  
>  	hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
>  	hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
> @@ -304,7 +309,6 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
>  		hpte_v = hpte_old_to_new_v(hpte_v);
>  	}
>  
> -	release_hpte_lock();
>  	hptep->r = cpu_to_be64(hpte_r);
>  	/* Guarantee the second dword is visible before the valid bit */
>  	eieio();
> @@ -312,10 +316,13 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
>  	 * Now set the first dword including the valid bit
>  	 * NOTE: this also unlocks the hpte
>  	 */
> +	release_hpte_lock();
>  	hptep->v = cpu_to_be64(hpte_v);
>  
>  	__asm__ __volatile__ ("ptesync" : : : "memory");
>  
> +	local_irq_restore(flags);
> +
>  	return i | (!!(vflags & HPTE_V_SECONDARY) << 3);
>  }
>  
> @@ -366,6 +373,9 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
>  	struct hash_pte *hptep = htab_address + slot;
>  	unsigned long hpte_v, want_v;
>  	int ret = 0, local = 0;
> +	unsigned long irqflags;
> +
> +	local_irq_save(irqflags);
>  
>  	want_v = hpte_encode_avpn(vpn, bpsize, ssize);
>  
> @@ -409,6 +419,8 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
>  	if (!(flags & HPTE_NOHPTE_UPDATE))
>  		tlbie(vpn, bpsize, apsize, ssize, local);
>  
> +	local_irq_restore(irqflags);
> +
>  	return ret;
>  }
>  
> @@ -472,6 +484,9 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
>  	unsigned long vsid;
>  	long slot;
>  	struct hash_pte *hptep;
> +	unsigned long flags;
> +
> +	local_irq_save(flags);
>  
>  	vsid = get_kernel_vsid(ea, ssize);
>  	vpn = hpt_vpn(ea, vsid, ssize);
> @@ -490,6 +505,8 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
>  	 * actual page size will be same.
>  	 */
>  	tlbie(vpn, psize, psize, ssize, 0);
> +
> +	local_irq_restore(flags);
>  }
>  
>  /*
> @@ -503,6 +520,9 @@ static int native_hpte_removebolted(unsigned long ea, int psize, int ssize)
>  	unsigned long vsid;
>  	long slot;
>  	struct hash_pte *hptep;
> +	unsigned long flags;
> +
> +	local_irq_save(flags);
>  
>  	vsid = get_kernel_vsid(ea, ssize);
>  	vpn = hpt_vpn(ea, vsid, ssize);
> @@ -520,6 +540,9 @@ static int native_hpte_removebolted(unsigned long ea, int psize, int ssize)
>  
>  	/* Invalidate the TLB */
>  	tlbie(vpn, psize, psize, ssize, 0);
> +
> +	local_irq_restore(flags);
> +
>  	return 0;
>  }
>  
> -- 
> 2.37.2
> 


More information about the Linuxppc-dev mailing list