aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/ucma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/ucma.c')
-rw-r--r--drivers/infiniband/core/ucma.c92
1 files changed, 92 insertions, 0 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,