Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Nov 2017 20:14:50 +0000 (12:14 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Nov 2017 20:14:50 +0000 (12:14 -0800)
Pull x86 fixes from Ingo Molnar:
 "Two fixes:

   - A PCID related revert that fixes power management and performance
     regressions.

   - The module loader robustization and sanity check commit is rather
     fresh, but it looked like a good idea to apply because of the
     hidden data corruption problem such invalid modules could cause"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/module: Detect and skip invalid relocations
  Revert "x86/mm: Stop calling leave_mm() in idle code"

arch/ia64/include/asm/acpi.h
arch/x86/include/asm/acpi.h
arch/x86/kernel/module.c
arch/x86/mm/tlb.c
drivers/acpi/processor_idle.c
drivers/idle/intel_idle.c

index c86a947f5368633b86d1a8e5dc7ddd1803982c64..a3d0211970e95e5152edbaeeecd8ab3a42041ac6 100644 (file)
@@ -112,6 +112,8 @@ static inline void arch_acpi_set_pdc_bits(u32 *buf)
        buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP;
 }
 
+#define acpi_unlazy_tlb(x)
+
 #ifdef CONFIG_ACPI_NUMA
 extern cpumask_t early_cpu_possible_map;
 #define for_each_possible_early_cpu(cpu)  \
index 72d867f6b518e4db5a79a10c924f858a3edb0af8..8d0ec9df1cbeb53894f47454cd1391b297e6086c 100644 (file)
@@ -150,6 +150,8 @@ static inline void disable_acpi(void) { }
 extern int x86_acpi_numa_init(void);
 #endif /* CONFIG_ACPI_NUMA */
 
+#define acpi_unlazy_tlb(x)     leave_mm(x)
+
 #ifdef CONFIG_ACPI_APEI
 static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
 {
index 62e7d70aadd5ffece72b357ac1e3024a1b9f7897..da0c160e558905c2164bf1d3879bd1a1cf368f34 100644 (file)
@@ -172,19 +172,27 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_X86_64_NONE:
                        break;
                case R_X86_64_64:
+                       if (*(u64 *)loc != 0)
+                               goto invalid_relocation;
                        *(u64 *)loc = val;
                        break;
                case R_X86_64_32:
+                       if (*(u32 *)loc != 0)
+                               goto invalid_relocation;
                        *(u32 *)loc = val;
                        if (val != *(u32 *)loc)
                                goto overflow;
                        break;
                case R_X86_64_32S:
+                       if (*(s32 *)loc != 0)
+                               goto invalid_relocation;
                        *(s32 *)loc = val;
                        if ((s64)val != *(s32 *)loc)
                                goto overflow;
                        break;
                case R_X86_64_PC32:
+                       if (*(u32 *)loc != 0)
+                               goto invalid_relocation;
                        val -= (u64)loc;
                        *(u32 *)loc = val;
 #if 0
@@ -200,6 +208,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
        }
        return 0;
 
+invalid_relocation:
+       pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
+              (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
+       return -ENOEXEC;
+
 overflow:
        pr_err("overflow in relocation type %d val %Lx\n",
               (int)ELF64_R_TYPE(rel[i].r_info), val);
index 0f3d0cea4d00ca253ee5b46ed78158d460797a56..3118392cdf756bfc913d7a4137d5f7e0d46b046d 100644 (file)
@@ -85,6 +85,7 @@ void leave_mm(int cpu)
 
        switch_mm(NULL, &init_mm, NULL);
 }
+EXPORT_SYMBOL_GPL(leave_mm);
 
 void switch_mm(struct mm_struct *prev, struct mm_struct *next,
               struct task_struct *tsk)
@@ -195,12 +196,22 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                        this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id);
                        this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen);
                        write_cr3(build_cr3(next, new_asid));
-                       trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH,
-                                       TLB_FLUSH_ALL);
+
+                       /*
+                        * NB: This gets called via leave_mm() in the idle path
+                        * where RCU functions differently.  Tracing normally
+                        * uses RCU, so we need to use the _rcuidle variant.
+                        *
+                        * (There is no good reason for this.  The idle code should
+                        *  be rearranged to call this before rcu_idle_enter().)
+                        */
+                       trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
                } else {
                        /* The new ASID is already up to date. */
                        write_cr3(build_cr3_noflush(next, new_asid));
-                       trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, 0);
+
+                       /* See above wrt _rcuidle. */
+                       trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, 0);
                }
 
                this_cpu_write(cpu_tlbstate.loaded_mm, next);
index 2736e25e9dc6458d736383ed0bc60761e7eb4a5f..d50a7b6ccddd99785dc7c6b1e0f368144c597d0e 100644 (file)
@@ -710,6 +710,8 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
 static void acpi_idle_enter_bm(struct acpi_processor *pr,
                               struct acpi_processor_cx *cx, bool timer_bc)
 {
+       acpi_unlazy_tlb(smp_processor_id());
+
        /*
         * Must be done before busmaster disable as we might need to
         * access HPET !
index 5dc7ea4b6bc4cc207cffd8d8efbaed776179c9d9..f0b06b14e782b5b926b5ba7876d827551ce4cfa9 100644 (file)
@@ -913,15 +913,16 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev,
        struct cpuidle_state *state = &drv->states[index];
        unsigned long eax = flg2MWAIT(state->flags);
        unsigned int cstate;
+       int cpu = smp_processor_id();
 
        cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
 
        /*
-        * NB: if CPUIDLE_FLAG_TLB_FLUSHED is set, this idle transition
-        * will probably flush the TLB.  It's not guaranteed to flush
-        * the TLB, though, so it's not clear that we can do anything
-        * useful with this knowledge.
+        * leave_mm() to avoid costly and often unnecessary wakeups
+        * for flushing the user TLB's associated with the active mm.
         */
+       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
+               leave_mm(cpu);
 
        if (!(lapic_timer_reliable_states & (1 << (cstate))))
                tick_broadcast_enter();