Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'irq-urgent-2020-07-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into master

Pull irq fixes from Thomas Gleixner:
"Two fixes for the interrupt subsystem:

- Make the handling of the firmware node consistent and do not free
the node after the domain has been created successfully. The core
code stores a pointer to it which can lead to a use after free or
double free.

This used to "work" because the pointer was not stored when the
initial code was written, but at some point later it was required
to store it. Of course nobody noticed that the existing users break
that way.

- Handle affinity setting on inactive interrupts correctly when
hierarchical irq domains are enabled.

When interrupts are inactive with the modern hierarchical irqdomain
design, the interrupt chips are not necessarily in a state where
affinity changes can be handled. The legacy irq chip design allowed
this because interrupts are immediately fully initialized at
allocation time. X86 has a hacky workaround for this, but other
implementations do not.

This cased malfunction on GIC-V3. Instead of playing whack a mole
to find all affected drivers, change the core code to store the
requested affinity setting and then establish it when the interrupt
is allocated, which makes the X86 hack go away"

* tag 'irq-urgent-2020-07-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq/affinity: Handle affinity setting on inactive interrupts correctly
irqdomain/treewide: Keep firmware node unconditionally allocated

+76 -42
+3 -2
arch/mips/pci/pci-xtalk-bridge.c
··· 627 627 return -ENOMEM; 628 628 domain = irq_domain_create_hierarchy(parent, 0, 8, fn, 629 629 &bridge_domain_ops, NULL); 630 - irq_domain_free_fwnode(fn); 631 - if (!domain) 630 + if (!domain) { 631 + irq_domain_free_fwnode(fn); 632 632 return -ENOMEM; 633 + } 633 634 634 635 pci_set_flags(PCI_PROBE_ONLY); 635 636
+5 -5
arch/x86/kernel/apic/io_apic.c
··· 2316 2316 ip->irqdomain = irq_domain_create_linear(fn, hwirqs, cfg->ops, 2317 2317 (void *)(long)ioapic); 2318 2318 2319 - /* Release fw handle if it was allocated above */ 2320 - if (!cfg->dev) 2321 - irq_domain_free_fwnode(fn); 2322 - 2323 - if (!ip->irqdomain) 2319 + if (!ip->irqdomain) { 2320 + /* Release fw handle if it was allocated above */ 2321 + if (!cfg->dev) 2322 + irq_domain_free_fwnode(fn); 2324 2323 return -ENOMEM; 2324 + } 2325 2325 2326 2326 ip->irqdomain->parent = parent; 2327 2327
+12 -6
arch/x86/kernel/apic/msi.c
··· 263 263 msi_default_domain = 264 264 pci_msi_create_irq_domain(fn, &pci_msi_domain_info, 265 265 parent); 266 - irq_domain_free_fwnode(fn); 267 266 } 268 - if (!msi_default_domain) 267 + if (!msi_default_domain) { 268 + irq_domain_free_fwnode(fn); 269 269 pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n"); 270 - else 270 + } else { 271 271 msi_default_domain->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK; 272 + } 272 273 } 273 274 274 275 #ifdef CONFIG_IRQ_REMAP ··· 302 301 if (!fn) 303 302 return NULL; 304 303 d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent); 305 - irq_domain_free_fwnode(fn); 304 + if (!d) 305 + irq_domain_free_fwnode(fn); 306 306 return d; 307 307 } 308 308 #endif ··· 366 364 if (fn) { 367 365 dmar_domain = msi_create_irq_domain(fn, &dmar_msi_domain_info, 368 366 x86_vector_domain); 369 - irq_domain_free_fwnode(fn); 367 + if (!dmar_domain) 368 + irq_domain_free_fwnode(fn); 370 369 } 371 370 out: 372 371 mutex_unlock(&dmar_lock); ··· 492 489 } 493 490 494 491 d = msi_create_irq_domain(fn, domain_info, parent); 495 - irq_domain_free_fwnode(fn); 492 + if (!d) { 493 + irq_domain_free_fwnode(fn); 494 + kfree(domain_info); 495 + } 496 496 return d; 497 497 } 498 498
+5 -18
arch/x86/kernel/apic/vector.c
··· 446 446 trace_vector_activate(irqd->irq, apicd->is_managed, 447 447 apicd->can_reserve, reserve); 448 448 449 - /* Nothing to do for fixed assigned vectors */ 450 - if (!apicd->can_reserve && !apicd->is_managed) 451 - return 0; 452 - 453 449 raw_spin_lock_irqsave(&vector_lock, flags); 454 - if (reserve || irqd_is_managed_and_shutdown(irqd)) 450 + if (!apicd->can_reserve && !apicd->is_managed) 451 + assign_irq_vector_any_locked(irqd); 452 + else if (reserve || irqd_is_managed_and_shutdown(irqd)) 455 453 vector_assign_managed_shutdown(irqd); 456 454 else if (apicd->is_managed) 457 455 ret = activate_managed(irqd); ··· 707 709 x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops, 708 710 NULL); 709 711 BUG_ON(x86_vector_domain == NULL); 710 - irq_domain_free_fwnode(fn); 711 712 irq_set_default_host(x86_vector_domain); 712 713 713 714 arch_init_msi_domain(x86_vector_domain); ··· 772 775 static int apic_set_affinity(struct irq_data *irqd, 773 776 const struct cpumask *dest, bool force) 774 777 { 775 - struct apic_chip_data *apicd = apic_chip_data(irqd); 776 778 int err; 777 779 778 - /* 779 - * Core code can call here for inactive interrupts. For inactive 780 - * interrupts which use managed or reservation mode there is no 781 - * point in going through the vector assignment right now as the 782 - * activation will assign a vector which fits the destination 783 - * cpumask. Let the core code store the destination mask and be 784 - * done with it. 785 - */ 786 - if (!irqd_is_activated(irqd) && 787 - (apicd->is_managed || apicd->can_reserve)) 788 - return IRQ_SET_MASK_OK; 780 + if (WARN_ON_ONCE(!irqd_is_activated(irqd))) 781 + return -EIO; 789 782 790 783 raw_spin_lock(&vector_lock); 791 784 cpumask_and(vector_searchmask, dest, cpu_online_mask);
+2 -1
arch/x86/platform/uv/uv_irq.c
··· 167 167 goto out; 168 168 169 169 uv_domain = irq_domain_create_tree(fn, &uv_domain_ops, NULL); 170 - irq_domain_free_fwnode(fn); 171 170 if (uv_domain) 172 171 uv_domain->parent = x86_vector_domain; 172 + else 173 + irq_domain_free_fwnode(fn); 173 174 out: 174 175 mutex_unlock(&uv_lock); 175 176
+3 -2
drivers/iommu/amd/iommu.c
··· 3985 3985 if (!fn) 3986 3986 return -ENOMEM; 3987 3987 iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, iommu); 3988 - irq_domain_free_fwnode(fn); 3989 - if (!iommu->ir_domain) 3988 + if (!iommu->ir_domain) { 3989 + irq_domain_free_fwnode(fn); 3990 3990 return -ENOMEM; 3991 + } 3991 3992 3992 3993 iommu->ir_domain->parent = arch_get_ir_parent_domain(); 3993 3994 iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
+4 -1
drivers/iommu/hyperv-iommu.c
··· 155 155 0, IOAPIC_REMAPPING_ENTRY, fn, 156 156 &hyperv_ir_domain_ops, NULL); 157 157 158 - irq_domain_free_fwnode(fn); 158 + if (!ioapic_ir_domain) { 159 + irq_domain_free_fwnode(fn); 160 + return -ENOMEM; 161 + } 159 162 160 163 /* 161 164 * Hyper-V doesn't provide irq remapping function for
+1 -1
drivers/iommu/intel/irq_remapping.c
··· 563 563 0, INTR_REMAP_TABLE_ENTRIES, 564 564 fn, &intel_ir_domain_ops, 565 565 iommu); 566 - irq_domain_free_fwnode(fn); 567 566 if (!iommu->ir_domain) { 567 + irq_domain_free_fwnode(fn); 568 568 pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id); 569 569 goto out_free_bitmap; 570 570 }
+3 -2
drivers/mfd/ioc3.c
··· 142 142 goto err; 143 143 144 144 domain = irq_domain_create_linear(fn, 24, &ioc3_irq_domain_ops, ipd); 145 - if (!domain) 145 + if (!domain) { 146 + irq_domain_free_fwnode(fn); 146 147 goto err; 148 + } 147 149 148 - irq_domain_free_fwnode(fn); 149 150 ipd->domain = domain; 150 151 151 152 irq_set_chained_handler_and_data(irq, ioc3_irq_handler, domain);
+3 -2
drivers/pci/controller/vmd.c
··· 546 546 547 547 vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, 548 548 x86_vector_domain); 549 - irq_domain_free_fwnode(fn); 550 - if (!vmd->irq_domain) 549 + if (!vmd->irq_domain) { 550 + irq_domain_free_fwnode(fn); 551 551 return -ENODEV; 552 + } 552 553 553 554 pci_add_resource(&resources, &vmd->resources[0]); 554 555 pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]);
+35 -2
kernel/irq/manage.c
··· 195 195 set_bit(IRQTF_AFFINITY, &action->thread_flags); 196 196 } 197 197 198 + #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK 198 199 static void irq_validate_effective_affinity(struct irq_data *data) 199 200 { 200 - #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK 201 201 const struct cpumask *m = irq_data_get_effective_affinity_mask(data); 202 202 struct irq_chip *chip = irq_data_get_irq_chip(data); 203 203 ··· 205 205 return; 206 206 pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n", 207 207 chip->name, data->irq); 208 - #endif 209 208 } 209 + 210 + static inline void irq_init_effective_affinity(struct irq_data *data, 211 + const struct cpumask *mask) 212 + { 213 + cpumask_copy(irq_data_get_effective_affinity_mask(data), mask); 214 + } 215 + #else 216 + static inline void irq_validate_effective_affinity(struct irq_data *data) { } 217 + static inline void irq_init_effective_affinity(struct irq_data *data, 218 + const struct cpumask *mask) { } 219 + #endif 210 220 211 221 int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, 212 222 bool force) ··· 314 304 return ret; 315 305 } 316 306 307 + static bool irq_set_affinity_deactivated(struct irq_data *data, 308 + const struct cpumask *mask, bool force) 309 + { 310 + struct irq_desc *desc = irq_data_to_desc(data); 311 + 312 + /* 313 + * If the interrupt is not yet activated, just store the affinity 314 + * mask and do not call the chip driver at all. On activation the 315 + * driver has to make sure anyway that the interrupt is in a 316 + * useable state so startup works. 317 + */ 318 + if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) || irqd_is_activated(data)) 319 + return false; 320 + 321 + cpumask_copy(desc->irq_common_data.affinity, mask); 322 + irq_init_effective_affinity(data, mask); 323 + irqd_set(data, IRQD_AFFINITY_SET); 324 + return true; 325 + } 326 + 317 327 int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, 318 328 bool force) 319 329 { ··· 343 313 344 314 if (!chip || !chip->irq_set_affinity) 345 315 return -EINVAL; 316 + 317 + if (irq_set_affinity_deactivated(data, mask, force)) 318 + return 0; 346 319 347 320 if (irq_can_move_pcntxt(data) && !irqd_is_setaffinity_pending(data)) { 348 321 ret = irq_try_set_affinity(data, mask, force);