[PATCH v1 1/2] genirq: clean up for irq_set_affinity_notifier().
From: Weongyo Jeong
Date: Fri Mar 25 2016 - 11:54:23 EST
At current irq_set_affinity_notifier() implementation, it has two meaning;
set and clear notify. To be more clear, separate it into two;
irq_set_affinity_notifier() and irq_del_affinity_notifier().
At irq_set_affinity_notifier() function, no longer might_sleep() function
is called unnecessarily and -EEXIST code is returned.
Signed-off-by: Weongyo Jeong <weongyo.linux@xxxxxxxxx>
---
drivers/infiniband/hw/qib/qib_iba7322.c | 8 ++---
drivers/scsi/qla2xxx/qla_isr.c | 2 +-
include/linux/interrupt.h | 2 ++
kernel/irq/manage.c | 60 ++++++++++++++++++++++++---------
lib/cpu_rmap.c | 2 +-
5 files changed, 52 insertions(+), 22 deletions(-)
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 6c8ff10..58c482a 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -3355,10 +3355,10 @@ static void reset_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
"Disabling notifier on HCA %d irq %d\n",
dd->unit,
m->msix.vector);
- irq_set_affinity_notifier(
- m->msix.vector,
- NULL);
- m->notifier = NULL;
+ if (m->notifier != NULL) {
+ irq_del_affinity_notifier(&m->notifier->notify);
+ m->notifier = NULL;
+ }
}
static void setup_dca_notifier(struct qib_devdata *dd, struct qib_msix_entry *m)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 5649c20..0a652fa 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3013,7 +3013,7 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
qentry = &ha->msix_entries[i];
if (qentry->have_irq) {
/* un-register irq cpu affinity notification */
- irq_set_affinity_notifier(qentry->vector, NULL);
+ irq_del_affinity_notifier(&qentry->irq_notify);
free_irq(qentry->vector, qentry->rsp);
}
}
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 358076e..fc54356 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -277,6 +277,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
extern int
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
+extern int
+irq_del_affinity_notifier(struct irq_affinity_notify *notify);
#else /* CONFIG_SMP */
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 64731e8..6fb1414 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -282,39 +282,67 @@ out:
}
/**
- * irq_set_affinity_notifier - control notification of IRQ affinity changes
- * @irq: Interrupt for which to enable/disable notification
- * @notify: Context for notification, or %NULL to disable
- * notification. Function pointers must be initialised;
+ * irq_set_affinity_notifier - set notification of IRQ affinity changes
+ * @irq: Interrupt for which to enable notification
+ * @notify: Context for notification.
+ * Function pointers must be initialised;
* the other fields will be initialised by this function.
*
- * Must be called in process context. Notification may only be enabled
- * after the IRQ is allocated and must be disabled before the IRQ is
- * freed using free_irq().
+ * Notification may only be enabled after the IRQ is allocated.
*/
int
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
{
struct irq_desc *desc = irq_to_desc(irq);
+ unsigned long flags;
+
+ if (!desc)
+ return -EINVAL;
+ if (!notify)
+ return -EINVAL;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ if (desc->affinity_notify != NULL) {
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ return -EEXIST;
+ }
+ notify->irq = irq;
+ kref_init(¬ify->kref);
+ INIT_WORK(¬ify->work, irq_affinity_notify);
+
+ desc->affinity_notify = notify;
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(irq_set_affinity_notifier);
+
+/**
+ * irq_del_affinity_notifier - delete notification of IRQ affinity changes
+ * @notify: Context for notification.
+ *
+ * Must be called in process context. Notification must be disabled
+ * before the IRQ is freed using free_irq().
+ */
+int
+irq_del_affinity_notifier(struct irq_affinity_notify *notify)
+{
+ struct irq_desc *desc;
struct irq_affinity_notify *old_notify;
unsigned long flags;
/* The release function is promised process context */
might_sleep();
+ if (!notify)
+ return -EINVAL;
+ desc = irq_to_desc(notify->irq);
if (!desc)
return -EINVAL;
- /* Complete initialisation of *notify */
- if (notify) {
- notify->irq = irq;
- kref_init(¬ify->kref);
- INIT_WORK(¬ify->work, irq_affinity_notify);
- }
-
raw_spin_lock_irqsave(&desc->lock, flags);
old_notify = desc->affinity_notify;
- desc->affinity_notify = notify;
+ desc->affinity_notify = NULL;
raw_spin_unlock_irqrestore(&desc->lock, flags);
if (old_notify)
@@ -322,7 +350,7 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
return 0;
}
-EXPORT_SYMBOL_GPL(irq_set_affinity_notifier);
+EXPORT_SYMBOL_GPL(irq_del_affinity_notifier);
#ifndef CONFIG_AUTO_IRQ_AFFINITY
/*
diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c
index f610b2a..0412a51 100644
--- a/lib/cpu_rmap.c
+++ b/lib/cpu_rmap.c
@@ -235,7 +235,7 @@ void free_irq_cpu_rmap(struct cpu_rmap *rmap)
for (index = 0; index < rmap->used; index++) {
glue = rmap->obj[index];
- irq_set_affinity_notifier(glue->notify.irq, NULL);
+ irq_del_affinity_notifier(&glue->notify);
}
cpu_rmap_put(rmap);
--
2.1.3