mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers
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> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
		
							parent
							
								
									241414967f
								
							
						
					
					
						commit
						4785860e04
					
				
					 9 changed files with 99 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	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(uhw_in)) {
 | 
			
		||||
		udata->inlen = uhw_in->ptr_attr.len;
 | 
			
		||||
		if (uverbs_attr_ptr_is_inline(uhw_in))
 | 
			
		||||
	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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								drivers/infiniband/core/uverbs_std_types_device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								drivers/infiniband/core/uverbs_std_types_device.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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),
 | 
			
		||||
	{},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -621,6 +621,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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue