diff options
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/uverbs.h | 8 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 549 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 16 |
3 files changed, 572 insertions, 1 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 475153e510a9..63c8085c0c98 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | 3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. |
4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. |
5 | * Copyright (c) 2005 Voltaire, Inc. All rights reserved. | 5 | * Copyright (c) 2005 Voltaire, Inc. All rights reserved. |
6 | * Copyright (c) 2005 PathScale, Inc. All rights reserved. | ||
6 | * | 7 | * |
7 | * This software is available to you under a choice of one of two | 8 | * This software is available to you under a choice of one of two |
8 | * licenses. You may choose to be licensed under the terms of the GNU | 9 | * licenses. You may choose to be licensed under the terms of the GNU |
@@ -140,10 +141,17 @@ IB_UVERBS_DECLARE_CMD(reg_mr); | |||
140 | IB_UVERBS_DECLARE_CMD(dereg_mr); | 141 | IB_UVERBS_DECLARE_CMD(dereg_mr); |
141 | IB_UVERBS_DECLARE_CMD(create_comp_channel); | 142 | IB_UVERBS_DECLARE_CMD(create_comp_channel); |
142 | IB_UVERBS_DECLARE_CMD(create_cq); | 143 | IB_UVERBS_DECLARE_CMD(create_cq); |
144 | IB_UVERBS_DECLARE_CMD(poll_cq); | ||
145 | IB_UVERBS_DECLARE_CMD(req_notify_cq); | ||
143 | IB_UVERBS_DECLARE_CMD(destroy_cq); | 146 | IB_UVERBS_DECLARE_CMD(destroy_cq); |
144 | IB_UVERBS_DECLARE_CMD(create_qp); | 147 | IB_UVERBS_DECLARE_CMD(create_qp); |
145 | IB_UVERBS_DECLARE_CMD(modify_qp); | 148 | IB_UVERBS_DECLARE_CMD(modify_qp); |
146 | IB_UVERBS_DECLARE_CMD(destroy_qp); | 149 | IB_UVERBS_DECLARE_CMD(destroy_qp); |
150 | IB_UVERBS_DECLARE_CMD(post_send); | ||
151 | IB_UVERBS_DECLARE_CMD(post_recv); | ||
152 | IB_UVERBS_DECLARE_CMD(post_srq_recv); | ||
153 | IB_UVERBS_DECLARE_CMD(create_ah); | ||
154 | IB_UVERBS_DECLARE_CMD(destroy_ah); | ||
147 | IB_UVERBS_DECLARE_CMD(attach_mcast); | 155 | IB_UVERBS_DECLARE_CMD(attach_mcast); |
148 | IB_UVERBS_DECLARE_CMD(detach_mcast); | 156 | IB_UVERBS_DECLARE_CMD(detach_mcast); |
149 | IB_UVERBS_DECLARE_CMD(create_srq); | 157 | IB_UVERBS_DECLARE_CMD(create_srq); |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 2e959acf2ff1..14583bb6e2c0 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -665,6 +665,93 @@ err: | |||
665 | return ret; | 665 | return ret; |
666 | } | 666 | } |
667 | 667 | ||
668 | ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, | ||
669 | const char __user *buf, int in_len, | ||
670 | int out_len) | ||
671 | { | ||
672 | struct ib_uverbs_poll_cq cmd; | ||
673 | struct ib_uverbs_poll_cq_resp *resp; | ||
674 | struct ib_cq *cq; | ||
675 | struct ib_wc *wc; | ||
676 | int ret = 0; | ||
677 | int i; | ||
678 | int rsize; | ||
679 | |||
680 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
681 | return -EFAULT; | ||
682 | |||
683 | wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); | ||
684 | if (!wc) | ||
685 | return -ENOMEM; | ||
686 | |||
687 | rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); | ||
688 | resp = kmalloc(rsize, GFP_KERNEL); | ||
689 | if (!resp) { | ||
690 | ret = -ENOMEM; | ||
691 | goto out_wc; | ||
692 | } | ||
693 | |||
694 | down(&ib_uverbs_idr_mutex); | ||
695 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | ||
696 | if (!cq || cq->uobject->context != file->ucontext) { | ||
697 | ret = -EINVAL; | ||
698 | goto out; | ||
699 | } | ||
700 | |||
701 | resp->count = ib_poll_cq(cq, cmd.ne, wc); | ||
702 | |||
703 | for (i = 0; i < resp->count; i++) { | ||
704 | resp->wc[i].wr_id = wc[i].wr_id; | ||
705 | resp->wc[i].status = wc[i].status; | ||
706 | resp->wc[i].opcode = wc[i].opcode; | ||
707 | resp->wc[i].vendor_err = wc[i].vendor_err; | ||
708 | resp->wc[i].byte_len = wc[i].byte_len; | ||
709 | resp->wc[i].imm_data = wc[i].imm_data; | ||
710 | resp->wc[i].qp_num = wc[i].qp_num; | ||
711 | resp->wc[i].src_qp = wc[i].src_qp; | ||
712 | resp->wc[i].wc_flags = wc[i].wc_flags; | ||
713 | resp->wc[i].pkey_index = wc[i].pkey_index; | ||
714 | resp->wc[i].slid = wc[i].slid; | ||
715 | resp->wc[i].sl = wc[i].sl; | ||
716 | resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; | ||
717 | resp->wc[i].port_num = wc[i].port_num; | ||
718 | } | ||
719 | |||
720 | if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) | ||
721 | ret = -EFAULT; | ||
722 | |||
723 | out: | ||
724 | up(&ib_uverbs_idr_mutex); | ||
725 | kfree(resp); | ||
726 | |||
727 | out_wc: | ||
728 | kfree(wc); | ||
729 | return ret ? ret : in_len; | ||
730 | } | ||
731 | |||
732 | ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, | ||
733 | const char __user *buf, int in_len, | ||
734 | int out_len) | ||
735 | { | ||
736 | struct ib_uverbs_req_notify_cq cmd; | ||
737 | struct ib_cq *cq; | ||
738 | int ret = -EINVAL; | ||
739 | |||
740 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
741 | return -EFAULT; | ||
742 | |||
743 | down(&ib_uverbs_idr_mutex); | ||
744 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | ||
745 | if (cq && cq->uobject->context == file->ucontext) { | ||
746 | ib_req_notify_cq(cq, cmd.solicited_only ? | ||
747 | IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); | ||
748 | ret = in_len; | ||
749 | } | ||
750 | up(&ib_uverbs_idr_mutex); | ||
751 | |||
752 | return ret; | ||
753 | } | ||
754 | |||
668 | ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | 755 | ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, |
669 | const char __user *buf, int in_len, | 756 | const char __user *buf, int in_len, |
670 | int out_len) | 757 | int out_len) |
@@ -1003,6 +1090,468 @@ out: | |||
1003 | return ret ? ret : in_len; | 1090 | return ret ? ret : in_len; |
1004 | } | 1091 | } |
1005 | 1092 | ||
1093 | ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | ||
1094 | const char __user *buf, int in_len, | ||
1095 | int out_len) | ||
1096 | { | ||
1097 | struct ib_uverbs_post_send cmd; | ||
1098 | struct ib_uverbs_post_send_resp resp; | ||
1099 | struct ib_uverbs_send_wr *user_wr; | ||
1100 | struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; | ||
1101 | struct ib_qp *qp; | ||
1102 | int i, sg_ind; | ||
1103 | ssize_t ret = -EINVAL; | ||
1104 | |||
1105 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
1106 | return -EFAULT; | ||
1107 | |||
1108 | if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count + | ||
1109 | cmd.sge_count * sizeof (struct ib_uverbs_sge)) | ||
1110 | return -EINVAL; | ||
1111 | |||
1112 | if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr)) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); | ||
1116 | if (!user_wr) | ||
1117 | return -ENOMEM; | ||
1118 | |||
1119 | down(&ib_uverbs_idr_mutex); | ||
1120 | |||
1121 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
1122 | if (!qp || qp->uobject->context != file->ucontext) | ||
1123 | goto out; | ||
1124 | |||
1125 | sg_ind = 0; | ||
1126 | last = NULL; | ||
1127 | for (i = 0; i < cmd.wr_count; ++i) { | ||
1128 | if (copy_from_user(user_wr, | ||
1129 | buf + sizeof cmd + i * cmd.wqe_size, | ||
1130 | cmd.wqe_size)) { | ||
1131 | ret = -EFAULT; | ||
1132 | goto out; | ||
1133 | } | ||
1134 | |||
1135 | if (user_wr->num_sge + sg_ind > cmd.sge_count) { | ||
1136 | ret = -EINVAL; | ||
1137 | goto out; | ||
1138 | } | ||
1139 | |||
1140 | next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + | ||
1141 | user_wr->num_sge * sizeof (struct ib_sge), | ||
1142 | GFP_KERNEL); | ||
1143 | if (!next) { | ||
1144 | ret = -ENOMEM; | ||
1145 | goto out; | ||
1146 | } | ||
1147 | |||
1148 | if (!last) | ||
1149 | wr = next; | ||
1150 | else | ||
1151 | last->next = next; | ||
1152 | last = next; | ||
1153 | |||
1154 | next->next = NULL; | ||
1155 | next->wr_id = user_wr->wr_id; | ||
1156 | next->num_sge = user_wr->num_sge; | ||
1157 | next->opcode = user_wr->opcode; | ||
1158 | next->send_flags = user_wr->send_flags; | ||
1159 | next->imm_data = user_wr->imm_data; | ||
1160 | |||
1161 | if (qp->qp_type == IB_QPT_UD) { | ||
1162 | next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, | ||
1163 | user_wr->wr.ud.ah); | ||
1164 | if (!next->wr.ud.ah) { | ||
1165 | ret = -EINVAL; | ||
1166 | goto out; | ||
1167 | } | ||
1168 | next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; | ||
1169 | next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; | ||
1170 | } else { | ||
1171 | switch (next->opcode) { | ||
1172 | case IB_WR_RDMA_WRITE: | ||
1173 | case IB_WR_RDMA_WRITE_WITH_IMM: | ||
1174 | case IB_WR_RDMA_READ: | ||
1175 | next->wr.rdma.remote_addr = | ||
1176 | user_wr->wr.rdma.remote_addr; | ||
1177 | next->wr.rdma.rkey = | ||
1178 | user_wr->wr.rdma.rkey; | ||
1179 | break; | ||
1180 | case IB_WR_ATOMIC_CMP_AND_SWP: | ||
1181 | case IB_WR_ATOMIC_FETCH_AND_ADD: | ||
1182 | next->wr.atomic.remote_addr = | ||
1183 | user_wr->wr.atomic.remote_addr; | ||
1184 | next->wr.atomic.compare_add = | ||
1185 | user_wr->wr.atomic.compare_add; | ||
1186 | next->wr.atomic.swap = user_wr->wr.atomic.swap; | ||
1187 | next->wr.atomic.rkey = user_wr->wr.atomic.rkey; | ||
1188 | break; | ||
1189 | default: | ||
1190 | break; | ||
1191 | } | ||
1192 | } | ||
1193 | |||
1194 | if (next->num_sge) { | ||
1195 | next->sg_list = (void *) next + | ||
1196 | ALIGN(sizeof *next, sizeof (struct ib_sge)); | ||
1197 | if (copy_from_user(next->sg_list, | ||
1198 | buf + sizeof cmd + | ||
1199 | cmd.wr_count * cmd.wqe_size + | ||
1200 | sg_ind * sizeof (struct ib_sge), | ||
1201 | next->num_sge * sizeof (struct ib_sge))) { | ||
1202 | ret = -EFAULT; | ||
1203 | goto out; | ||
1204 | } | ||
1205 | sg_ind += next->num_sge; | ||
1206 | } else | ||
1207 | next->sg_list = NULL; | ||
1208 | } | ||
1209 | |||
1210 | resp.bad_wr = 0; | ||
1211 | ret = qp->device->post_send(qp, wr, &bad_wr); | ||
1212 | if (ret) | ||
1213 | for (next = wr; next; next = next->next) { | ||
1214 | ++resp.bad_wr; | ||
1215 | if (next == bad_wr) | ||
1216 | break; | ||
1217 | } | ||
1218 | |||
1219 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1220 | &resp, sizeof resp)) | ||
1221 | ret = -EFAULT; | ||
1222 | |||
1223 | out: | ||
1224 | up(&ib_uverbs_idr_mutex); | ||
1225 | |||
1226 | while (wr) { | ||
1227 | next = wr->next; | ||
1228 | kfree(wr); | ||
1229 | wr = next; | ||
1230 | } | ||
1231 | |||
1232 | kfree(user_wr); | ||
1233 | |||
1234 | return ret ? ret : in_len; | ||
1235 | } | ||
1236 | |||
1237 | static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, | ||
1238 | int in_len, | ||
1239 | u32 wr_count, | ||
1240 | u32 sge_count, | ||
1241 | u32 wqe_size) | ||
1242 | { | ||
1243 | struct ib_uverbs_recv_wr *user_wr; | ||
1244 | struct ib_recv_wr *wr = NULL, *last, *next; | ||
1245 | int sg_ind; | ||
1246 | int i; | ||
1247 | int ret; | ||
1248 | |||
1249 | if (in_len < wqe_size * wr_count + | ||
1250 | sge_count * sizeof (struct ib_uverbs_sge)) | ||
1251 | return ERR_PTR(-EINVAL); | ||
1252 | |||
1253 | if (wqe_size < sizeof (struct ib_uverbs_recv_wr)) | ||
1254 | return ERR_PTR(-EINVAL); | ||
1255 | |||
1256 | user_wr = kmalloc(wqe_size, GFP_KERNEL); | ||
1257 | if (!user_wr) | ||
1258 | return ERR_PTR(-ENOMEM); | ||
1259 | |||
1260 | sg_ind = 0; | ||
1261 | last = NULL; | ||
1262 | for (i = 0; i < wr_count; ++i) { | ||
1263 | if (copy_from_user(user_wr, buf + i * wqe_size, | ||
1264 | wqe_size)) { | ||
1265 | ret = -EFAULT; | ||
1266 | goto err; | ||
1267 | } | ||
1268 | |||
1269 | if (user_wr->num_sge + sg_ind > sge_count) { | ||
1270 | ret = -EINVAL; | ||
1271 | goto err; | ||
1272 | } | ||
1273 | |||
1274 | next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + | ||
1275 | user_wr->num_sge * sizeof (struct ib_sge), | ||
1276 | GFP_KERNEL); | ||
1277 | if (!next) { | ||
1278 | ret = -ENOMEM; | ||
1279 | goto err; | ||
1280 | } | ||
1281 | |||
1282 | if (!last) | ||
1283 | wr = next; | ||
1284 | else | ||
1285 | last->next = next; | ||
1286 | last = next; | ||
1287 | |||
1288 | next->next = NULL; | ||
1289 | next->wr_id = user_wr->wr_id; | ||
1290 | next->num_sge = user_wr->num_sge; | ||
1291 | |||
1292 | if (next->num_sge) { | ||
1293 | next->sg_list = (void *) next + | ||
1294 | ALIGN(sizeof *next, sizeof (struct ib_sge)); | ||
1295 | if (copy_from_user(next->sg_list, | ||
1296 | buf + wr_count * wqe_size + | ||
1297 | sg_ind * sizeof (struct ib_sge), | ||
1298 | next->num_sge * sizeof (struct ib_sge))) { | ||
1299 | ret = -EFAULT; | ||
1300 | goto err; | ||
1301 | } | ||
1302 | sg_ind += next->num_sge; | ||
1303 | } else | ||
1304 | next->sg_list = NULL; | ||
1305 | } | ||
1306 | |||
1307 | kfree(user_wr); | ||
1308 | return wr; | ||
1309 | |||
1310 | err: | ||
1311 | kfree(user_wr); | ||
1312 | |||
1313 | while (wr) { | ||
1314 | next = wr->next; | ||
1315 | kfree(wr); | ||
1316 | wr = next; | ||
1317 | } | ||
1318 | |||
1319 | return ERR_PTR(ret); | ||
1320 | } | ||
1321 | |||
1322 | ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, | ||
1323 | const char __user *buf, int in_len, | ||
1324 | int out_len) | ||
1325 | { | ||
1326 | struct ib_uverbs_post_recv cmd; | ||
1327 | struct ib_uverbs_post_recv_resp resp; | ||
1328 | struct ib_recv_wr *wr, *next, *bad_wr; | ||
1329 | struct ib_qp *qp; | ||
1330 | ssize_t ret = -EINVAL; | ||
1331 | |||
1332 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
1333 | return -EFAULT; | ||
1334 | |||
1335 | wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, | ||
1336 | in_len - sizeof cmd, cmd.wr_count, | ||
1337 | cmd.sge_count, cmd.wqe_size); | ||
1338 | if (IS_ERR(wr)) | ||
1339 | return PTR_ERR(wr); | ||
1340 | |||
1341 | down(&ib_uverbs_idr_mutex); | ||
1342 | |||
1343 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
1344 | if (!qp || qp->uobject->context != file->ucontext) | ||
1345 | goto out; | ||
1346 | |||
1347 | resp.bad_wr = 0; | ||
1348 | ret = qp->device->post_recv(qp, wr, &bad_wr); | ||
1349 | if (ret) | ||
1350 | for (next = wr; next; next = next->next) { | ||
1351 | ++resp.bad_wr; | ||
1352 | if (next == bad_wr) | ||
1353 | break; | ||
1354 | } | ||
1355 | |||
1356 | |||
1357 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1358 | &resp, sizeof resp)) | ||
1359 | ret = -EFAULT; | ||
1360 | |||
1361 | out: | ||
1362 | up(&ib_uverbs_idr_mutex); | ||
1363 | |||
1364 | while (wr) { | ||
1365 | next = wr->next; | ||
1366 | kfree(wr); | ||
1367 | wr = next; | ||
1368 | } | ||
1369 | |||
1370 | return ret ? ret : in_len; | ||
1371 | } | ||
1372 | |||
1373 | ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, | ||
1374 | const char __user *buf, int in_len, | ||
1375 | int out_len) | ||
1376 | { | ||
1377 | struct ib_uverbs_post_srq_recv cmd; | ||
1378 | struct ib_uverbs_post_srq_recv_resp resp; | ||
1379 | struct ib_recv_wr *wr, *next, *bad_wr; | ||
1380 | struct ib_srq *srq; | ||
1381 | ssize_t ret = -EINVAL; | ||
1382 | |||
1383 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
1384 | return -EFAULT; | ||
1385 | |||
1386 | wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, | ||
1387 | in_len - sizeof cmd, cmd.wr_count, | ||
1388 | cmd.sge_count, cmd.wqe_size); | ||
1389 | if (IS_ERR(wr)) | ||
1390 | return PTR_ERR(wr); | ||
1391 | |||
1392 | down(&ib_uverbs_idr_mutex); | ||
1393 | |||
1394 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | ||
1395 | if (!srq || srq->uobject->context != file->ucontext) | ||
1396 | goto out; | ||
1397 | |||
1398 | resp.bad_wr = 0; | ||
1399 | ret = srq->device->post_srq_recv(srq, wr, &bad_wr); | ||
1400 | if (ret) | ||
1401 | for (next = wr; next; next = next->next) { | ||
1402 | ++resp.bad_wr; | ||
1403 | if (next == bad_wr) | ||
1404 | break; | ||
1405 | } | ||
1406 | |||
1407 | |||
1408 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1409 | &resp, sizeof resp)) | ||
1410 | ret = -EFAULT; | ||
1411 | |||
1412 | out: | ||
1413 | up(&ib_uverbs_idr_mutex); | ||
1414 | |||
1415 | while (wr) { | ||
1416 | next = wr->next; | ||
1417 | kfree(wr); | ||
1418 | wr = next; | ||
1419 | } | ||
1420 | |||
1421 | return ret ? ret : in_len; | ||
1422 | } | ||
1423 | |||
1424 | ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, | ||
1425 | const char __user *buf, int in_len, | ||
1426 | int out_len) | ||
1427 | { | ||
1428 | struct ib_uverbs_create_ah cmd; | ||
1429 | struct ib_uverbs_create_ah_resp resp; | ||
1430 | struct ib_uobject *uobj; | ||
1431 | struct ib_pd *pd; | ||
1432 | struct ib_ah *ah; | ||
1433 | struct ib_ah_attr attr; | ||
1434 | int ret; | ||
1435 | |||
1436 | if (out_len < sizeof resp) | ||
1437 | return -ENOSPC; | ||
1438 | |||
1439 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
1440 | return -EFAULT; | ||
1441 | |||
1442 | uobj = kmalloc(sizeof *uobj, GFP_KERNEL); | ||
1443 | if (!uobj) | ||
1444 | return -ENOMEM; | ||
1445 | |||
1446 | down(&ib_uverbs_idr_mutex); | ||
1447 | |||
1448 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | ||
1449 | if (!pd || pd->uobject->context != file->ucontext) { | ||
1450 | ret = -EINVAL; | ||
1451 | goto err_up; | ||
1452 | } | ||
1453 | |||
1454 | uobj->user_handle = cmd.user_handle; | ||
1455 | uobj->context = file->ucontext; | ||
1456 | |||
1457 | attr.dlid = cmd.attr.dlid; | ||
1458 | attr.sl = cmd.attr.sl; | ||
1459 | attr.src_path_bits = cmd.attr.src_path_bits; | ||
1460 | attr.static_rate = cmd.attr.static_rate; | ||
1461 | attr.port_num = cmd.attr.port_num; | ||
1462 | attr.grh.flow_label = cmd.attr.grh.flow_label; | ||
1463 | attr.grh.sgid_index = cmd.attr.grh.sgid_index; | ||
1464 | attr.grh.hop_limit = cmd.attr.grh.hop_limit; | ||
1465 | attr.grh.traffic_class = cmd.attr.grh.traffic_class; | ||
1466 | memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); | ||
1467 | |||
1468 | ah = ib_create_ah(pd, &attr); | ||
1469 | if (IS_ERR(ah)) { | ||
1470 | ret = PTR_ERR(ah); | ||
1471 | goto err_up; | ||
1472 | } | ||
1473 | |||
1474 | ah->uobject = uobj; | ||
1475 | |||
1476 | retry: | ||
1477 | if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) { | ||
1478 | ret = -ENOMEM; | ||
1479 | goto err_destroy; | ||
1480 | } | ||
1481 | |||
1482 | ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id); | ||
1483 | |||
1484 | if (ret == -EAGAIN) | ||
1485 | goto retry; | ||
1486 | if (ret) | ||
1487 | goto err_destroy; | ||
1488 | |||
1489 | resp.ah_handle = uobj->id; | ||
1490 | |||
1491 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
1492 | &resp, sizeof resp)) { | ||
1493 | ret = -EFAULT; | ||
1494 | goto err_idr; | ||
1495 | } | ||
1496 | |||
1497 | down(&file->mutex); | ||
1498 | list_add_tail(&uobj->list, &file->ucontext->ah_list); | ||
1499 | up(&file->mutex); | ||
1500 | |||
1501 | up(&ib_uverbs_idr_mutex); | ||
1502 | |||
1503 | return in_len; | ||
1504 | |||
1505 | err_idr: | ||
1506 | idr_remove(&ib_uverbs_ah_idr, uobj->id); | ||
1507 | |||
1508 | err_destroy: | ||
1509 | ib_destroy_ah(ah); | ||
1510 | |||
1511 | err_up: | ||
1512 | up(&ib_uverbs_idr_mutex); | ||
1513 | |||
1514 | kfree(uobj); | ||
1515 | return ret; | ||
1516 | } | ||
1517 | |||
1518 | ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, | ||
1519 | const char __user *buf, int in_len, int out_len) | ||
1520 | { | ||
1521 | struct ib_uverbs_destroy_ah cmd; | ||
1522 | struct ib_ah *ah; | ||
1523 | struct ib_uobject *uobj; | ||
1524 | int ret = -EINVAL; | ||
1525 | |||
1526 | if (copy_from_user(&cmd, buf, sizeof cmd)) | ||
1527 | return -EFAULT; | ||
1528 | |||
1529 | down(&ib_uverbs_idr_mutex); | ||
1530 | |||
1531 | ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle); | ||
1532 | if (!ah || ah->uobject->context != file->ucontext) | ||
1533 | goto out; | ||
1534 | |||
1535 | uobj = ah->uobject; | ||
1536 | |||
1537 | ret = ib_destroy_ah(ah); | ||
1538 | if (ret) | ||
1539 | goto out; | ||
1540 | |||
1541 | idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle); | ||
1542 | |||
1543 | down(&file->mutex); | ||
1544 | list_del(&uobj->list); | ||
1545 | up(&file->mutex); | ||
1546 | |||
1547 | kfree(uobj); | ||
1548 | |||
1549 | out: | ||
1550 | up(&ib_uverbs_idr_mutex); | ||
1551 | |||
1552 | return ret ? ret : in_len; | ||
1553 | } | ||
1554 | |||
1006 | ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, | 1555 | ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, |
1007 | const char __user *buf, int in_len, | 1556 | const char __user *buf, int in_len, |
1008 | int out_len) | 1557 | int out_len) |
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 6a5e5084db7a..ef2312a9ea76 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | 3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. |
4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. |
5 | * Copyright (c) 2005 Voltaire, Inc. All rights reserved. | 5 | * Copyright (c) 2005 Voltaire, Inc. All rights reserved. |
6 | * Copyright (c) 2005 PathScale, Inc. All rights reserved. | ||
6 | * | 7 | * |
7 | * This software is available to you under a choice of one of two | 8 | * This software is available to you under a choice of one of two |
8 | * licenses. You may choose to be licensed under the terms of the GNU | 9 | * licenses. You may choose to be licensed under the terms of the GNU |
@@ -86,10 +87,17 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, | |||
86 | [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, | 87 | [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, |
87 | [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, | 88 | [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, |
88 | [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, | 89 | [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, |
90 | [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, | ||
91 | [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, | ||
89 | [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, | 92 | [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, |
90 | [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, | 93 | [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, |
91 | [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, | 94 | [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, |
92 | [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, | 95 | [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, |
96 | [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, | ||
97 | [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, | ||
98 | [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, | ||
99 | [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, | ||
100 | [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, | ||
93 | [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, | 101 | [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, |
94 | [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, | 102 | [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, |
95 | [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, | 103 | [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, |
@@ -111,7 +119,13 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
111 | 119 | ||
112 | down(&ib_uverbs_idr_mutex); | 120 | down(&ib_uverbs_idr_mutex); |
113 | 121 | ||
114 | /* XXX Free AHs */ | 122 | list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { |
123 | struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); | ||
124 | idr_remove(&ib_uverbs_ah_idr, uobj->id); | ||
125 | ib_destroy_ah(ah); | ||
126 | list_del(&uobj->list); | ||
127 | kfree(uobj); | ||
128 | } | ||
115 | 129 | ||
116 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { | 130 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { |
117 | struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); | 131 | struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); |