Skip to content

Commit d6f4a21

Browse files
committed
RDMA/uverbs: Mark ioctl responses with UVERBS_ATTR_F_VALID_OUTPUT
When the ioctl interface for the write commands was introduced it did not mark the core response with UVERBS_ATTR_F_VALID_OUTPUT. This causes rdma-core in userspace to not mark the buffers as written for valgrind. Along the same lines it turns out we have always missed marking the driver data. Fixing both of these makes valgrind work properly with rdma-core and ioctl. Fixes: 4785860 ("RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers") Signed-off-by: Jason Gunthorpe <jgg@mellanox.com> Reviewed-by: Artemy Kovalyov <artemyko@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
1 parent 9d9f59b commit d6f4a21

File tree

4 files changed

+59
-13
lines changed

4 files changed

+59
-13
lines changed

drivers/infiniband/core/rdma_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ int uverbs_finalize_object(struct ib_uobject *uobj,
106106
enum uverbs_obj_access access,
107107
bool commit);
108108

109+
int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx);
110+
109111
void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
110112
void release_ufile_idr_uobject(struct ib_uverbs_file *ufile);
111113

drivers/infiniband/core/uverbs_cmd.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
6060
{
6161
int ret;
6262

63+
if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
64+
return uverbs_copy_to_struct_or_zero(
65+
attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
66+
6367
if (copy_to_user(attrs->ucore.outbuf, resp,
6468
min(attrs->ucore.outlen, resp_len)))
6569
return -EFAULT;
@@ -1181,6 +1185,9 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
11811185
goto out_put;
11821186
}
11831187

1188+
if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
1189+
ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
1190+
11841191
ret = 0;
11851192

11861193
out_put:

drivers/infiniband/core/uverbs_ioctl.c

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
144144
0, uattr->len - len);
145145
}
146146

147+
static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
148+
const struct uverbs_attr *attr)
149+
{
150+
struct bundle_priv *pbundle =
151+
container_of(bundle, struct bundle_priv, bundle);
152+
u16 flags;
153+
154+
flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
155+
UVERBS_ATTR_F_VALID_OUTPUT;
156+
if (put_user(flags,
157+
&pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
158+
return -EFAULT;
159+
return 0;
160+
}
161+
147162
static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
148163
const struct uverbs_api_attr *attr_uapi,
149164
struct uverbs_objs_arr_attr *attr,
@@ -455,6 +470,19 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
455470
ret = handler(&pbundle->bundle);
456471
}
457472

473+
/*
474+
* Until the drivers are revised to use the bundle directly we have to
475+
* assume that the driver wrote to its UHW_OUT and flag userspace
476+
* appropriately.
477+
*/
478+
if (!ret && pbundle->method_elm->has_udata) {
479+
const struct uverbs_attr *attr =
480+
uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT);
481+
482+
if (!IS_ERR(attr))
483+
ret = uverbs_set_output(&pbundle->bundle, attr);
484+
}
485+
458486
/*
459487
* EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
460488
* not invoke the method because the request is not supported. No
@@ -706,10 +734,7 @@ void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
706734
int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
707735
const void *from, size_t size)
708736
{
709-
struct bundle_priv *pbundle =
710-
container_of(bundle, struct bundle_priv, bundle);
711737
const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
712-
u16 flags;
713738
size_t min_size;
714739

715740
if (IS_ERR(attr))
@@ -719,16 +744,25 @@ int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
719744
if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
720745
return -EFAULT;
721746

722-
flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
723-
UVERBS_ATTR_F_VALID_OUTPUT;
724-
if (put_user(flags,
725-
&pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
726-
return -EFAULT;
727-
728-
return 0;
747+
return uverbs_set_output(bundle, attr);
729748
}
730749
EXPORT_SYMBOL(uverbs_copy_to);
731750

751+
752+
/*
753+
* This is only used if the caller has directly used copy_to_use to write the
754+
* data. It signals to user space that the buffer is filled in.
755+
*/
756+
int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx)
757+
{
758+
const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
759+
760+
if (IS_ERR(attr))
761+
return PTR_ERR(attr);
762+
763+
return uverbs_set_output(bundle, attr);
764+
}
765+
732766
int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
733767
size_t idx, s64 lower_bound, u64 upper_bound,
734768
s64 *def_val)
@@ -757,8 +791,10 @@ int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
757791
{
758792
const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
759793

760-
if (clear_user(u64_to_user_ptr(attr->ptr_attr.data),
761-
attr->ptr_attr.len))
762-
return -EFAULT;
794+
if (size < attr->ptr_attr.len) {
795+
if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
796+
attr->ptr_attr.len - size))
797+
return -EFAULT;
798+
}
763799
return uverbs_copy_to(bundle, idx, from, size);
764800
}

drivers/infiniband/core/uverbs_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
690690

691691
buf += sizeof(hdr);
692692

693+
memset(bundle.attr_present, 0, sizeof(bundle.attr_present));
693694
bundle.ufile = file;
694695
if (!method_elm->is_ex) {
695696
size_t in_len = hdr.in_words * 4 - sizeof(hdr);

0 commit comments

Comments
 (0)