[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