Commit 0953fffe authored by Mark Bloch's avatar Mark Bloch Committed by Jason Gunthorpe

RDMA/uverbs: Add UVERBS_ATTR_CONST_IN to the specs language

This makes it clear and safe to access constants passed in from user
space. We define a consistent ABI of u64 for all constants, and verify
that the data passed in can be represented by the type the user supplies.

The expectation is this will always be used with an enum declaring the
constant values, and the user will use the enum type as input to the
accessor.

To retrieve the attribute value we introduce two helper calls - one
standard which may fail if attribute is not valid and one where caller can
provide a default value which will be used in case the attribute is not
valid (useful when attribute is optional).
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
Signed-off-by: default avatarAriel Levkovich <lariel@mellanox.com>
Signed-off-by: default avatarMark Bloch <markb@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
parent 50acec06
......@@ -611,3 +611,26 @@ int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
return 0;
}
EXPORT_SYMBOL(uverbs_copy_to);
int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
size_t idx, s64 lower_bound, u64 upper_bound,
s64 *def_val)
{
const struct uverbs_attr *attr;
attr = uverbs_attr_get(attrs_bundle, idx);
if (IS_ERR(attr)) {
if ((PTR_ERR(attr) != -ENOENT) || !def_val)
return PTR_ERR(attr);
*to = *def_val;
} else {
*to = attr->ptr_attr.data;
}
if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(_uverbs_get_const);
......@@ -365,6 +365,15 @@ struct uverbs_object_tree_def {
__VA_ARGS__ }, \
})
/* An input value that is a member in the enum _enum_type. */
#define UVERBS_ATTR_CONST_IN(_attr_id, _enum_type, ...) \
UVERBS_ATTR_PTR_IN( \
_attr_id, \
UVERBS_ATTR_SIZE( \
sizeof(u64) + BUILD_BUG_ON_ZERO(!sizeof(_enum_type)), \
sizeof(u64)), \
__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
......@@ -603,6 +612,9 @@ static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle,
{
return _uverbs_alloc(bundle, size, GFP_KERNEL | __GFP_ZERO);
}
int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
size_t idx, s64 lower_bound, u64 upper_bound,
s64 *def_val);
#else
static inline int
uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
......@@ -631,6 +643,34 @@ static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle,
{
return ERR_PTR(-EINVAL);
}
static inline int
_uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
size_t idx, s64 lower_bound, u64 upper_bound,
s64 *def_val)
{
return -EINVAL;
}
#endif
#define uverbs_get_const(_to, _attrs_bundle, _idx) \
({ \
s64 _val; \
int _ret = _uverbs_get_const(&_val, _attrs_bundle, _idx, \
type_min(typeof(*_to)), \
type_max(typeof(*_to)), NULL); \
(*_to) = _val; \
_ret; \
})
#define uverbs_get_const_default(_to, _attrs_bundle, _idx, _default) \
({ \
s64 _val; \
s64 _def_val = _default; \
int _ret = \
_uverbs_get_const(&_val, _attrs_bundle, _idx, \
type_min(typeof(*_to)), \
type_max(typeof(*_to)), &_def_val); \
(*_to) = _val; \
_ret; \
})
#endif
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