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.li...@gmail.com>
---
 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(&notify->kref);
+       INIT_WORK(&notify->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(&notify->kref);
-               INIT_WORK(&notify->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

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to