aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2007-11-14 03:29:50 -0500
committerRoland Dreier <rolandd@cisco.com>2008-01-25 17:15:32 -0500
commit88314e4dda1e158aabce76429ef4d017b48f8b92 (patch)
tree951aad1d512d0ac0fce5bfd6189e7ed1fbd84e71
parent45d9478da106c749203056f56e94d0e370dfac87 (diff)
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 <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/core/ucma.c92
-rw-r--r--include/rdma/rdma_user_cm.h13
2 files changed, 104 insertions, 1 deletions
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 90d675ad9ec8..15937eb38aae 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -31,6 +31,7 @@
31 */ 31 */
32 32
33#include <linux/completion.h> 33#include <linux/completion.h>
34#include <linux/file.h>
34#include <linux/mutex.h> 35#include <linux/mutex.h>
35#include <linux/poll.h> 36#include <linux/poll.h>
36#include <linux/idr.h> 37#include <linux/idr.h>
@@ -991,6 +992,96 @@ out:
991 return ret; 992 return ret;
992} 993}
993 994
995static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
996{
997 /* Acquire mutex's based on pointer comparison to prevent deadlock. */
998 if (file1 < file2) {
999 mutex_lock(&file1->mut);
1000 mutex_lock(&file2->mut);
1001 } else {
1002 mutex_lock(&file2->mut);
1003 mutex_lock(&file1->mut);
1004 }
1005}
1006
1007static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
1008{
1009 if (file1 < file2) {
1010 mutex_unlock(&file2->mut);
1011 mutex_unlock(&file1->mut);
1012 } else {
1013 mutex_unlock(&file1->mut);
1014 mutex_unlock(&file2->mut);
1015 }
1016}
1017
1018static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
1019{
1020 struct ucma_event *uevent, *tmp;
1021
1022 list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
1023 if (uevent->ctx == ctx)
1024 list_move_tail(&uevent->list, &file->event_list);
1025}
1026
1027static ssize_t ucma_migrate_id(struct ucma_file *new_file,
1028 const char __user *inbuf,
1029 int in_len, int out_len)
1030{
1031 struct rdma_ucm_migrate_id cmd;
1032 struct rdma_ucm_migrate_resp resp;
1033 struct ucma_context *ctx;
1034 struct file *filp;
1035 struct ucma_file *cur_file;
1036 int ret = 0;
1037
1038 if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
1039 return -EFAULT;
1040
1041 /* Get current fd to protect against it being closed */
1042 filp = fget(cmd.fd);
1043 if (!filp)
1044 return -ENOENT;
1045
1046 /* Validate current fd and prevent destruction of id. */
1047 ctx = ucma_get_ctx(filp->private_data, cmd.id);
1048 if (IS_ERR(ctx)) {
1049 ret = PTR_ERR(ctx);
1050 goto file_put;
1051 }
1052
1053 cur_file = ctx->file;
1054 if (cur_file == new_file) {
1055 resp.events_reported = ctx->events_reported;
1056 goto response;
1057 }
1058
1059 /*
1060 * Migrate events between fd's, maintaining order, and avoiding new
1061 * events being added before existing events.
1062 */
1063 ucma_lock_files(cur_file, new_file);
1064 mutex_lock(&mut);
1065
1066 list_move_tail(&ctx->list, &new_file->ctx_list);
1067 ucma_move_events(ctx, new_file);
1068 ctx->file = new_file;
1069 resp.events_reported = ctx->events_reported;
1070
1071 mutex_unlock(&mut);
1072 ucma_unlock_files(cur_file, new_file);
1073
1074response:
1075 if (copy_to_user((void __user *)(unsigned long)cmd.response,
1076 &resp, sizeof(resp)))
1077 ret = -EFAULT;
1078
1079 ucma_put_ctx(ctx);
1080file_put:
1081 fput(filp);
1082 return ret;
1083}
1084
994static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, 1085static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
995 const char __user *inbuf, 1086 const char __user *inbuf,
996 int in_len, int out_len) = { 1087 int in_len, int out_len) = {
@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
1012 [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, 1103 [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
1013 [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, 1104 [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
1014 [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, 1105 [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
1106 [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id
1015}; 1107};
1016 1108
1017static ssize_t ucma_write(struct file *filp, const char __user *buf, 1109static 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 9749c1b34d00..c55705460b87 100644
--- a/include/rdma/rdma_user_cm.h
+++ b/include/rdma/rdma_user_cm.h
@@ -60,7 +60,8 @@ enum {
60 RDMA_USER_CM_CMD_SET_OPTION, 60 RDMA_USER_CM_CMD_SET_OPTION,
61 RDMA_USER_CM_CMD_NOTIFY, 61 RDMA_USER_CM_CMD_NOTIFY,
62 RDMA_USER_CM_CMD_JOIN_MCAST, 62 RDMA_USER_CM_CMD_JOIN_MCAST,
63 RDMA_USER_CM_CMD_LEAVE_MCAST 63 RDMA_USER_CM_CMD_LEAVE_MCAST,
64 RDMA_USER_CM_CMD_MIGRATE_ID
64}; 65};
65 66
66/* 67/*
@@ -230,4 +231,14 @@ struct rdma_ucm_set_option {
230 __u32 optlen; 231 __u32 optlen;
231}; 232};
232 233
234struct rdma_ucm_migrate_id {
235 __u64 response;
236 __u32 id;
237 __u32 fd;
238};
239
240struct rdma_ucm_migrate_resp {
241 __u32 events_reported;
242};
243
233#endif /* RDMA_USER_CM_H */ 244#endif /* RDMA_USER_CM_H */