aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/uverbs.h8
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c549
-rw-r--r--drivers/infiniband/core/uverbs_main.c16
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);
140IB_UVERBS_DECLARE_CMD(dereg_mr); 141IB_UVERBS_DECLARE_CMD(dereg_mr);
141IB_UVERBS_DECLARE_CMD(create_comp_channel); 142IB_UVERBS_DECLARE_CMD(create_comp_channel);
142IB_UVERBS_DECLARE_CMD(create_cq); 143IB_UVERBS_DECLARE_CMD(create_cq);
144IB_UVERBS_DECLARE_CMD(poll_cq);
145IB_UVERBS_DECLARE_CMD(req_notify_cq);
143IB_UVERBS_DECLARE_CMD(destroy_cq); 146IB_UVERBS_DECLARE_CMD(destroy_cq);
144IB_UVERBS_DECLARE_CMD(create_qp); 147IB_UVERBS_DECLARE_CMD(create_qp);
145IB_UVERBS_DECLARE_CMD(modify_qp); 148IB_UVERBS_DECLARE_CMD(modify_qp);
146IB_UVERBS_DECLARE_CMD(destroy_qp); 149IB_UVERBS_DECLARE_CMD(destroy_qp);
150IB_UVERBS_DECLARE_CMD(post_send);
151IB_UVERBS_DECLARE_CMD(post_recv);
152IB_UVERBS_DECLARE_CMD(post_srq_recv);
153IB_UVERBS_DECLARE_CMD(create_ah);
154IB_UVERBS_DECLARE_CMD(destroy_ah);
147IB_UVERBS_DECLARE_CMD(attach_mcast); 155IB_UVERBS_DECLARE_CMD(attach_mcast);
148IB_UVERBS_DECLARE_CMD(detach_mcast); 156IB_UVERBS_DECLARE_CMD(detach_mcast);
149IB_UVERBS_DECLARE_CMD(create_srq); 157IB_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
668ssize_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
723out:
724 up(&ib_uverbs_idr_mutex);
725 kfree(resp);
726
727out_wc:
728 kfree(wc);
729 return ret ? ret : in_len;
730}
731
732ssize_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
668ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, 755ssize_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
1093ssize_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
1223out:
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
1237static 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
1310err:
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
1322ssize_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
1361out:
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
1373ssize_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
1412out:
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
1424ssize_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
1476retry:
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
1505err_idr:
1506 idr_remove(&ib_uverbs_ah_idr, uobj->id);
1507
1508err_destroy:
1509 ib_destroy_ah(ah);
1510
1511err_up:
1512 up(&ib_uverbs_idr_mutex);
1513
1514 kfree(uobj);
1515 return ret;
1516}
1517
1518ssize_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
1549out:
1550 up(&ib_uverbs_idr_mutex);
1551
1552 return ret ? ret : in_len;
1553}
1554
1006ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, 1555ssize_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);