3.16.66-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Martin Schwidefsky <schwidef...@de.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.carst...@de.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carst...@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidef...@de.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 <b...@decadent.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);
 }
 

Reply via email to