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 branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq core fix from Thomas Gleixner:
"A single fix plugging a long standing race between proc/stat and
proc/interrupts access and freeing of interrupt descriptors"

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq: Prevent proc race against freeing of irq descriptors

+79 -2
+1 -1
fs/proc/stat.c
··· 159 159 160 160 /* sum again ? it could be updated? */ 161 161 for_each_irq_nr(j) 162 - seq_put_decimal_ull(p, ' ', kstat_irqs(j)); 162 + seq_put_decimal_ull(p, ' ', kstat_irqs_usr(j)); 163 163 164 164 seq_printf(p, 165 165 "\nctxt %llu\n"
+1
include/linux/kernel_stat.h
··· 68 68 * Number of interrupts per specific IRQ source, since bootup 69 69 */ 70 70 extern unsigned int kstat_irqs(unsigned int irq); 71 + extern unsigned int kstat_irqs_usr(unsigned int irq); 71 72 72 73 /* 73 74 * Number of interrupts per cpu, since bootup
+4
kernel/irq/internals.h
··· 78 78 79 79 #ifdef CONFIG_SPARSE_IRQ 80 80 static inline void irq_mark_irq(unsigned int irq) { } 81 + extern void irq_lock_sparse(void); 82 + extern void irq_unlock_sparse(void); 81 83 #else 82 84 extern void irq_mark_irq(unsigned int irq); 85 + static inline void irq_lock_sparse(void) { } 86 + static inline void irq_unlock_sparse(void) { } 83 87 #endif 84 88 85 89 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
+52
kernel/irq/irqdesc.c
··· 132 132 static inline void free_masks(struct irq_desc *desc) { } 133 133 #endif 134 134 135 + void irq_lock_sparse(void) 136 + { 137 + mutex_lock(&sparse_irq_lock); 138 + } 139 + 140 + void irq_unlock_sparse(void) 141 + { 142 + mutex_unlock(&sparse_irq_lock); 143 + } 144 + 135 145 static struct irq_desc *alloc_desc(int irq, int node, struct module *owner) 136 146 { 137 147 struct irq_desc *desc; ··· 178 168 179 169 unregister_irq_proc(irq, desc); 180 170 171 + /* 172 + * sparse_irq_lock protects also show_interrupts() and 173 + * kstat_irq_usr(). Once we deleted the descriptor from the 174 + * sparse tree we can free it. Access in proc will fail to 175 + * lookup the descriptor. 176 + */ 181 177 mutex_lock(&sparse_irq_lock); 182 178 delete_irq_desc(irq); 183 179 mutex_unlock(&sparse_irq_lock); ··· 590 574 kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); 591 575 } 592 576 577 + /** 578 + * kstat_irqs_cpu - Get the statistics for an interrupt on a cpu 579 + * @irq: The interrupt number 580 + * @cpu: The cpu number 581 + * 582 + * Returns the sum of interrupt counts on @cpu since boot for 583 + * @irq. The caller must ensure that the interrupt is not removed 584 + * concurrently. 585 + */ 593 586 unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) 594 587 { 595 588 struct irq_desc *desc = irq_to_desc(irq); ··· 607 582 *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; 608 583 } 609 584 585 + /** 586 + * kstat_irqs - Get the statistics for an interrupt 587 + * @irq: The interrupt number 588 + * 589 + * Returns the sum of interrupt counts on all cpus since boot for 590 + * @irq. The caller must ensure that the interrupt is not removed 591 + * concurrently. 592 + */ 610 593 unsigned int kstat_irqs(unsigned int irq) 611 594 { 612 595 struct irq_desc *desc = irq_to_desc(irq); ··· 625 592 return 0; 626 593 for_each_possible_cpu(cpu) 627 594 sum += *per_cpu_ptr(desc->kstat_irqs, cpu); 595 + return sum; 596 + } 597 + 598 + /** 599 + * kstat_irqs_usr - Get the statistics for an interrupt 600 + * @irq: The interrupt number 601 + * 602 + * Returns the sum of interrupt counts on all cpus since boot for 603 + * @irq. Contrary to kstat_irqs() this can be called from any 604 + * preemptible context. It's protected against concurrent removal of 605 + * an interrupt descriptor when sparse irqs are enabled. 606 + */ 607 + unsigned int kstat_irqs_usr(unsigned int irq) 608 + { 609 + int sum; 610 + 611 + irq_lock_sparse(); 612 + sum = kstat_irqs(irq); 613 + irq_unlock_sparse(); 628 614 return sum; 629 615 }
+21 -1
kernel/irq/proc.c
··· 15 15 16 16 #include "internals.h" 17 17 18 + /* 19 + * Access rules: 20 + * 21 + * procfs protects read/write of /proc/irq/N/ files against a 22 + * concurrent free of the interrupt descriptor. remove_proc_entry() 23 + * immediately prevents new read/writes to happen and waits for 24 + * already running read/write functions to complete. 25 + * 26 + * We remove the proc entries first and then delete the interrupt 27 + * descriptor from the radix tree and free it. So it is guaranteed 28 + * that irq_to_desc(N) is valid as long as the read/writes are 29 + * permitted by procfs. 30 + * 31 + * The read from /proc/interrupts is a different problem because there 32 + * is no protection. So the lookup and the access to irqdesc 33 + * information must be protected by sparse_irq_lock. 34 + */ 18 35 static struct proc_dir_entry *root_irq_dir; 19 36 20 37 #ifdef CONFIG_SMP ··· 454 437 seq_putc(p, '\n'); 455 438 } 456 439 440 + irq_lock_sparse(); 457 441 desc = irq_to_desc(i); 458 442 if (!desc) 459 - return 0; 443 + goto outsparse; 460 444 461 445 raw_spin_lock_irqsave(&desc->lock, flags); 462 446 for_each_online_cpu(j) ··· 497 479 seq_putc(p, '\n'); 498 480 out: 499 481 raw_spin_unlock_irqrestore(&desc->lock, flags); 482 + outsparse: 483 + irq_unlock_sparse(); 500 484 return 0; 501 485 } 502 486 #endif