diff options
Diffstat (limited to 'drivers/infiniband/core/uverbs_cmd.c')
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 0cb0007724a2..3983a0552775 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -48,6 +48,7 @@ struct uverbs_lock_class { | |||
48 | 48 | ||
49 | static struct uverbs_lock_class pd_lock_class = { .name = "PD-uobj" }; | 49 | static struct uverbs_lock_class pd_lock_class = { .name = "PD-uobj" }; |
50 | static struct uverbs_lock_class mr_lock_class = { .name = "MR-uobj" }; | 50 | static struct uverbs_lock_class mr_lock_class = { .name = "MR-uobj" }; |
51 | static struct uverbs_lock_class mw_lock_class = { .name = "MW-uobj" }; | ||
51 | static struct uverbs_lock_class cq_lock_class = { .name = "CQ-uobj" }; | 52 | static struct uverbs_lock_class cq_lock_class = { .name = "CQ-uobj" }; |
52 | static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" }; | 53 | static struct uverbs_lock_class qp_lock_class = { .name = "QP-uobj" }; |
53 | static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" }; | 54 | static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" }; |
@@ -1049,6 +1050,126 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
1049 | return in_len; | 1050 | return in_len; |
1050 | } | 1051 | } |
1051 | 1052 | ||
1053 | ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file, | ||
1054 | const char __user *buf, int in_len, | ||
1055 | int out_len) | ||
1056 | { | ||
1057 | struct ib_uverbs_alloc_mw cmd; | ||
1058 | struct ib_uverbs_alloc_mw_resp resp; | ||
1059 | struct ib_uobject *uobj; | ||
1060 | struct ib_pd *pd; | ||
1061 | struct ib_mw *mw; | ||
1062 | int ret; | ||
1063 | |||
1064 | if (out_len < sizeof(resp)) | ||
1065 | return -ENOSPC; | ||
1066 | |||
1067 | if (copy_from_user(&cmd, buf, sizeof(cmd))) | ||
1068 | return -EFAULT; | ||
1069 | |||
1070 | uobj = kmalloc(sizeof(*uobj), GFP_KERNEL); | ||
1071 | if (!uobj) | ||
1072 | return -ENOMEM; | ||
1073 | |||
1074 | init_uobj(uobj, 0, file->ucontext, &mw_lock_class); | ||
1075 | down_write(&uobj->mutex); | ||
1076 | |||
1077 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); | ||
1078 | if (!pd) { | ||
1079 | ret = -EINVAL; | ||
1080 | goto err_free; | ||
1081 | } | ||
1082 | |||
1083 | mw = pd->device->alloc_mw(pd, cmd.mw_type); | ||
1084 | if (IS_ERR(mw)) { | ||
1085 | ret = PTR_ERR(mw); | ||
1086 | goto err_put; | ||
1087 | } | ||
1088 | |||
1089 | mw->device = pd->device; | ||
1090 | mw->pd = pd; | ||
1091 | mw->uobject = uobj; | ||
1092 | atomic_inc(&pd->usecnt); | ||
1093 | |||
1094 | uobj->object = mw; | ||
1095 | ret = idr_add_uobj(&ib_uverbs_mw_idr, uobj); | ||
1096 | if (ret) | ||
1097 | goto err_unalloc; | ||
1098 | |||
1099 | memset(&resp, 0, sizeof(resp)); | ||
1100 | resp.rkey = mw->rkey; | ||
1101 | resp.mw_handle = uobj->id; | ||
1102 | |||
1103 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | ||
1104 | &resp, sizeof(resp))) { | ||
1105 | ret = -EFAULT; | ||
1106 | goto err_copy; | ||
1107 | } | ||
1108 | |||
1109 | put_pd_read(pd); | ||
1110 | |||
1111 | mutex_lock(&file->mutex); | ||
1112 | list_add_tail(&uobj->list, &file->ucontext->mw_list); | ||
1113 | mutex_unlock(&file->mutex); | ||
1114 | |||
1115 | uobj->live = 1; | ||
1116 | |||
1117 | up_write(&uobj->mutex); | ||
1118 | |||
1119 | return in_len; | ||
1120 | |||
1121 | err_copy: | ||
1122 | idr_remove_uobj(&ib_uverbs_mw_idr, uobj); | ||
1123 | |||
1124 | err_unalloc: | ||
1125 | ib_dealloc_mw(mw); | ||
1126 | |||
1127 | err_put: | ||
1128 | put_pd_read(pd); | ||
1129 | |||
1130 | err_free: | ||
1131 | put_uobj_write(uobj); | ||
1132 | return ret; | ||
1133 | } | ||
1134 | |||
1135 | ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file, | ||
1136 | const char __user *buf, int in_len, | ||
1137 | int out_len) | ||
1138 | { | ||
1139 | struct ib_uverbs_dealloc_mw cmd; | ||
1140 | struct ib_mw *mw; | ||
1141 | struct ib_uobject *uobj; | ||
1142 | int ret = -EINVAL; | ||
1143 | |||
1144 | if (copy_from_user(&cmd, buf, sizeof(cmd))) | ||
1145 | return -EFAULT; | ||
1146 | |||
1147 | uobj = idr_write_uobj(&ib_uverbs_mw_idr, cmd.mw_handle, file->ucontext); | ||
1148 | if (!uobj) | ||
1149 | return -EINVAL; | ||
1150 | |||
1151 | mw = uobj->object; | ||
1152 | |||
1153 | ret = ib_dealloc_mw(mw); | ||
1154 | if (!ret) | ||
1155 | uobj->live = 0; | ||
1156 | |||
1157 | put_uobj_write(uobj); | ||
1158 | |||
1159 | if (ret) | ||
1160 | return ret; | ||
1161 | |||
1162 | idr_remove_uobj(&ib_uverbs_mw_idr, uobj); | ||
1163 | |||
1164 | mutex_lock(&file->mutex); | ||
1165 | list_del(&uobj->list); | ||
1166 | mutex_unlock(&file->mutex); | ||
1167 | |||
1168 | put_uobj(uobj); | ||
1169 | |||
1170 | return in_len; | ||
1171 | } | ||
1172 | |||
1052 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, | 1173 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, |
1053 | const char __user *buf, int in_len, | 1174 | const char __user *buf, int in_len, |
1054 | int out_len) | 1175 | int out_len) |