From patchwork Tue Jan 22 07:39:40 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Srivatsa S. Bhat" X-Patchwork-Id: 2016641 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id EE1BFDFB7A for ; Tue, 22 Jan 2013 07:50:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755198Ab3AVHlq (ORCPT ); Tue, 22 Jan 2013 02:41:46 -0500 Received: from e28smtp03.in.ibm.com ([122.248.162.3]:57509 "EHLO e28smtp03.in.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755119Ab3AVHlm (ORCPT ); Tue, 22 Jan 2013 02:41:42 -0500 Received: from /spool/local by e28smtp03.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 22 Jan 2013 13:10:06 +0530 Received: from d28dlp01.in.ibm.com (9.184.220.126) by e28smtp03.in.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 22 Jan 2013 13:10:04 +0530 Received: from d28relay01.in.ibm.com (d28relay01.in.ibm.com [9.184.220.58]) by d28dlp01.in.ibm.com (Postfix) with ESMTP id 4F4E5E004C; Tue, 22 Jan 2013 13:12:03 +0530 (IST) Received: from d28av04.in.ibm.com (d28av04.in.ibm.com [9.184.220.66]) by d28relay01.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r0M7fXTC12058762; Tue, 22 Jan 2013 13:11:33 +0530 Received: from d28av04.in.ibm.com (loopback [127.0.0.1]) by d28av04.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r0M7fUVF020406; Tue, 22 Jan 2013 18:41:34 +1100 Received: from srivatsabhat.in.ibm.com (srivatsabhat.in.ibm.com [9.124.35.112]) by d28av04.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id r0M7fPXE020043; Tue, 22 Jan 2013 18:41:25 +1100 From: "Srivatsa S. Bhat" Subject: [PATCH v5 25/45] x86: Use get/put_online_cpus_atomic() to prevent CPU offline To: tglx@linutronix.de, peterz@infradead.org, tj@kernel.org, oleg@redhat.com, paulmck@linux.vnet.ibm.com, rusty@rustcorp.com.au, mingo@kernel.org, akpm@linux-foundation.org, namhyung@kernel.org Cc: rostedt@goodmis.org, wangyun@linux.vnet.ibm.com, xiaoguangrong@linux.vnet.ibm.com, rjw@sisk.pl, sbw@mit.edu, fweisbec@gmail.com, linux@arm.linux.org.uk, nikunj@linux.vnet.ibm.com, srivatsa.bhat@linux.vnet.ibm.com, linux-pm@vger.kernel.org, linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linuxppc-dev@lists.ozlabs.org, netdev@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 22 Jan 2013 13:09:40 +0530 Message-ID: <20130122073936.13822.32560.stgit@srivatsabhat.in.ibm.com> In-Reply-To: <20130122073210.13822.50434.stgit@srivatsabhat.in.ibm.com> References: <20130122073210.13822.50434.stgit@srivatsabhat.in.ibm.com> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13012207-3864-0000-0000-000006840747 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Once stop_machine() is gone from the CPU offline path, we won't be able to depend on preempt_disable() or local_irq_disable() to prevent CPUs from going offline from under us. Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline, while invoking from atomic context. Cc: "H. Peter Anvin" Cc: x86@kernel.org Cc: Tony Luck Cc: Borislav Petkov Cc: Yinghai Lu Cc: Daniel J Blueman Cc: Steffen Persvold Cc: Joerg Roedel Cc: linux-edac@vger.kernel.org Signed-off-by: Srivatsa S. Bhat --- arch/x86/include/asm/ipi.h | 5 +++++ arch/x86/kernel/apic/apic_flat_64.c | 10 ++++++++++ arch/x86/kernel/apic/apic_numachip.c | 5 +++++ arch/x86/kernel/apic/es7000_32.c | 5 +++++ arch/x86/kernel/apic/io_apic.c | 7 +++++-- arch/x86/kernel/apic/ipi.c | 10 ++++++++++ arch/x86/kernel/apic/x2apic_cluster.c | 4 ++++ arch/x86/kernel/apic/x2apic_uv_x.c | 4 ++++ arch/x86/kernel/cpu/mcheck/therm_throt.c | 4 ++-- arch/x86/mm/tlb.c | 14 +++++++------- 10 files changed, 57 insertions(+), 11 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/x86/include/asm/ipi.h b/arch/x86/include/asm/ipi.h index 615fa90..112249c 100644 --- a/arch/x86/include/asm/ipi.h +++ b/arch/x86/include/asm/ipi.h @@ -20,6 +20,7 @@ * Subject to the GNU Public License, v.2 */ +#include #include #include #include @@ -131,18 +132,22 @@ extern int no_broadcast; static inline void __default_local_send_IPI_allbutself(int vector) { + get_online_cpus_atomic(); if (no_broadcast || vector == NMI_VECTOR) apic->send_IPI_mask_allbutself(cpu_online_mask, vector); else __default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, apic->dest_logical); + put_online_cpus_atomic(); } static inline void __default_local_send_IPI_all(int vector) { + get_online_cpus_atomic(); if (no_broadcast || vector == NMI_VECTOR) apic->send_IPI_mask(cpu_online_mask, vector); else __default_send_IPI_shortcut(APIC_DEST_ALLINC, vector, apic->dest_logical); + put_online_cpus_atomic(); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 00c77cf..8207ade 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,8 @@ static void flat_send_IPI_allbutself(int vector) #else int hotplug = 0; #endif + + get_online_cpus_atomic(); if (hotplug || vector == NMI_VECTOR) { if (!cpumask_equal(cpu_online_mask, cpumask_of(cpu))) { unsigned long mask = cpumask_bits(cpu_online_mask)[0]; @@ -105,16 +108,19 @@ static void flat_send_IPI_allbutself(int vector) __default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, apic->dest_logical); } + put_online_cpus_atomic(); } static void flat_send_IPI_all(int vector) { + get_online_cpus_atomic(); if (vector == NMI_VECTOR) { flat_send_IPI_mask(cpu_online_mask, vector); } else { __default_send_IPI_shortcut(APIC_DEST_ALLINC, vector, apic->dest_logical); } + put_online_cpus_atomic(); } static unsigned int flat_get_apic_id(unsigned long x) @@ -255,12 +261,16 @@ static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask, static void physflat_send_IPI_allbutself(int vector) { + get_online_cpus_atomic(); default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); + put_online_cpus_atomic(); } static void physflat_send_IPI_all(int vector) { + get_online_cpus_atomic(); physflat_send_IPI_mask(cpu_online_mask, vector); + put_online_cpus_atomic(); } static int physflat_probe(void) diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index 9c2aa89..7d19c1d 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -131,15 +132,19 @@ static void numachip_send_IPI_allbutself(int vector) unsigned int this_cpu = smp_processor_id(); unsigned int cpu; + get_online_cpus_atomic(); for_each_online_cpu(cpu) { if (cpu != this_cpu) numachip_send_IPI_one(cpu, vector); } + put_online_cpus_atomic(); } static void numachip_send_IPI_all(int vector) { + get_online_cpus_atomic(); numachip_send_IPI_mask(cpu_online_mask, vector); + put_online_cpus_atomic(); } static void numachip_send_IPI_self(int vector) diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 0874799..ddf2995 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -412,12 +413,16 @@ static void es7000_send_IPI_mask(const struct cpumask *mask, int vector) static void es7000_send_IPI_allbutself(int vector) { + get_online_cpus_atomic(); default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); + put_online_cpus_atomic(); } static void es7000_send_IPI_all(int vector) { + get_online_cpus_atomic(); es7000_send_IPI_mask(cpu_online_mask, vector); + put_online_cpus_atomic(); } static int es7000_apic_id_registered(void) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index b739d39..ca1c2a5 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1788,13 +1789,13 @@ __apicdebuginit(void) print_local_APICs(int maxcpu) if (!maxcpu) return; - preempt_disable(); + get_online_cpus_atomic(); for_each_online_cpu(cpu) { if (cpu >= maxcpu) break; smp_call_function_single(cpu, print_local_APIC, NULL, 1); } - preempt_enable(); + put_online_cpus_atomic(); } __apicdebuginit(void) print_PIC(void) @@ -2209,6 +2210,7 @@ void send_cleanup_vector(struct irq_cfg *cfg) { cpumask_var_t cleanup_mask; + get_online_cpus_atomic(); if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { unsigned int i; for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) @@ -2219,6 +2221,7 @@ void send_cleanup_vector(struct irq_cfg *cfg) free_cpumask_var(cleanup_mask); } cfg->move_in_progress = 0; + put_online_cpus_atomic(); } asmlinkage void smp_irq_move_cleanup_interrupt(void) diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index cce91bf..c65aa77 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -29,12 +29,14 @@ void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector) * to an arbitrary mask, so I do a unicast to each CPU instead. * - mbligh */ + get_online_cpus_atomic(); local_irq_save(flags); for_each_cpu(query_cpu, mask) { __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, query_cpu), vector, APIC_DEST_PHYSICAL); } local_irq_restore(flags); + put_online_cpus_atomic(); } void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, @@ -46,6 +48,7 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, /* See Hack comment above */ + get_online_cpus_atomic(); local_irq_save(flags); for_each_cpu(query_cpu, mask) { if (query_cpu == this_cpu) @@ -54,6 +57,7 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, query_cpu), vector, APIC_DEST_PHYSICAL); } local_irq_restore(flags); + put_online_cpus_atomic(); } #ifdef CONFIG_X86_32 @@ -70,12 +74,14 @@ void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, * should be modified to do 1 message per cluster ID - mbligh */ + get_online_cpus_atomic(); local_irq_save(flags); for_each_cpu(query_cpu, mask) __default_send_IPI_dest_field( early_per_cpu(x86_cpu_to_logical_apicid, query_cpu), vector, apic->dest_logical); local_irq_restore(flags); + put_online_cpus_atomic(); } void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, @@ -87,6 +93,7 @@ void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, /* See Hack comment above */ + get_online_cpus_atomic(); local_irq_save(flags); for_each_cpu(query_cpu, mask) { if (query_cpu == this_cpu) @@ -96,6 +103,7 @@ void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, vector, apic->dest_logical); } local_irq_restore(flags); + put_online_cpus_atomic(); } /* @@ -109,10 +117,12 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector) if (WARN_ONCE(!mask, "empty IPI mask")) return; + get_online_cpus_atomic(); local_irq_save(flags); WARN_ON(mask & ~cpumask_bits(cpu_online_mask)[0]); __default_send_IPI_dest_field(mask, vector, apic->dest_logical); local_irq_restore(flags); + put_online_cpus_atomic(); } void default_send_IPI_allbutself(int vector) diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index c88baa4..cb08e6b 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -88,12 +88,16 @@ x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector) static void x2apic_send_IPI_allbutself(int vector) { + get_online_cpus_atomic(); __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT); + put_online_cpus_atomic(); } static void x2apic_send_IPI_all(int vector) { + get_online_cpus_atomic(); __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC); + put_online_cpus_atomic(); } static int diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 8cfade9..cc469a3 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -244,15 +244,19 @@ static void uv_send_IPI_allbutself(int vector) unsigned int this_cpu = smp_processor_id(); unsigned int cpu; + get_online_cpus_atomic(); for_each_online_cpu(cpu) { if (cpu != this_cpu) uv_send_IPI_one(cpu, vector); } + put_online_cpus_atomic(); } static void uv_send_IPI_all(int vector) { + get_online_cpus_atomic(); uv_send_IPI_mask(cpu_online_mask, vector); + put_online_cpus_atomic(); } static int uv_apic_id_valid(int apicid) diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 47a1870..d128ba4 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -82,13 +82,13 @@ static ssize_t therm_throt_device_show_##event##_##name( \ unsigned int cpu = dev->id; \ ssize_t ret; \ \ - preempt_disable(); /* CPU hotplug */ \ + get_online_cpus_atomic(); /* CPU hotplug */ \ if (cpu_online(cpu)) { \ ret = sprintf(buf, "%lu\n", \ per_cpu(thermal_state, cpu).event.name); \ } else \ ret = 0; \ - preempt_enable(); \ + put_online_cpus_atomic(); \ \ return ret; \ } diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 13a6b29..2c3ec76 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -147,12 +147,12 @@ void flush_tlb_current_task(void) { struct mm_struct *mm = current->mm; - preempt_disable(); + get_online_cpus_atomic(); local_flush_tlb(); if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); - preempt_enable(); + put_online_cpus_atomic(); } /* @@ -187,7 +187,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long addr; unsigned act_entries, tlb_entries = 0; - preempt_disable(); + get_online_cpus_atomic(); if (current->active_mm != mm) goto flush_all; @@ -225,21 +225,21 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, start, end); - preempt_enable(); + put_online_cpus_atomic(); return; } flush_all: if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); - preempt_enable(); + put_online_cpus_atomic(); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) { struct mm_struct *mm = vma->vm_mm; - preempt_disable(); + get_online_cpus_atomic(); if (current->active_mm == mm) { if (current->mm) @@ -251,7 +251,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) flush_tlb_others(mm_cpumask(mm), mm, start, 0UL); - preempt_enable(); + put_online_cpus_atomic(); } static void do_flush_tlb_all(void *info)