Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7103b71b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  IB/uverbs: Handle large number of entries in poll CQ
parents a49cd5f6 7182afea
Loading
Loading
Loading
Loading
+56 −43
Original line number Original line Diff line number Diff line
@@ -893,68 +893,81 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
	return ret ? ret : in_len;
	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,
ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
			  const char __user *buf, int in_len,
			  const char __user *buf, int in_len,
			  int out_len)
			  int out_len)
{
{
	struct ib_uverbs_poll_cq       cmd;
	struct ib_uverbs_poll_cq       cmd;
	struct ib_uverbs_poll_cq_resp *resp;
	struct ib_uverbs_poll_cq_resp  resp;
	u8 __user                     *header_ptr;
	u8 __user                     *data_ptr;
	struct ib_cq                  *cq;
	struct ib_cq                  *cq;
	struct ib_wc                  *wc;
	struct ib_wc                   wc;
	int                            ret = 0;
	int                            ret;
	int                            i;
	int                            rsize;


	if (copy_from_user(&cmd, buf, sizeof cmd))
	if (copy_from_user(&cmd, buf, sizeof cmd))
		return -EFAULT;
		return -EFAULT;


	wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
	if (!wc)
	if (!cq)
		return -ENOMEM;
		return -EINVAL;


	rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
	/* we copy a struct ib_uverbs_poll_cq_resp to user space */
	resp = kmalloc(rsize, GFP_KERNEL);
	header_ptr = (void __user *)(unsigned long) cmd.response;
	if (!resp) {
	data_ptr = header_ptr + sizeof resp;
		ret = -ENOMEM;
		goto out_wc;
	}


	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
	memset(&resp, 0, sizeof resp);
	if (!cq) {
	while (resp.count < cmd.ne) {
		ret = -EINVAL;
		ret = ib_poll_cq(cq, 1, &wc);
		goto out;
		if (ret < 0)
	}
			goto out_put;
		if (!ret)
			break;


	resp->count = ib_poll_cq(cq, cmd.ne, wc);
		ret = copy_wc_to_user(data_ptr, &wc);
		if (ret)
			goto out_put;


	put_cq_read(cq);
		data_ptr += sizeof(struct ib_uverbs_wc);
		++resp.count;
	}


	for (i = 0; i < resp->count; i++) {
	if (copy_to_user(header_ptr, &resp, sizeof resp)) {
		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((void __user *) (unsigned long) cmd.response, resp, rsize))
		ret = -EFAULT;
		ret = -EFAULT;
		goto out_put;
	}


out:
	ret = in_len;
	kfree(resp);


out_wc:
out_put:
	kfree(wc);
	put_cq_read(cq);
	return ret ? ret : in_len;
	return ret;
}
}


ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,