Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=88314e4dda1e158aabce76429ef4d017b48f8b92
Commit:     88314e4dda1e158aabce76429ef4d017b48f8b92
Parent:     45d9478da106c749203056f56e94d0e370dfac87
Author:     Sean Hefty <[EMAIL PROTECTED]>
AuthorDate: Wed Nov 14 00:29:50 2007 -0800
Committer:  Roland Dreier <[EMAIL PROTECTED]>
CommitDate: Fri Jan 25 14:15:32 2008 -0800

    RDMA/cma: add support for rdma_migrate_id()
    
    This is based on user feedback from Doug Ledford at RedHat:
    
    Events that occur on an rdma_cm_id are reported to userspace through an
    event channel.  Connection request events are reported on the event
    channel associated with the listen.  When the connection is accepted, a
    new rdma_cm_id is created and automatically uses the listen event
    channel.  This is suboptimal where the user only wants listen events on
    that channel.
    
    Additionally, it may be desirable to have events related to connection
    establishment use a different event channel than those related to
    already established connections.
    
    Allow the user to migrate an rdma_cm_id between event channels. All
    pending events associated with the rdma_cm_id are moved to the new event
    channel.
    
    Signed-off-by: Sean Hefty <[EMAIL PROTECTED]>
    Signed-off-by: Roland Dreier <[EMAIL PROTECTED]>
---
 drivers/infiniband/core/ucma.c |   92 ++++++++++++++++++++++++++++++++++++++++
 include/rdma/rdma_user_cm.h    |   13 +++++-
 2 files changed, 104 insertions(+), 1 deletions(-)

diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 90d675a..15937eb 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -31,6 +31,7 @@
  */
 
 #include <linux/completion.h>
+#include <linux/file.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/idr.h>
@@ -991,6 +992,96 @@ out:
        return ret;
 }
 
+static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+       /* Acquire mutex's based on pointer comparison to prevent deadlock. */
+       if (file1 < file2) {
+               mutex_lock(&file1->mut);
+               mutex_lock(&file2->mut);
+       } else {
+               mutex_lock(&file2->mut);
+               mutex_lock(&file1->mut);
+       }
+}
+
+static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+       if (file1 < file2) {
+               mutex_unlock(&file2->mut);
+               mutex_unlock(&file1->mut);
+       } else {
+               mutex_unlock(&file1->mut);
+               mutex_unlock(&file2->mut);
+       }
+}
+
+static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
+{
+       struct ucma_event *uevent, *tmp;
+
+       list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
+               if (uevent->ctx == ctx)
+                       list_move_tail(&uevent->list, &file->event_list);
+}
+
+static ssize_t ucma_migrate_id(struct ucma_file *new_file,
+                              const char __user *inbuf,
+                              int in_len, int out_len)
+{
+       struct rdma_ucm_migrate_id cmd;
+       struct rdma_ucm_migrate_resp resp;
+       struct ucma_context *ctx;
+       struct file *filp;
+       struct ucma_file *cur_file;
+       int ret = 0;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       /* Get current fd to protect against it being closed */
+       filp = fget(cmd.fd);
+       if (!filp)
+               return -ENOENT;
+
+       /* Validate current fd and prevent destruction of id. */
+       ctx = ucma_get_ctx(filp->private_data, cmd.id);
+       if (IS_ERR(ctx)) {
+               ret = PTR_ERR(ctx);
+               goto file_put;
+       }
+
+       cur_file = ctx->file;
+       if (cur_file == new_file) {
+               resp.events_reported = ctx->events_reported;
+               goto response;
+       }
+
+       /*
+        * Migrate events between fd's, maintaining order, and avoiding new
+        * events being added before existing events.
+        */
+       ucma_lock_files(cur_file, new_file);
+       mutex_lock(&mut);
+
+       list_move_tail(&ctx->list, &new_file->ctx_list);
+       ucma_move_events(ctx, new_file);
+       ctx->file = new_file;
+       resp.events_reported = ctx->events_reported;
+
+       mutex_unlock(&mut);
+       ucma_unlock_files(cur_file, new_file);
+
+response:
+       if (copy_to_user((void __user *)(unsigned long)cmd.response,
+                        &resp, sizeof(resp)))
+               ret = -EFAULT;
+
+       ucma_put_ctx(ctx);
+file_put:
+       fput(filp);
+       return ret;
+}
+
 static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
                                   const char __user *inbuf,
                                   int in_len, int out_len) = {
@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
        [RDMA_USER_CM_CMD_NOTIFY]       = ucma_notify,
        [RDMA_USER_CM_CMD_JOIN_MCAST]   = ucma_join_multicast,
        [RDMA_USER_CM_CMD_LEAVE_MCAST]  = ucma_leave_multicast,
+       [RDMA_USER_CM_CMD_MIGRATE_ID]   = ucma_migrate_id
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,
diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h
index 9749c1b..c557054 100644
--- a/include/rdma/rdma_user_cm.h
+++ b/include/rdma/rdma_user_cm.h
@@ -60,7 +60,8 @@ enum {
        RDMA_USER_CM_CMD_SET_OPTION,
        RDMA_USER_CM_CMD_NOTIFY,
        RDMA_USER_CM_CMD_JOIN_MCAST,
-       RDMA_USER_CM_CMD_LEAVE_MCAST
+       RDMA_USER_CM_CMD_LEAVE_MCAST,
+       RDMA_USER_CM_CMD_MIGRATE_ID
 };
 
 /*
@@ -230,4 +231,14 @@ struct rdma_ucm_set_option {
        __u32 optlen;
 };
 
+struct rdma_ucm_migrate_id {
+       __u64 response;
+       __u32 id;
+       __u32 fd;
+};
+
+struct rdma_ucm_migrate_resp {
+       __u32 events_reported;
+};
+
 #endif /* RDMA_USER_CM_H */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to