Commit 4785860e authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Doug Ledford

RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers

Now that the handlers do not process their own udata we can make a
sensible ioctl that wrappers them. The ioctl follows the same format as
the write_ex() and has the user explicitly specify the core and driver
in/out opaque structures and a command number.

This works for all forms of write commands.
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 24141496
...@@ -38,4 +38,4 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \ ...@@ -38,4 +38,4 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
uverbs_std_types_cq.o \ uverbs_std_types_cq.o \
uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
uverbs_std_types_mr.o uverbs_std_types_counters.o \ uverbs_std_types_mr.o uverbs_std_types_counters.o \
uverbs_uapi.o uverbs_uapi.o uverbs_std_types_device.o
...@@ -188,6 +188,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile); ...@@ -188,6 +188,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
extern const struct uapi_definition uverbs_def_obj_counters[]; extern const struct uapi_definition uverbs_def_obj_counters[];
extern const struct uapi_definition uverbs_def_obj_cq[]; extern const struct uapi_definition uverbs_def_obj_cq[];
extern const struct uapi_definition uverbs_def_obj_device[];
extern const struct uapi_definition uverbs_def_obj_dm[]; extern const struct uapi_definition uverbs_def_obj_dm[];
extern const struct uapi_definition uverbs_def_obj_flow_action[]; extern const struct uapi_definition uverbs_def_obj_flow_action[];
extern const struct uapi_definition uverbs_def_obj_intf[]; extern const struct uapi_definition uverbs_def_obj_intf[];
...@@ -214,4 +215,8 @@ uapi_get_method(const struct uverbs_api *uapi, u32 command) ...@@ -214,4 +215,8 @@ uapi_get_method(const struct uverbs_api *uapi, u32 command)
return uapi->write_methods[cmd_idx]; return uapi->write_methods[cmd_idx];
} }
void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
struct ib_udata *udata, unsigned int attr_in,
unsigned int attr_out);
#endif /* RDMA_CORE_H */ #endif /* RDMA_CORE_H */
...@@ -246,7 +246,6 @@ int uverbs_dealloc_mw(struct ib_mw *mw); ...@@ -246,7 +246,6 @@ int uverbs_dealloc_mw(struct ib_mw *mw);
void ib_uverbs_detach_umcast(struct ib_qp *qp, void ib_uverbs_detach_umcast(struct ib_qp *qp,
struct ib_uqp_object *uobj); struct ib_uqp_object *uobj);
void create_udata(struct uverbs_attr_bundle *ctx, struct ib_udata *udata);
long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
struct ib_uverbs_flow_spec { struct ib_uverbs_flow_spec {
......
...@@ -436,7 +436,9 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle, ...@@ -436,7 +436,9 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
return -EINVAL; return -EINVAL;
if (pbundle->method_elm->has_udata) if (pbundle->method_elm->has_udata)
create_udata(&pbundle->bundle, &pbundle->bundle.driver_udata); uverbs_fill_udata(&pbundle->bundle,
&pbundle->bundle.driver_udata,
UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) { if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
struct uverbs_obj_attr *destroy_attr = struct uverbs_obj_attr *destroy_attr =
...@@ -664,35 +666,37 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, ...@@ -664,35 +666,37 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
EXPORT_SYMBOL(uverbs_get_flags32); EXPORT_SYMBOL(uverbs_get_flags32);
/* /*
* This is for ease of conversion. The purpose is to convert all drivers to * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
* use uverbs_attr_bundle instead of ib_udata. Assume attr == 0 is input and * This is primarily used to convert the UVERBS_ATTR_UHW() into the
* attr == 1 is output. * ib_udata format used by the drivers.
*/ */
void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata) void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
struct ib_udata *udata, unsigned int attr_in,
unsigned int attr_out)
{ {
struct bundle_priv *pbundle = struct bundle_priv *pbundle =
container_of(bundle, struct bundle_priv, bundle); container_of(bundle, struct bundle_priv, bundle);
const struct uverbs_attr *uhw_in = const struct uverbs_attr *in =
uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN); uverbs_attr_get(&pbundle->bundle, attr_in);
const struct uverbs_attr *uhw_out = const struct uverbs_attr *out =
uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT); uverbs_attr_get(&pbundle->bundle, attr_out);
if (!IS_ERR(uhw_in)) { if (!IS_ERR(in)) {
udata->inlen = uhw_in->ptr_attr.len; udata->inlen = in->ptr_attr.len;
if (uverbs_attr_ptr_is_inline(uhw_in)) if (uverbs_attr_ptr_is_inline(in))
udata->inbuf = udata->inbuf =
&pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx] &pbundle->user_attrs[in->ptr_attr.uattr_idx]
.data; .data;
else else
udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); udata->inbuf = u64_to_user_ptr(in->ptr_attr.data);
} else { } else {
udata->inbuf = NULL; udata->inbuf = NULL;
udata->inlen = 0; udata->inlen = 0;
} }
if (!IS_ERR(uhw_out)) { if (!IS_ERR(out)) {
udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); udata->outbuf = u64_to_user_ptr(out->ptr_attr.data);
udata->outlen = uhw_out->ptr_attr.len; udata->outlen = out->ptr_attr.len;
} else { } else {
udata->outbuf = NULL; udata->outbuf = NULL;
udata->outlen = 0; udata->outlen = 0;
......
...@@ -259,10 +259,7 @@ DECLARE_UVERBS_NAMED_OBJECT( ...@@ -259,10 +259,7 @@ DECLARE_UVERBS_NAMED_OBJECT(
DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD, DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD,
UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd)); UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd));
DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE);
const struct uapi_definition uverbs_def_obj_intf[] = { const struct uapi_definition uverbs_def_obj_intf[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD, UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD,
UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)), UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL, UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL,
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
*/
#include <rdma/uverbs_std_types.h>
#include "rdma_core.h"
#include "uverbs.h"
/*
* This ioctl method allows calling any defined write or write_ex
* handler. This essentially replaces the hdr/ex_hdr system with the ioctl
* marshalling, and brings the non-ex path into the same marshalling as the ex
* path.
*/
static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)(
struct uverbs_attr_bundle *attrs)
{
struct uverbs_api *uapi = attrs->ufile->device->uapi;
const struct uverbs_api_write_method *method_elm;
u32 cmd;
int rc;
rc = uverbs_get_const(&cmd, attrs, UVERBS_ATTR_WRITE_CMD);
if (rc)
return rc;
method_elm = uapi_get_method(uapi, cmd);
if (IS_ERR(method_elm))
return PTR_ERR(method_elm);
uverbs_fill_udata(attrs, &attrs->ucore, UVERBS_ATTR_CORE_IN,
UVERBS_ATTR_CORE_OUT);
if (attrs->ucore.inlen < method_elm->req_size ||
attrs->ucore.outlen < method_elm->resp_size)
return -ENOSPC;
return method_elm->handler(attrs);
}
DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_INVOKE_WRITE,
UVERBS_ATTR_CONST_IN(UVERBS_ATTR_WRITE_CMD,
enum ib_uverbs_write_cmds,
UA_MANDATORY),
UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CORE_IN,
UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
UA_OPTIONAL),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CORE_OUT,
UVERBS_ATTR_MIN_SIZE(0),
UA_OPTIONAL),
UVERBS_ATTR_UHW());
DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
&UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE));
const struct uapi_definition uverbs_def_obj_device[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
{},
};
...@@ -621,6 +621,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi) ...@@ -621,6 +621,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi)
static const struct uapi_definition uverbs_core_api[] = { static const struct uapi_definition uverbs_core_api[] = {
UAPI_DEF_CHAIN(uverbs_def_obj_counters), UAPI_DEF_CHAIN(uverbs_def_obj_counters),
UAPI_DEF_CHAIN(uverbs_def_obj_cq), UAPI_DEF_CHAIN(uverbs_def_obj_cq),
UAPI_DEF_CHAIN(uverbs_def_obj_device),
UAPI_DEF_CHAIN(uverbs_def_obj_dm), UAPI_DEF_CHAIN(uverbs_def_obj_dm),
UAPI_DEF_CHAIN(uverbs_def_obj_flow_action), UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
UAPI_DEF_CHAIN(uverbs_def_obj_intf), UAPI_DEF_CHAIN(uverbs_def_obj_intf),
......
...@@ -63,6 +63,16 @@ enum { ...@@ -63,6 +63,16 @@ enum {
UVERBS_ATTR_UHW_OUT, UVERBS_ATTR_UHW_OUT,
}; };
enum uverbs_methods_device {
UVERBS_METHOD_INVOKE_WRITE,
};
enum uverbs_attrs_invoke_write_cmd_attr_ids {
UVERBS_ATTR_CORE_IN,
UVERBS_ATTR_CORE_OUT,
UVERBS_ATTR_WRITE_CMD,
};
enum uverbs_attrs_create_cq_cmd_attr_ids { enum uverbs_attrs_create_cq_cmd_attr_ids {
UVERBS_ATTR_CREATE_CQ_HANDLE, UVERBS_ATTR_CREATE_CQ_HANDLE,
UVERBS_ATTR_CREATE_CQ_CQE, UVERBS_ATTR_CREATE_CQ_CQE,
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#define IB_USER_VERBS_ABI_VERSION 6 #define IB_USER_VERBS_ABI_VERSION 6
#define IB_USER_VERBS_CMD_THRESHOLD 50 #define IB_USER_VERBS_CMD_THRESHOLD 50
enum { enum ib_uverbs_write_cmds {
IB_USER_VERBS_CMD_GET_CONTEXT, IB_USER_VERBS_CMD_GET_CONTEXT,
IB_USER_VERBS_CMD_QUERY_DEVICE, IB_USER_VERBS_CMD_QUERY_DEVICE,
IB_USER_VERBS_CMD_QUERY_PORT, IB_USER_VERBS_CMD_QUERY_PORT,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment