return ret ? ret : in_len;
}
-static int copy_wc_to_user(void __user *dest, struct ib_wc *wc)
-{
- struct ib_uverbs_wc tmp;
-
- tmp.wr_id = wc->wr_id;
- tmp.status = wc->status;
- tmp.opcode = wc->opcode;
- tmp.vendor_err = wc->vendor_err;
- tmp.byte_len = wc->byte_len;
- tmp.ex.imm_data = (__u32 __force) wc->ex.imm_data;
- tmp.qp_num = wc->qp->qp_num;
- tmp.src_qp = wc->src_qp;
- tmp.wc_flags = wc->wc_flags;
- tmp.pkey_index = wc->pkey_index;
- tmp.slid = wc->slid;
- tmp.sl = wc->sl;
- tmp.dlid_path_bits = wc->dlid_path_bits;
- tmp.port_num = wc->port_num;
- tmp.reserved = 0;
-
- if (copy_to_user(dest, &tmp, sizeof tmp))
- return -EFAULT;
-
- return 0;
-}
-
ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_poll_cq cmd;
- struct ib_uverbs_poll_cq_resp resp;
- u8 __user *header_ptr;
- u8 __user *data_ptr;
+ struct ib_uverbs_poll_cq_resp *resp;
struct ib_cq *cq;
- struct ib_wc wc;
- int ret;
+ struct ib_wc *wc;
+ int ret = 0;
+ int i;
+ int rsize;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
- if (!cq)
- return -EINVAL;
+ wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
+ if (!wc)
+ return -ENOMEM;
- /* we copy a struct ib_uverbs_poll_cq_resp to user space */
- header_ptr = (void __user *)(unsigned long) cmd.response;
- data_ptr = header_ptr + sizeof resp;
+ rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
+ resp = kmalloc(rsize, GFP_KERNEL);
+ if (!resp) {
+ ret = -ENOMEM;
+ goto out_wc;
+ }
- memset(&resp, 0, sizeof resp);
- while (resp.count < cmd.ne) {
- ret = ib_poll_cq(cq, 1, &wc);
- if (ret < 0)
- goto out_put;
- if (!ret)
- break;
+ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+ if (!cq) {
+ ret = -EINVAL;
+ goto out;
+ }
- ret = copy_wc_to_user(data_ptr, &wc);
- if (ret)
- goto out_put;
+ resp->count = ib_poll_cq(cq, cmd.ne, wc);
+
+ put_cq_read(cq);
- data_ptr += sizeof(struct ib_uverbs_wc);
- ++resp.count;
+ for (i = 0; i < resp->count; i++) {
+ resp->wc[i].wr_id = wc[i].wr_id;
+ resp->wc[i].status = wc[i].status;
+ resp->wc[i].opcode = wc[i].opcode;
+ resp->wc[i].vendor_err = wc[i].vendor_err;
+ resp->wc[i].byte_len = wc[i].byte_len;
+ resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data;
+ resp->wc[i].qp_num = wc[i].qp->qp_num;
+ resp->wc[i].src_qp = wc[i].src_qp;
+ resp->wc[i].wc_flags = wc[i].wc_flags;
+ resp->wc[i].pkey_index = wc[i].pkey_index;
+ resp->wc[i].slid = wc[i].slid;
+ resp->wc[i].sl = wc[i].sl;
+ resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
+ resp->wc[i].port_num = wc[i].port_num;
}
- if (copy_to_user(header_ptr, &resp, sizeof resp)) {
+ if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
ret = -EFAULT;
- goto out_put;
- }
- ret = in_len;
+out:
+ kfree(resp);
-out_put:
- put_cq_read(cq);
- return ret;
+out_wc:
+ kfree(wc);
+ return ret ? ret : in_len;
}
ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,