Skip to content

Commit 9ed3e5f

Browse files
committed
IB/uverbs: Build the specs into a radix tree at runtime
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>
1 parent 7d96c9b commit 9ed3e5f

File tree

6 files changed

+545
-3
lines changed

6 files changed

+545
-3
lines changed

drivers/infiniband/core/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
3737
rdma_core.o uverbs_std_types.o uverbs_ioctl.o \
3838
uverbs_ioctl_merge.o uverbs_std_types_cq.o \
3939
uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
40-
uverbs_std_types_mr.o uverbs_std_types_counters.o
40+
uverbs_std_types_mr.o uverbs_std_types_counters.o \
41+
uverbs_uapi.o

drivers/infiniband/core/rdma_core.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include <rdma/ib_verbs.h>
4444
#include <linux/mutex.h>
4545

46+
struct ib_uverbs_device;
47+
4648
int uverbs_ns_idx(u16 *id, unsigned int ns_count);
4749
const struct uverbs_object_spec *uverbs_get_object(struct ib_uverbs_file *ufile,
4850
uint16_t object);
@@ -113,4 +115,52 @@ int uverbs_finalize_object(struct ib_uobject *uobj,
113115
void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
114116
void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);
115117

118+
/*
119+
* This is the runtime description of the uverbs API, used by the syscall
120+
* machinery to validate and dispatch calls.
121+
*/
122+
123+
/*
124+
* Depending on ID the slot pointer in the radix tree points at one of these
125+
* structs.
126+
*/
127+
struct uverbs_api_object {
128+
const struct uverbs_obj_type *type_attrs;
129+
const struct uverbs_obj_type_class *type_class;
130+
};
131+
132+
struct uverbs_api_ioctl_method {
133+
int (__rcu *handler)(struct ib_uverbs_file *ufile,
134+
struct uverbs_attr_bundle *ctx);
135+
DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN);
136+
u8 driver_method:1;
137+
u8 key_bitmap_len;
138+
u8 destroy_bkey;
139+
};
140+
141+
struct uverbs_api_attr {
142+
struct uverbs_attr_spec spec;
143+
};
144+
145+
struct uverbs_api_object;
146+
struct uverbs_api {
147+
/* radix tree contains struct uverbs_api_* pointers */
148+
struct radix_tree_root radix;
149+
enum rdma_driver_id driver_id;
150+
};
151+
152+
static inline const struct uverbs_api_object *
153+
uapi_get_object(struct uverbs_api *uapi, u16 object_id)
154+
{
155+
return radix_tree_lookup(&uapi->radix, uapi_key_obj(object_id));
156+
}
157+
158+
char *uapi_key_format(char *S, unsigned int key);
159+
struct uverbs_api *uverbs_alloc_api(
160+
const struct uverbs_object_tree_def *const *driver_specs,
161+
enum rdma_driver_id driver_id);
162+
void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev);
163+
void uverbs_disassociate_api(struct uverbs_api *uapi);
164+
void uverbs_destroy_api(struct uverbs_api *uapi);
165+
116166
#endif /* RDMA_CORE_H */

drivers/infiniband/core/uverbs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct ib_uverbs_device {
112112
struct list_head uverbs_file_list;
113113
struct list_head uverbs_events_file_list;
114114
struct uverbs_root_spec *specs_root;
115+
struct uverbs_api *uapi;
115116
};
116117

117118
struct ib_uverbs_event_queue {

drivers/infiniband/core/uverbs_main.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ static void ib_uverbs_release_dev(struct kobject *kobj)
174174
struct ib_uverbs_device *dev =
175175
container_of(kobj, struct ib_uverbs_device, kobj);
176176

177+
uverbs_destroy_api(dev->uapi);
177178
cleanup_srcu_struct(&dev->disassociate_srcu);
178179
uverbs_free_spec_tree(dev->specs_root);
179180
kfree(dev);
@@ -1000,6 +1001,7 @@ static int ib_uverbs_create_uapi(struct ib_device *device,
10001001
const struct uverbs_object_tree_def **specs;
10011002
struct uverbs_root_spec *specs_root;
10021003
unsigned int num_specs = 1;
1004+
struct uverbs_api *uapi;
10031005
unsigned int i;
10041006

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

1025+
uapi = uverbs_alloc_api(device->driver_specs, device->driver_id);
1026+
if (IS_ERR(uapi)) {
1027+
uverbs_free_spec_tree(specs_root);
1028+
return PTR_ERR(uapi);
1029+
}
1030+
10231031
uverbs_dev->specs_root = specs_root;
1032+
uverbs_dev->uapi = uapi;
10241033
return 0;
10251034
}
10261035

@@ -1115,7 +1124,7 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
11151124
struct ib_event event;
11161125

11171126
/* Pending running commands to terminate */
1118-
synchronize_srcu(&uverbs_dev->disassociate_srcu);
1127+
uverbs_disassociate_api_pre(uverbs_dev);
11191128
event.event = IB_EVENT_DEVICE_FATAL;
11201129
event.element.port_num = 0;
11211130
event.device = ib_dev;
@@ -1161,6 +1170,8 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
11611170
kill_fasync(&event_file->ev_queue.async_queue, SIGIO, POLL_IN);
11621171
}
11631172
mutex_unlock(&uverbs_dev->lists_mutex);
1173+
1174+
uverbs_disassociate_api(uverbs_dev->uapi);
11641175
}
11651176

11661177
static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
@@ -1188,7 +1199,6 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
11881199
* cdev was deleted, however active clients can still issue
11891200
* commands and close their open files.
11901201
*/
1191-
rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
11921202
ib_uverbs_free_hw_resources(uverbs_dev, device);
11931203
wait_clients = 0;
11941204
}

0 commit comments

Comments
 (0)