Patch "x86/irq: Check vector allocation early" has been added to the 4.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    x86/irq: Check vector allocation early

to the 4.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     x86-irq-check-vector-allocation-early.patch
and it can be found in the queue-4.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.


>From 3716fd27a604d61a91cda47083504971486b80f1 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Date: Thu, 31 Dec 2015 16:30:48 +0000
Subject: x86/irq: Check vector allocation early

From: Thomas Gleixner <tglx@xxxxxxxxxxxxx>

commit 3716fd27a604d61a91cda47083504971486b80f1 upstream.

__assign_irq_vector() uses the vector_cpumask which is assigned by
apic->vector_allocation_domain() without doing basic sanity checks. That can
result in a situation where the final assignement of a newly found vector
fails in apic->cpu_mask_to_apicid_and(). So we have to do rollbacks for no
reason.

apic->cpu_mask_to_apicid_and() only fails if

  vector_cpumask & requested_cpumask & cpu_online_mask

is empty.

Check for this condition right away and if the result is empty try immediately
the next possible cpu in the requested mask. So in case of a failure the old
setting is unchanged and we can remove the rollback code.

Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Tested-by: Borislav Petkov <bp@xxxxxxxxx>
Tested-by: Joe Lawrence <joe.lawrence@xxxxxxxxxxx>
Cc: Jiang Liu <jiang.liu@xxxxxxxxxxxxxxx>
Cc: Jeremiah Mahler <jmmahler@xxxxxxxxx>
Cc: andy.shevchenko@xxxxxxxxx
Cc: Guenter Roeck <linux@xxxxxxxxxxxx>
Link: http://lkml.kernel.org/r/20151231160106.561877324@xxxxxxxxxxxxx
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
 arch/x86/kernel/apic/vector.c |   38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -30,7 +30,7 @@ struct apic_chip_data {
 
 struct irq_domain *x86_vector_domain;
 static DEFINE_RAW_SPINLOCK(vector_lock);
-static cpumask_var_t vector_cpumask, searched_cpumask;
+static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask;
 static struct irq_chip lapic_controller;
 #ifdef	CONFIG_X86_IO_APIC
 static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
@@ -128,8 +128,20 @@ static int __assign_irq_vector(int irq,
 	while (cpu < nr_cpu_ids) {
 		int new_cpu, vector, offset;
 
+		/* Get the possible target cpus for @mask/@cpu from the apic */
 		apic->vector_allocation_domain(cpu, vector_cpumask, mask);
 
+		/*
+		 * Clear the offline cpus from @vector_cpumask for searching
+		 * and verify whether the result overlaps with @mask. If true,
+		 * then the call to apic->cpu_mask_to_apicid_and() will
+		 * succeed as well. If not, no point in trying to find a
+		 * vector in this mask.
+		 */
+		cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask);
+		if (!cpumask_intersects(vector_searchmask, mask))
+			goto next_cpu;
+
 		if (cpumask_subset(vector_cpumask, d->domain)) {
 			if (cpumask_equal(vector_cpumask, d->domain))
 				goto success;
@@ -162,7 +174,7 @@ next:
 		if (test_bit(vector, used_vectors))
 			goto next;
 
-		for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
+		for_each_cpu(new_cpu, vector_searchmask) {
 			if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
 				goto next;
 		}
@@ -174,7 +186,7 @@ next:
 			d->move_in_progress =
 			   cpumask_intersects(d->old_domain, cpu_online_mask);
 		}
-		for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
+		for_each_cpu(new_cpu, vector_searchmask)
 			per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
 		d->cfg.vector = vector;
 		cpumask_copy(d->domain, vector_cpumask);
@@ -196,8 +208,14 @@ next_cpu:
 	return -ENOSPC;
 
 success:
-	/* cache destination APIC IDs into cfg->dest_apicid */
-	return apic->cpu_mask_to_apicid_and(mask, d->domain, &d->cfg.dest_apicid);
+	/*
+	 * Cache destination APIC IDs into cfg->dest_apicid. This cannot fail
+	 * as we already established, that mask & d->domain & cpu_online_mask
+	 * is not empty.
+	 */
+	BUG_ON(apic->cpu_mask_to_apicid_and(mask, d->domain,
+					    &d->cfg.dest_apicid));
+	return 0;
 }
 
 static int assign_irq_vector(int irq, struct apic_chip_data *data,
@@ -407,6 +425,7 @@ int __init arch_early_irq_init(void)
 	arch_init_htirq_domain(x86_vector_domain);
 
 	BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
+	BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
 	BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL));
 
 	return arch_early_ioapic_init();
@@ -496,14 +515,7 @@ static int apic_set_affinity(struct irq_
 		return -EINVAL;
 
 	err = assign_irq_vector(irq, data, dest);
-	if (err) {
-		if (assign_irq_vector(irq, data,
-				      irq_data_get_affinity_mask(irq_data)))
-			pr_err("Failed to recover vector for irq %d\n", irq);
-		return err;
-	}
-
-	return IRQ_SET_MASK_OK;
+	return err ? err : IRQ_SET_MASK_OK;
 }
 
 static struct irq_chip lapic_controller = {


Patches currently in stable-queue which might be from tglx@xxxxxxxxxxxxx are

queue-4.4/x86-irq-validate-that-irq-descriptor-is-still-active.patch
queue-4.4/x86-irq-remove-outgoing-cpu-from-vector-cleanup-mask.patch
queue-4.4/x86-irq-get-rid-of-code-duplication.patch
queue-4.4/x86-entry-compat-add-missing-clac-to-entry_int80_32.patch
queue-4.4/tick-nohz-set-the-correct-expiry-when-switching-to-nohz-lowres-mode.patch
queue-4.4/irqchip-mxs-add-missing-set_handle_irq.patch
queue-4.4/genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch
queue-4.4/x86-irq-remove-offline-cpus-from-vector-cleanup.patch
queue-4.4/posix-clock-fix-return-code-on-the-poll-method-s-error-path.patch
queue-4.4/x86-irq-reorganize-the-return-path-in-assign_irq_vector.patch
queue-4.4/cputime-prevent-32bit-overflow-in-time_to_cputime.patch
queue-4.4/x86-irq-copy-vectormask-instead-of-an-and-operation.patch
queue-4.4/x86-irq-call-irq_force_move_complete-with-irq-descriptor.patch
queue-4.4/x86-irq-call-chip-irq_set_affinity-in-proper-context.patch
queue-4.4/x86-irq-plug-vector-cleanup-race.patch
queue-4.4/x86-irq-do-not-use-apic_chip_data.old_domain-as-temporary-buffer.patch
queue-4.4/clockevents-tcb_clksrc-prevent-disabling-an-already-disabled-clock.patch
queue-4.4/x86-irq-reorganize-the-search-in-assign_irq_vector.patch
queue-4.4/x86-irq-remove-the-cpumask-allocation-from-send_cleanup_vector.patch
queue-4.4/x86-irq-fix-a-race-in-x86_vector_free_irqs.patch
queue-4.4/x86-irq-check-vector-allocation-early.patch
queue-4.4/irqchip-omap-intc-add-support-for-spurious-irq-handling.patch
queue-4.4/x86-irq-clear-move_in_progress-before-sending-cleanup-ipi.patch
queue-4.4/x86-mpx-fix-off-by-one-comparison-with-nr_registers.patch
queue-4.4/irqchip-atmel-aic-fix-wrong-bit-operation-for-irq-priority.patch
queue-4.4/revert-workqueue-make-sure-delayed-work-run-in-local-cpu.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]