Commit 0cbf432d authored by Jason Gunthorpe's avatar Jason Gunthorpe

RDMA/uverbs: Use a linear list to describe the compiled-in uapi

The 'tree' data structure is very hard to build at compile time, and this
makes it very limited. The new radix tree based compiler can handle a more
complex input language that does not require the compiler to perfectly
group everything into a neat tree structure.

Instead use a simple list to describe to input, where the list elements
can be of various different 'opcodes' instructing the radix compiler what
to do. Start out with opcodes chaining to other definition lists and
chaining to the existing 'tree' definition.

Replace the very top level of the 'object tree' with this list type and
get rid of struct uverbs_object_tree_def and DECLARE_UVERBS_OBJECT_TREE.
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
parent dfb631a1
......@@ -152,9 +152,8 @@ uapi_get_object(struct uverbs_api *uapi, u16 object_id)
}
char *uapi_key_format(char *S, unsigned int key);
struct uverbs_api *uverbs_alloc_api(
const struct uverbs_object_tree_def *const *driver_specs,
enum rdma_driver_id driver_id);
struct uverbs_api *uverbs_alloc_api(const struct uapi_definition *driver_def,
enum rdma_driver_id driver_id);
void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev);
void uverbs_disassociate_api(struct uverbs_api *uapi);
void uverbs_destroy_api(struct uverbs_api *uapi);
......@@ -162,4 +161,6 @@ void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
unsigned int num_attrs);
void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
extern const struct uapi_definition uverbs_def_obj_intf[];
#endif /* RDMA_CORE_H */
......@@ -1224,7 +1224,7 @@ static int ib_uverbs_create_uapi(struct ib_device *device,
{
struct uverbs_api *uapi;
uapi = uverbs_alloc_api(device->driver_specs, device->driver_id);
uapi = uverbs_alloc_api(device->driver_def, device->driver_id);
if (IS_ERR(uapi))
return PTR_ERR(uapi);
......
......@@ -262,25 +262,22 @@ DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD,
DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE);
DECLARE_UVERBS_OBJECT_TREE(uverbs_default_objects,
&UVERBS_OBJECT(UVERBS_OBJECT_DEVICE),
&UVERBS_OBJECT(UVERBS_OBJECT_PD),
&UVERBS_OBJECT(UVERBS_OBJECT_MR),
&UVERBS_OBJECT(UVERBS_OBJECT_COMP_CHANNEL),
&UVERBS_OBJECT(UVERBS_OBJECT_CQ),
&UVERBS_OBJECT(UVERBS_OBJECT_QP),
&UVERBS_OBJECT(UVERBS_OBJECT_AH),
&UVERBS_OBJECT(UVERBS_OBJECT_MW),
&UVERBS_OBJECT(UVERBS_OBJECT_SRQ),
&UVERBS_OBJECT(UVERBS_OBJECT_FLOW),
&UVERBS_OBJECT(UVERBS_OBJECT_WQ),
&UVERBS_OBJECT(UVERBS_OBJECT_RWQ_IND_TBL),
&UVERBS_OBJECT(UVERBS_OBJECT_XRCD),
&UVERBS_OBJECT(UVERBS_OBJECT_FLOW_ACTION),
&UVERBS_OBJECT(UVERBS_OBJECT_DM),
&UVERBS_OBJECT(UVERBS_OBJECT_COUNTERS));
const struct uverbs_object_tree_def *uverbs_default_get_objects(void)
{
return &uverbs_default_objects;
}
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_MR),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_CQ),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_QP),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_AH),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_MW),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_SRQ),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_FLOW),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_WQ),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_RWQ_IND_TBL),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_XRCD),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_FLOW_ACTION),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DM),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COUNTERS),
{}
};
......@@ -98,72 +98,96 @@ static int uapi_merge_method(struct uverbs_api *uapi,
return 0;
}
static int uapi_merge_tree(struct uverbs_api *uapi,
const struct uverbs_object_tree_def *tree,
bool is_driver)
static int uapi_merge_obj_tree(struct uverbs_api *uapi,
const struct uverbs_object_def *obj,
bool is_driver)
{
unsigned int i, j;
struct uverbs_api_object *obj_elm;
unsigned int i;
u32 obj_key;
int rc;
if (!tree->objects)
obj_key = uapi_key_obj(obj->id);
obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm));
if (IS_ERR(obj_elm)) {
if (obj_elm != ERR_PTR(-EEXIST))
return PTR_ERR(obj_elm);
/* This occurs when a driver uses ADD_UVERBS_METHODS */
if (WARN_ON(obj->type_attrs))
return -EINVAL;
obj_elm = radix_tree_lookup(&uapi->radix, obj_key);
if (WARN_ON(!obj_elm))
return -EINVAL;
} else {
obj_elm->type_attrs = obj->type_attrs;
if (obj->type_attrs) {
obj_elm->type_class = obj->type_attrs->type_class;
/*
* Today drivers are only permitted to use idr_class
* types. They cannot use FD types because we
* currently have no way to revoke the fops pointer
* after device disassociation.
*/
if (WARN_ON(is_driver && obj->type_attrs->type_class !=
&uverbs_idr_class))
return -EINVAL;
}
}
if (!obj->methods)
return 0;
for (i = 0; i != tree->num_objects; i++) {
const struct uverbs_object_def *obj = (*tree->objects)[i];
struct uverbs_api_object *obj_elm;
u32 obj_key;
for (i = 0; i != obj->num_methods; i++) {
const struct uverbs_method_def *method = (*obj->methods)[i];
if (!obj)
if (!method)
continue;
obj_key = uapi_key_obj(obj->id);
obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm));
if (IS_ERR(obj_elm)) {
if (obj_elm != ERR_PTR(-EEXIST))
return PTR_ERR(obj_elm);
rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
is_driver);
if (rc)
return rc;
}
/* This occurs when a driver uses ADD_UVERBS_METHODS */
if (WARN_ON(obj->type_attrs))
return -EINVAL;
obj_elm = radix_tree_lookup(&uapi->radix, obj_key);
if (WARN_ON(!obj_elm))
return -EINVAL;
} else {
obj_elm->type_attrs = obj->type_attrs;
if (obj->type_attrs) {
obj_elm->type_class =
obj->type_attrs->type_class;
/*
* Today drivers are only permitted to use
* idr_class types. They cannot use FD types
* because we currently have no way to revoke
* the fops pointer after device
* disassociation.
*/
if (WARN_ON(is_driver &&
obj->type_attrs->type_class !=
&uverbs_idr_class))
return -EINVAL;
}
}
return 0;
}
static int uapi_merge_def(struct uverbs_api *uapi,
const struct uapi_definition *def_list,
bool is_driver)
{
const struct uapi_definition *def = def_list;
int rc;
if (!def_list)
return 0;
if (!obj->methods)
for (;; def++) {
switch ((enum uapi_definition_kind)def->kind) {
case UAPI_DEF_CHAIN:
rc = uapi_merge_def(uapi, def->chain, is_driver);
if (rc)
return rc;
continue;
for (j = 0; j != obj->num_methods; j++) {
const struct uverbs_method_def *method =
(*obj->methods)[j];
if (!method)
continue;
case UAPI_DEF_CHAIN_OBJ_TREE:
if (WARN_ON(def->object_start.object_id !=
def->chain_obj_tree->id))
return -EINVAL;
rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
is_driver);
rc = uapi_merge_obj_tree(uapi, def->chain_obj_tree,
is_driver);
if (rc)
return rc;
continue;
case UAPI_DEF_END:
return 0;
}
WARN_ON(true);
return -EINVAL;
}
return 0;
}
static int
......@@ -263,9 +287,13 @@ void uverbs_destroy_api(struct uverbs_api *uapi)
kfree(uapi);
}
struct uverbs_api *uverbs_alloc_api(
const struct uverbs_object_tree_def *const *driver_specs,
enum rdma_driver_id driver_id)
static const struct uapi_definition uverbs_core_api[] = {
UAPI_DEF_CHAIN(uverbs_def_obj_intf),
{},
};
struct uverbs_api *uverbs_alloc_api(const struct uapi_definition *driver_def,
enum rdma_driver_id driver_id)
{
struct uverbs_api *uapi;
int rc;
......@@ -277,15 +305,12 @@ struct uverbs_api *uverbs_alloc_api(
INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
uapi->driver_id = driver_id;
rc = uapi_merge_tree(uapi, uverbs_default_get_objects(), false);
rc = uapi_merge_def(uapi, uverbs_core_api, false);
if (rc)
goto err;
rc = uapi_merge_def(uapi, driver_def, true);
if (rc)
goto err;
for (; driver_specs && *driver_specs; driver_specs++) {
rc = uapi_merge_tree(uapi, *driver_specs, true);
if (rc)
goto err;
}
rc = uapi_finalize(uapi);
if (rc)
......
......@@ -1323,12 +1323,9 @@ DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM,
&UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_REG),
&UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG));
DECLARE_UVERBS_OBJECT_TREE(devx_objects,
&UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX),
&UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ),
&UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM));
const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void)
{
return &devx_objects;
}
const struct uapi_definition mlx5_ib_devx_defs[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX_OBJ),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX_UMEM),
{},
};
......@@ -610,16 +610,10 @@ DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER,
&UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
&UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
DECLARE_UVERBS_OBJECT_TREE(flow_objects,
&UVERBS_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER));
int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
{
int i = 0;
root[i++] = &flow_objects;
root[i++] = &mlx5_ib_fs;
root[i++] = &mlx5_ib_flow_actions;
return i;
}
const struct uapi_definition mlx5_ib_flow_defs[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_FLOW_MATCHER),
UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW, &mlx5_ib_fs),
UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
&mlx5_ib_flow_actions),
{},
};
......@@ -5550,23 +5550,34 @@ ADD_UVERBS_ATTRIBUTES_SIMPLE(
UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_CREATE_FLOW_ACTION_FLAGS,
enum mlx5_ib_uapi_flow_action_flags));
static const struct uapi_definition mlx5_ib_defs[] = {
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
UAPI_DEF_CHAIN(mlx5_ib_flow_defs),
#endif
UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
&mlx5_ib_flow_action),
UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_DM, &mlx5_ib_dm),
{}
};
static int populate_specs_root(struct mlx5_ib_dev *dev)
{
const struct uverbs_object_tree_def **trees = dev->driver_trees;
size_t num_trees = 0;
trees[num_trees++] = &mlx5_ib_flow_action;
trees[num_trees++] = &mlx5_ib_dm;
struct uapi_definition *defs = dev->driver_defs;
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
if (MLX5_CAP_GEN_64(dev->mdev, general_obj_types) &
MLX5_GENERAL_OBJ_TYPES_CAP_UCTX)
trees[num_trees++] = mlx5_ib_get_devx_tree();
*defs++ = (struct uapi_definition)UAPI_DEF_CHAIN(
mlx5_ib_devx_defs);
#endif
num_trees += mlx5_ib_get_flow_trees(trees + num_trees);
*defs++ = (struct uapi_definition)UAPI_DEF_CHAIN(mlx5_ib_defs);
*defs++ = (struct uapi_definition){};
WARN_ON(defs - dev->driver_defs >= ARRAY_SIZE(dev->driver_defs));
WARN_ON(num_trees >= ARRAY_SIZE(dev->driver_trees));
trees[num_trees] = NULL;
dev->ib_dev.driver_specs = trees;
if (IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS))
dev->ib_dev.driver_def = dev->driver_defs;
return 0;
}
......
......@@ -891,7 +891,7 @@ struct mlx5_ib_pf_eq {
struct mlx5_ib_dev {
struct ib_device ib_dev;
const struct uverbs_object_tree_def *driver_trees[7];
struct uapi_definition driver_defs[7];
struct mlx5_core_dev *mdev;
struct mlx5_roce roce[MLX5_MAX_PORTS];
int num_ports;
......@@ -1264,29 +1264,23 @@ void mlx5_ib_put_native_port_mdev(struct mlx5_ib_dev *dev,
int mlx5_ib_devx_create(struct mlx5_ib_dev *dev);
void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid);
const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void);
extern const struct uapi_definition mlx5_ib_devx_defs[];
extern const struct uapi_definition mlx5_ib_flow_defs[];
struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add(
struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher,
struct mlx5_flow_act *flow_act, void *cmd_in, int inlen,
int dest_id, int dest_type);
bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type);
int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root);
void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction);
#else
static inline int
mlx5_ib_devx_create(struct mlx5_ib_dev *dev) { return -EOPNOTSUPP; };
static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) {}
static inline const struct uverbs_object_tree_def *
mlx5_ib_get_devx_tree(void) { return NULL; }
static inline bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id,
int *dest_type)
{
return false;
}
static inline int
mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
{
return 0;
}
static inline void
mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
{
......
......@@ -2600,7 +2600,7 @@ struct ib_device {
const struct cpumask *(*get_vector_affinity)(struct ib_device *ibdev,
int comp_vector);
const struct uverbs_object_tree_def *const *driver_specs;
const struct uapi_definition *driver_def;
enum rdma_driver_id driver_id;
};
......
......@@ -296,11 +296,43 @@ struct uverbs_object_def {
const struct uverbs_method_def * const (*methods)[];
};
struct uverbs_object_tree_def {
size_t num_objects;
const struct uverbs_object_def * const (*objects)[];
enum uapi_definition_kind {
UAPI_DEF_END = 0,
UAPI_DEF_CHAIN_OBJ_TREE,
UAPI_DEF_CHAIN,
};
struct uapi_definition {
u8 kind;
union {
struct {
u16 object_id;
} object_start;
};
union {
const struct uapi_definition *chain;
const struct uverbs_object_def *chain_obj_tree;
};
};
/* Include another struct uapi_definition in this one */
#define UAPI_DEF_CHAIN(_def_var) \
{ \
.kind = UAPI_DEF_CHAIN, .chain = _def_var, \
}
/* Temporary until the tree base description is replaced */
#define UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, _object_ptr) \
{ \
.kind = UAPI_DEF_CHAIN_OBJ_TREE, \
.object_start = { .object_id = _object_enum }, \
.chain_obj_tree = _object_ptr, \
}
#define UAPI_DEF_CHAIN_OBJ_TREE_NAMED(_object_enum, ...) \
UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, &UVERBS_OBJECT(_object_enum)), \
##__VA_ARGS__
/*
* =======================================
* Attribute Specifications
......@@ -438,21 +470,6 @@ struct uverbs_object_tree_def {
UVERBS_ATTR_MIN_SIZE(0), \
UA_OPTIONAL)
/*
* =======================================
* Declaration helpers
* =======================================
*/
#define DECLARE_UVERBS_OBJECT_TREE(_name, ...) \
static const struct uverbs_object_def *const _name##_ptr[] = { \
__VA_ARGS__, \
}; \
static const struct uverbs_object_tree_def _name = { \
.num_objects = ARRAY_SIZE(_name##_ptr), \
.objects = &_name##_ptr, \
}
/* =================================================
* Parsing infrastructure
* =================================================
......
......@@ -102,18 +102,11 @@
#define ADD_UVERBS_METHODS(_name, _object_id, ...) \
static const struct uverbs_method_def *const UVERBS_OBJECT_METHODS( \
_object_id)[] = { __VA_ARGS__ }; \
static const struct uverbs_object_def _name##_struct = { \
static const struct uverbs_object_def _name = { \
.id = _object_id, \
.num_methods = ARRAY_SIZE(UVERBS_OBJECT_METHODS(_object_id)), \
.methods = &UVERBS_OBJECT_METHODS(_object_id) \
}; \
static const struct uverbs_object_def *const _name##_ptrs[] = { \
&_name##_struct, \
}; \
static const struct uverbs_object_tree_def _name = { \
.num_objects = 1, \
.objects = &_name##_ptrs, \
}
};
/* Used by drivers to declare a complete parsing tree for a single method that
* differs only in having additional driver specific attributes.
......
......@@ -37,15 +37,6 @@
#include <rdma/uverbs_ioctl.h>
#include <rdma/ib_user_ioctl_verbs.h>
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
const struct uverbs_object_tree_def *uverbs_default_get_objects(void);
#else
static inline const struct uverbs_object_tree_def *uverbs_default_get_objects(void)
{
return NULL;
}
#endif
/* Returns _id, or causes a compile error if _id is not a u32.
*
* The uobj APIs should only be used with the write based uAPI to access
......
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