diff mbox series

[rdma-next] RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers

Message ID 20181130110621.18267-1-leon@kernel.org (mailing list archive)
State Accepted
Commit 4785860e04bc8d7e244b25257168e1cf8a5529ab
Headers show
Series [rdma-next] RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers | expand

Commit Message

Leon Romanovsky Nov. 30, 2018, 11:06 a.m. UTC
From: Jason Gunthorpe <jgg@mellanox.com>

Now that the handlers do not process their own udata we can make a
sensible ioctl that wrappers them. The ioctl follows the same format as
the write_ex() and has the user explicitly specify the core and driver
in/out opaque structures and a command number.

This works for all forms of write commands.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 drivers/infiniband/core/Makefile              |  2 +-
 drivers/infiniband/core/rdma_core.h           |  5 ++
 drivers/infiniband/core/uverbs.h              |  1 -
 drivers/infiniband/core/uverbs_ioctl.c        | 40 +++++++------
 drivers/infiniband/core/uverbs_std_types.c    |  3 -
 .../infiniband/core/uverbs_std_types_device.c | 60 +++++++++++++++++++
 drivers/infiniband/core/uverbs_uapi.c         |  1 +
 include/uapi/rdma/ib_user_ioctl_cmds.h        | 10 ++++
 include/uapi/rdma/ib_user_verbs.h             |  2 +-
 9 files changed, 100 insertions(+), 24 deletions(-)
 create mode 100644 drivers/infiniband/core/uverbs_std_types_device.c

Comments

Doug Ledford Dec. 12, 2018, 5:44 p.m. UTC | #1
On Fri, 2018-11-30 at 13:06 +0200, Leon Romanovsky wrote:
> From: Jason Gunthorpe <jgg@mellanox.com>
> 
> Now that the handlers do not process their own udata we can make a
> sensible ioctl that wrappers them. The ioctl follows the same format as
> the write_ex() and has the user explicitly specify the core and driver
> in/out opaque structures and a command number.
> 
> This works for all forms of write commands.



I'm ready to merge this, and the corresponding rdma-core patch.  What
about you Jason?

> 
> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> ---
>  drivers/infiniband/core/Makefile              |  2 +-
>  drivers/infiniband/core/rdma_core.h           |  5 ++
>  drivers/infiniband/core/uverbs.h              |  1 -
>  drivers/infiniband/core/uverbs_ioctl.c        | 40 +++++++------
>  drivers/infiniband/core/uverbs_std_types.c    |  3 -
>  .../infiniband/core/uverbs_std_types_device.c | 60 +++++++++++++++++++
>  drivers/infiniband/core/uverbs_uapi.c         |  1 +
>  include/uapi/rdma/ib_user_ioctl_cmds.h        | 10 ++++
>  include/uapi/rdma/ib_user_verbs.h             |  2 +-
>  9 files changed, 100 insertions(+), 24 deletions(-)
>  create mode 100644 drivers/infiniband/core/uverbs_std_types_device.c
> 
> diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
> index 781b3172e596..fc1d5adfb24b 100644
> --- a/drivers/infiniband/core/Makefile
> +++ b/drivers/infiniband/core/Makefile
> @@ -38,4 +38,4 @@ ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
>  				uverbs_std_types_cq.o \
>  				uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
>  				uverbs_std_types_mr.o uverbs_std_types_counters.o \
> -				uverbs_uapi.o
> +				uverbs_uapi.o uverbs_std_types_device.o
> diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
> index b3ca7457ac42..be6b8e1257d0 100644
> --- a/drivers/infiniband/core/rdma_core.h
> +++ b/drivers/infiniband/core/rdma_core.h
> @@ -188,6 +188,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
>  
>  extern const struct uapi_definition uverbs_def_obj_counters[];
>  extern const struct uapi_definition uverbs_def_obj_cq[];
> +extern const struct uapi_definition uverbs_def_obj_device[];
>  extern const struct uapi_definition uverbs_def_obj_dm[];
>  extern const struct uapi_definition uverbs_def_obj_flow_action[];
>  extern const struct uapi_definition uverbs_def_obj_intf[];
> @@ -214,4 +215,8 @@ uapi_get_method(const struct uverbs_api *uapi, u32 command)
>  	return uapi->write_methods[cmd_idx];
>  }
>  
> +void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
> +		       struct ib_udata *udata, unsigned int attr_in,
> +		       unsigned int attr_out);
> +
>  #endif /* RDMA_CORE_H */
> diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
> index 8b41c95300c6..88029f3b6853 100644
> --- a/drivers/infiniband/core/uverbs.h
> +++ b/drivers/infiniband/core/uverbs.h
> @@ -246,7 +246,6 @@ int uverbs_dealloc_mw(struct ib_mw *mw);
>  void ib_uverbs_detach_umcast(struct ib_qp *qp,
>  			     struct ib_uqp_object *uobj);
>  
> -void create_udata(struct uverbs_attr_bundle *ctx, struct ib_udata *udata);
>  long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
>  
>  struct ib_uverbs_flow_spec {
> diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
> index e643a43dce8d..3cc46447240e 100644
> --- a/drivers/infiniband/core/uverbs_ioctl.c
> +++ b/drivers/infiniband/core/uverbs_ioctl.c
> @@ -436,7 +436,9 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
>  		return -EINVAL;
>  
>  	if (pbundle->method_elm->has_udata)
> -		create_udata(&pbundle->bundle, &pbundle->bundle.driver_udata);
> +		uverbs_fill_udata(&pbundle->bundle,
> +				  &pbundle->bundle.driver_udata,
> +				  UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
>  
>  	if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
>  		struct uverbs_obj_attr *destroy_attr =
> @@ -664,35 +666,37 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
>  EXPORT_SYMBOL(uverbs_get_flags32);
>  
>  /*
> - * This is for ease of conversion. The purpose is to convert all drivers to
> - * use uverbs_attr_bundle instead of ib_udata.  Assume attr == 0 is input and
> - * attr == 1 is output.
> + * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
> + * This is primarily used to convert the UVERBS_ATTR_UHW() into the
> + * ib_udata format used by the drivers.
>   */
> -void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata)
> +void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
> +		       struct ib_udata *udata, unsigned int attr_in,
> +		       unsigned int attr_out)
>  {
>  	struct bundle_priv *pbundle =
>  		container_of(bundle, struct bundle_priv, bundle);
> -	const struct uverbs_attr *uhw_in =
> -		uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN);
> -	const struct uverbs_attr *uhw_out =
> -		uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT);
> -
> -	if (!IS_ERR(uhw_in)) {
> -		udata->inlen = uhw_in->ptr_attr.len;
> -		if (uverbs_attr_ptr_is_inline(uhw_in))
> +	const struct uverbs_attr *in =
> +		uverbs_attr_get(&pbundle->bundle, attr_in);
> +	const struct uverbs_attr *out =
> +		uverbs_attr_get(&pbundle->bundle, attr_out);
> +
> +	if (!IS_ERR(in)) {
> +		udata->inlen = in->ptr_attr.len;
> +		if (uverbs_attr_ptr_is_inline(in))
>  			udata->inbuf =
> -				&pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx]
> +				&pbundle->user_attrs[in->ptr_attr.uattr_idx]
>  					 .data;
>  		else
> -			udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
> +			udata->inbuf = u64_to_user_ptr(in->ptr_attr.data);
>  	} else {
>  		udata->inbuf = NULL;
>  		udata->inlen = 0;
>  	}
>  
> -	if (!IS_ERR(uhw_out)) {
> -		udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
> -		udata->outlen = uhw_out->ptr_attr.len;
> +	if (!IS_ERR(out)) {
> +		udata->outbuf = u64_to_user_ptr(out->ptr_attr.data);
> +		udata->outlen = out->ptr_attr.len;
>  	} else {
>  		udata->outbuf = NULL;
>  		udata->outlen = 0;
> diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c
> index 063aff9e7a04..8db5d23ca087 100644
> --- a/drivers/infiniband/core/uverbs_std_types.c
> +++ b/drivers/infiniband/core/uverbs_std_types.c
> @@ -259,10 +259,7 @@ DECLARE_UVERBS_NAMED_OBJECT(
>  DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD,
>  			    UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd));
>  
> -DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE);
> -
>  const struct uapi_definition uverbs_def_obj_intf[] = {
> -	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
>  	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD,
>  				      UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)),
>  	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL,
> diff --git a/drivers/infiniband/core/uverbs_std_types_device.c b/drivers/infiniband/core/uverbs_std_types_device.c
> new file mode 100644
> index 000000000000..aafb251b7d37
> --- /dev/null
> +++ b/drivers/infiniband/core/uverbs_std_types_device.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
> +/*
> + * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
> + */
> +
> +#include <rdma/uverbs_std_types.h>
> +#include "rdma_core.h"
> +#include "uverbs.h"
> +
> +/*
> + * This ioctl method allows calling any defined write or write_ex
> + * handler. This essentially replaces the hdr/ex_hdr system with the ioctl
> + * marshalling, and brings the non-ex path into the same marshalling as the ex
> + * path.
> + */
> +static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)(
> +	struct uverbs_attr_bundle *attrs)
> +{
> +	struct uverbs_api *uapi = attrs->ufile->device->uapi;
> +	const struct uverbs_api_write_method *method_elm;
> +	u32 cmd;
> +	int rc;
> +
> +	rc = uverbs_get_const(&cmd, attrs, UVERBS_ATTR_WRITE_CMD);
> +	if (rc)
> +		return rc;
> +
> +	method_elm = uapi_get_method(uapi, cmd);
> +	if (IS_ERR(method_elm))
> +		return PTR_ERR(method_elm);
> +
> +	uverbs_fill_udata(attrs, &attrs->ucore, UVERBS_ATTR_CORE_IN,
> +			  UVERBS_ATTR_CORE_OUT);
> +
> +	if (attrs->ucore.inlen < method_elm->req_size ||
> +	    attrs->ucore.outlen < method_elm->resp_size)
> +		return -ENOSPC;
> +
> +	return method_elm->handler(attrs);
> +}
> +
> +DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_INVOKE_WRITE,
> +			    UVERBS_ATTR_CONST_IN(UVERBS_ATTR_WRITE_CMD,
> +						 enum ib_uverbs_write_cmds,
> +						 UA_MANDATORY),
> +			    UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CORE_IN,
> +					       UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
> +					       UA_OPTIONAL),
> +			    UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CORE_OUT,
> +						UVERBS_ATTR_MIN_SIZE(0),
> +						UA_OPTIONAL),
> +			    UVERBS_ATTR_UHW());
> +
> +DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
> +			      &UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE));
> +
> +const struct uapi_definition uverbs_def_obj_device[] = {
> +	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
> +	{},
> +};
> diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
> index 0136c1d78a0f..7097cae8d2b7 100644
> --- a/drivers/infiniband/core/uverbs_uapi.c
> +++ b/drivers/infiniband/core/uverbs_uapi.c
> @@ -620,6 +620,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi)
>  static const struct uapi_definition uverbs_core_api[] = {
>  	UAPI_DEF_CHAIN(uverbs_def_obj_counters),
>  	UAPI_DEF_CHAIN(uverbs_def_obj_cq),
> +	UAPI_DEF_CHAIN(uverbs_def_obj_device),
>  	UAPI_DEF_CHAIN(uverbs_def_obj_dm),
>  	UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
>  	UAPI_DEF_CHAIN(uverbs_def_obj_intf),
> diff --git a/include/uapi/rdma/ib_user_ioctl_cmds.h b/include/uapi/rdma/ib_user_ioctl_cmds.h
> index 2c881aaf05c2..34e71994f4a5 100644
> --- a/include/uapi/rdma/ib_user_ioctl_cmds.h
> +++ b/include/uapi/rdma/ib_user_ioctl_cmds.h
> @@ -63,6 +63,16 @@ enum {
>  	UVERBS_ATTR_UHW_OUT,
>  };
>  
> +enum uverbs_methods_device {
> +	UVERBS_METHOD_INVOKE_WRITE,
> +};
> +
> +enum uverbs_attrs_invoke_write_cmd_attr_ids {
> +	UVERBS_ATTR_CORE_IN,
> +	UVERBS_ATTR_CORE_OUT,
> +	UVERBS_ATTR_WRITE_CMD,
> +};
> +
>  enum uverbs_attrs_create_cq_cmd_attr_ids {
>  	UVERBS_ATTR_CREATE_CQ_HANDLE,
>  	UVERBS_ATTR_CREATE_CQ_CQE,
> diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
> index c586fc43739c..480d9a60b68e 100644
> --- a/include/uapi/rdma/ib_user_verbs.h
> +++ b/include/uapi/rdma/ib_user_verbs.h
> @@ -46,7 +46,7 @@
>  #define IB_USER_VERBS_ABI_VERSION	6
>  #define IB_USER_VERBS_CMD_THRESHOLD    50
>  
> -enum {
> +enum ib_uverbs_write_cmds {
>  	IB_USER_VERBS_CMD_GET_CONTEXT,
>  	IB_USER_VERBS_CMD_QUERY_DEVICE,
>  	IB_USER_VERBS_CMD_QUERY_PORT,
Jason Gunthorpe Dec. 13, 2018, 3:38 a.m. UTC | #2
On Wed, Dec 12, 2018 at 12:44:54PM -0500, Doug Ledford wrote:
> On Fri, 2018-11-30 at 13:06 +0200, Leon Romanovsky wrote:
> > From: Jason Gunthorpe <jgg@mellanox.com>
> > 
> > Now that the handlers do not process their own udata we can make a
> > sensible ioctl that wrappers them. The ioctl follows the same format as
> > the write_ex() and has the user explicitly specify the core and driver
> > in/out opaque structures and a command number.
> > 
> > This works for all forms of write commands.
> 
> I'm ready to merge this, and the corresponding rdma-core patch.
> What about you Jason?

Yeah, it should all be good now.

Thanks,
Jason
Doug Ledford Dec. 18, 2018, 7:23 p.m. UTC | #3
On Thu, 2018-12-13 at 03:38 +0000, Jason Gunthorpe wrote:
> On Wed, Dec 12, 2018 at 12:44:54PM -0500, Doug Ledford wrote:
> > On Fri, 2018-11-30 at 13:06 +0200, Leon Romanovsky wrote:
> > > From: Jason Gunthorpe <jgg@mellanox.com>
> > > 
> > > Now that the handlers do not process their own udata we can make a
> > > sensible ioctl that wrappers them. The ioctl follows the same format as
> > > the write_ex() and has the user explicitly specify the core and driver
> > > in/out opaque structures and a command number.
> > > 
> > > This works for all forms of write commands.
> > 
> > I'm ready to merge this, and the corresponding rdma-core patch.
> > What about you Jason?
> 
> Yeah, it should all be good now.

Test build just finished.  Applied to for-next.  Thanks!
diff mbox series

Patch

diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 781b3172e596..fc1d5adfb24b 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -38,4 +38,4 @@  ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
 				uverbs_std_types_cq.o \
 				uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
 				uverbs_std_types_mr.o uverbs_std_types_counters.o \
-				uverbs_uapi.o
+				uverbs_uapi.o uverbs_std_types_device.o
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index b3ca7457ac42..be6b8e1257d0 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -188,6 +188,7 @@  void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
 
 extern const struct uapi_definition uverbs_def_obj_counters[];
 extern const struct uapi_definition uverbs_def_obj_cq[];
+extern const struct uapi_definition uverbs_def_obj_device[];
 extern const struct uapi_definition uverbs_def_obj_dm[];
 extern const struct uapi_definition uverbs_def_obj_flow_action[];
 extern const struct uapi_definition uverbs_def_obj_intf[];
@@ -214,4 +215,8 @@  uapi_get_method(const struct uverbs_api *uapi, u32 command)
 	return uapi->write_methods[cmd_idx];
 }
 
+void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
+		       struct ib_udata *udata, unsigned int attr_in,
+		       unsigned int attr_out);
+
 #endif /* RDMA_CORE_H */
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 8b41c95300c6..88029f3b6853 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -246,7 +246,6 @@  int uverbs_dealloc_mw(struct ib_mw *mw);
 void ib_uverbs_detach_umcast(struct ib_qp *qp,
 			     struct ib_uqp_object *uobj);
 
-void create_udata(struct uverbs_attr_bundle *ctx, struct ib_udata *udata);
 long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 
 struct ib_uverbs_flow_spec {
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index e643a43dce8d..3cc46447240e 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -436,7 +436,9 @@  static int ib_uverbs_run_method(struct bundle_priv *pbundle,
 		return -EINVAL;
 
 	if (pbundle->method_elm->has_udata)
-		create_udata(&pbundle->bundle, &pbundle->bundle.driver_udata);
+		uverbs_fill_udata(&pbundle->bundle,
+				  &pbundle->bundle.driver_udata,
+				  UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
 
 	if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
 		struct uverbs_obj_attr *destroy_attr =
@@ -664,35 +666,37 @@  int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
 EXPORT_SYMBOL(uverbs_get_flags32);
 
 /*
- * This is for ease of conversion. The purpose is to convert all drivers to
- * use uverbs_attr_bundle instead of ib_udata.  Assume attr == 0 is input and
- * attr == 1 is output.
+ * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
+ * This is primarily used to convert the UVERBS_ATTR_UHW() into the
+ * ib_udata format used by the drivers.
  */
-void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata)
+void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
+		       struct ib_udata *udata, unsigned int attr_in,
+		       unsigned int attr_out)
 {
 	struct bundle_priv *pbundle =
 		container_of(bundle, struct bundle_priv, bundle);
-	const struct uverbs_attr *uhw_in =
-		uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN);
-	const struct uverbs_attr *uhw_out =
-		uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT);
-
-	if (!IS_ERR(uhw_in)) {
-		udata->inlen = uhw_in->ptr_attr.len;
-		if (uverbs_attr_ptr_is_inline(uhw_in))
+	const struct uverbs_attr *in =
+		uverbs_attr_get(&pbundle->bundle, attr_in);
+	const struct uverbs_attr *out =
+		uverbs_attr_get(&pbundle->bundle, attr_out);
+
+	if (!IS_ERR(in)) {
+		udata->inlen = in->ptr_attr.len;
+		if (uverbs_attr_ptr_is_inline(in))
 			udata->inbuf =
-				&pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx]
+				&pbundle->user_attrs[in->ptr_attr.uattr_idx]
 					 .data;
 		else
-			udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
+			udata->inbuf = u64_to_user_ptr(in->ptr_attr.data);
 	} else {
 		udata->inbuf = NULL;
 		udata->inlen = 0;
 	}
 
-	if (!IS_ERR(uhw_out)) {
-		udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
-		udata->outlen = uhw_out->ptr_attr.len;
+	if (!IS_ERR(out)) {
+		udata->outbuf = u64_to_user_ptr(out->ptr_attr.data);
+		udata->outlen = out->ptr_attr.len;
 	} else {
 		udata->outbuf = NULL;
 		udata->outlen = 0;
diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c
index 063aff9e7a04..8db5d23ca087 100644
--- a/drivers/infiniband/core/uverbs_std_types.c
+++ b/drivers/infiniband/core/uverbs_std_types.c
@@ -259,10 +259,7 @@  DECLARE_UVERBS_NAMED_OBJECT(
 DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD,
 			    UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd));
 
-DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE);
-
 const struct uapi_definition uverbs_def_obj_intf[] = {
-	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD,
 				      UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)),
 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL,
diff --git a/drivers/infiniband/core/uverbs_std_types_device.c b/drivers/infiniband/core/uverbs_std_types_device.c
new file mode 100644
index 000000000000..aafb251b7d37
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_std_types_device.c
@@ -0,0 +1,60 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
+ */
+
+#include <rdma/uverbs_std_types.h>
+#include "rdma_core.h"
+#include "uverbs.h"
+
+/*
+ * This ioctl method allows calling any defined write or write_ex
+ * handler. This essentially replaces the hdr/ex_hdr system with the ioctl
+ * marshalling, and brings the non-ex path into the same marshalling as the ex
+ * path.
+ */
+static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)(
+	struct uverbs_attr_bundle *attrs)
+{
+	struct uverbs_api *uapi = attrs->ufile->device->uapi;
+	const struct uverbs_api_write_method *method_elm;
+	u32 cmd;
+	int rc;
+
+	rc = uverbs_get_const(&cmd, attrs, UVERBS_ATTR_WRITE_CMD);
+	if (rc)
+		return rc;
+
+	method_elm = uapi_get_method(uapi, cmd);
+	if (IS_ERR(method_elm))
+		return PTR_ERR(method_elm);
+
+	uverbs_fill_udata(attrs, &attrs->ucore, UVERBS_ATTR_CORE_IN,
+			  UVERBS_ATTR_CORE_OUT);
+
+	if (attrs->ucore.inlen < method_elm->req_size ||
+	    attrs->ucore.outlen < method_elm->resp_size)
+		return -ENOSPC;
+
+	return method_elm->handler(attrs);
+}
+
+DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_INVOKE_WRITE,
+			    UVERBS_ATTR_CONST_IN(UVERBS_ATTR_WRITE_CMD,
+						 enum ib_uverbs_write_cmds,
+						 UA_MANDATORY),
+			    UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CORE_IN,
+					       UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
+					       UA_OPTIONAL),
+			    UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CORE_OUT,
+						UVERBS_ATTR_MIN_SIZE(0),
+						UA_OPTIONAL),
+			    UVERBS_ATTR_UHW());
+
+DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
+			      &UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE));
+
+const struct uapi_definition uverbs_def_obj_device[] = {
+	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
+	{},
+};
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index 0136c1d78a0f..7097cae8d2b7 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -620,6 +620,7 @@  void uverbs_destroy_api(struct uverbs_api *uapi)
 static const struct uapi_definition uverbs_core_api[] = {
 	UAPI_DEF_CHAIN(uverbs_def_obj_counters),
 	UAPI_DEF_CHAIN(uverbs_def_obj_cq),
+	UAPI_DEF_CHAIN(uverbs_def_obj_device),
 	UAPI_DEF_CHAIN(uverbs_def_obj_dm),
 	UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
 	UAPI_DEF_CHAIN(uverbs_def_obj_intf),
diff --git a/include/uapi/rdma/ib_user_ioctl_cmds.h b/include/uapi/rdma/ib_user_ioctl_cmds.h
index 2c881aaf05c2..34e71994f4a5 100644
--- a/include/uapi/rdma/ib_user_ioctl_cmds.h
+++ b/include/uapi/rdma/ib_user_ioctl_cmds.h
@@ -63,6 +63,16 @@  enum {
 	UVERBS_ATTR_UHW_OUT,
 };
 
+enum uverbs_methods_device {
+	UVERBS_METHOD_INVOKE_WRITE,
+};
+
+enum uverbs_attrs_invoke_write_cmd_attr_ids {
+	UVERBS_ATTR_CORE_IN,
+	UVERBS_ATTR_CORE_OUT,
+	UVERBS_ATTR_WRITE_CMD,
+};
+
 enum uverbs_attrs_create_cq_cmd_attr_ids {
 	UVERBS_ATTR_CREATE_CQ_HANDLE,
 	UVERBS_ATTR_CREATE_CQ_CQE,
diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
index c586fc43739c..480d9a60b68e 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -46,7 +46,7 @@ 
 #define IB_USER_VERBS_ABI_VERSION	6
 #define IB_USER_VERBS_CMD_THRESHOLD    50
 
-enum {
+enum ib_uverbs_write_cmds {
 	IB_USER_VERBS_CMD_GET_CONTEXT,
 	IB_USER_VERBS_CMD_QUERY_DEVICE,
 	IB_USER_VERBS_CMD_QUERY_PORT,