linux-stable/drivers/infiniband/core/uverbs_std_types_wq.c
Leon Romanovsky efa968ee20 RDMA/core: Postpone uobject cleanup on failure till FD close
Remove the ib_is_destroyable_retryable() concept.

The idea here was to allow the drivers to forcibly clean the HW object
even if they otherwise didn't want to (eg because of usecnt). This was an
attempt to clean up in a world where drivers were not allowed to fail HW
object destruction.

Now that we are going back to allowing HW objects to fail destroy this
doesn't make sense. Instead if a uobject's HW object can't be destroyed it
is left on the uobject list and it is up to uverbs_destroy_ufile_hw() to
clean it. Multiple passes over the uobject list allow hidden dependencies
to be resolved. If that fails the HW driver is broken, throw a WARN_ON and
leak the HW object memory.

All the other tricky failure paths (eg on creation error unwind) have
already been updated to this new model.

Link: https://lore.kernel.org/r/20201104144556.3809085-2-leon@kernel.org
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
2020-11-12 12:32:17 -04:00

194 lines
5.5 KiB
C

// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved.
*/
#include <rdma/uverbs_std_types.h>
#include "rdma_core.h"
#include "uverbs.h"
static int uverbs_free_wq(struct ib_uobject *uobject,
enum rdma_remove_reason why,
struct uverbs_attr_bundle *attrs)
{
struct ib_wq *wq = uobject->object;
struct ib_uwq_object *uwq =
container_of(uobject, struct ib_uwq_object, uevent.uobject);
int ret;
ret = ib_destroy_wq_user(wq, &attrs->driver_udata);
if (ret)
return ret;
ib_uverbs_release_uevent(&uwq->uevent);
return 0;
}
static int UVERBS_HANDLER(UVERBS_METHOD_WQ_CREATE)(
struct uverbs_attr_bundle *attrs)
{
struct ib_uwq_object *obj = container_of(
uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_WQ_HANDLE),
typeof(*obj), uevent.uobject);
struct ib_pd *pd =
uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_WQ_PD_HANDLE);
struct ib_cq *cq =
uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_WQ_CQ_HANDLE);
struct ib_wq_init_attr wq_init_attr = {};
struct ib_wq *wq;
u64 user_handle;
int ret;
ret = uverbs_get_flags32(&wq_init_attr.create_flags, attrs,
UVERBS_ATTR_CREATE_WQ_FLAGS,
IB_UVERBS_WQ_FLAGS_CVLAN_STRIPPING |
IB_UVERBS_WQ_FLAGS_SCATTER_FCS |
IB_UVERBS_WQ_FLAGS_DELAY_DROP |
IB_UVERBS_WQ_FLAGS_PCI_WRITE_END_PADDING);
if (!ret)
ret = uverbs_copy_from(&wq_init_attr.max_sge, attrs,
UVERBS_ATTR_CREATE_WQ_MAX_SGE);
if (!ret)
ret = uverbs_copy_from(&wq_init_attr.max_wr, attrs,
UVERBS_ATTR_CREATE_WQ_MAX_WR);
if (!ret)
ret = uverbs_copy_from(&user_handle, attrs,
UVERBS_ATTR_CREATE_WQ_USER_HANDLE);
if (!ret)
ret = uverbs_get_const(&wq_init_attr.wq_type, attrs,
UVERBS_ATTR_CREATE_WQ_TYPE);
if (ret)
return ret;
if (wq_init_attr.wq_type != IB_WQT_RQ)
return -EINVAL;
obj->uevent.event_file = ib_uverbs_get_async_event(attrs,
UVERBS_ATTR_CREATE_WQ_EVENT_FD);
obj->uevent.uobject.user_handle = user_handle;
INIT_LIST_HEAD(&obj->uevent.event_list);
wq_init_attr.event_handler = ib_uverbs_wq_event_handler;
wq_init_attr.wq_context = attrs->ufile;
wq_init_attr.cq = cq;
wq = pd->device->ops.create_wq(pd, &wq_init_attr, &attrs->driver_udata);
if (IS_ERR(wq)) {
ret = PTR_ERR(wq);
goto err;
}
obj->uevent.uobject.object = wq;
wq->wq_type = wq_init_attr.wq_type;
wq->cq = cq;
wq->pd = pd;
wq->device = pd->device;
wq->wq_context = wq_init_attr.wq_context;
atomic_set(&wq->usecnt, 0);
atomic_inc(&pd->usecnt);
atomic_inc(&cq->usecnt);
wq->uobject = obj;
uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_WQ_HANDLE);
ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_MAX_WR,
&wq_init_attr.max_wr,
sizeof(wq_init_attr.max_wr));
if (ret)
return ret;
ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_MAX_SGE,
&wq_init_attr.max_sge,
sizeof(wq_init_attr.max_sge));
if (ret)
return ret;
ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_WQ_NUM,
&wq->wq_num,
sizeof(wq->wq_num));
return ret;
err:
if (obj->uevent.event_file)
uverbs_uobject_put(&obj->uevent.event_file->uobj);
return ret;
};
DECLARE_UVERBS_NAMED_METHOD(
UVERBS_METHOD_WQ_CREATE,
UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_HANDLE,
UVERBS_OBJECT_WQ,
UVERBS_ACCESS_NEW,
UA_MANDATORY),
UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_PD_HANDLE,
UVERBS_OBJECT_PD,
UVERBS_ACCESS_READ,
UA_MANDATORY),
UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_WQ_TYPE,
enum ib_wq_type,
UA_MANDATORY),
UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_USER_HANDLE,
UVERBS_ATTR_TYPE(u64),
UA_MANDATORY),
UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_MAX_WR,
UVERBS_ATTR_TYPE(u32),
UA_MANDATORY),
UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_MAX_SGE,
UVERBS_ATTR_TYPE(u32),
UA_MANDATORY),
UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_WQ_FLAGS,
enum ib_uverbs_wq_flags,
UA_MANDATORY),
UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_CQ_HANDLE,
UVERBS_OBJECT_CQ,
UVERBS_ACCESS_READ,
UA_OPTIONAL),
UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_WQ_EVENT_FD,
UVERBS_OBJECT_ASYNC_EVENT,
UVERBS_ACCESS_READ,
UA_OPTIONAL),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_MAX_WR,
UVERBS_ATTR_TYPE(u32),
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_MAX_SGE,
UVERBS_ATTR_TYPE(u32),
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_WQ_NUM,
UVERBS_ATTR_TYPE(u32),
UA_OPTIONAL),
UVERBS_ATTR_UHW());
static int UVERBS_HANDLER(UVERBS_METHOD_WQ_DESTROY)(
struct uverbs_attr_bundle *attrs)
{
struct ib_uobject *uobj =
uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_WQ_HANDLE);
struct ib_uwq_object *obj =
container_of(uobj, struct ib_uwq_object, uevent.uobject);
return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_WQ_RESP,
&obj->uevent.events_reported,
sizeof(obj->uevent.events_reported));
}
DECLARE_UVERBS_NAMED_METHOD(
UVERBS_METHOD_WQ_DESTROY,
UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_WQ_HANDLE,
UVERBS_OBJECT_WQ,
UVERBS_ACCESS_DESTROY,
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_WQ_RESP,
UVERBS_ATTR_TYPE(u32),
UA_MANDATORY));
DECLARE_UVERBS_NAMED_OBJECT(
UVERBS_OBJECT_WQ,
UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uwq_object), uverbs_free_wq),
&UVERBS_METHOD(UVERBS_METHOD_WQ_CREATE),
&UVERBS_METHOD(UVERBS_METHOD_WQ_DESTROY)
);
const struct uapi_definition uverbs_def_obj_wq[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_WQ,
UAPI_DEF_OBJ_NEEDS_FN(destroy_wq)),
{}
};