Skip to content

Commit

Permalink
IB/uverbs: Build the specs into a radix tree at runtime
Browse files Browse the repository at this point in the history
This radix tree datastructure is intended to replace the 'hash' structure
used today for parsing ioctl methods during system calls. This first
commit introduces the structure and builds it from the existing .rodata
descriptions.

The so-called hash arrangement is actually a 5 level open coded radix tree.
This new version uses a 3 level radix tree built using the radix tree
library.

Overall this is much less code and much easier to build as the radix tree
API allows for dynamic modification during the building. There is a small
memory penalty to pay for this, but since the radix tree is allocated on
a per device basis, a few kb of RAM seems immaterial considering the
gained simplicity.

The radix tree is similar to the existing tree, but also has a 'attr_bkey'
concept, which is a small value'd index for each method attribute. This is
used to simplify and improve performance of everything in the next
patches.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
Reviewed-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
  • Loading branch information
Jason Gunthorpe committed Aug 10, 2018
1 parent 7d96c9b commit 9ed3e5f
Show file tree
Hide file tree
Showing 6 changed files with 545 additions and 3 deletions.
3 changes: 2 additions & 1 deletion drivers/infiniband/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
rdma_core.o uverbs_std_types.o uverbs_ioctl.o \
uverbs_ioctl_merge.o uverbs_std_types_cq.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
50 changes: 50 additions & 0 deletions drivers/infiniband/core/rdma_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#include <rdma/ib_verbs.h>
#include <linux/mutex.h>

struct ib_uverbs_device;

int uverbs_ns_idx(u16 *id, unsigned int ns_count);
const struct uverbs_object_spec *uverbs_get_object(struct ib_uverbs_file *ufile,
uint16_t object);
Expand Down Expand Up @@ -113,4 +115,52 @@ int uverbs_finalize_object(struct ib_uobject *uobj,
void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);

/*
* This is the runtime description of the uverbs API, used by the syscall
* machinery to validate and dispatch calls.
*/

/*
* Depending on ID the slot pointer in the radix tree points at one of these
* structs.
*/
struct uverbs_api_object {
const struct uverbs_obj_type *type_attrs;
const struct uverbs_obj_type_class *type_class;
};

struct uverbs_api_ioctl_method {
int (__rcu *handler)(struct ib_uverbs_file *ufile,
struct uverbs_attr_bundle *ctx);
DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN);
u8 driver_method:1;
u8 key_bitmap_len;
u8 destroy_bkey;
};

struct uverbs_api_attr {
struct uverbs_attr_spec spec;
};

struct uverbs_api_object;
struct uverbs_api {
/* radix tree contains struct uverbs_api_* pointers */
struct radix_tree_root radix;
enum rdma_driver_id driver_id;
};

static inline const struct uverbs_api_object *
uapi_get_object(struct uverbs_api *uapi, u16 object_id)
{
return radix_tree_lookup(&uapi->radix, uapi_key_obj(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);
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);

#endif /* RDMA_CORE_H */
1 change: 1 addition & 0 deletions drivers/infiniband/core/uverbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct ib_uverbs_device {
struct list_head uverbs_file_list;
struct list_head uverbs_events_file_list;
struct uverbs_root_spec *specs_root;
struct uverbs_api *uapi;
};

struct ib_uverbs_event_queue {
Expand Down
14 changes: 12 additions & 2 deletions drivers/infiniband/core/uverbs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ static void ib_uverbs_release_dev(struct kobject *kobj)
struct ib_uverbs_device *dev =
container_of(kobj, struct ib_uverbs_device, kobj);

uverbs_destroy_api(dev->uapi);
cleanup_srcu_struct(&dev->disassociate_srcu);
uverbs_free_spec_tree(dev->specs_root);
kfree(dev);
Expand Down Expand Up @@ -1000,6 +1001,7 @@ static int ib_uverbs_create_uapi(struct ib_device *device,
const struct uverbs_object_tree_def **specs;
struct uverbs_root_spec *specs_root;
unsigned int num_specs = 1;
struct uverbs_api *uapi;
unsigned int i;

if (device->driver_specs)
Expand All @@ -1020,7 +1022,14 @@ static int ib_uverbs_create_uapi(struct ib_device *device,
if (IS_ERR(specs_root))
return PTR_ERR(specs_root);

uapi = uverbs_alloc_api(device->driver_specs, device->driver_id);
if (IS_ERR(uapi)) {
uverbs_free_spec_tree(specs_root);
return PTR_ERR(uapi);
}

uverbs_dev->specs_root = specs_root;
uverbs_dev->uapi = uapi;
return 0;
}

Expand Down Expand Up @@ -1115,7 +1124,7 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
struct ib_event event;

/* Pending running commands to terminate */
synchronize_srcu(&uverbs_dev->disassociate_srcu);
uverbs_disassociate_api_pre(uverbs_dev);
event.event = IB_EVENT_DEVICE_FATAL;
event.element.port_num = 0;
event.device = ib_dev;
Expand Down Expand Up @@ -1161,6 +1170,8 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
kill_fasync(&event_file->ev_queue.async_queue, SIGIO, POLL_IN);
}
mutex_unlock(&uverbs_dev->lists_mutex);

uverbs_disassociate_api(uverbs_dev->uapi);
}

static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
Expand Down Expand Up @@ -1188,7 +1199,6 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
* cdev was deleted, however active clients can still issue
* commands and close their open files.
*/
rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
ib_uverbs_free_hw_resources(uverbs_dev, device);
wait_clients = 0;
}
Expand Down
Loading

0 comments on commit 9ed3e5f

Please sign in to comment.