Commit 3a863577 authored by Jason Gunthorpe's avatar Jason Gunthorpe

IB/uverbs: Use uverbs_api to unmarshal ioctl commands

Convert the ioctl method syscall path to use the uverbs_api data
structures. The new uapi structure includes all the same information, just
in a different and more optimal way.

 - Use attr_bkey instead of 2 level radix trees for everything related to
   attributes. This includes the attribute storage, presence, and
   detection of missing mandatory attributes.
 - Avoid iterating over all attribute storage at finish, instead use
   find_first_bit with the attr_bkey to locate only those attrs that need
   cleanup.
 - Organize things to always run, and always rely on, cleanup. This
   avoids a bunch of tricky error unwind cases.
 - Locate the method using the radix tree, and locate the attributes
   using a very efficient incremental radix tree lookup
 - Use the precomputed destroy_bkey to handle uobject destruction
 - Use the precomputed allocation sizes and precomputed 'need_stack'
   to avoid maths in the fast path. This is optimal if userspace
   does not pass (many) unsupported attributes.

Overall this results in much better codegen for the attribute accessors,
everything is now stored in bitmaps or linear arrays indexed by attr_bkey.
The compiler can compute attr_bkey values at compile time for all method
attributes, meaning things like uverbs_attr_is_valid() now compile into
single instruction bit tests.
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent b61815e2
...@@ -133,6 +133,8 @@ struct uverbs_api_ioctl_method { ...@@ -133,6 +133,8 @@ struct uverbs_api_ioctl_method {
int (__rcu *handler)(struct ib_uverbs_file *ufile, int (__rcu *handler)(struct ib_uverbs_file *ufile,
struct uverbs_attr_bundle *ctx); struct uverbs_attr_bundle *ctx);
DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN); DECLARE_BITMAP(attr_mandatory, UVERBS_API_ATTR_BKEY_LEN);
u16 bundle_size;
u8 use_stack:1;
u8 driver_method:1; u8 driver_method:1;
u8 key_bitmap_len; u8 key_bitmap_len;
u8 destroy_bkey; u8 destroy_bkey;
...@@ -162,5 +164,7 @@ struct uverbs_api *uverbs_alloc_api( ...@@ -162,5 +164,7 @@ struct uverbs_api *uverbs_alloc_api(
void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev); void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev);
void uverbs_disassociate_api(struct uverbs_api *uapi); void uverbs_disassociate_api(struct uverbs_api *uapi);
void uverbs_destroy_api(struct uverbs_api *uapi); void uverbs_destroy_api(struct uverbs_api *uapi);
void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
unsigned int num_attrs);
#endif /* RDMA_CORE_H */ #endif /* RDMA_CORE_H */
This diff is collapsed.
...@@ -160,6 +160,7 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi, ...@@ -160,6 +160,7 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi,
u32 method_key) u32 method_key)
{ {
struct radix_tree_iter iter; struct radix_tree_iter iter;
unsigned int num_attrs = 0;
unsigned int max_bkey = 0; unsigned int max_bkey = 0;
bool single_uobj = false; bool single_uobj = false;
void __rcu **slot; void __rcu **slot;
...@@ -204,11 +205,13 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi, ...@@ -204,11 +205,13 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi,
} }
max_bkey = max(max_bkey, attr_bkey); max_bkey = max(max_bkey, attr_bkey);
num_attrs++;
} }
method_elm->key_bitmap_len = max_bkey + 1; method_elm->key_bitmap_len = max_bkey + 1;
WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN); WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN);
uapi_compute_bundle_size(method_elm, num_attrs);
return 0; return 0;
} }
......
...@@ -451,6 +451,7 @@ struct uverbs_object_tree_def { ...@@ -451,6 +451,7 @@ struct uverbs_object_tree_def {
* ================================================= * =================================================
*/ */
struct uverbs_ptr_attr { struct uverbs_ptr_attr {
/* /*
* If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is * If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is
...@@ -467,6 +468,7 @@ struct uverbs_ptr_attr { ...@@ -467,6 +468,7 @@ struct uverbs_ptr_attr {
struct uverbs_obj_attr { struct uverbs_obj_attr {
struct ib_uobject *uobject; struct ib_uobject *uobject;
const struct uverbs_api_attr *attr_elm;
}; };
struct uverbs_attr { struct uverbs_attr {
...@@ -476,39 +478,17 @@ struct uverbs_attr { ...@@ -476,39 +478,17 @@ struct uverbs_attr {
}; };
}; };
struct uverbs_attr_bundle_hash {
/* if bit i is set, it means attrs[i] contains valid information */
unsigned long *valid_bitmap;
size_t num_attrs;
/*
* arrays of attributes, each element corresponds to the specification
* of the attribute in the same index.
*/
struct uverbs_attr *attrs;
};
struct uverbs_attr_bundle { struct uverbs_attr_bundle {
struct ib_uverbs_file *ufile; struct ib_uverbs_file *ufile;
size_t num_buckets; DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN);
struct uverbs_attr_bundle_hash hash[]; struct uverbs_attr attrs[];
}; };
static inline bool uverbs_attr_is_valid_in_hash(const struct uverbs_attr_bundle_hash *attrs_hash,
unsigned int idx)
{
return test_bit(idx, attrs_hash->valid_bitmap);
}
static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_bundle, static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_bundle,
unsigned int idx) unsigned int idx)
{ {
u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT; return test_bit(uapi_bkey_attr(uapi_key_attr(idx)),
attrs_bundle->attr_present);
if (attrs_bundle->num_buckets <= idx_bucket)
return false;
return uverbs_attr_is_valid_in_hash(&attrs_bundle->hash[idx_bucket],
idx & ~UVERBS_ID_NS_MASK);
} }
#define IS_UVERBS_COPY_ERR(_ret) ((_ret) && (_ret) != -ENOENT) #define IS_UVERBS_COPY_ERR(_ret) ((_ret) && (_ret) != -ENOENT)
...@@ -516,12 +496,10 @@ static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_b ...@@ -516,12 +496,10 @@ static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_b
static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle, static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle,
u16 idx) u16 idx)
{ {
u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT;
if (!uverbs_attr_is_valid(attrs_bundle, idx)) if (!uverbs_attr_is_valid(attrs_bundle, idx))
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
return &attrs_bundle->hash[idx_bucket].attrs[idx & ~UVERBS_ID_NS_MASK]; return &attrs_bundle->attrs[uapi_bkey_attr(uapi_key_attr(idx))];
} }
static inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle *attrs_bundle, static inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle *attrs_bundle,
......
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