[openib-general] [PATCH] CM listen update
Sean Hefty
mshefty at ichips.intel.com
Fri Dec 17 17:23:21 PST 2004
The following patch implements a call to ib_cm_listen. Listen requests are
stored using a red-black tree. A service mask was also added to the listen
request. The changes only affect the CM module.
- Sean
Index: include/ib_cm.h
===================================================================
--- include/ib_cm.h (revision 1359)
+++ include/ib_cm.h (working copy)
@@ -93,6 +93,7 @@
ib_cm_handler cm_handler;
void *context;
u64 service_id;
+ u64 service_mask;
enum ib_cm_state state;
};
@@ -125,7 +126,8 @@
* @service_id: Service identifier matched against incoming connection
* and service ID resolution requests.
* @service_mask: Mask applied to service ID used to listen across a
- * range of service IDs.
+ * range of service IDs. If set to 0, the service ID is matched
+ * exactly.
*/
int ib_cm_listen(struct ib_cm_id *cm_id,
u64 service_id,
@@ -136,7 +138,6 @@
struct ib_path_record *primary_path;
struct ib_path_record *alternate_path;
u64 service_id;
- int timeout_ms;
void *private_data;
u8 private_data_len;
u8 peer_to_peer;
Index: core/cm.c
===================================================================
--- core/cm.c (revision 1359)
+++ core/cm.c (working copy)
@@ -34,6 +34,7 @@
* $Id$
*/
#include <linux/err.h>
+#include <linux/rbtree.h>
#include <linux/spinlock.h>
#include <ib_cm.h>
@@ -51,6 +52,11 @@
.remove = cm_remove_one
};
+static struct ib_cm {
+ spinlock_t lock;
+ struct rb_root service_table;
+} cm;
+
struct cm_port {
struct ib_mad_agent *mad_agent;
};
@@ -58,11 +64,51 @@
struct ib_cm_id_private {
struct ib_cm_id id;
+ struct rb_node node;
spinlock_t lock;
wait_queue_head_t wait;
atomic_t refcount;
};
+static struct ib_cm_id_private *find_cm_service(u64 service_id)
+{
+ struct rb_node *node = cm.service_table.rb_node;
+ struct ib_cm_id_private *cm_id_priv;
+
+ while (node) {
+ cm_id_priv = rb_entry(node, struct ib_cm_id_private, node);
+ if ((cm_id_priv->id.service_mask & service_id) ==
+ (cm_id_priv->id.service_mask & cm_id_priv->id.service_id))
+ return cm_id_priv;
+
+ if (service_id < cm_id_priv->id.service_id)
+ node = node->rb_left;
+ else
+ node = node->rb_right;
+ }
+ return NULL;
+}
+
+static void insert_cm_service(struct ib_cm_id_private *cm_id_priv)
+{
+ struct rb_node **link = &cm.service_table.rb_node;
+ struct rb_node *parent = NULL;
+ struct ib_cm_id_private *cur_cm_id_priv;
+ u64 service_id = cm_id_priv->id.service_id;
+
+ while (*link) {
+ parent = *link;
+ cur_cm_id_priv = rb_entry(parent, struct ib_cm_id_private,
+ node);
+ if (service_id < cur_cm_id_priv->id.service_id)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+ rb_link_node(&cm_id_priv->node, parent, link);
+ rb_insert_color(&cm_id_priv->node, &cm.service_table);
+}
+
struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler,
void *context)
{
@@ -72,7 +118,7 @@
if (!cm_id_priv)
return ERR_PTR(-ENOMEM);
- cm_id_priv->id.service_id = 0;
+ memset(cm_id_priv, 0, sizeof *cm_id_priv);
cm_id_priv->id.state = IB_CM_IDLE;
cm_id_priv->id.cm_handler = cm_handler;
cm_id_priv->id.context = context;
@@ -95,16 +141,21 @@
int ib_destroy_cm_id(struct ib_cm_id *cm_id)
{
struct ib_cm_id_private *cm_id_priv;
- unsigned long flags;
+ unsigned long flags, flags2;
cm_id_priv = container_of(cm_id, struct ib_cm_id_private, id);
spin_lock_irqsave(&cm_id_priv->lock, flags);
switch(cm_id->state) {
- case IB_CM_IDLE:
case IB_CM_LISTEN:
+ spin_lock_irqsave(&cm.lock, flags2);
+ rb_erase(&cm_id_priv->node, &cm.service_table);
+ spin_lock_irqrestore(&cm.lock, flags2);
+ break;
+ case IB_CM_IDLE:
+ break;
case IB_CM_TIMEWAIT:
- break; /* Connection is ready to be destroyed. */
+ break;
default:
reset_cm_state(cm_id_priv);
break;
@@ -113,8 +164,7 @@
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
atomic_dec(&cm_id_priv->refcount);
- wait_event(cm_id_priv->wait,
- !atomic_read(&cm_id_priv->refcount));
+ wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount));
kfree(cm_id_priv);
return 0;
}
@@ -124,7 +174,33 @@
u64 service_id,
u64 service_mask)
{
- return -EINVAL;
+ struct ib_cm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret = 0;
+
+ cm_id_priv = container_of(cm_id, struct ib_cm_id_private, id);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id->state != IB_CM_IDLE) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = -EINVAL;
+ goto out;
+ }
+ cm_id->state = IB_CM_LISTEN;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ cm_id->service_id = service_id;
+ cm_id->service_mask = service_mask ? service_mask : ~0ULL;
+
+ spin_lock_irqsave(&cm.lock, flags);
+ if (find_cm_service(service_id)) {
+ /* No one else is able to change the cm_id state. */
+ cm_id->state = IB_CM_IDLE;
+ ret = -EBUSY;
+ } else
+ insert_cm_service(cm_id_priv);
+ spin_unlock_irqrestore(&cm.lock, flags);
+out:
+ return ret;
}
EXPORT_SYMBOL(ib_cm_listen);
@@ -291,6 +367,9 @@
static int __init ib_cm_init(void)
{
+ memset(&cm, 0, sizeof cm);
+ spin_lock_init(&cm.lock);
+ cm.service_table = RB_ROOT;
return ib_register_client(&cm_client);
}
More information about the general
mailing list