How about this approach?  Basically it just open-codes delayed work by
splitting the timer and the work struct, and switches to mod_timer()
instead of del_timer() + add_timer().  It passes very light testing here
(basically I started ipoib and nothing blew up).
---
 drivers/infiniband/core/mad.c      |   51 +++++++++++++++++------------------
 drivers/infiniband/core/mad_priv.h |    3 +-
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 5cef8f8..16ff496 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -174,6 +174,15 @@ int ib_response_mad(struct ib_mad *mad)
 }
 EXPORT_SYMBOL(ib_response_mad);
 
+static void timeout_callback(unsigned long data)
+{
+       struct ib_mad_agent_private *mad_agent_priv =
+               (struct ib_mad_agent_private *) data;
+
+       queue_work(mad_agent_priv->qp_info->port_priv->wq,
+                  &mad_agent_priv->timeout_work);
+}
+
 /*
  * ib_register_mad_agent - Register to send/receive MADs
  */
@@ -305,7 +314,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device 
*device,
        INIT_LIST_HEAD(&mad_agent_priv->wait_list);
        INIT_LIST_HEAD(&mad_agent_priv->done_list);
        INIT_LIST_HEAD(&mad_agent_priv->rmpp_list);
-       INIT_DELAYED_WORK(&mad_agent_priv->timed_work, timeout_sends);
+       INIT_WORK(&mad_agent_priv->timeout_work, timeout_sends);
+       setup_timer(&mad_agent_priv->timeout_timer, timeout_callback,
+                   (unsigned long) mad_agent_priv);
        INIT_LIST_HEAD(&mad_agent_priv->local_list);
        INIT_WORK(&mad_agent_priv->local_work, local_completions);
        atomic_set(&mad_agent_priv->refcount, 1);
@@ -512,7 +523,8 @@ static void unregister_mad_agent(struct 
ib_mad_agent_private *mad_agent_priv)
         */
        cancel_mads(mad_agent_priv);
        port_priv = mad_agent_priv->qp_info->port_priv;
-       cancel_delayed_work(&mad_agent_priv->timed_work);
+       del_timer_sync(&mad_agent_priv->timeout_timer);
+       cancel_work_sync(&mad_agent_priv->timeout_work);
 
        spin_lock_irqsave(&port_priv->reg_lock, flags);
        remove_mad_reg_req(mad_agent_priv);
@@ -1970,10 +1982,9 @@ out:
 static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv)
 {
        struct ib_mad_send_wr_private *mad_send_wr;
-       unsigned long delay;
 
        if (list_empty(&mad_agent_priv->wait_list)) {
-               cancel_delayed_work(&mad_agent_priv->timed_work);
+               del_timer(&mad_agent_priv->timeout_timer);
        } else {
                mad_send_wr = list_entry(mad_agent_priv->wait_list.next,
                                         struct ib_mad_send_wr_private,
@@ -1982,13 +1993,8 @@ static void adjust_timeout(struct ib_mad_agent_private 
*mad_agent_priv)
                if (time_after(mad_agent_priv->timeout,
                               mad_send_wr->timeout)) {
                        mad_agent_priv->timeout = mad_send_wr->timeout;
-                       cancel_delayed_work(&mad_agent_priv->timed_work);
-                       delay = mad_send_wr->timeout - jiffies;
-                       if ((long)delay <= 0)
-                               delay = 1;
-                       queue_delayed_work(mad_agent_priv->qp_info->
-                                          port_priv->wq,
-                                          &mad_agent_priv->timed_work, delay);
+                       mod_timer(&mad_agent_priv->timeout_timer,
+                                 mad_send_wr->timeout);
                }
        }
 }
@@ -2015,17 +2021,14 @@ static void wait_for_response(struct 
ib_mad_send_wr_private *mad_send_wr)
                                       temp_mad_send_wr->timeout))
                                break;
                }
-       }
-       else
+       } else
                list_item = &mad_agent_priv->wait_list;
        list_add(&mad_send_wr->agent_list, list_item);
 
        /* Reschedule a work item if we have a shorter timeout */
-       if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list) {
-               cancel_delayed_work(&mad_agent_priv->timed_work);
-               queue_delayed_work(mad_agent_priv->qp_info->port_priv->wq,
-                                  &mad_agent_priv->timed_work, delay);
-       }
+       if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list)
+               mod_timer(&mad_agent_priv->timeout_timer,
+                         mad_send_wr->timeout);
 }
 
 void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr,
@@ -2469,10 +2472,10 @@ static void timeout_sends(struct work_struct *work)
        struct ib_mad_agent_private *mad_agent_priv;
        struct ib_mad_send_wr_private *mad_send_wr;
        struct ib_mad_send_wc mad_send_wc;
-       unsigned long flags, delay;
+       unsigned long flags;
 
        mad_agent_priv = container_of(work, struct ib_mad_agent_private,
-                                     timed_work.work);
+                                     timeout_work);
        mad_send_wc.vendor_err = 0;
 
        spin_lock_irqsave(&mad_agent_priv->lock, flags);
@@ -2482,12 +2485,8 @@ static void timeout_sends(struct work_struct *work)
                                         agent_list);
 
                if (time_after(mad_send_wr->timeout, jiffies)) {
-                       delay = mad_send_wr->timeout - jiffies;
-                       if ((long)delay <= 0)
-                               delay = 1;
-                       queue_delayed_work(mad_agent_priv->qp_info->
-                                          port_priv->wq,
-                                          &mad_agent_priv->timed_work, delay);
+                       mod_timer(&mad_agent_priv->timeout_timer,
+                                 mad_send_wr->timeout);
                        break;
                }
 
diff --git a/drivers/infiniband/core/mad_priv.h 
b/drivers/infiniband/core/mad_priv.h
index 05ce331..1526fa2 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -99,7 +99,8 @@ struct ib_mad_agent_private {
        struct list_head send_list;
        struct list_head wait_list;
        struct list_head done_list;
-       struct delayed_work timed_work;
+       struct work_struct timeout_work;
+       struct timer_list timeout_timer;
        unsigned long timeout;
        struct list_head local_list;
        struct work_struct local_work;
_______________________________________________
general mailing list
general@lists.openfabrics.org
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to