Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a1f444f authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

IB/uverbs: Remove the ib_uverbs_attr pointer from each attr



Memory in the bundle is valuable, do not waste it holding an 8 byte
pointer for the rare case of writing to a PTR_OUT. We can compute the
pointer by storing a small 1 byte array offset and the base address of the
uattr memory in the bundle private memory.

This also means we can access the kernel's copy of the ib_uverbs_attr, so
drop the copy of flags as well.

Since the uattr base should be private bundle information this also
de-inlines the already too big uverbs_copy_to inline and moves
create_udata into uverbs_ioctl.c so they can see the private struct
definition.

Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
Reviewed-by: default avatarLeon Romanovsky <leonro@mellanox.com>
parent 4b3dd2bb
Loading
Loading
Loading
Loading
+64 −3
Original line number Diff line number Diff line
@@ -84,7 +84,6 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
	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:
@@ -124,8 +123,8 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
		    uattr->attr_data.reserved)
			return -EINVAL;

		e->ptr_attr.uattr_idx = uattr - pbundle->uattrs;
		e->ptr_attr.len = uattr->len;
		e->ptr_attr.flags = uattr->flags;

		if (val_spec->alloc_and_copy && !uverbs_attr_ptr_is_inline(e)) {
			void *p;
@@ -181,7 +180,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
			s64 id = o_attr->uobject->id;

			/* Copy the allocated id to the user-space */
			if (put_user(id, &e->uattr->data)) {
			if (put_user(id, &uattr_ptr->data)) {
				uverbs_finalize_object(o_attr->uobject,
						       UVERBS_ACCESS_NEW,
						       false);
@@ -562,3 +561,65 @@ int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
	return 0;
}
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.
 */
void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata)
{
	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))
			udata->inbuf =
				&pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx]
					 .data;
		else
			udata->inbuf = u64_to_user_ptr(uhw_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;
	} else {
		udata->outbuf = NULL;
		udata->outlen = 0;
	}
}

int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
		   const void *from, size_t size)
{
	struct bundle_priv *pbundle =
		container_of(bundle, struct bundle_priv, bundle);
	const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
	u16 flags;
	size_t min_size;

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

	min_size = min_t(size_t, attr->ptr_attr.len, size);
	if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
		return -EFAULT;

	flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
		UVERBS_ATTR_F_VALID_OUTPUT;
	if (put_user(flags,
		     &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
		return -EFAULT;

	return 0;
}
EXPORT_SYMBOL(uverbs_copy_to);
+0 −32
Original line number Diff line number Diff line
@@ -217,38 +217,6 @@ int uverbs_destroy_def_handler(struct ib_uverbs_file *file,
}
EXPORT_SYMBOL(uverbs_destroy_def_handler);

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.
	 */
	const struct uverbs_attr *uhw_in =
		uverbs_attr_get(ctx, UVERBS_ATTR_UHW_IN);
	const struct uverbs_attr *uhw_out =
		uverbs_attr_get(ctx, UVERBS_ATTR_UHW_OUT);

	if (!IS_ERR(uhw_in)) {
		udata->inlen = uhw_in->ptr_attr.len;
		if (uverbs_attr_ptr_is_inline(uhw_in))
			udata->inbuf = &uhw_in->uattr->data;
		else
			udata->inbuf = u64_to_user_ptr(uhw_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;
	} else {
		udata->outbuf = NULL;
		udata->outlen = 0;
	}
}

DECLARE_UVERBS_NAMED_OBJECT(
	UVERBS_OBJECT_COMP_CHANNEL,
	UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_completion_event_file),
+8 −28
Original line number Diff line number Diff line
@@ -461,8 +461,7 @@ struct uverbs_ptr_attr {
		u64 data;
	};
	u16		len;
	/* Combination of bits from enum UVERBS_ATTR_F_XXXX */
	u16		flags;
	u16		uattr_idx;
	u8		enum_id;
};

@@ -471,11 +470,6 @@ struct uverbs_obj_attr {
};

struct uverbs_attr {
	/*
	 * pointer to the user-space given attribute, in order to write the
	 * new uobject's id or update flags.
	 */
	struct ib_uverbs_attr __user	*uattr;
	union {
		struct uverbs_ptr_attr	ptr_attr;
		struct uverbs_obj_attr	obj_attr;
@@ -575,27 +569,6 @@ uverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx)
	return attr->ptr_attr.len;
}

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

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

	min_size = min_t(size_t, attr->ptr_attr.len, size);
	if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
		return -EFAULT;

	flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
	if (put_user(flags, &attr->uattr->flags))
		return -EFAULT;

	return 0;
}

static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)
{
	return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data);
@@ -676,6 +649,8 @@ int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
		       size_t idx, u64 allowed_bits);
int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
		       size_t idx, u64 allowed_bits);
int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, size_t idx,
		   const void *from, size_t size);
#else
static inline int
uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
@@ -689,6 +664,11 @@ uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
{
	return -EINVAL;
}
static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
				 size_t idx, const void *from, size_t size)
{
	return -EINVAL;
}
#endif

/* =================================================