RE: [PATCH rdma-next 06/12] IB/uverbs: Add enum attribute type to ioctl() interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: linux-rdma-owner@xxxxxxxxxxxxxxx [mailto:linux-rdma-
> owner@xxxxxxxxxxxxxxx] On Behalf Of Leon Romanovsky
> Sent: Thursday, March 8, 2018 12:19 PM
> To: Doug Ledford <dledford@xxxxxxxxxx>; Jason Gunthorpe
> <jgg@xxxxxxxxxxxx>
> Cc: Leon Romanovsky <leonro@xxxxxxxxxxxx>; RDMA mailing list <linux-
> rdma@xxxxxxxxxxxxxxx>; Aviad Yehezkel <aviadye@xxxxxxxxxxxx>; Boris
> Pismenny <borisp@xxxxxxxxxxxx>; Matan Barak <matanb@xxxxxxxxxxxx>;
> Yishai Hadas <yishaih@xxxxxxxxxxxx>
> Subject: [PATCH rdma-next 06/12] IB/uverbs: Add enum attribute type to
> ioctl() interface
> 
> From: Matan Barak <matanb@xxxxxxxxxxxx>
> 
> Methods sometimes need to get one attribute out of a group of
> pre-defined attributes. This is an enum-like behavior. Since
> this is a common requirement, we add a new ENUM attribute to the
> generic uverbs ioctl() layer. This attribute is embedded in methods,
> like any other attributes we currently have. ENUM attributes point to
> an array of standard UVERBS_ATTR_PTR_IN. The user-space encodes the
> enum's attribute id in the id field and the internal PTR_IN attr id in
> the enum_data.elem_id field. This ENUM attribute could be shared by
> several attributes and it can get UVERBS_ATTR_SPEC_F_MANDATORY flag,
> stating this attribute must be supported by the kernel, like any other
> attribute.
> 
> Reviewed-by: Yishai Hadas <yishaih@xxxxxxxxxxxx>
> Signed-off-by: Matan Barak <matanb@xxxxxxxxxxxx>
> Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
> ---
>  drivers/infiniband/core/uverbs_ioctl.c   | 41 ++++++++++++++++++++++++-
> -------
>  include/rdma/uverbs_ioctl.h              | 34 ++++++++++++++++++++++++++
>  include/uapi/rdma/rdma_user_ioctl_cmds.h |  8 ++++++-
>  3 files changed, 72 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/infiniband/core/uverbs_ioctl.c
> b/drivers/infiniband/core/uverbs_ioctl.c
> index 76828fd7fdba..ca25e4959ba7 100644
> --- a/drivers/infiniband/core/uverbs_ioctl.c
> +++ b/drivers/infiniband/core/uverbs_ioctl.c
> @@ -44,14 +44,12 @@ static int uverbs_process_attr(struct ib_device
> *ibdev,
>  			       struct ib_uverbs_attr __user *uattr_ptr)
>  {
>  	const struct uverbs_attr_spec *spec;
> +	const struct uverbs_attr_spec *val_spec;
>  	struct uverbs_attr *e;
>  	const struct uverbs_object_spec *object;
>  	struct uverbs_obj_attr *o_attr;
>  	struct uverbs_attr *elements = attr_bundle_h->attrs;
> 
> -	if (uattr->reserved)
> -		return -EINVAL;
> -
>  	if (attr_id >= attr_spec_bucket->num_attrs) {
>  		if (uattr->flags & UVERBS_ATTR_F_MANDATORY)
>  			return -EINVAL;
> @@ -63,23 +61,43 @@ static int uverbs_process_attr(struct ib_device
> *ibdev,
>  		return -EINVAL;
> 
>  	spec = &attr_spec_bucket->attrs[attr_id];
> +	val_spec = spec;
>  	e = &elements[attr_id];
>  	e->uattr = uattr_ptr;
> 
>  	switch (spec->type) {
> +	case UVERBS_ATTR_TYPE_ENUM_IN:
> +		if (uattr->attr_data.enum_data.elem_id >= spec-
> >enum_def.num_elems)
> +			return -EOPNOTSUPP;
> +
> +		if (uattr->attr_data.enum_data.reserved)
> +			return -EINVAL;
> +
> +		val_spec = &spec->enum_def.ids[uattr-
> >attr_data.enum_data.elem_id];
> +
> +		/* Currently we only support PTR_IN based enums */
> +		if (val_spec->type != UVERBS_ATTR_TYPE_PTR_IN)
> +			return -EOPNOTSUPP;
> +
> +		e->ptr_attr.enum_id = uattr-
> >attr_data.enum_data.elem_id;
> +	/* fall through */
>  	case UVERBS_ATTR_TYPE_PTR_IN:
> -		if (uattr->len > spec->ptr.len &&
> -		    spec->flags & UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO
> &&
> +		if (uattr->len > val_spec->ptr.len &&
> +		    val_spec->flags &
> UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO &&
>  		    uattr->len > sizeof(((struct ib_uverbs_attr *)0)->data) &&
> -		    !ib_is_buffer_cleared(u64_to_user_ptr(uattr->data) +
> spec->ptr.len,
> -					  uattr->len - spec->ptr.len))
> +		    !ib_is_buffer_cleared(u64_to_user_ptr(uattr->data) +
> val_spec->ptr.len,
> +					  uattr->len - val_spec->ptr.len))
>  			return -EOPNOTSUPP;
> 
>  	/* fall through */
>  	case UVERBS_ATTR_TYPE_PTR_OUT:
> -		if (uattr->len < spec->ptr.min_len ||
> -		    (!(spec->flags &
> UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO) &&
> -		     uattr->len > spec->ptr.len))
> +		if (uattr->len < val_spec->ptr.min_len ||
> +		    (!(val_spec->flags &
> UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO) &&
> +		     uattr->len > val_spec->ptr.len))
> +			return -EINVAL;
> +
> +		if (spec->type != UVERBS_ATTR_TYPE_ENUM_IN &&
> +		    uattr->attr_data.reserved)
>  			return -EINVAL;
> 
>  		e->ptr_attr.data = uattr->data;
> @@ -92,6 +110,9 @@ static int uverbs_process_attr(struct ib_device *ibdev,
>  			return -EINVAL;
>  	/* fall through */
>  	case UVERBS_ATTR_TYPE_FD:
> +		if (uattr->attr_data.reserved)
> +			return -EINVAL;
> +
>  		if (uattr->len != 0 || !ucontext || uattr->data > INT_MAX)
>  			return -EINVAL;
> 
> diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
> index 39ce30322211..264a07694f49 100644
> --- a/include/rdma/uverbs_ioctl.h
> +++ b/include/rdma/uverbs_ioctl.h
> @@ -51,6 +51,7 @@ enum uverbs_attr_type {
>  	UVERBS_ATTR_TYPE_PTR_OUT,
>  	UVERBS_ATTR_TYPE_IDR,
>  	UVERBS_ATTR_TYPE_FD,
> +	UVERBS_ATTR_TYPE_ENUM_IN,
>  };
> 
>  enum uverbs_obj_access {
> @@ -95,6 +96,18 @@ struct uverbs_attr_spec {
>  			u16			obj_type;
>  			u8			access;
>  		} obj;
> +		struct {
> +			enum uverbs_attr_type		type;
> +			/* Combination of bits from enum
> UVERBS_ATTR_SPEC_F_XXXX */
> +			u8				flags;
> +			u8				num_elems;
> +			/*
> +			 * The enum attribute can select one of the attributes
> +			 * contained in the ids array. Currently only PTR_IN
> +			 * attributes are supported in the ids array.
> +			 */
> +			struct uverbs_attr_spec		*ids;
> +		} enum_def;
>  	};
>  };
> 
> @@ -215,6 +228,10 @@ struct uverbs_object_tree_def {
>  	UVERBS_ATTR(_id, UVERBS_ATTR_TYPE_PTR_OUT, ptr, _len,
> ##__VA_ARGS__)
>  #define UVERBS_ATTR_PTR_OUT(_id, _type, ...)
> 	\
>  	UVERBS_ATTR_PTR_OUT_SZ(_id, _type, ##__VA_ARGS__)
> +#define UVERBS_ATTR_ENUM_IN(_id, _enum_arr, ...)
> 	\
> +	UVERBS_ATTR(_id, UVERBS_ATTR_TYPE_ENUM_IN, enum_def,
> 		\
> +		    .ids = (_enum_arr),					\
> +		    .num_elems = ARRAY_SIZE(_enum_arr),
> ##__VA_ARGS__)
> 
>  /*
>   * In new compiler, UVERBS_ATTR_IDR (and FD) could be simplified by
> declaring
> @@ -254,6 +271,11 @@ struct uverbs_object_tree_def {
>  #define DECLARE_UVERBS_ATTR_SPEC(_name, ...)
> 	\
>  	const struct uverbs_attr_def _name = __VA_ARGS__
> 
> +#define DECLARE_UVERBS_ENUM(_name, ...)
> 		\
> +	const struct uverbs_enum_spec _name = {
> 	\
> +		.len = ARRAY_SIZE(((struct
> uverbs_attr_spec[]){__VA_ARGS__})),\
> +		.ids = {__VA_ARGS__},					\
> +	}
>  #define _UVERBS_METHOD_ATTRS_SZ(...)
> 	\
>  	(sizeof((const struct uverbs_attr_def * const []){__VA_ARGS__}) /\
>  	 sizeof(const struct uverbs_attr_def *))
> @@ -305,6 +327,7 @@ struct uverbs_ptr_attr {
>  	u16		len;
>  	/* Combination of bits from enum UVERBS_ATTR_F_XXXX */
>  	u16		flags;
> +	u8		enum_id;
>  };
> 
>  struct uverbs_obj_attr {
> @@ -372,6 +395,17 @@ static inline const struct uverbs_attr
> *uverbs_attr_get(const struct uverbs_attr
>  	return &attrs_bundle->hash[idx_bucket].attrs[idx &
> ~UVERBS_ID_NS_MASK];
>  }
> 
> +static inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle
> *attrs_bundle,
> +					  u16 idx)
> +{
> +	const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
> +
> +	if (IS_ERR(attr))
> +		return PTR_ERR(attr);
> +
> +	return attr->ptr_attr.enum_id;
> +}
> +
>  static inline int uverbs_copy_to(const struct uverbs_attr_bundle
> *attrs_bundle,
>  				 size_t idx, const void *from, size_t size)
>  {
> diff --git a/include/uapi/rdma/rdma_user_ioctl_cmds.h
> b/include/uapi/rdma/rdma_user_ioctl_cmds.h
> index c29584fbfa5d..bfc9b230e9bf 100644
> --- a/include/uapi/rdma/rdma_user_ioctl_cmds.h
> +++ b/include/uapi/rdma/rdma_user_ioctl_cmds.h
> @@ -56,7 +56,13 @@ struct ib_uverbs_attr {
>  	__u16 attr_id;		/* command specific type attribute */
>  	__u16 len;		/* only for pointers */
>  	__u16 flags;		/* combination of UVERBS_ATTR_F_XXXX */
> -	__u16 reserved;
> +	union {
> +		struct {
> +			__u8 elem_id;
> +			__u8 reserved;
> +		} enum_data;
> +		__u16 reserved;
> +	} attr_data;
>  	__aligned_u64 data;	/* ptr to command, inline data or idr/fd */
>  };

Is there are reason that you are adding a new data structure instead of doing
this:

-  	__aligned_u64 data;	/* ptr to command, inline data or idr/fd */
+  	__aligned_u64 data;	/* ptr to command, inline data, idr/fd, or enum */

?

I see that the enum fits in the __16 reserved space, but you could "unionize" the 
__u64 data, and use it consistently just as you use it or all the other data types
(and match how the attribute data structures are being used/optimized)

Just a thought.

Thanks,

Mike

> --
> 2.16.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux