From bccd06223f21654eb268e153426a77deb117c1e8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 26 Jul 2018 16:37:14 -0600 Subject: IB/uverbs: Add UVERBS_ATTR_FLAGS_IN to the specs language This clearly indicates that the input is a bitwise combination of values in an enum, and identifies which enum contains the definition of the bits. Special accessors are provided that handle the mandatory validation of the allowed bits and enforce the correct type for bitwise flags. If we had introduced this at the start then the kabi would have uniformly used u64 data to pass flags, however today there is a mixture of u64 and u32 flags. All places are converted to accept both sizes and the accessor fixes it. This allows all existing flags to grow to u64 in future without any hassle. Finally all flags are, by definition, optional. If flags are not passed the accessor does not fail, but provides a value of zero. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- include/rdma/uverbs_ioctl.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'include/rdma') diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index d16d31d4322d..5e6d0569d97c 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -268,6 +268,19 @@ struct uverbs_object_tree_def { __VA_ARGS__ }, \ }) +/* + * An input value that is a bitwise combination of values of _enum_type. + * This permits the flag value to be passed as either a u32 or u64, it must + * be retrieved via uverbs_get_flag(). + */ +#define UVERBS_ATTR_FLAGS_IN(_attr_id, _enum_type, ...) \ + UVERBS_ATTR_PTR_IN( \ + _attr_id, \ + UVERBS_ATTR_SIZE(sizeof(u32) + BUILD_BUG_ON_ZERO( \ + !sizeof(_enum_type *)), \ + sizeof(u64)), \ + __VA_ARGS__) + /* * This spec is used in order to pass information to the hardware driver in a * legacy way. Every verb that could get driver specific data should get this @@ -520,6 +533,26 @@ static inline int _uverbs_copy_from_or_zero(void *to, #define uverbs_copy_from_or_zero(to, attrs_bundle, idx) \ _uverbs_copy_from_or_zero(to, attrs_bundle, idx, sizeof(*to)) +#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) +int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, u64 allowed_bits); +int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, u64 allowed_bits); +#else +static inline int +uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, u64 allowed_bits) +{ + return -EINVAL; +} +static inline int +uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, u64 allowed_bits) +{ + return -EINVAL; +} +#endif + /* ================================================= * Definitions -> Specs infrastructure * ================================================= -- cgit v1.2.1