[openib-general] [PATCH] timeout wq code
Sean Hefty
Thu Oct 21 16:08:49 PDT 2004
Code to use a work queue to time out MADs. There is one work queue per port. (Completion handling code was not changed.)
I'm working on creating a few simple test cases to verify MAD functionality (registration, timeouts, sends, receives, and RMPP in the future), but these are not yet done.
-Sean
Index: access/ib_mad_priv.h
===================================================================
--- access/ib_mad_priv.h (revision 1036)
+++ access/ib_mad_priv.h (working copy)
@@ -58,6 +58,7 @@
#include <linux/pci.h>
#include <linux/kthread.h>
+#include <linux/workqueue.h>
#include <ib_mad.h>
#include <ib_smi.h>
@@ -112,6 +113,8 @@
spinlock_t lock;
struct list_head send_list;
struct list_head wait_list;
+ struct work_struct work;
+ unsigned long timeout;
atomic_t refcount;
wait_queue_head_t wait;
@@ -149,6 +152,7 @@
spinlock_t reg_lock;
struct ib_mad_mgmt_class_table *version[MAX_MGMT_VERSION];
struct list_head agent_list;
+ struct workqueue_struct *wq;
spinlock_t send_list_lock;
struct list_head send_posted_mad_list;
Index: access/ib_mad.c
===================================================================
--- access/ib_mad.c (revision 1036)
+++ access/ib_mad.c (working copy)
@@ -87,6 +87,7 @@
static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv);
static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
struct ib_mad_send_wc *mad_send_wc);
+static void timeout_sends(void *data);
/*
* Returns a ib_mad_port_private structure or NULL for a device/port.
@@ -264,6 +265,7 @@
spin_lock_init(&mad_agent_priv->lock);
INIT_LIST_HEAD(&mad_agent_priv->send_list);
INIT_LIST_HEAD(&mad_agent_priv->wait_list);
+ INIT_WORK(&mad_agent_priv->work, timeout_sends, mad_agent_priv);
atomic_set(&mad_agent_priv->refcount, 1);
init_waitqueue_head(&mad_agent_priv->wait);
mad_agent_priv->port_priv = port_priv;
@@ -299,6 +301,9 @@
*/
cancel_mads(mad_agent_priv);
+ cancel_delayed_work(&mad_agent_priv->work);
+ flush_workqueue(mad_agent_priv->port_priv->wq);
+
spin_lock_irqsave(&mad_agent_priv->port_priv->reg_lock, flags);
remove_mad_reg_req(mad_agent_priv);
list_del(&mad_agent_priv->agent_list);
@@ -398,7 +403,8 @@
mad_send_wr->tid = send_wr->wr.ud.mad_hdr->tid;
mad_send_wr->agent = mad_agent;
/* Timeout will be updated after send completes. */
- mad_send_wr->timeout = cur_send_wr->wr.ud.timeout_ms;
+ mad_send_wr->timeout = msecs_to_jiffies(cur_send_wr->wr.
+ ud.timeout_ms);
/* One reference for each work request to QP + response. */
mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
mad_send_wr->status = IB_WC_SUCCESS;
@@ -422,9 +428,7 @@
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
*bad_send_wr = cur_send_wr;
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
-
+ atomic_dec(&mad_agent_priv->refcount);
return ret;
}
cur_send_wr= next_send_wr;
@@ -1007,6 +1011,30 @@
return;
}
+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->work);
+ } else {
+ mad_send_wr = list_entry(mad_agent_priv->wait_list.next,
+ struct ib_mad_send_wr_private,
+ agent_list);
+
+ 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->work);
+ delay = mad_send_wr->timeout - jiffies;
+ if ((long)delay <= 0)
+ delay = 1;
+ queue_delayed_work(mad_agent_priv->port_priv->wq,
+ &mad_agent_priv->work, delay);
+ }
+ }
+}
+
static void wait_for_response(struct ib_mad_agent_private *mad_agent_priv,
struct ib_mad_send_wr_private *mad_send_wr )
{
@@ -1027,6 +1055,13 @@
break;
}
list_add(&mad_send_wr->agent_list, list_item);
+
+ /* Re-schedule 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->work);
+ queue_delayed_work(mad_agent_priv->port_priv->wq,
+ &mad_agent_priv->work, delay);
+ }
}
/*
@@ -1059,6 +1094,7 @@
/* Remove send from MAD agent and notify client of completion */
list_del(&mad_send_wr->agent_list);
+ adjust_timeout(mad_agent_priv);
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
if (mad_send_wr->status != IB_WC_SUCCESS )
@@ -1233,6 +1269,7 @@
}
list_del(&mad_send_wr->agent_list);
+ adjust_timeout(mad_agent_priv);
spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
mad_send_wc.status = IB_WC_WR_FLUSH_ERR;
@@ -1250,6 +1287,47 @@
}
EXPORT_SYMBOL(ib_cancel_mad);
+static void timeout_sends(void *data)
+{
+ 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;
+
+ mad_agent_priv = (struct ib_mad_agent_private *)data;
+
+ mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR;
+ mad_send_wc.vendor_err = 0;
+
+ spin_lock_irqsave(&mad_agent_priv->lock, flags);
+ while (!list_empty(&mad_agent_priv->wait_list)) {
+ mad_send_wr = list_entry(mad_agent_priv->wait_list.next,
+ struct ib_mad_send_wr_private,
+ 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->port_priv->wq,
+ &mad_agent_priv->work, delay);
+ break;
+ }
+
+ list_del(&mad_send_wr->agent_list);
+ spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+
+ mad_send_wc.wr_id = mad_send_wr->wr_id;
+ mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
+ &mad_send_wc);
+
+ kfree(mad_send_wr);
+ atomic_dec(&mad_agent_priv->refcount);
+ spin_lock_irqsave(&mad_agent_priv->lock, flags);
+ }
+ spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+}
+
/*
* IB MAD thread
*/
@@ -1756,14 +1834,20 @@
for (i = 0; i < IB_MAD_QPS_CORE; i++)
INIT_LIST_HEAD(&port_priv->recv_posted_mad_list[i]);
+ port_priv->wq = create_workqueue("ib_mad");
+ if (!port_priv->wq) {
+ ret = -ENOMEM;
+ goto error8;
+ }
+
ret = ib_mad_thread_init(port_priv);
if (ret)
- goto error8;
+ goto error9;
ret = ib_mad_port_start(port_priv);
if (ret) {
printk(KERN_ERR PFX "Couldn't start port\n");
- goto error9;
+ goto error10;
}
spin_lock_irqsave(&ib_mad_port_list_lock, flags);
@@ -1772,8 +1856,10 @@
return 0;
-error9:
+error10:
kthread_stop(port_priv->mad_thread);
+error9:
+ destroy_workqueue(port_priv->wq);
error8:
ib_destroy_qp(port_priv->qp[1]);
error7:
@@ -1814,6 +1900,7 @@
ib_mad_port_stop(port_priv);
kthread_stop(port_priv->mad_thread);
+ destroy_workqueue(port_priv->wq);
ib_destroy_qp(port_priv->qp[1]);
ib_destroy_qp(port_priv->qp[0]);
ib_dereg_mr(port_priv->mr);
--
More information about the openib-general mailing list