Commit 81f8f745 authored by Maher Sanalla's avatar Maher Sanalla Committed by Leon Romanovsky
Browse files

RDMA/uverbs: Propagate errors from rdma_lookup_get_uobject()



Currently, the IB uverbs API calls uobj_get_uobj_read(), which in turn
uses the rdma_lookup_get_uobject() helper to retrieve user objects.
In case of failure, uobj_get_uobj_read() returns NULL, overriding the
error code from rdma_lookup_get_uobject(). The IB uverbs API then
translates this NULL to -EINVAL, masking the actual error and
complicating debugging. For example, applications calling ibv_modify_qp
that fails with EBUSY when retrieving the QP uobject will see the
overridden error code EINVAL instead, masking the actual error.

Furthermore, based on rdma-core commit:
"2a22f1ced5f3 ("Merge pull request #1568 from jakemoroni/master")"
Kernel's IB uverbs return values are either ignored and passed on as is
to application or overridden with other errnos in a few cases.

Thus, to improve error reporting and debuggability, propagate the
original error from rdma_lookup_get_uobject() instead of replacing it
with EINVAL.

Signed-off-by: default avatarMaher Sanalla <msanalla@nvidia.com>
Link: https://patch.msgid.link/64f9d3711b183984e939962c2f83383904f97dfb.1740577869.git.leon@kernel.org


Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
parent bee35b71
Loading
Loading
Loading
Loading
+76 −68
Original line number Diff line number Diff line
@@ -735,8 +735,8 @@ static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs)
		goto err_free;

	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
	if (!pd) {
		ret = -EINVAL;
	if (IS_ERR(pd)) {
		ret = PTR_ERR(pd);
		goto err_free;
	}

@@ -826,8 +826,8 @@ static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs)
	if (cmd.flags & IB_MR_REREG_PD) {
		new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle,
					   attrs);
		if (!new_pd) {
			ret = -EINVAL;
		if (IS_ERR(new_pd)) {
			ret = PTR_ERR(new_pd);
			goto put_uobjs;
		}
	} else {
@@ -936,8 +936,8 @@ static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs)
		return PTR_ERR(uobj);

	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
	if (!pd) {
		ret = -EINVAL;
	if (IS_ERR(pd)) {
		ret = PTR_ERR(pd);
		goto err_free;
	}

@@ -1144,8 +1144,8 @@ static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs)
		return ret;

	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
	if (!cq)
		return -EINVAL;
	if (IS_ERR(cq))
		return PTR_ERR(cq);

	ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata);
	if (ret)
@@ -1206,8 +1206,8 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
		return ret;

	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
	if (!cq)
		return -EINVAL;
	if (IS_ERR(cq))
		return PTR_ERR(cq);

	/* we copy a struct ib_uverbs_poll_cq_resp to user space */
	header_ptr = attrs->ucore.outbuf;
@@ -1255,8 +1255,8 @@ static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs)
		return ret;

	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
	if (!cq)
		return -EINVAL;
	if (IS_ERR(cq))
		return PTR_ERR(cq);

	ib_req_notify_cq(cq, cmd.solicited_only ?
			 IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
@@ -1338,8 +1338,8 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
		ind_tbl = uobj_get_obj_read(rwq_ind_table,
					    UVERBS_OBJECT_RWQ_IND_TBL,
					    cmd->rwq_ind_tbl_handle, attrs);
		if (!ind_tbl) {
			ret = -EINVAL;
		if (IS_ERR(ind_tbl)) {
			ret = PTR_ERR(ind_tbl);
			goto err_put;
		}

@@ -1377,8 +1377,10 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
			if (cmd->is_srq) {
				srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ,
							cmd->srq_handle, attrs);
				if (!srq || srq->srq_type == IB_SRQT_XRC) {
					ret = -EINVAL;
				if (IS_ERR(srq) ||
				    srq->srq_type == IB_SRQT_XRC) {
					ret = IS_ERR(srq) ? PTR_ERR(srq) :
								  -EINVAL;
					goto err_put;
				}
			}
@@ -1388,23 +1390,29 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
					rcq = uobj_get_obj_read(
						cq, UVERBS_OBJECT_CQ,
						cmd->recv_cq_handle, attrs);
					if (!rcq) {
						ret = -EINVAL;
					if (IS_ERR(rcq)) {
						ret = PTR_ERR(rcq);
						goto err_put;
					}
				}
			}
		}

		if (has_sq)
		if (has_sq) {
			scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
						cmd->send_cq_handle, attrs);
			if (IS_ERR(scq)) {
				ret = PTR_ERR(scq);
				goto err_put;
			}
		}

		if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI)
			rcq = rcq ?: scq;
		pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle,
				       attrs);
		if (!pd || (!scq && has_sq)) {
			ret = -EINVAL;
		if (IS_ERR(pd)) {
			ret = PTR_ERR(pd);
			goto err_put;
		}

@@ -1499,18 +1507,18 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
err_put:
	if (!IS_ERR(xrcd_uobj))
		uobj_put_read(xrcd_uobj);
	if (pd)
	if (!IS_ERR_OR_NULL(pd))
		uobj_put_obj_read(pd);
	if (scq)
	if (!IS_ERR_OR_NULL(scq))
		rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
					UVERBS_LOOKUP_READ);
	if (rcq && rcq != scq)
	if (!IS_ERR_OR_NULL(rcq) && rcq != scq)
		rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
					UVERBS_LOOKUP_READ);
	if (srq)
	if (!IS_ERR_OR_NULL(srq))
		rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
					UVERBS_LOOKUP_READ);
	if (ind_tbl)
	if (!IS_ERR_OR_NULL(ind_tbl))
		uobj_put_obj_read(ind_tbl);

	uobj_alloc_abort(&obj->uevent.uobject, attrs);
@@ -1672,8 +1680,8 @@ static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs)
	}

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp) {
		ret = -EINVAL;
	if (IS_ERR(qp)) {
		ret = PTR_ERR(qp);
		goto out;
	}

@@ -1778,8 +1786,8 @@ static int modify_qp(struct uverbs_attr_bundle *attrs,

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle,
			       attrs);
	if (!qp) {
		ret = -EINVAL;
	if (IS_ERR(qp)) {
		ret = PTR_ERR(qp);
		goto out;
	}

@@ -2045,8 +2053,8 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
		return -ENOMEM;

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp) {
		ret = -EINVAL;
	if (IS_ERR(qp)) {
		ret = PTR_ERR(qp);
		goto out;
	}

@@ -2083,9 +2091,9 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)

			ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH,
						   user_wr->wr.ud.ah, attrs);
			if (!ud->ah) {
			if (IS_ERR(ud->ah)) {
				ret = PTR_ERR(ud->ah);
				kfree(ud);
				ret = -EINVAL;
				goto out_put;
			}
			ud->remote_qpn = user_wr->wr.ud.remote_qpn;
@@ -2322,8 +2330,8 @@ static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs)
		return PTR_ERR(wr);

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp) {
		ret = -EINVAL;
	if (IS_ERR(qp)) {
		ret = PTR_ERR(qp);
		goto out;
	}

@@ -2373,8 +2381,8 @@ static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs)
		return PTR_ERR(wr);

	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
	if (!srq) {
		ret = -EINVAL;
	if (IS_ERR(srq)) {
		ret = PTR_ERR(srq);
		goto out;
	}

@@ -2430,8 +2438,8 @@ static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs)
	}

	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
	if (!pd) {
		ret = -EINVAL;
	if (IS_ERR(pd)) {
		ret = PTR_ERR(pd);
		goto err;
	}

@@ -2500,8 +2508,8 @@ static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs)
		return ret;

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp)
		return -EINVAL;
	if (IS_ERR(qp))
		return PTR_ERR(qp);

	obj = qp->uobject;

@@ -2550,8 +2558,8 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
		return ret;

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp)
		return -EINVAL;
	if (IS_ERR(qp))
		return PTR_ERR(qp);

	obj = qp->uobject;
	mutex_lock(&obj->mcast_lock);
@@ -2685,8 +2693,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
							UVERBS_OBJECT_FLOW_ACTION,
							kern_spec->action.handle,
							attrs);
		if (!ib_spec->action.act)
			return -EINVAL;
		if (IS_ERR(ib_spec->action.act))
			return PTR_ERR(ib_spec->action.act);
		ib_spec->action.size =
			sizeof(struct ib_flow_spec_action_handle);
		flow_resources_add(uflow_res,
@@ -2703,8 +2711,8 @@ static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
					  UVERBS_OBJECT_COUNTERS,
					  kern_spec->flow_count.handle,
					  attrs);
		if (!ib_spec->flow_count.counters)
			return -EINVAL;
		if (IS_ERR(ib_spec->flow_count.counters))
			return PTR_ERR(ib_spec->flow_count.counters);
		ib_spec->flow_count.size =
				sizeof(struct ib_flow_spec_action_count);
		flow_resources_add(uflow_res,
@@ -2922,14 +2930,14 @@ static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs)
		return PTR_ERR(obj);

	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
	if (!pd) {
		err = -EINVAL;
	if (IS_ERR(pd)) {
		err = PTR_ERR(pd);
		goto err_uobj;
	}

	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
	if (!cq) {
		err = -EINVAL;
	if (IS_ERR(cq)) {
		err = PTR_ERR(cq);
		goto err_put_pd;
	}

@@ -3030,8 +3038,8 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs)
		return -EINVAL;

	wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
	if (!wq)
		return -EINVAL;
	if (IS_ERR(wq))
		return PTR_ERR(wq);

	if (cmd.attr_mask & IB_WQ_FLAGS) {
		wq_attr.flags = cmd.flags;
@@ -3114,8 +3122,8 @@ static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs)
			num_read_wqs++) {
		wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ,
				       wqs_handles[num_read_wqs], attrs);
		if (!wq) {
			err = -EINVAL;
		if (IS_ERR(wq)) {
			err = PTR_ERR(wq);
			goto put_wqs;
		}

@@ -3270,8 +3278,8 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs)
	}

	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
	if (!qp) {
		err = -EINVAL;
	if (IS_ERR(qp)) {
		err = PTR_ERR(qp);
		goto err_uobj;
	}

@@ -3417,15 +3425,15 @@ static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs,
	if (ib_srq_has_cq(cmd->srq_type)) {
		attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
						cmd->cq_handle, attrs);
		if (!attr.ext.cq) {
			ret = -EINVAL;
		if (IS_ERR(attr.ext.cq)) {
			ret = PTR_ERR(attr.ext.cq);
			goto err_put_xrcd;
		}
	}

	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs);
	if (!pd) {
		ret = -EINVAL;
	if (IS_ERR(pd)) {
		ret = PTR_ERR(pd);
		goto err_put_cq;
	}

@@ -3532,8 +3540,8 @@ static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs)
		return ret;

	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
	if (!srq)
		return -EINVAL;
	if (IS_ERR(srq))
		return PTR_ERR(srq);

	attr.max_wr    = cmd.max_wr;
	attr.srq_limit = cmd.srq_limit;
@@ -3560,8 +3568,8 @@ static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs)
		return ret;

	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
	if (!srq)
		return -EINVAL;
	if (IS_ERR(srq))
		return PTR_ERR(srq);

	ret = ib_query_srq(srq, &attr);

@@ -3686,8 +3694,8 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
		return -EOPNOTSUPP;

	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
	if (!cq)
		return -EINVAL;
	if (IS_ERR(cq))
		return PTR_ERR(cq);

	ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period);

+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@
static inline void *_uobj_get_obj_read(struct ib_uobject *uobj)
{
	if (IS_ERR(uobj))
		return NULL;
		return ERR_CAST(uobj);
	return uobj->object;
}
#define uobj_get_obj_read(_object, _type, _id, _attrs)                         \