[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1556377989.498629332@decadent.org.uk>
Date: Sat, 27 Apr 2019 16:13:09 +0100
From: Ben Hutchings <ben@...adent.org.uk>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC: akpm@...ux-foundation.org, Denis Kirjanov <kda@...ux-powerpc.org>,
"Heiko Carstens" <heiko.carstens@...ibm.com>,
"Martin Schwidefsky" <schwidefsky@...ibm.com>
Subject: [PATCH 3.16 035/202] s390/mm: always force a load of the primary
ASCE on context switch
3.16.66-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Martin Schwidefsky <schwidefsky@...ibm.com>
commit a38662084c8bdb829ff486468c7ea801c13fcc34 upstream.
The ASCE of an mm_struct can be modified after a task has been created,
e.g. via crst_table_downgrade for a compat process. The active_mm logic
to avoid the switch_mm call if the next task is a kernel thread can
lead to a situation where switch_mm is called where 'prev == next' is
true but 'prev->context.asce == next->context.asce' is not.
This can lead to a situation where a CPU uses the outdated ASCE to run
a task. The result can be a crash, endless loops and really subtle
problem due to TLBs being created with an invalid ASCE.
Fixes: 53e857f30867 ("s390/mm,tlb: race of lazy TLB flush vs. recreation")
Reported-by: Heiko Carstens <heiko.carstens@...ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@...ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@...ibm.com>
[bwh: Backported to 3.16:
- Keep the updates of mm_context_t::attach_count conditional on prev != next
- Keep the update of mm_context_t::cpu_attach_mask conditional on both
MACHINE_HAS_TLB_LC and prev != next
- Adjust context]
Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -69,17 +69,17 @@ static inline void switch_mm(struct mm_s
{
int cpu = smp_processor_id();
- if (prev == next)
- return;
if (MACHINE_HAS_TLB_LC)
cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
/* Clear old ASCE by loading the kernel ASCE. */
__ctl_load(S390_lowcore.kernel_asce, 1, 1);
__ctl_load(S390_lowcore.kernel_asce, 7, 7);
- atomic_inc(&next->context.attach_count);
- atomic_dec(&prev->context.attach_count);
- if (MACHINE_HAS_TLB_LC)
- cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
+ if (prev != next) {
+ atomic_inc(&next->context.attach_count);
+ atomic_dec(&prev->context.attach_count);
+ if (MACHINE_HAS_TLB_LC)
+ cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
+ }
S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd);
}
Powered by blists - more mailing lists