]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
genirq: Add rcuref count to struct irq_desc
authorThomas Gleixner <tglx@kernel.org>
Sun, 17 May 2026 20:02:34 +0000 (22:02 +0200)
committerThomas Gleixner <tglx@kernel.org>
Tue, 26 May 2026 14:21:14 +0000 (16:21 +0200)
Prepare for a smarter iterator for /proc/interrupts so that the next
interrupt descriptor can be cached after lookup.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Reviewed-by: Dmitry Ilvokhin <d@ilvokhin.com>
Link: https://patch.msgid.link/20260517194931.917415190@kernel.org
include/linux/irqdesc.h
kernel/irq/internals.h
kernel/irq/irqdesc.c

index 1058786d76ebb353ed59cb00fff56616a5202792..8080db17c1b1b6fc106ef8695608a88146d5aefd 100644 (file)
@@ -70,6 +70,7 @@ struct irq_redirect {
  *                     IRQF_NO_SUSPEND set
  * @force_resume_depth:        number of irqactions on a irq descriptor with
  *                     IRQF_FORCE_RESUME set
+ * @refcnt:            Reference count mainly for /proc/interrupts
  * @rcu:               rcu head for delayed free
  * @kobj:              kobject used to represent this struct in sysfs
  * @request_mutex:     mutex to protect request/free before locking desc->lock
@@ -119,6 +120,7 @@ struct irq_desc {
        struct dentry           *debugfs_file;
        const char              *dev_name;
 #endif
+       rcuref_t                refcnt;
 #ifdef CONFIG_SPARSE_IRQ
        struct rcu_head         rcu;
        struct kobject          kobj;
index be702dd64422bb17d12dc3a362472edbd35ee9c3..bacbf4020242fa71b7a2a65f48300c30410fa689 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/irqdesc.h>
 #include <linux/kernel_stat.h>
 #include <linux/pm_runtime.h>
+#include <linux/rcuref.h>
 #include <linux/sched/clock.h>
 
 #ifdef CONFIG_SPARSE_IRQ
@@ -101,9 +102,23 @@ extern void unmask_irq(struct irq_desc *desc);
 extern void unmask_threaded_irq(struct irq_desc *desc);
 
 #ifdef CONFIG_SPARSE_IRQ
-static inline void irq_mark_irq(unsigned int irq) { }
+static __always_inline void irq_mark_irq(unsigned int irq) { }
+void irq_desc_free_rcu(struct irq_desc *desc);
+
+static __always_inline bool irq_desc_get_ref(struct irq_desc *desc)
+{
+       return rcuref_get(&desc->refcnt);
+}
+
+static __always_inline void irq_desc_put_ref(struct irq_desc *desc)
+{
+       if (rcuref_put(&desc->refcnt))
+               irq_desc_free_rcu(desc);
+}
 #else
 extern void irq_mark_irq(unsigned int irq);
+static __always_inline bool irq_desc_get_ref(struct irq_desc *desc) { return true; }
+static __always_inline void irq_desc_put_ref(struct irq_desc *desc) { }
 #endif
 
 irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc);
index 90595eefb4779bbe886914fd60ee71db61b0ef44..23f21763bfed7738e13f20aed58ec9132899d7d7 100644 (file)
@@ -137,6 +137,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
        desc->tot_count = 0;
        desc->name = NULL;
        desc->owner = owner;
+       rcuref_init(&desc->refcnt, 1);
        desc_smp_init(desc, node, affinity);
 }
 
@@ -465,6 +466,17 @@ static void delayed_free_desc(struct rcu_head *rhp)
        kobject_put(&desc->kobj);
 }
 
+void irq_desc_free_rcu(struct irq_desc *desc)
+{
+       /*
+        * We free the descriptor, masks and stat fields via RCU. That
+        * allows demultiplex interrupts to do rcu based management of
+        * the child interrupts.
+        * This also allows us to use rcu in kstat_irqs_usr().
+        */
+       call_rcu(&desc->rcu, delayed_free_desc);
+}
+
 static void free_desc(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
@@ -483,14 +495,7 @@ static void free_desc(unsigned int irq)
         */
        irq_sysfs_del(desc);
        delete_irq_desc(irq);
-
-       /*
-        * We free the descriptor, masks and stat fields via RCU. That
-        * allows demultiplex interrupts to do rcu based management of
-        * the child interrupts.
-        * This also allows us to use rcu in kstat_irqs_usr().
-        */
-       call_rcu(&desc->rcu, delayed_free_desc);
+       irq_desc_put_ref(desc);
 }
 
 static int alloc_descs(unsigned int start, unsigned int cnt, int node,