netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Leon Romanovsky <leon@kernel.org>
To: Doug Ledford <dledford@redhat.com>, Jason Gunthorpe <jgg@mellanox.com>
Cc: Leon Romanovsky <leonro@mellanox.com>,
	RDMA mailing list <linux-rdma@vger.kernel.org>,
	Guy Levi <guyle@mellanox.com>, Mark Bloch <markb@mellanox.com>,
	Or Gerlitz <ogerlitz@mellanox.com>,
	Saeed Mahameed <saeedm@mellanox.com>,
	linux-netdev <netdev@vger.kernel.org>
Subject: [PATCH rdma-next 22/27] IB/uverbs: Add IDRs array attribute type to ioctl() interface
Date: Sun, 29 Jul 2018 15:59:00 +0300	[thread overview]
Message-ID: <20180729125905.31989-23-leon@kernel.org> (raw)
In-Reply-To: <20180729125905.31989-1-leon@kernel.org>

From: Guy Levi <guyle@mellanox.com>

Methods sometimes need to get a flexible set of idrs and not a strict
set as can be achieved today by the conventional idr attribute. This is
an idrs-array-like behavior.
Since this may be popular used, we add a new IDRS_ARRAY attribute to the
generic uverbs ioctl layer.

This attribute is embedded in methods, like any other attributes we
currently have. IDRS_ARRAY points to array of idrs of the same object
type and same access rights (only write and read are supported). It
is defined with minimum and maximum length to be enforced and can be
defined as mandatory attribute.

Signed-off-by: Guy Levi <guyle@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 drivers/infiniband/core/uverbs_ioctl.c   | 94 +++++++++++++++++++++++++++++++-
 include/rdma/uverbs_ioctl.h              | 68 ++++++++++++++++++++++-
 include/uapi/rdma/rdma_user_ioctl_cmds.h |  2 +-
 3 files changed, 160 insertions(+), 4 deletions(-)

diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index 3ad3b69e32ab..ce40f97dbbf2 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -46,6 +46,79 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
 			   0, uattr->len - len);
 }
 
+static int uverbs_process_idrs_arr_attr(struct ib_uverbs_file *ufile,
+					struct uverbs_objs_arr_attr *attr,
+					const struct ib_uverbs_attr *uattr,
+					const struct uverbs_attr_spec *spec)
+{
+	const struct uverbs_object_spec *object;
+	int err;
+	int i = 0; /* Initialization for error flow */
+
+	if (!ufile->ucontext || uattr->attr_data.reserved)
+		return -EINVAL;
+
+	if (uattr->len % sizeof(u32))
+		return -EINVAL;
+
+	attr->len = uattr->len / sizeof(u32);
+
+	if (attr->len < spec->u2.objs_arr.min_len ||
+	    attr->len > spec->u2.objs_arr.max_len)
+		return -EINVAL;
+
+	attr->uobjects = kvmalloc_array(attr->len, sizeof(*attr->uobjects),
+					GFP_KERNEL);
+	if (!attr->uobjects)
+		return -ENOMEM;
+
+	/* Since idr is 4B and *uobjects is >= 4B, we can use
+	 * attr->uobjects to store idrs array and avoid additional memory
+	 * allocation. The idrs array is offset to the end of the uobjects
+	 * array so we will be able to read a 4B idr and replace with a
+	 * 8B pointer.
+	 */
+	if (uattr->len > sizeof(uattr->data)) {
+		err = copy_from_user((u8 *)attr->uobjects + uattr->len,
+				     u64_to_user_ptr(uattr->data),
+				     uattr->len);
+		if (err) {
+			err = -EFAULT;
+			goto err_objs_arr;
+		}
+	} else {
+		memcpy((u8 *)attr->uobjects + uattr->len, &uattr->data,
+		       uattr->len);
+	}
+
+	object = uverbs_get_object(ufile, spec->u2.objs_arr.obj_type);
+	if (!object) {
+		err = -EINVAL;
+		goto err_objs_arr;
+	}
+
+	for (i = 0; i < attr->len; i++) {
+		attr->uobjects[i] =
+			uverbs_get_uobject_from_file(object->type_attrs, ufile,
+						     spec->u2.objs_arr.access,
+						     ((u32 *)attr->uobjects)[attr->len + i]);
+		if (IS_ERR(attr->uobjects[i])) {
+			err = PTR_ERR(attr->uobjects[i]);
+			goto err_objs_arr;
+		}
+	}
+
+	return 0;
+
+err_objs_arr:
+	while (i > 0)
+		uverbs_finalize_object(attr->uobjects[--i],
+				       spec->u2.objs_arr.access, false);
+
+	kvfree(attr->uobjects);
+	return err;
+}
+
 static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 			       const struct ib_uverbs_attr *uattr,
 			       u16 attr_id,
@@ -59,6 +132,7 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 	const struct uverbs_object_spec *object;
 	struct uverbs_obj_attr *o_attr;
 	struct uverbs_attr *elements = attr_bundle_h->attrs;
+	int err;
 
 	if (attr_id >= attr_spec_bucket->num_attrs) {
 		if (uattr->flags & UVERBS_ATTR_F_MANDATORY)
@@ -176,6 +250,14 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile,
 		}
 
 		break;
+
+	case UVERBS_ATTR_TYPE_IDRS_ARRAY:
+		err = uverbs_process_idrs_arr_attr(ufile, &e->objs_arr_attr,
+						   uattr, spec);
+		if (err)
+			return err;
+
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -204,6 +286,7 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle,
 		for (j = 0; j < curr_bundle->num_attrs; j++) {
 			struct uverbs_attr *attr;
 			const struct uverbs_attr_spec *spec;
+			int current_ret;
 
 			if (!uverbs_attr_is_valid_in_hash(curr_bundle, j))
 				continue;
@@ -213,8 +296,6 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle,
 
 			if (spec->type == UVERBS_ATTR_TYPE_IDR ||
 			    spec->type == UVERBS_ATTR_TYPE_FD) {
-				int current_ret;
-
 				current_ret = uverbs_finalize_object(
 					attr->obj_attr.uobject,
 					spec->u.obj.access, commit);
@@ -224,6 +305,15 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle,
 				   spec->alloc_and_copy &&
 				   !uverbs_attr_ptr_is_inline(attr)) {
 				kvfree(attr->ptr_attr.ptr);
+			} else if (spec->type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
+				for (i = 0; i < attr->objs_arr_attr.len; i++) {
+					current_ret =
+						uverbs_finalize_object(attr->objs_arr_attr.uobjects[i],
+								       spec->u2.objs_arr.access, commit);
+					if (!ret)
+						ret = current_ret;
+				}
+				kvfree(attr->objs_arr_attr.uobjects);
 			}
 		}
 	}
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index f703c8ebbb02..6ab75235940b 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -52,6 +52,7 @@ enum uverbs_attr_type {
 	UVERBS_ATTR_TYPE_IDR,
 	UVERBS_ATTR_TYPE_FD,
 	UVERBS_ATTR_TYPE_ENUM_IN,
+	UVERBS_ATTR_TYPE_IDRS_ARRAY,
 };
 
 enum uverbs_obj_access {
@@ -101,7 +102,7 @@ struct uverbs_attr_spec {
 		} enum_def;
 	} u;
 
-	/* This weird split of the enum lets us remove some padding */
+	/* This weird split lets us remove some padding */
 	union {
 		struct {
 			/*
@@ -111,6 +112,17 @@ struct uverbs_attr_spec {
 			 */
 			const struct uverbs_attr_spec *ids;
 		} enum_def;
+
+		struct {
+			/*
+			 * higher bits mean the namespace and lower bits mean
+			 * the type id within the namespace.
+			 */
+			u16				obj_type;
+			u16				min_len;
+			u16				max_len;
+			u8				access;
+		} objs_arr;
 	} u2;
 };
 
@@ -226,6 +238,27 @@ struct uverbs_object_tree_def {
 #define UA_MANDATORY .mandatory = 1
 #define UA_OPTIONAL .mandatory = 0
 
+/* min_len must be bigger than 0 and _max_len must be smaller than 4095.
+ * Only READ\WRITE accesses are supported.
+ */
+#define UVERBS_ATTR_IDRS_ARR(_attr_id, _idr_type, _access, _min_len, _max_len, \
+			     ...)                                              \
+	(&(const struct uverbs_attr_def){                                      \
+		.id = (_attr_id) +                                             \
+		      BUILD_BUG_ON_ZERO((_min_len) == 0 ||                     \
+					(_max_len) > 4095 ||                   \
+					(_min_len) > (_max_len) ||             \
+					(_access) == UVERBS_ACCESS_NEW ||      \
+					(_access) == UVERBS_ACCESS_DESTROY),   \
+		.attr = {                                                      \
+			.type = UVERBS_ATTR_TYPE_IDRS_ARRAY,                   \
+			.u2.objs_arr.obj_type = _idr_type,                     \
+			.u2.objs_arr.access = _access,                         \
+			.u2.objs_arr.min_len = _min_len,                       \
+			.u2.objs_arr.max_len = _max_len,                       \
+			__VA_ARGS__                                            \
+		} })
+
 #define UVERBS_ATTR_IDR(_attr_id, _idr_type, _access, ...)                     \
 	(&(const struct uverbs_attr_def){                                      \
 		.id = _attr_id,                                                \
@@ -341,6 +374,11 @@ struct uverbs_obj_attr {
 	struct ib_uobject		*uobject;
 };
 
+struct uverbs_objs_arr_attr {
+	struct ib_uobject	**uobjects;
+	u16			len;
+};
+
 struct uverbs_attr {
 	/*
 	 * pointer to the user-space given attribute, in order to write the
@@ -350,6 +388,7 @@ struct uverbs_attr {
 	union {
 		struct uverbs_ptr_attr	ptr_attr;
 		struct uverbs_obj_attr	obj_attr;
+		struct uverbs_objs_arr_attr	objs_arr_attr;
 	};
 };
 
@@ -445,6 +484,33 @@ uverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx)
 	return attr->ptr_attr.len;
 }
 
+/*
+ * uverbs_attr_get_uobjs_arr - Provides array's properties for attribute for
+ * UVERBS_ATTR_TYPE_IDRS_ARRAY.
+ * @***arr: Returned pointer to array of pointers for uobjects or NULL if
+ * attribute isn't provided.
+ *
+ * Returns:
+ * If attribute isn't provided - return 0. Otherwise, return the array
+ * length.
+ */
+static inline int uverbs_attr_get_uobjs_arr(const struct uverbs_attr_bundle *attrs_bundle,
+					    u16 attr_idx,
+					    struct ib_uobject ***arr)
+{
+	const struct uverbs_attr *attr =
+			uverbs_attr_get(attrs_bundle, attr_idx);
+
+	if (IS_ERR(attr)) {
+		*arr = NULL;
+		return 0;
+	}
+
+	*arr = attr->objs_arr_attr.uobjects;
+
+	return attr->objs_arr_attr.len;
+}
+
 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 24800c6c1f32..95762b04a72d 100644
--- a/include/uapi/rdma/rdma_user_ioctl_cmds.h
+++ b/include/uapi/rdma/rdma_user_ioctl_cmds.h
@@ -53,7 +53,7 @@ enum {
 
 struct ib_uverbs_attr {
 	__u16 attr_id;		/* command specific type attribute */
-	__u16 len;		/* only for pointers */
+	__u16 len;		/* only for pointers and IDRs array */
 	__u16 flags;		/* combination of UVERBS_ATTR_F_XXXX */
 	union {
 		struct {
-- 
2.14.4

  parent reply	other threads:[~2018-07-29 14:30 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-29 12:58 [PATCH rdma-next 00/27] Flow actions to mutate packets Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 01/27] net/mlx5: Cleanup flow namespace getter switch logic Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 02/27] net/mlx5: Add proper NIC TX steering flow tables support Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 03/27] net/mlx5: Export modify header alloc/dealloc functions Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 04/27] net/mlx5: Add support for more namespaces when allocating modify header Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 05/27] net/mlx5: Break encap/decap into two separated flow table creation flags Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 06/27] net/mlx5: Move header encap type to IFC header file Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 07/27] {net, RDMA}/mlx5: Rename encap to reformat packet Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 08/27] net/mlx5: Expose new packet reformat capabilities Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 09/27] net/mlx5: Pass a namespace for packet reformat ID allocation Leon Romanovsky
2018-07-29 12:58 ` [PATCH mlx5-next 10/27] net/mlx5: Export packet reformat alloc/dealloc functions Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 11/27] RDMA/mlx5: Add NIC TX steering support Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 12/27] RDMA/uverbs: Add UVERBS_ATTR_CONST_IN to the specs language Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 13/27] RDMA/mlx5: Add a new flow action verb, modify header Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 14/27] RDMA/mlx5: Enable attaching modify header to steering flows Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 15/27] RDMA/mlx5: Enable decap and packet reformat on flow tables Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 16/27] RDMA/uverbs: Add generic function to fill in flow action object Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 17/27] RDMA/mlx5: Add new flow action verb, packet reformat Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 18/27] RDMA/mlx5: Enable attaching DECAP action to steering flows Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 19/27] RDMA/mlx5: Extend packet reformat verbs Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 20/27] RDMA/mlx5: Enable reformat on NIC RX if supported Leon Romanovsky
2018-07-29 12:58 ` [PATCH rdma-next 21/27] RDMA/mlx5: Enable attaching packet reformat action to steering flows Leon Romanovsky
2018-07-29 12:59 ` Leon Romanovsky [this message]
2018-07-29 12:59 ` [PATCH rdma-next 23/27] RDMA/mlx5: Refactor flow action parsing to be more generic Leon Romanovsky
2018-07-29 12:59 ` [PATCH rdma-next 24/27] RDMA/mlx5: Refactor DEVX flow creation Leon Romanovsky
2018-07-29 12:59 ` [PATCH rdma-next 25/27] RDMA/mlx5: Add flow actions support to DEVX create flow Leon Romanovsky
2018-07-29 12:59 ` [PATCH rdma-next 26/27] RDMA/mlx5: Add NIC TX namespace when getting a flow table Leon Romanovsky
2018-07-29 12:59 ` [PATCH rdma-next 27/27] RDMA/mlx5: Allow creating a matcher for a NIC TX " Leon Romanovsky
2018-07-30 17:09 ` [PATCH rdma-next 00/27] Flow actions to mutate packets Jason Gunthorpe
2018-07-30 17:37   ` Mark Bloch
2018-07-31 14:11 ` Leon Romanovsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180729125905.31989-23-leon@kernel.org \
    --to=leon@kernel.org \
    --cc=dledford@redhat.com \
    --cc=guyle@mellanox.com \
    --cc=jgg@mellanox.com \
    --cc=leonro@mellanox.com \
    --cc=linux-rdma@vger.kernel.org \
    --cc=markb@mellanox.com \
    --cc=netdev@vger.kernel.org \
    --cc=ogerlitz@mellanox.com \
    --cc=saeedm@mellanox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).