Skip to content

Commit

Permalink
IB/core: Add legacy driver's user-data
Browse files Browse the repository at this point in the history
In this phase, we don't want to change all the drivers to use
flexible driver's specific attributes. Therefore, we add two default
attributes: UHW_IN and UHW_OUT. These attributes are optional in some
methods and they encode the driver specific command data. We add
a function that extract this data and creates the legacy udata over
it.

Driver's data should start from UVERBS_UDATA_DRIVER_DATA_FLAG. This
turns on the first bit of the namespace, indicating this attribute
belongs to the driver's namespace.

Signed-off-by: Matan Barak <matanb@mellanox.com>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
  • Loading branch information
Matan Barak authored and Doug Ledford committed Aug 31, 2017
1 parent 64b19e1 commit d70724f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
40 changes: 40 additions & 0 deletions drivers/infiniband/core/uverbs_std_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,46 @@ static int uverbs_hot_unplug_completion_event_file(struct ib_uobject_file *uobj_
return 0;
};

/*
* This spec is used in order to pass information to the hardware driver in a
* legacy way. Every verb that could get driver specific data should get this
* spec.
*/
static const struct uverbs_attr_def uverbs_uhw_compat_in =
UVERBS_ATTR_PTR_IN_SZ(UVERBS_UHW_IN, 0, UA_FLAGS(UVERBS_ATTR_SPEC_F_MIN_SZ));
static const struct uverbs_attr_def uverbs_uhw_compat_out =
UVERBS_ATTR_PTR_OUT_SZ(UVERBS_UHW_OUT, 0, UA_FLAGS(UVERBS_ATTR_SPEC_F_MIN_SZ));

static void create_udata(struct uverbs_attr_bundle *ctx,
struct ib_udata *udata)
{
/*
* 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.
*/
void __user *inbuf;
size_t inbuf_len = 0;
void __user *outbuf;
size_t outbuf_len = 0;
const struct uverbs_attr *uhw_in =
uverbs_attr_get(ctx, UVERBS_UHW_IN);
const struct uverbs_attr *uhw_out =
uverbs_attr_get(ctx, UVERBS_UHW_OUT);

if (!IS_ERR(uhw_in)) {
inbuf = uhw_in->ptr_attr.ptr;
inbuf_len = uhw_in->ptr_attr.len;
}

if (!IS_ERR(uhw_out)) {
outbuf = uhw_out->ptr_attr.ptr;
outbuf_len = uhw_out->ptr_attr.len;
}

INIT_UDATA_BUF_OR_NULL(udata, inbuf, outbuf, inbuf_len, outbuf_len);
}

DECLARE_UVERBS_OBJECT(uverbs_object_comp_channel,
UVERBS_OBJECT_COMP_CHANNEL,
&UVERBS_TYPE_ALLOC_FD(0,
Expand Down
46 changes: 46 additions & 0 deletions include/rdma/uverbs_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <rdma/uverbs_types.h>
#include <linux/uaccess.h>
#include <rdma/rdma_user_ioctl.h>
#include <rdma/ib_user_ioctl_verbs.h>

/*
* =======================================
Expand Down Expand Up @@ -338,6 +339,51 @@ static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_b
idx & ~UVERBS_ID_NS_MASK);
}

static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle,
u16 idx)
{
u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT;

if (!uverbs_attr_is_valid(attrs_bundle, idx))
return ERR_PTR(-ENOENT);

return &attrs_bundle->hash[idx_bucket].attrs[idx & ~UVERBS_ID_NS_MASK];
}

static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
size_t idx, const void *from)
{
const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
u16 flags;

if (IS_ERR(attr))
return PTR_ERR(attr);

flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
return (!copy_to_user(attr->ptr_attr.ptr, from, attr->ptr_attr.len) &&
!put_user(flags, &attr->uattr->flags)) ? 0 : -EFAULT;
}

static inline int _uverbs_copy_from(void *to, size_t to_size,
const struct uverbs_attr_bundle *attrs_bundle,
size_t idx)
{
const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);

if (IS_ERR(attr))
return PTR_ERR(attr);

if (to_size <= sizeof(((struct ib_uverbs_attr *)0)->data))
memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len);
else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len))
return -EFAULT;

return 0;
}

#define uverbs_copy_from(to, attrs_bundle, idx) \
_uverbs_copy_from(to, sizeof(*(to)), attrs_bundle, idx)

/* =================================================
* Definitions -> Specs infrastructure
* =================================================
Expand Down
10 changes: 10 additions & 0 deletions include/uapi/rdma/ib_user_ioctl_verbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
#ifndef IB_USER_IOCTL_VERBS_H
#define IB_USER_IOCTL_VERBS_H

#include <rdma/rdma_user_ioctl.h>

#define UVERBS_UDATA_DRIVER_DATA_NS 1
#define UVERBS_UDATA_DRIVER_DATA_FLAG (1UL << UVERBS_ID_NS_SHIFT)

enum uverbs_default_objects {
UVERBS_OBJECT_DEVICE, /* No instances of DEVICE are allowed */
UVERBS_OBJECT_PD,
Expand All @@ -50,5 +55,10 @@ enum uverbs_default_objects {
UVERBS_OBJECT_LAST,
};

enum {
UVERBS_UHW_IN = UVERBS_UDATA_DRIVER_DATA_FLAG,
UVERBS_UHW_OUT,
};

#endif

0 comments on commit d70724f

Please sign in to comment.