aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2005-10-14 18:26:04 -0400
committerRoland Dreier <rolandd@cisco.com>2005-10-17 18:20:31 -0400
commit67cdb40ca444c09853ab4d8a41cf547ac26a4de4 (patch)
treefc0ecdf4e2c39db11849c79c594711c9e8e76a13 /drivers/infiniband
parent91ecd4ae178bed83da4f6a94ced7992e4d7711eb (diff)
[IB] uverbs: Implement more commands
Add kernel support for userspace calling poll CQ, request CQ notification, post send, post receive, post SRQ receive, create AH and destroy AH commands. These commands allow us to support userspace verbs for devices that can't perform these operations directly from userspace (eg the PathScale HCA). Signed-off-by: Roland Dreier <rolandd@cisco.com>
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);