]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
x86/irq: Simplify hotplug vector accounting
authorThomas Gleixner <tglx@linutronix.de>
Wed, 13 Sep 2017 21:29:53 +0000 (23:29 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 25 Sep 2017 18:52:02 +0000 (20:52 +0200)
Before a CPU is taken offline the number of active interrupt vectors on the
outgoing CPU and the number of vectors which are available on the other
online CPUs are counted and compared. If the active vectors are more than
the available vectors on the other CPUs then the CPU hot-unplug operation
is aborted. This again uses loop based search and is inaccurate.

The bitmap matrix allocator has accurate accounting information and can
tell exactly whether the vector space is sufficient or not.

Emit a message when the number of globaly reserved (unallocated) vectors is
larger than the number of available vectors after offlining a CPU because
after that point request_irq() might fail.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213156.351193962@linutronix.de
arch/x86/include/asm/apic.h
arch/x86/include/asm/irq.h
arch/x86/kernel/apic/vector.c
arch/x86/kernel/irq.c
arch/x86/kernel/smpboot.c

index 7a8651921ed538780619abc622f40f8d86a2911c..a9e57f08bfa641d4cc9fb736bf2d1d4d22a6640c 100644 (file)
@@ -386,6 +386,7 @@ extern struct apic *__apicdrivers[], *__apicdrivers_end[];
  */
 #ifdef CONFIG_SMP
 extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip);
+extern int lapic_can_unplug_cpu(void);
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
index 9958ceea2fa3c7bd3b48571eaf9d35fb82b6afd4..1002a3e8fccc9b484de4fafd0ba6ee357c77be6c 100644 (file)
@@ -25,11 +25,7 @@ extern void irq_ctx_init(int cpu);
 
 struct irq_desc;
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <linux/cpumask.h>
-extern int check_irq_vectors_for_cpu_disable(void);
 extern void fixup_irqs(void);
-#endif
 
 #ifdef CONFIG_HAVE_KVM
 extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));
index 5e58da8efe77d7d2e7e7d222a39d624e10986ecc..14b21ca4483c5e56a18004193d69656583e117b1 100644 (file)
@@ -945,7 +945,37 @@ void irq_force_complete_move(struct irq_desc *desc)
 unlock:
        raw_spin_unlock(&vector_lock);
 }
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Note, this is not accurate accounting, but at least good enough to
+ * prevent that the actual interrupt move will run out of vectors.
+ */
+int lapic_can_unplug_cpu(void)
+{
+       unsigned int rsvd, avl, tomove, cpu = smp_processor_id();
+       int ret = 0;
+
+       raw_spin_lock(&vector_lock);
+       tomove = irq_matrix_allocated(vector_matrix);
+       avl = irq_matrix_available(vector_matrix, true);
+       if (avl < tomove) {
+               pr_warn("CPU %u has %u vectors, %u available. Cannot disable CPU\n",
+                       cpu, tomove, avl);
+               ret = -ENOSPC;
+               goto out;
+       }
+       rsvd = irq_matrix_reserved(vector_matrix);
+       if (avl < rsvd) {
+               pr_warn("Reserved vectors %u > available %u. IRQ request may fail\n",
+                       rsvd, avl);
+       }
+out:
+       raw_spin_unlock(&vector_lock);
+       return ret;
+}
+#endif /* HOTPLUG_CPU */
+#endif /* SMP */
 
 static void __init print_APIC_field(int base)
 {
index 188990c3a5140c214cb73c4e056075b2944e490c..49cfd9fe7589fa5ef2bef5d4a5d6431b7007836f 100644 (file)
@@ -333,105 +333,6 @@ __visible void smp_kvm_posted_intr_nested_ipi(struct pt_regs *regs)
 
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* These two declarations are only used in check_irq_vectors_for_cpu_disable()
- * below, which is protected by stop_machine().  Putting them on the stack
- * results in a stack frame overflow.  Dynamically allocating could result in a
- * failure so declare these two cpumasks as global.
- */
-static struct cpumask affinity_new, online_new;
-
-/*
- * This cpu is going to be removed and its vectors migrated to the remaining
- * online cpus.  Check to see if there are enough vectors in the remaining cpus.
- * This function is protected by stop_machine().
- */
-int check_irq_vectors_for_cpu_disable(void)
-{
-       unsigned int this_cpu, vector, this_count, count;
-       struct irq_desc *desc;
-       struct irq_data *data;
-       int cpu;
-
-       this_cpu = smp_processor_id();
-       cpumask_copy(&online_new, cpu_online_mask);
-       cpumask_clear_cpu(this_cpu, &online_new);
-
-       this_count = 0;
-       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-               desc = __this_cpu_read(vector_irq[vector]);
-               if (IS_ERR_OR_NULL(desc))
-                       continue;
-               /*
-                * Protect against concurrent action removal, affinity
-                * changes etc.
-                */
-               raw_spin_lock(&desc->lock);
-               data = irq_desc_get_irq_data(desc);
-               cpumask_copy(&affinity_new,
-                            irq_data_get_affinity_mask(data));
-               cpumask_clear_cpu(this_cpu, &affinity_new);
-
-               /* Do not count inactive or per-cpu irqs. */
-               if (!irq_desc_has_action(desc) || irqd_is_per_cpu(data)) {
-                       raw_spin_unlock(&desc->lock);
-                       continue;
-               }
-
-               raw_spin_unlock(&desc->lock);
-               /*
-                * A single irq may be mapped to multiple cpu's
-                * vector_irq[] (for example IOAPIC cluster mode).  In
-                * this case we have two possibilities:
-                *
-                * 1) the resulting affinity mask is empty; that is
-                * this the down'd cpu is the last cpu in the irq's
-                * affinity mask, or
-                *
-                * 2) the resulting affinity mask is no longer a
-                * subset of the online cpus but the affinity mask is
-                * not zero; that is the down'd cpu is the last online
-                * cpu in a user set affinity mask.
-                */
-               if (cpumask_empty(&affinity_new) ||
-                   !cpumask_subset(&affinity_new, &online_new))
-                       this_count++;
-       }
-       /* No need to check any further. */
-       if (!this_count)
-               return 0;
-
-       count = 0;
-       for_each_online_cpu(cpu) {
-               if (cpu == this_cpu)
-                       continue;
-               /*
-                * We scan from FIRST_EXTERNAL_VECTOR to first system
-                * vector. If the vector is marked in the used vectors
-                * bitmap or an irq is assigned to it, we don't count
-                * it as available.
-                *
-                * As this is an inaccurate snapshot anyway, we can do
-                * this w/o holding vector_lock.
-                */
-               for (vector = FIRST_EXTERNAL_VECTOR;
-                    vector < FIRST_SYSTEM_VECTOR; vector++) {
-                       if (!test_bit(vector, system_vectors) &&
-                           IS_ERR_OR_NULL(per_cpu(vector_irq, cpu)[vector])) {
-                               if (++count == this_count)
-                                       return 0;
-                       }
-               }
-       }
-
-       if (count < this_count) {
-               pr_warn("CPU %d disable failed: CPU has %u vectors assigned and there are only %u available.\n",
-                       this_cpu, this_count, count);
-               return -ERANGE;
-       }
-       return 0;
-}
-
 /* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
 void fixup_irqs(void)
 {
index 86739f04701b6890a0cf37c61e671f983bded58b..92aadfa30d6120a989b364270289d9f1e4b35bf4 100644 (file)
@@ -1525,7 +1525,7 @@ int native_cpu_disable(void)
 {
        int ret;
 
-       ret = check_irq_vectors_for_cpu_disable();
+       ret = lapic_can_unplug_cpu();
        if (ret)
                return ret;