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);
 }
 
_______________________________________________
openib-general mailing list
[EMAIL PROTECTED]
http://openib.org/mailman/listinfo/openib-general

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

Reply via email to