]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/infiniband/core/uverbs_cmd.c
IB/uverbs: Fix reference counting on error paths
[mirror_ubuntu-hirsute-kernel.git] / drivers / infiniband / core / uverbs_cmd.c
CommitLineData
bc38a6ab
RD
1/*
2 * Copyright (c) 2005 Topspin Communications. All rights reserved.
3 * Copyright (c) 2005 Cisco Systems. All rights reserved.
eb9d3cd5 4 * Copyright (c) 2005 PathScale, Inc. All rights reserved.
bc38a6ab
RD
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $
35 */
36
6b73597e 37#include <linux/file.h>
70a30e16 38#include <linux/fs.h>
6b73597e 39
bc38a6ab
RD
40#include <asm/uaccess.h>
41
42#include "uverbs.h"
43
44#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
45 do { \
46 (udata)->inbuf = (void __user *) (ibuf); \
47 (udata)->outbuf = (void __user *) (obuf); \
48 (udata)->inlen = (ilen); \
49 (udata)->outlen = (olen); \
50 } while (0)
51
bc38a6ab
RD
52ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
53 const char __user *buf,
54 int in_len, int out_len)
55{
56 struct ib_uverbs_get_context cmd;
57 struct ib_uverbs_get_context_resp resp;
58 struct ib_udata udata;
59 struct ib_device *ibdev = file->device->ib_dev;
63c47c28 60 struct ib_ucontext *ucontext;
6b73597e 61 struct file *filp;
63c47c28 62 int ret;
bc38a6ab
RD
63
64 if (out_len < sizeof resp)
65 return -ENOSPC;
66
67 if (copy_from_user(&cmd, buf, sizeof cmd))
68 return -EFAULT;
69
63c47c28
RD
70 down(&file->mutex);
71
72 if (file->ucontext) {
73 ret = -EINVAL;
74 goto err;
75 }
76
bc38a6ab
RD
77 INIT_UDATA(&udata, buf + sizeof cmd,
78 (unsigned long) cmd.response + sizeof resp,
79 in_len - sizeof cmd, out_len - sizeof resp);
80
63c47c28
RD
81 ucontext = ibdev->alloc_ucontext(ibdev, &udata);
82 if (IS_ERR(ucontext))
83 return PTR_ERR(file->ucontext);
bc38a6ab 84
63c47c28
RD
85 ucontext->device = ibdev;
86 INIT_LIST_HEAD(&ucontext->pd_list);
87 INIT_LIST_HEAD(&ucontext->mr_list);
88 INIT_LIST_HEAD(&ucontext->mw_list);
89 INIT_LIST_HEAD(&ucontext->cq_list);
90 INIT_LIST_HEAD(&ucontext->qp_list);
91 INIT_LIST_HEAD(&ucontext->srq_list);
92 INIT_LIST_HEAD(&ucontext->ah_list);
bc38a6ab 93
6b73597e
RD
94 resp.num_comp_vectors = file->device->num_comp_vectors;
95
96 filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd);
97 if (IS_ERR(filp)) {
98 ret = PTR_ERR(filp);
99 goto err_free;
100 }
bc38a6ab
RD
101
102 if (copy_to_user((void __user *) (unsigned long) cmd.response,
63c47c28
RD
103 &resp, sizeof resp)) {
104 ret = -EFAULT;
6b73597e 105 goto err_file;
63c47c28
RD
106 }
107
6b73597e
RD
108 file->async_file = filp->private_data;
109
110 INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev,
111 ib_uverbs_event_handler);
112 ret = ib_register_event_handler(&file->event_handler);
113 if (ret)
114 goto err_file;
115
116 kref_get(&file->async_file->ref);
117 kref_get(&file->ref);
70a30e16 118 file->ucontext = ucontext;
6b73597e
RD
119
120 fd_install(resp.async_fd, filp);
121
63c47c28 122 up(&file->mutex);
bc38a6ab
RD
123
124 return in_len;
125
6b73597e
RD
126err_file:
127 put_unused_fd(resp.async_fd);
128 fput(filp);
129
63c47c28
RD
130err_free:
131 ibdev->dealloc_ucontext(ucontext);
bc38a6ab 132
63c47c28
RD
133err:
134 up(&file->mutex);
135 return ret;
bc38a6ab
RD
136}
137
138ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
139 const char __user *buf,
140 int in_len, int out_len)
141{
142 struct ib_uverbs_query_device cmd;
143 struct ib_uverbs_query_device_resp resp;
144 struct ib_device_attr attr;
145 int ret;
146
147 if (out_len < sizeof resp)
148 return -ENOSPC;
149
150 if (copy_from_user(&cmd, buf, sizeof cmd))
151 return -EFAULT;
152
153 ret = ib_query_device(file->device->ib_dev, &attr);
154 if (ret)
155 return ret;
156
157 memset(&resp, 0, sizeof resp);
158
159 resp.fw_ver = attr.fw_ver;
160 resp.node_guid = attr.node_guid;
161 resp.sys_image_guid = attr.sys_image_guid;
162 resp.max_mr_size = attr.max_mr_size;
163 resp.page_size_cap = attr.page_size_cap;
164 resp.vendor_id = attr.vendor_id;
165 resp.vendor_part_id = attr.vendor_part_id;
166 resp.hw_ver = attr.hw_ver;
167 resp.max_qp = attr.max_qp;
168 resp.max_qp_wr = attr.max_qp_wr;
169 resp.device_cap_flags = attr.device_cap_flags;
170 resp.max_sge = attr.max_sge;
171 resp.max_sge_rd = attr.max_sge_rd;
172 resp.max_cq = attr.max_cq;
173 resp.max_cqe = attr.max_cqe;
174 resp.max_mr = attr.max_mr;
175 resp.max_pd = attr.max_pd;
176 resp.max_qp_rd_atom = attr.max_qp_rd_atom;
177 resp.max_ee_rd_atom = attr.max_ee_rd_atom;
178 resp.max_res_rd_atom = attr.max_res_rd_atom;
179 resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom;
180 resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom;
181 resp.atomic_cap = attr.atomic_cap;
182 resp.max_ee = attr.max_ee;
183 resp.max_rdd = attr.max_rdd;
184 resp.max_mw = attr.max_mw;
185 resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp;
186 resp.max_raw_ethy_qp = attr.max_raw_ethy_qp;
187 resp.max_mcast_grp = attr.max_mcast_grp;
188 resp.max_mcast_qp_attach = attr.max_mcast_qp_attach;
189 resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
190 resp.max_ah = attr.max_ah;
191 resp.max_fmr = attr.max_fmr;
192 resp.max_map_per_fmr = attr.max_map_per_fmr;
193 resp.max_srq = attr.max_srq;
194 resp.max_srq_wr = attr.max_srq_wr;
195 resp.max_srq_sge = attr.max_srq_sge;
196 resp.max_pkeys = attr.max_pkeys;
197 resp.local_ca_ack_delay = attr.local_ca_ack_delay;
198 resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt;
199
200 if (copy_to_user((void __user *) (unsigned long) cmd.response,
201 &resp, sizeof resp))
202 return -EFAULT;
203
204 return in_len;
205}
206
207ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
208 const char __user *buf,
209 int in_len, int out_len)
210{
211 struct ib_uverbs_query_port cmd;
212 struct ib_uverbs_query_port_resp resp;
213 struct ib_port_attr attr;
214 int ret;
215
216 if (out_len < sizeof resp)
217 return -ENOSPC;
218
219 if (copy_from_user(&cmd, buf, sizeof cmd))
220 return -EFAULT;
221
222 ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr);
223 if (ret)
224 return ret;
225
226 memset(&resp, 0, sizeof resp);
227
228 resp.state = attr.state;
229 resp.max_mtu = attr.max_mtu;
230 resp.active_mtu = attr.active_mtu;
231 resp.gid_tbl_len = attr.gid_tbl_len;
232 resp.port_cap_flags = attr.port_cap_flags;
233 resp.max_msg_sz = attr.max_msg_sz;
234 resp.bad_pkey_cntr = attr.bad_pkey_cntr;
235 resp.qkey_viol_cntr = attr.qkey_viol_cntr;
236 resp.pkey_tbl_len = attr.pkey_tbl_len;
237 resp.lid = attr.lid;
238 resp.sm_lid = attr.sm_lid;
239 resp.lmc = attr.lmc;
240 resp.max_vl_num = attr.max_vl_num;
241 resp.sm_sl = attr.sm_sl;
242 resp.subnet_timeout = attr.subnet_timeout;
243 resp.init_type_reply = attr.init_type_reply;
244 resp.active_width = attr.active_width;
245 resp.active_speed = attr.active_speed;
246 resp.phys_state = attr.phys_state;
247
248 if (copy_to_user((void __user *) (unsigned long) cmd.response,
249 &resp, sizeof resp))
250 return -EFAULT;
251
252 return in_len;
253}
254
bc38a6ab
RD
255ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
256 const char __user *buf,
257 int in_len, int out_len)
258{
259 struct ib_uverbs_alloc_pd cmd;
260 struct ib_uverbs_alloc_pd_resp resp;
261 struct ib_udata udata;
262 struct ib_uobject *uobj;
263 struct ib_pd *pd;
264 int ret;
265
266 if (out_len < sizeof resp)
267 return -ENOSPC;
268
269 if (copy_from_user(&cmd, buf, sizeof cmd))
270 return -EFAULT;
271
272 INIT_UDATA(&udata, buf + sizeof cmd,
273 (unsigned long) cmd.response + sizeof resp,
274 in_len - sizeof cmd, out_len - sizeof resp);
275
276 uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
277 if (!uobj)
278 return -ENOMEM;
279
280 uobj->context = file->ucontext;
281
282 pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
283 file->ucontext, &udata);
284 if (IS_ERR(pd)) {
285 ret = PTR_ERR(pd);
286 goto err;
287 }
288
289 pd->device = file->device->ib_dev;
290 pd->uobject = uobj;
291 atomic_set(&pd->usecnt, 0);
292
eb9d3cd5
RD
293 down(&ib_uverbs_idr_mutex);
294
bc38a6ab
RD
295retry:
296 if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
297 ret = -ENOMEM;
eb9d3cd5 298 goto err_up;
bc38a6ab
RD
299 }
300
bc38a6ab 301 ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id);
bc38a6ab
RD
302
303 if (ret == -EAGAIN)
304 goto retry;
305 if (ret)
eb9d3cd5 306 goto err_up;
bc38a6ab
RD
307
308 memset(&resp, 0, sizeof resp);
309 resp.pd_handle = uobj->id;
310
311 if (copy_to_user((void __user *) (unsigned long) cmd.response,
312 &resp, sizeof resp)) {
313 ret = -EFAULT;
eb9d3cd5 314 goto err_idr;
bc38a6ab
RD
315 }
316
eb9d3cd5
RD
317 down(&file->mutex);
318 list_add_tail(&uobj->list, &file->ucontext->pd_list);
63c47c28 319 up(&file->mutex);
bc38a6ab 320
bc38a6ab
RD
321 up(&ib_uverbs_idr_mutex);
322
eb9d3cd5
RD
323 return in_len;
324
325err_idr:
326 idr_remove(&ib_uverbs_pd_idr, uobj->id);
327
328err_up:
329 up(&ib_uverbs_idr_mutex);
bc38a6ab
RD
330 ib_dealloc_pd(pd);
331
332err:
333 kfree(uobj);
334 return ret;
335}
336
337ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
338 const char __user *buf,
339 int in_len, int out_len)
340{
341 struct ib_uverbs_dealloc_pd cmd;
342 struct ib_pd *pd;
343 struct ib_uobject *uobj;
344 int ret = -EINVAL;
345
346 if (copy_from_user(&cmd, buf, sizeof cmd))
347 return -EFAULT;
348
349 down(&ib_uverbs_idr_mutex);
350
351 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
352 if (!pd || pd->uobject->context != file->ucontext)
353 goto out;
354
355 uobj = pd->uobject;
356
357 ret = ib_dealloc_pd(pd);
358 if (ret)
359 goto out;
360
361 idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
362
63c47c28 363 down(&file->mutex);
bc38a6ab 364 list_del(&uobj->list);
63c47c28 365 up(&file->mutex);
bc38a6ab
RD
366
367 kfree(uobj);
368
369out:
370 up(&ib_uverbs_idr_mutex);
371
372 return ret ? ret : in_len;
373}
374
375ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
376 const char __user *buf, int in_len,
377 int out_len)
378{
379 struct ib_uverbs_reg_mr cmd;
380 struct ib_uverbs_reg_mr_resp resp;
381 struct ib_udata udata;
382 struct ib_umem_object *obj;
383 struct ib_pd *pd;
384 struct ib_mr *mr;
385 int ret;
386
387 if (out_len < sizeof resp)
388 return -ENOSPC;
389
390 if (copy_from_user(&cmd, buf, sizeof cmd))
391 return -EFAULT;
392
393 INIT_UDATA(&udata, buf + sizeof cmd,
394 (unsigned long) cmd.response + sizeof resp,
395 in_len - sizeof cmd, out_len - sizeof resp);
396
397 if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
398 return -EINVAL;
399
f575394f
RD
400 /*
401 * Local write permission is required if remote write or
402 * remote atomic permission is also requested.
403 */
404 if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) &&
405 !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE))
406 return -EINVAL;
407
bc38a6ab
RD
408 obj = kmalloc(sizeof *obj, GFP_KERNEL);
409 if (!obj)
410 return -ENOMEM;
411
412 obj->uobject.context = file->ucontext;
413
414 /*
415 * We ask for writable memory if any access flags other than
416 * "remote read" are set. "Local write" and "remote write"
417 * obviously require write access. "Remote atomic" can do
418 * things like fetch and add, which will modify memory, and
419 * "MW bind" can change permissions by binding a window.
420 */
421 ret = ib_umem_get(file->device->ib_dev, &obj->umem,
422 (void *) (unsigned long) cmd.start, cmd.length,
423 !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ));
424 if (ret)
425 goto err_free;
426
427 obj->umem.virt_base = cmd.hca_va;
428
429 down(&ib_uverbs_idr_mutex);
430
431 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
432 if (!pd || pd->uobject->context != file->ucontext) {
433 ret = -EINVAL;
434 goto err_up;
435 }
436
437 if (!pd->device->reg_user_mr) {
438 ret = -ENOSYS;
439 goto err_up;
440 }
441
442 mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
443 if (IS_ERR(mr)) {
444 ret = PTR_ERR(mr);
445 goto err_up;
446 }
447
448 mr->device = pd->device;
449 mr->pd = pd;
450 mr->uobject = &obj->uobject;
451 atomic_inc(&pd->usecnt);
452 atomic_set(&mr->usecnt, 0);
453
454 memset(&resp, 0, sizeof resp);
455 resp.lkey = mr->lkey;
456 resp.rkey = mr->rkey;
457
458retry:
459 if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) {
460 ret = -ENOMEM;
461 goto err_unreg;
462 }
463
464 ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id);
465
466 if (ret == -EAGAIN)
467 goto retry;
468 if (ret)
469 goto err_unreg;
470
471 resp.mr_handle = obj->uobject.id;
472
bc38a6ab
RD
473 if (copy_to_user((void __user *) (unsigned long) cmd.response,
474 &resp, sizeof resp)) {
475 ret = -EFAULT;
eb9d3cd5 476 goto err_idr;
bc38a6ab
RD
477 }
478
eb9d3cd5
RD
479 down(&file->mutex);
480 list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
481 up(&file->mutex);
482
bc38a6ab
RD
483 up(&ib_uverbs_idr_mutex);
484
485 return in_len;
486
eb9d3cd5
RD
487err_idr:
488 idr_remove(&ib_uverbs_mr_idr, obj->uobject.id);
bc38a6ab
RD
489
490err_unreg:
491 ib_dereg_mr(mr);
b4ca1a3f 492 atomic_dec(&pd->usecnt);
bc38a6ab
RD
493
494err_up:
495 up(&ib_uverbs_idr_mutex);
496
497 ib_umem_release(file->device->ib_dev, &obj->umem);
498
499err_free:
500 kfree(obj);
501 return ret;
502}
503
504ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
505 const char __user *buf, int in_len,
506 int out_len)
507{
508 struct ib_uverbs_dereg_mr cmd;
509 struct ib_mr *mr;
510 struct ib_umem_object *memobj;
511 int ret = -EINVAL;
512
513 if (copy_from_user(&cmd, buf, sizeof cmd))
514 return -EFAULT;
515
516 down(&ib_uverbs_idr_mutex);
517
518 mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
519 if (!mr || mr->uobject->context != file->ucontext)
520 goto out;
521
522 memobj = container_of(mr->uobject, struct ib_umem_object, uobject);
523
524 ret = ib_dereg_mr(mr);
525 if (ret)
526 goto out;
527
528 idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
529
63c47c28 530 down(&file->mutex);
bc38a6ab 531 list_del(&memobj->uobject.list);
63c47c28 532 up(&file->mutex);
bc38a6ab
RD
533
534 ib_umem_release(file->device->ib_dev, &memobj->umem);
535 kfree(memobj);
536
537out:
538 up(&ib_uverbs_idr_mutex);
539
540 return ret ? ret : in_len;
541}
542
6b73597e
RD
543ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
544 const char __user *buf, int in_len,
545 int out_len)
546{
547 struct ib_uverbs_create_comp_channel cmd;
548 struct ib_uverbs_create_comp_channel_resp resp;
549 struct file *filp;
550
551 if (out_len < sizeof resp)
552 return -ENOSPC;
553
554 if (copy_from_user(&cmd, buf, sizeof cmd))
555 return -EFAULT;
556
557 filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd);
558 if (IS_ERR(filp))
559 return PTR_ERR(filp);
560
561 if (copy_to_user((void __user *) (unsigned long) cmd.response,
562 &resp, sizeof resp)) {
563 put_unused_fd(resp.fd);
564 fput(filp);
565 return -EFAULT;
566 }
567
568 fd_install(resp.fd, filp);
569 return in_len;
570}
571
bc38a6ab
RD
572ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
573 const char __user *buf, int in_len,
574 int out_len)
575{
576 struct ib_uverbs_create_cq cmd;
577 struct ib_uverbs_create_cq_resp resp;
578 struct ib_udata udata;
63aaf647 579 struct ib_ucq_object *uobj;
6b73597e 580 struct ib_uverbs_event_file *ev_file = NULL;
bc38a6ab
RD
581 struct ib_cq *cq;
582 int ret;
583
584 if (out_len < sizeof resp)
585 return -ENOSPC;
586
587 if (copy_from_user(&cmd, buf, sizeof cmd))
588 return -EFAULT;
589
590 INIT_UDATA(&udata, buf + sizeof cmd,
591 (unsigned long) cmd.response + sizeof resp,
592 in_len - sizeof cmd, out_len - sizeof resp);
593
6b73597e 594 if (cmd.comp_vector >= file->device->num_comp_vectors)
bc38a6ab
RD
595 return -EINVAL;
596
6b73597e
RD
597 if (cmd.comp_channel >= 0)
598 ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
599
bc38a6ab
RD
600 uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
601 if (!uobj)
602 return -ENOMEM;
603
63aaf647
RD
604 uobj->uobject.user_handle = cmd.user_handle;
605 uobj->uobject.context = file->ucontext;
7162a3e0 606 uobj->uverbs_file = file;
63aaf647
RD
607 uobj->comp_events_reported = 0;
608 uobj->async_events_reported = 0;
609 INIT_LIST_HEAD(&uobj->comp_list);
610 INIT_LIST_HEAD(&uobj->async_list);
bc38a6ab
RD
611
612 cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
613 file->ucontext, &udata);
614 if (IS_ERR(cq)) {
615 ret = PTR_ERR(cq);
616 goto err;
617 }
618
619 cq->device = file->device->ib_dev;
63aaf647 620 cq->uobject = &uobj->uobject;
bc38a6ab
RD
621 cq->comp_handler = ib_uverbs_comp_handler;
622 cq->event_handler = ib_uverbs_cq_event_handler;
6b73597e 623 cq->cq_context = ev_file;
bc38a6ab
RD
624 atomic_set(&cq->usecnt, 0);
625
eb9d3cd5
RD
626 down(&ib_uverbs_idr_mutex);
627
bc38a6ab
RD
628retry:
629 if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
630 ret = -ENOMEM;
eb9d3cd5 631 goto err_up;
bc38a6ab
RD
632 }
633
63aaf647 634 ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id);
bc38a6ab
RD
635
636 if (ret == -EAGAIN)
637 goto retry;
638 if (ret)
eb9d3cd5 639 goto err_up;
bc38a6ab
RD
640
641 memset(&resp, 0, sizeof resp);
63aaf647 642 resp.cq_handle = uobj->uobject.id;
bc38a6ab
RD
643 resp.cqe = cq->cqe;
644
645 if (copy_to_user((void __user *) (unsigned long) cmd.response,
646 &resp, sizeof resp)) {
647 ret = -EFAULT;
eb9d3cd5 648 goto err_idr;
bc38a6ab
RD
649 }
650
eb9d3cd5
RD
651 down(&file->mutex);
652 list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list);
63c47c28 653 up(&file->mutex);
bc38a6ab 654
bc38a6ab
RD
655 up(&ib_uverbs_idr_mutex);
656
eb9d3cd5
RD
657 return in_len;
658
659err_idr:
660 idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id);
661
662err_up:
663 up(&ib_uverbs_idr_mutex);
bc38a6ab
RD
664 ib_destroy_cq(cq);
665
666err:
667 kfree(uobj);
668 return ret;
669}
670
67cdb40c
RD
671ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
672 const char __user *buf, int in_len,
673 int out_len)
674{
675 struct ib_uverbs_poll_cq cmd;
676 struct ib_uverbs_poll_cq_resp *resp;
677 struct ib_cq *cq;
678 struct ib_wc *wc;
679 int ret = 0;
680 int i;
681 int rsize;
682
683 if (copy_from_user(&cmd, buf, sizeof cmd))
684 return -EFAULT;
685
686 wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
687 if (!wc)
688 return -ENOMEM;
689
690 rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
691 resp = kmalloc(rsize, GFP_KERNEL);
692 if (!resp) {
693 ret = -ENOMEM;
694 goto out_wc;
695 }
696
697 down(&ib_uverbs_idr_mutex);
698 cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
699 if (!cq || cq->uobject->context != file->ucontext) {
700 ret = -EINVAL;
701 goto out;
702 }
703
704 resp->count = ib_poll_cq(cq, cmd.ne, wc);
705
706 for (i = 0; i < resp->count; i++) {
707 resp->wc[i].wr_id = wc[i].wr_id;
708 resp->wc[i].status = wc[i].status;
709 resp->wc[i].opcode = wc[i].opcode;
710 resp->wc[i].vendor_err = wc[i].vendor_err;
711 resp->wc[i].byte_len = wc[i].byte_len;
77369ed3 712 resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data;
67cdb40c
RD
713 resp->wc[i].qp_num = wc[i].qp_num;
714 resp->wc[i].src_qp = wc[i].src_qp;
715 resp->wc[i].wc_flags = wc[i].wc_flags;
716 resp->wc[i].pkey_index = wc[i].pkey_index;
717 resp->wc[i].slid = wc[i].slid;
718 resp->wc[i].sl = wc[i].sl;
719 resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
720 resp->wc[i].port_num = wc[i].port_num;
721 }
722
723 if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
724 ret = -EFAULT;
725
726out:
727 up(&ib_uverbs_idr_mutex);
728 kfree(resp);
729
730out_wc:
731 kfree(wc);
732 return ret ? ret : in_len;
733}
734
735ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
736 const char __user *buf, int in_len,
737 int out_len)
738{
739 struct ib_uverbs_req_notify_cq cmd;
740 struct ib_cq *cq;
741 int ret = -EINVAL;
742
743 if (copy_from_user(&cmd, buf, sizeof cmd))
744 return -EFAULT;
745
746 down(&ib_uverbs_idr_mutex);
747 cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
748 if (cq && cq->uobject->context == file->ucontext) {
749 ib_req_notify_cq(cq, cmd.solicited_only ?
750 IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
751 ret = in_len;
752 }
753 up(&ib_uverbs_idr_mutex);
754
755 return ret;
756}
757
bc38a6ab
RD
758ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
759 const char __user *buf, int in_len,
760 int out_len)
761{
63aaf647
RD
762 struct ib_uverbs_destroy_cq cmd;
763 struct ib_uverbs_destroy_cq_resp resp;
764 struct ib_cq *cq;
765 struct ib_ucq_object *uobj;
6b73597e 766 struct ib_uverbs_event_file *ev_file;
63aaf647
RD
767 u64 user_handle;
768 int ret = -EINVAL;
bc38a6ab
RD
769
770 if (copy_from_user(&cmd, buf, sizeof cmd))
771 return -EFAULT;
772
63aaf647
RD
773 memset(&resp, 0, sizeof resp);
774
bc38a6ab
RD
775 down(&ib_uverbs_idr_mutex);
776
777 cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
778 if (!cq || cq->uobject->context != file->ucontext)
779 goto out;
780
63aaf647 781 user_handle = cq->uobject->user_handle;
6b73597e
RD
782 uobj = container_of(cq->uobject, struct ib_ucq_object, uobject);
783 ev_file = cq->cq_context;
bc38a6ab
RD
784
785 ret = ib_destroy_cq(cq);
786 if (ret)
787 goto out;
788
789 idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
790
63c47c28 791 down(&file->mutex);
63aaf647 792 list_del(&uobj->uobject.list);
63c47c28 793 up(&file->mutex);
bc38a6ab 794
70a30e16 795 ib_uverbs_release_ucq(file, ev_file, uobj);
63aaf647
RD
796
797 resp.comp_events_reported = uobj->comp_events_reported;
798 resp.async_events_reported = uobj->async_events_reported;
799
bc38a6ab
RD
800 kfree(uobj);
801
63aaf647
RD
802 if (copy_to_user((void __user *) (unsigned long) cmd.response,
803 &resp, sizeof resp))
804 ret = -EFAULT;
805
bc38a6ab
RD
806out:
807 up(&ib_uverbs_idr_mutex);
808
809 return ret ? ret : in_len;
810}
811
812ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
813 const char __user *buf, int in_len,
814 int out_len)
815{
816 struct ib_uverbs_create_qp cmd;
817 struct ib_uverbs_create_qp_resp resp;
818 struct ib_udata udata;
f4e40156 819 struct ib_uqp_object *uobj;
bc38a6ab
RD
820 struct ib_pd *pd;
821 struct ib_cq *scq, *rcq;
f520ba5a 822 struct ib_srq *srq;
bc38a6ab
RD
823 struct ib_qp *qp;
824 struct ib_qp_init_attr attr;
825 int ret;
826
827 if (out_len < sizeof resp)
828 return -ENOSPC;
829
830 if (copy_from_user(&cmd, buf, sizeof cmd))
831 return -EFAULT;
832
833 INIT_UDATA(&udata, buf + sizeof cmd,
834 (unsigned long) cmd.response + sizeof resp,
835 in_len - sizeof cmd, out_len - sizeof resp);
836
837 uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
838 if (!uobj)
839 return -ENOMEM;
840
841 down(&ib_uverbs_idr_mutex);
842
843 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
844 scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
845 rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
f520ba5a 846 srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL;
bc38a6ab
RD
847
848 if (!pd || pd->uobject->context != file->ucontext ||
849 !scq || scq->uobject->context != file->ucontext ||
f520ba5a
RD
850 !rcq || rcq->uobject->context != file->ucontext ||
851 (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) {
bc38a6ab
RD
852 ret = -EINVAL;
853 goto err_up;
854 }
855
856 attr.event_handler = ib_uverbs_qp_event_handler;
857 attr.qp_context = file;
858 attr.send_cq = scq;
859 attr.recv_cq = rcq;
f520ba5a 860 attr.srq = srq;
bc38a6ab
RD
861 attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
862 attr.qp_type = cmd.qp_type;
863
864 attr.cap.max_send_wr = cmd.max_send_wr;
865 attr.cap.max_recv_wr = cmd.max_recv_wr;
866 attr.cap.max_send_sge = cmd.max_send_sge;
867 attr.cap.max_recv_sge = cmd.max_recv_sge;
868 attr.cap.max_inline_data = cmd.max_inline_data;
869
f4e40156
JM
870 uobj->uevent.uobject.user_handle = cmd.user_handle;
871 uobj->uevent.uobject.context = file->ucontext;
872 uobj->uevent.events_reported = 0;
873 INIT_LIST_HEAD(&uobj->uevent.event_list);
874 INIT_LIST_HEAD(&uobj->mcast_list);
bc38a6ab
RD
875
876 qp = pd->device->create_qp(pd, &attr, &udata);
877 if (IS_ERR(qp)) {
878 ret = PTR_ERR(qp);
879 goto err_up;
880 }
881
882 qp->device = pd->device;
883 qp->pd = pd;
884 qp->send_cq = attr.send_cq;
885 qp->recv_cq = attr.recv_cq;
886 qp->srq = attr.srq;
f4e40156 887 qp->uobject = &uobj->uevent.uobject;
bc38a6ab
RD
888 qp->event_handler = attr.event_handler;
889 qp->qp_context = attr.qp_context;
890 qp->qp_type = attr.qp_type;
891 atomic_inc(&pd->usecnt);
892 atomic_inc(&attr.send_cq->usecnt);
893 atomic_inc(&attr.recv_cq->usecnt);
894 if (attr.srq)
895 atomic_inc(&attr.srq->usecnt);
896
897 memset(&resp, 0, sizeof resp);
898 resp.qpn = qp->qp_num;
899
900retry:
901 if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) {
902 ret = -ENOMEM;
903 goto err_destroy;
904 }
905
f4e40156 906 ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id);
bc38a6ab
RD
907
908 if (ret == -EAGAIN)
909 goto retry;
910 if (ret)
911 goto err_destroy;
912
f4e40156 913 resp.qp_handle = uobj->uevent.uobject.id;
77369ed3
JM
914 resp.max_recv_sge = attr.cap.max_recv_sge;
915 resp.max_send_sge = attr.cap.max_send_sge;
916 resp.max_recv_wr = attr.cap.max_recv_wr;
917 resp.max_send_wr = attr.cap.max_send_wr;
918 resp.max_inline_data = attr.cap.max_inline_data;
bc38a6ab 919
bc38a6ab
RD
920 if (copy_to_user((void __user *) (unsigned long) cmd.response,
921 &resp, sizeof resp)) {
922 ret = -EFAULT;
eb9d3cd5 923 goto err_idr;
bc38a6ab
RD
924 }
925
eb9d3cd5 926 down(&file->mutex);
f4e40156 927 list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
eb9d3cd5
RD
928 up(&file->mutex);
929
bc38a6ab
RD
930 up(&ib_uverbs_idr_mutex);
931
932 return in_len;
933
eb9d3cd5 934err_idr:
f4e40156 935 idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id);
bc38a6ab
RD
936
937err_destroy:
938 ib_destroy_qp(qp);
b4ca1a3f
JM
939 atomic_dec(&pd->usecnt);
940 atomic_dec(&attr.send_cq->usecnt);
941 atomic_dec(&attr.recv_cq->usecnt);
942 if (attr.srq)
943 atomic_dec(&attr.srq->usecnt);
bc38a6ab
RD
944
945err_up:
946 up(&ib_uverbs_idr_mutex);
947
948 kfree(uobj);
949 return ret;
950}
951
952ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
953 const char __user *buf, int in_len,
954 int out_len)
955{
956 struct ib_uverbs_modify_qp cmd;
957 struct ib_qp *qp;
958 struct ib_qp_attr *attr;
959 int ret;
960
961 if (copy_from_user(&cmd, buf, sizeof cmd))
962 return -EFAULT;
963
964 attr = kmalloc(sizeof *attr, GFP_KERNEL);
965 if (!attr)
966 return -ENOMEM;
967
968 down(&ib_uverbs_idr_mutex);
969
970 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
971 if (!qp || qp->uobject->context != file->ucontext) {
972 ret = -EINVAL;
973 goto out;
974 }
975
976 attr->qp_state = cmd.qp_state;
977 attr->cur_qp_state = cmd.cur_qp_state;
978 attr->path_mtu = cmd.path_mtu;
979 attr->path_mig_state = cmd.path_mig_state;
980 attr->qkey = cmd.qkey;
981 attr->rq_psn = cmd.rq_psn;
982 attr->sq_psn = cmd.sq_psn;
983 attr->dest_qp_num = cmd.dest_qp_num;
984 attr->qp_access_flags = cmd.qp_access_flags;
985 attr->pkey_index = cmd.pkey_index;
986 attr->alt_pkey_index = cmd.pkey_index;
987 attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
988 attr->max_rd_atomic = cmd.max_rd_atomic;
989 attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic;
990 attr->min_rnr_timer = cmd.min_rnr_timer;
991 attr->port_num = cmd.port_num;
992 attr->timeout = cmd.timeout;
993 attr->retry_cnt = cmd.retry_cnt;
994 attr->rnr_retry = cmd.rnr_retry;
995 attr->alt_port_num = cmd.alt_port_num;
996 attr->alt_timeout = cmd.alt_timeout;
997
998 memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
999 attr->ah_attr.grh.flow_label = cmd.dest.flow_label;
1000 attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index;
1001 attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit;
1002 attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class;
1003 attr->ah_attr.dlid = cmd.dest.dlid;
1004 attr->ah_attr.sl = cmd.dest.sl;
1005 attr->ah_attr.src_path_bits = cmd.dest.src_path_bits;
1006 attr->ah_attr.static_rate = cmd.dest.static_rate;
1007 attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0;
1008 attr->ah_attr.port_num = cmd.dest.port_num;
1009
1010 memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
1011 attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label;
1012 attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index;
1013 attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit;
1014 attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
1015 attr->alt_ah_attr.dlid = cmd.alt_dest.dlid;
1016 attr->alt_ah_attr.sl = cmd.alt_dest.sl;
1017 attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits;
1018 attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate;
1019 attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
1020 attr->alt_ah_attr.port_num = cmd.alt_dest.port_num;
1021
1022 ret = ib_modify_qp(qp, attr, cmd.attr_mask);
1023 if (ret)
1024 goto out;
1025
1026 ret = in_len;
1027
1028out:
1029 up(&ib_uverbs_idr_mutex);
1030 kfree(attr);
1031
1032 return ret;
1033}
1034
1035ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
1036 const char __user *buf, int in_len,
1037 int out_len)
1038{
63aaf647
RD
1039 struct ib_uverbs_destroy_qp cmd;
1040 struct ib_uverbs_destroy_qp_resp resp;
1041 struct ib_qp *qp;
f4e40156 1042 struct ib_uqp_object *uobj;
63aaf647 1043 int ret = -EINVAL;
bc38a6ab
RD
1044
1045 if (copy_from_user(&cmd, buf, sizeof cmd))
1046 return -EFAULT;
1047
63aaf647
RD
1048 memset(&resp, 0, sizeof resp);
1049
bc38a6ab
RD
1050 down(&ib_uverbs_idr_mutex);
1051
1052 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
1053 if (!qp || qp->uobject->context != file->ucontext)
1054 goto out;
1055
f4e40156
JM
1056 uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1057
1058 if (!list_empty(&uobj->mcast_list)) {
1059 ret = -EBUSY;
1060 goto out;
1061 }
bc38a6ab
RD
1062
1063 ret = ib_destroy_qp(qp);
1064 if (ret)
1065 goto out;
1066
1067 idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
1068
63c47c28 1069 down(&file->mutex);
f4e40156 1070 list_del(&uobj->uevent.uobject.list);
63c47c28 1071 up(&file->mutex);
bc38a6ab 1072
f4e40156 1073 ib_uverbs_release_uevent(file, &uobj->uevent);
63aaf647 1074
f4e40156 1075 resp.events_reported = uobj->uevent.events_reported;
63aaf647 1076
bc38a6ab
RD
1077 kfree(uobj);
1078
63aaf647
RD
1079 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1080 &resp, sizeof resp))
1081 ret = -EFAULT;
1082
bc38a6ab
RD
1083out:
1084 up(&ib_uverbs_idr_mutex);
1085
1086 return ret ? ret : in_len;
1087}
1088
67cdb40c
RD
1089ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
1090 const char __user *buf, int in_len,
1091 int out_len)
1092{
1093 struct ib_uverbs_post_send cmd;
1094 struct ib_uverbs_post_send_resp resp;
1095 struct ib_uverbs_send_wr *user_wr;
1096 struct ib_send_wr *wr = NULL, *last, *next, *bad_wr;
1097 struct ib_qp *qp;
1098 int i, sg_ind;
1099 ssize_t ret = -EINVAL;
1100
1101 if (copy_from_user(&cmd, buf, sizeof cmd))
1102 return -EFAULT;
1103
1104 if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count +
1105 cmd.sge_count * sizeof (struct ib_uverbs_sge))
1106 return -EINVAL;
1107
1108 if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr))
1109 return -EINVAL;
1110
1111 user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL);
1112 if (!user_wr)
1113 return -ENOMEM;
1114
1115 down(&ib_uverbs_idr_mutex);
1116
1117 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
1118 if (!qp || qp->uobject->context != file->ucontext)
1119 goto out;
1120
1121 sg_ind = 0;
1122 last = NULL;
1123 for (i = 0; i < cmd.wr_count; ++i) {
1124 if (copy_from_user(user_wr,
1125 buf + sizeof cmd + i * cmd.wqe_size,
1126 cmd.wqe_size)) {
1127 ret = -EFAULT;
1128 goto out;
1129 }
1130
1131 if (user_wr->num_sge + sg_ind > cmd.sge_count) {
1132 ret = -EINVAL;
1133 goto out;
1134 }
1135
1136 next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
1137 user_wr->num_sge * sizeof (struct ib_sge),
1138 GFP_KERNEL);
1139 if (!next) {
1140 ret = -ENOMEM;
1141 goto out;
1142 }
1143
1144 if (!last)
1145 wr = next;
1146 else
1147 last->next = next;
1148 last = next;
1149
1150 next->next = NULL;
1151 next->wr_id = user_wr->wr_id;
1152 next->num_sge = user_wr->num_sge;
1153 next->opcode = user_wr->opcode;
1154 next->send_flags = user_wr->send_flags;
77369ed3 1155 next->imm_data = (__be32 __force) user_wr->imm_data;
67cdb40c
RD
1156
1157 if (qp->qp_type == IB_QPT_UD) {
1158 next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr,
1159 user_wr->wr.ud.ah);
1160 if (!next->wr.ud.ah) {
1161 ret = -EINVAL;
1162 goto out;
1163 }
1164 next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn;
1165 next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey;
1166 } else {
1167 switch (next->opcode) {
1168 case IB_WR_RDMA_WRITE:
1169 case IB_WR_RDMA_WRITE_WITH_IMM:
1170 case IB_WR_RDMA_READ:
1171 next->wr.rdma.remote_addr =
1172 user_wr->wr.rdma.remote_addr;
1173 next->wr.rdma.rkey =
1174 user_wr->wr.rdma.rkey;
1175 break;
1176 case IB_WR_ATOMIC_CMP_AND_SWP:
1177 case IB_WR_ATOMIC_FETCH_AND_ADD:
1178 next->wr.atomic.remote_addr =
1179 user_wr->wr.atomic.remote_addr;
1180 next->wr.atomic.compare_add =
1181 user_wr->wr.atomic.compare_add;
1182 next->wr.atomic.swap = user_wr->wr.atomic.swap;
1183 next->wr.atomic.rkey = user_wr->wr.atomic.rkey;
1184 break;
1185 default:
1186 break;
1187 }
1188 }
1189
1190 if (next->num_sge) {
1191 next->sg_list = (void *) next +
1192 ALIGN(sizeof *next, sizeof (struct ib_sge));
1193 if (copy_from_user(next->sg_list,
1194 buf + sizeof cmd +
1195 cmd.wr_count * cmd.wqe_size +
1196 sg_ind * sizeof (struct ib_sge),
1197 next->num_sge * sizeof (struct ib_sge))) {
1198 ret = -EFAULT;
1199 goto out;
1200 }
1201 sg_ind += next->num_sge;
1202 } else
1203 next->sg_list = NULL;
1204 }
1205
1206 resp.bad_wr = 0;
1207 ret = qp->device->post_send(qp, wr, &bad_wr);
1208 if (ret)
1209 for (next = wr; next; next = next->next) {
1210 ++resp.bad_wr;
1211 if (next == bad_wr)
1212 break;
1213 }
1214
1215 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1216 &resp, sizeof resp))
1217 ret = -EFAULT;
1218
1219out:
1220 up(&ib_uverbs_idr_mutex);
1221
1222 while (wr) {
1223 next = wr->next;
1224 kfree(wr);
1225 wr = next;
1226 }
1227
1228 kfree(user_wr);
1229
1230 return ret ? ret : in_len;
1231}
1232
1233static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf,
1234 int in_len,
1235 u32 wr_count,
1236 u32 sge_count,
1237 u32 wqe_size)
1238{
1239 struct ib_uverbs_recv_wr *user_wr;
1240 struct ib_recv_wr *wr = NULL, *last, *next;
1241 int sg_ind;
1242 int i;
1243 int ret;
1244
1245 if (in_len < wqe_size * wr_count +
1246 sge_count * sizeof (struct ib_uverbs_sge))
1247 return ERR_PTR(-EINVAL);
1248
1249 if (wqe_size < sizeof (struct ib_uverbs_recv_wr))
1250 return ERR_PTR(-EINVAL);
1251
1252 user_wr = kmalloc(wqe_size, GFP_KERNEL);
1253 if (!user_wr)
1254 return ERR_PTR(-ENOMEM);
1255
1256 sg_ind = 0;
1257 last = NULL;
1258 for (i = 0; i < wr_count; ++i) {
1259 if (copy_from_user(user_wr, buf + i * wqe_size,
1260 wqe_size)) {
1261 ret = -EFAULT;
1262 goto err;
1263 }
1264
1265 if (user_wr->num_sge + sg_ind > sge_count) {
1266 ret = -EINVAL;
1267 goto err;
1268 }
1269
1270 next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
1271 user_wr->num_sge * sizeof (struct ib_sge),
1272 GFP_KERNEL);
1273 if (!next) {
1274 ret = -ENOMEM;
1275 goto err;
1276 }
1277
1278 if (!last)
1279 wr = next;
1280 else
1281 last->next = next;
1282 last = next;
1283
1284 next->next = NULL;
1285 next->wr_id = user_wr->wr_id;
1286 next->num_sge = user_wr->num_sge;
1287
1288 if (next->num_sge) {
1289 next->sg_list = (void *) next +
1290 ALIGN(sizeof *next, sizeof (struct ib_sge));
1291 if (copy_from_user(next->sg_list,
1292 buf + wr_count * wqe_size +
1293 sg_ind * sizeof (struct ib_sge),
1294 next->num_sge * sizeof (struct ib_sge))) {
1295 ret = -EFAULT;
1296 goto err;
1297 }
1298 sg_ind += next->num_sge;
1299 } else
1300 next->sg_list = NULL;
1301 }
1302
1303 kfree(user_wr);
1304 return wr;
1305
1306err:
1307 kfree(user_wr);
1308
1309 while (wr) {
1310 next = wr->next;
1311 kfree(wr);
1312 wr = next;
1313 }
1314
1315 return ERR_PTR(ret);
1316}
1317
1318ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
1319 const char __user *buf, int in_len,
1320 int out_len)
1321{
1322 struct ib_uverbs_post_recv cmd;
1323 struct ib_uverbs_post_recv_resp resp;
1324 struct ib_recv_wr *wr, *next, *bad_wr;
1325 struct ib_qp *qp;
1326 ssize_t ret = -EINVAL;
1327
1328 if (copy_from_user(&cmd, buf, sizeof cmd))
1329 return -EFAULT;
1330
1331 wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd,
1332 in_len - sizeof cmd, cmd.wr_count,
1333 cmd.sge_count, cmd.wqe_size);
1334 if (IS_ERR(wr))
1335 return PTR_ERR(wr);
1336
1337 down(&ib_uverbs_idr_mutex);
1338
1339 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
1340 if (!qp || qp->uobject->context != file->ucontext)
1341 goto out;
1342
1343 resp.bad_wr = 0;
1344 ret = qp->device->post_recv(qp, wr, &bad_wr);
1345 if (ret)
1346 for (next = wr; next; next = next->next) {
1347 ++resp.bad_wr;
1348 if (next == bad_wr)
1349 break;
1350 }
1351
1352
1353 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1354 &resp, sizeof resp))
1355 ret = -EFAULT;
1356
1357out:
1358 up(&ib_uverbs_idr_mutex);
1359
1360 while (wr) {
1361 next = wr->next;
1362 kfree(wr);
1363 wr = next;
1364 }
1365
1366 return ret ? ret : in_len;
1367}
1368
1369ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
1370 const char __user *buf, int in_len,
1371 int out_len)
1372{
1373 struct ib_uverbs_post_srq_recv cmd;
1374 struct ib_uverbs_post_srq_recv_resp resp;
1375 struct ib_recv_wr *wr, *next, *bad_wr;
1376 struct ib_srq *srq;
1377 ssize_t ret = -EINVAL;
1378
1379 if (copy_from_user(&cmd, buf, sizeof cmd))
1380 return -EFAULT;
1381
1382 wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd,
1383 in_len - sizeof cmd, cmd.wr_count,
1384 cmd.sge_count, cmd.wqe_size);
1385 if (IS_ERR(wr))
1386 return PTR_ERR(wr);
1387
1388 down(&ib_uverbs_idr_mutex);
1389
1390 srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
1391 if (!srq || srq->uobject->context != file->ucontext)
1392 goto out;
1393
1394 resp.bad_wr = 0;
1395 ret = srq->device->post_srq_recv(srq, wr, &bad_wr);
1396 if (ret)
1397 for (next = wr; next; next = next->next) {
1398 ++resp.bad_wr;
1399 if (next == bad_wr)
1400 break;
1401 }
1402
1403
1404 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1405 &resp, sizeof resp))
1406 ret = -EFAULT;
1407
1408out:
1409 up(&ib_uverbs_idr_mutex);
1410
1411 while (wr) {
1412 next = wr->next;
1413 kfree(wr);
1414 wr = next;
1415 }
1416
1417 return ret ? ret : in_len;
1418}
1419
1420ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
1421 const char __user *buf, int in_len,
1422 int out_len)
1423{
1424 struct ib_uverbs_create_ah cmd;
1425 struct ib_uverbs_create_ah_resp resp;
1426 struct ib_uobject *uobj;
1427 struct ib_pd *pd;
1428 struct ib_ah *ah;
1429 struct ib_ah_attr attr;
1430 int ret;
1431
1432 if (out_len < sizeof resp)
1433 return -ENOSPC;
1434
1435 if (copy_from_user(&cmd, buf, sizeof cmd))
1436 return -EFAULT;
1437
1438 uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
1439 if (!uobj)
1440 return -ENOMEM;
1441
1442 down(&ib_uverbs_idr_mutex);
1443
1444 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
1445 if (!pd || pd->uobject->context != file->ucontext) {
1446 ret = -EINVAL;
1447 goto err_up;
1448 }
1449
1450 uobj->user_handle = cmd.user_handle;
1451 uobj->context = file->ucontext;
1452
1453 attr.dlid = cmd.attr.dlid;
1454 attr.sl = cmd.attr.sl;
1455 attr.src_path_bits = cmd.attr.src_path_bits;
1456 attr.static_rate = cmd.attr.static_rate;
1457 attr.port_num = cmd.attr.port_num;
1458 attr.grh.flow_label = cmd.attr.grh.flow_label;
1459 attr.grh.sgid_index = cmd.attr.grh.sgid_index;
1460 attr.grh.hop_limit = cmd.attr.grh.hop_limit;
1461 attr.grh.traffic_class = cmd.attr.grh.traffic_class;
1462 memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16);
1463
1464 ah = ib_create_ah(pd, &attr);
1465 if (IS_ERR(ah)) {
1466 ret = PTR_ERR(ah);
1467 goto err_up;
1468 }
1469
1470 ah->uobject = uobj;
1471
1472retry:
1473 if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) {
1474 ret = -ENOMEM;
1475 goto err_destroy;
1476 }
1477
1478 ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id);
1479
1480 if (ret == -EAGAIN)
1481 goto retry;
1482 if (ret)
1483 goto err_destroy;
1484
1485 resp.ah_handle = uobj->id;
1486
1487 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1488 &resp, sizeof resp)) {
1489 ret = -EFAULT;
1490 goto err_idr;
1491 }
1492
1493 down(&file->mutex);
1494 list_add_tail(&uobj->list, &file->ucontext->ah_list);
1495 up(&file->mutex);
1496
1497 up(&ib_uverbs_idr_mutex);
1498
1499 return in_len;
1500
1501err_idr:
1502 idr_remove(&ib_uverbs_ah_idr, uobj->id);
1503
1504err_destroy:
1505 ib_destroy_ah(ah);
1506
1507err_up:
1508 up(&ib_uverbs_idr_mutex);
1509
1510 kfree(uobj);
1511 return ret;
1512}
1513
1514ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
1515 const char __user *buf, int in_len, int out_len)
1516{
1517 struct ib_uverbs_destroy_ah cmd;
1518 struct ib_ah *ah;
1519 struct ib_uobject *uobj;
1520 int ret = -EINVAL;
1521
1522 if (copy_from_user(&cmd, buf, sizeof cmd))
1523 return -EFAULT;
1524
1525 down(&ib_uverbs_idr_mutex);
1526
1527 ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle);
1528 if (!ah || ah->uobject->context != file->ucontext)
1529 goto out;
1530
1531 uobj = ah->uobject;
1532
1533 ret = ib_destroy_ah(ah);
1534 if (ret)
1535 goto out;
1536
1537 idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle);
1538
1539 down(&file->mutex);
1540 list_del(&uobj->list);
1541 up(&file->mutex);
1542
1543 kfree(uobj);
1544
1545out:
1546 up(&ib_uverbs_idr_mutex);
1547
1548 return ret ? ret : in_len;
1549}
1550
bc38a6ab
RD
1551ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
1552 const char __user *buf, int in_len,
1553 int out_len)
1554{
1555 struct ib_uverbs_attach_mcast cmd;
1556 struct ib_qp *qp;
f4e40156
JM
1557 struct ib_uqp_object *uobj;
1558 struct ib_uverbs_mcast_entry *mcast;
bc38a6ab
RD
1559 int ret = -EINVAL;
1560
1561 if (copy_from_user(&cmd, buf, sizeof cmd))
1562 return -EFAULT;
1563
1564 down(&ib_uverbs_idr_mutex);
1565
1566 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
f4e40156
JM
1567 if (!qp || qp->uobject->context != file->ucontext)
1568 goto out;
1569
1570 uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1571
1572 list_for_each_entry(mcast, &uobj->mcast_list, list)
1573 if (cmd.mlid == mcast->lid &&
1574 !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1575 ret = 0;
1576 goto out;
1577 }
1578
1579 mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
1580 if (!mcast) {
1581 ret = -ENOMEM;
1582 goto out;
1583 }
1584
1585 mcast->lid = cmd.mlid;
1586 memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
bc38a6ab 1587
f4e40156
JM
1588 ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
1589 if (!ret) {
1590 uobj = container_of(qp->uobject, struct ib_uqp_object,
1591 uevent.uobject);
1592 list_add_tail(&mcast->list, &uobj->mcast_list);
1593 } else
1594 kfree(mcast);
1595
1596out:
bc38a6ab
RD
1597 up(&ib_uverbs_idr_mutex);
1598
1599 return ret ? ret : in_len;
1600}
1601
1602ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
1603 const char __user *buf, int in_len,
1604 int out_len)
1605{
1606 struct ib_uverbs_detach_mcast cmd;
f4e40156 1607 struct ib_uqp_object *uobj;
bc38a6ab 1608 struct ib_qp *qp;
f4e40156 1609 struct ib_uverbs_mcast_entry *mcast;
bc38a6ab
RD
1610 int ret = -EINVAL;
1611
1612 if (copy_from_user(&cmd, buf, sizeof cmd))
1613 return -EFAULT;
1614
1615 down(&ib_uverbs_idr_mutex);
1616
1617 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
f4e40156
JM
1618 if (!qp || qp->uobject->context != file->ucontext)
1619 goto out;
bc38a6ab 1620
f4e40156
JM
1621 ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
1622 if (ret)
1623 goto out;
1624
1625 uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1626
1627 list_for_each_entry(mcast, &uobj->mcast_list, list)
1628 if (cmd.mlid == mcast->lid &&
1629 !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1630 list_del(&mcast->list);
1631 kfree(mcast);
1632 break;
1633 }
1634
1635out:
bc38a6ab
RD
1636 up(&ib_uverbs_idr_mutex);
1637
1638 return ret ? ret : in_len;
1639}
f520ba5a
RD
1640
1641ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
1642 const char __user *buf, int in_len,
1643 int out_len)
1644{
1645 struct ib_uverbs_create_srq cmd;
1646 struct ib_uverbs_create_srq_resp resp;
1647 struct ib_udata udata;
63aaf647 1648 struct ib_uevent_object *uobj;
f520ba5a
RD
1649 struct ib_pd *pd;
1650 struct ib_srq *srq;
1651 struct ib_srq_init_attr attr;
1652 int ret;
1653
1654 if (out_len < sizeof resp)
1655 return -ENOSPC;
1656
1657 if (copy_from_user(&cmd, buf, sizeof cmd))
1658 return -EFAULT;
1659
1660 INIT_UDATA(&udata, buf + sizeof cmd,
1661 (unsigned long) cmd.response + sizeof resp,
1662 in_len - sizeof cmd, out_len - sizeof resp);
1663
1664 uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
1665 if (!uobj)
1666 return -ENOMEM;
1667
1668 down(&ib_uverbs_idr_mutex);
1669
1670 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
1671
1672 if (!pd || pd->uobject->context != file->ucontext) {
1673 ret = -EINVAL;
1674 goto err_up;
1675 }
1676
1677 attr.event_handler = ib_uverbs_srq_event_handler;
1678 attr.srq_context = file;
1679 attr.attr.max_wr = cmd.max_wr;
1680 attr.attr.max_sge = cmd.max_sge;
1681 attr.attr.srq_limit = cmd.srq_limit;
1682
63aaf647
RD
1683 uobj->uobject.user_handle = cmd.user_handle;
1684 uobj->uobject.context = file->ucontext;
1685 uobj->events_reported = 0;
1686 INIT_LIST_HEAD(&uobj->event_list);
f520ba5a
RD
1687
1688 srq = pd->device->create_srq(pd, &attr, &udata);
1689 if (IS_ERR(srq)) {
1690 ret = PTR_ERR(srq);
1691 goto err_up;
1692 }
1693
1694 srq->device = pd->device;
1695 srq->pd = pd;
63aaf647 1696 srq->uobject = &uobj->uobject;
f520ba5a
RD
1697 srq->event_handler = attr.event_handler;
1698 srq->srq_context = attr.srq_context;
1699 atomic_inc(&pd->usecnt);
1700 atomic_set(&srq->usecnt, 0);
1701
1702 memset(&resp, 0, sizeof resp);
1703
1704retry:
1705 if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) {
1706 ret = -ENOMEM;
1707 goto err_destroy;
1708 }
1709
63aaf647 1710 ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id);
f520ba5a
RD
1711
1712 if (ret == -EAGAIN)
1713 goto retry;
1714 if (ret)
1715 goto err_destroy;
1716
63aaf647 1717 resp.srq_handle = uobj->uobject.id;
f520ba5a 1718
f520ba5a
RD
1719 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1720 &resp, sizeof resp)) {
1721 ret = -EFAULT;
eb9d3cd5 1722 goto err_idr;
f520ba5a
RD
1723 }
1724
eb9d3cd5
RD
1725 down(&file->mutex);
1726 list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list);
1727 up(&file->mutex);
1728
f520ba5a
RD
1729 up(&ib_uverbs_idr_mutex);
1730
1731 return in_len;
1732
eb9d3cd5
RD
1733err_idr:
1734 idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id);
f520ba5a
RD
1735
1736err_destroy:
1737 ib_destroy_srq(srq);
b4ca1a3f 1738 atomic_dec(&pd->usecnt);
f520ba5a
RD
1739
1740err_up:
1741 up(&ib_uverbs_idr_mutex);
1742
1743 kfree(uobj);
1744 return ret;
1745}
1746
1747ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
1748 const char __user *buf, int in_len,
1749 int out_len)
1750{
1751 struct ib_uverbs_modify_srq cmd;
1752 struct ib_srq *srq;
1753 struct ib_srq_attr attr;
1754 int ret;
1755
1756 if (copy_from_user(&cmd, buf, sizeof cmd))
1757 return -EFAULT;
1758
1759 down(&ib_uverbs_idr_mutex);
1760
1761 srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
1762 if (!srq || srq->uobject->context != file->ucontext) {
1763 ret = -EINVAL;
1764 goto out;
1765 }
1766
1767 attr.max_wr = cmd.max_wr;
f520ba5a
RD
1768 attr.srq_limit = cmd.srq_limit;
1769
1770 ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
1771
1772out:
1773 up(&ib_uverbs_idr_mutex);
1774
1775 return ret ? ret : in_len;
1776}
1777
1778ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
1779 const char __user *buf, int in_len,
1780 int out_len)
1781{
63aaf647
RD
1782 struct ib_uverbs_destroy_srq cmd;
1783 struct ib_uverbs_destroy_srq_resp resp;
1784 struct ib_srq *srq;
1785 struct ib_uevent_object *uobj;
63aaf647 1786 int ret = -EINVAL;
f520ba5a
RD
1787
1788 if (copy_from_user(&cmd, buf, sizeof cmd))
1789 return -EFAULT;
1790
1791 down(&ib_uverbs_idr_mutex);
1792
63aaf647
RD
1793 memset(&resp, 0, sizeof resp);
1794
f520ba5a
RD
1795 srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
1796 if (!srq || srq->uobject->context != file->ucontext)
1797 goto out;
1798
63aaf647 1799 uobj = container_of(srq->uobject, struct ib_uevent_object, uobject);
f520ba5a
RD
1800
1801 ret = ib_destroy_srq(srq);
1802 if (ret)
1803 goto out;
1804
1805 idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
1806
63c47c28 1807 down(&file->mutex);
63aaf647 1808 list_del(&uobj->uobject.list);
63c47c28 1809 up(&file->mutex);
f520ba5a 1810
70a30e16 1811 ib_uverbs_release_uevent(file, uobj);
63aaf647
RD
1812
1813 resp.events_reported = uobj->events_reported;
1814
f520ba5a
RD
1815 kfree(uobj);
1816
63aaf647
RD
1817 if (copy_to_user((void __user *) (unsigned long) cmd.response,
1818 &resp, sizeof resp))
1819 ret = -EFAULT;
1820
f520ba5a
RD
1821out:
1822 up(&ib_uverbs_idr_mutex);
1823
1824 return ret ? ret : in_len;
1825}