2 * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <rdma/rdma_user_ioctl.h>
34 #include <rdma/uverbs_ioctl.h>
35 #include "rdma_core.h"
38 static int uverbs_process_attr(struct ib_device
*ibdev
,
39 struct ib_ucontext
*ucontext
,
40 const struct ib_uverbs_attr
*uattr
,
42 const struct uverbs_attr_spec_hash
*attr_spec_bucket
,
43 struct uverbs_attr_bundle_hash
*attr_bundle_h
,
44 struct ib_uverbs_attr __user
*uattr_ptr
)
46 const struct uverbs_attr_spec
*spec
;
47 struct uverbs_attr
*e
;
48 const struct uverbs_object_spec
*object
;
49 struct uverbs_obj_attr
*o_attr
;
50 struct uverbs_attr
*elements
= attr_bundle_h
->attrs
;
55 if (attr_id
>= attr_spec_bucket
->num_attrs
) {
56 if (uattr
->flags
& UVERBS_ATTR_F_MANDATORY
)
62 if (test_bit(attr_id
, attr_bundle_h
->valid_bitmap
))
65 spec
= &attr_spec_bucket
->attrs
[attr_id
];
66 e
= &elements
[attr_id
];
70 case UVERBS_ATTR_TYPE_PTR_IN
:
71 case UVERBS_ATTR_TYPE_PTR_OUT
:
72 if (uattr
->len
< spec
->len
||
73 (!(spec
->flags
& UVERBS_ATTR_SPEC_F_MIN_SZ
) &&
74 uattr
->len
> spec
->len
))
77 e
->ptr_attr
.data
= uattr
->data
;
78 e
->ptr_attr
.len
= uattr
->len
;
79 e
->ptr_attr
.flags
= uattr
->flags
;
82 case UVERBS_ATTR_TYPE_IDR
:
83 if (uattr
->data
>> 32)
86 case UVERBS_ATTR_TYPE_FD
:
87 if (uattr
->len
!= 0 || !ucontext
|| uattr
->data
> INT_MAX
)
90 o_attr
= &e
->obj_attr
;
91 object
= uverbs_get_object(ibdev
, spec
->obj
.obj_type
);
94 o_attr
->type
= object
->type_attrs
;
96 o_attr
->id
= (int)uattr
->data
;
97 o_attr
->uobject
= uverbs_get_uobject_from_context(
103 if (IS_ERR(o_attr
->uobject
))
104 return PTR_ERR(o_attr
->uobject
);
106 if (spec
->obj
.access
== UVERBS_ACCESS_NEW
) {
107 u64 id
= o_attr
->uobject
->id
;
109 /* Copy the allocated id to the user-space */
110 if (put_user(id
, &e
->uattr
->data
)) {
111 uverbs_finalize_object(o_attr
->uobject
,
123 set_bit(attr_id
, attr_bundle_h
->valid_bitmap
);
127 static int uverbs_uattrs_process(struct ib_device
*ibdev
,
128 struct ib_ucontext
*ucontext
,
129 const struct ib_uverbs_attr
*uattrs
,
131 const struct uverbs_method_spec
*method
,
132 struct uverbs_attr_bundle
*attr_bundle
,
133 struct ib_uverbs_attr __user
*uattr_ptr
)
137 int num_given_buckets
= 0;
139 for (i
= 0; i
< num_uattrs
; i
++) {
140 const struct ib_uverbs_attr
*uattr
= &uattrs
[i
];
141 u16 attr_id
= uattr
->attr_id
;
142 struct uverbs_attr_spec_hash
*attr_spec_bucket
;
144 ret
= uverbs_ns_idx(&attr_id
, method
->num_buckets
);
146 if (uattr
->flags
& UVERBS_ATTR_F_MANDATORY
) {
147 uverbs_finalize_objects(attr_bundle
,
148 method
->attr_buckets
,
157 * ret is the found ns, so increase num_given_buckets if
160 if (ret
>= num_given_buckets
)
161 num_given_buckets
= ret
+ 1;
163 attr_spec_bucket
= method
->attr_buckets
[ret
];
164 ret
= uverbs_process_attr(ibdev
, ucontext
, uattr
, attr_id
,
165 attr_spec_bucket
, &attr_bundle
->hash
[ret
],
168 uverbs_finalize_objects(attr_bundle
,
169 method
->attr_buckets
,
176 return num_given_buckets
;
179 static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec
*method_spec
,
180 struct uverbs_attr_bundle
*attr_bundle
)
184 for (i
= 0; i
< attr_bundle
->num_buckets
; i
++) {
185 struct uverbs_attr_spec_hash
*attr_spec_bucket
=
186 method_spec
->attr_buckets
[i
];
188 if (!bitmap_subset(attr_spec_bucket
->mandatory_attrs_bitmask
,
189 attr_bundle
->hash
[i
].valid_bitmap
,
190 attr_spec_bucket
->num_attrs
))
197 static int uverbs_handle_method(struct ib_uverbs_attr __user
*uattr_ptr
,
198 const struct ib_uverbs_attr
*uattrs
,
200 struct ib_device
*ibdev
,
201 struct ib_uverbs_file
*ufile
,
202 const struct uverbs_method_spec
*method_spec
,
203 struct uverbs_attr_bundle
*attr_bundle
)
207 int num_given_buckets
;
209 num_given_buckets
= uverbs_uattrs_process(ibdev
, ufile
->ucontext
, uattrs
,
210 num_uattrs
, method_spec
,
211 attr_bundle
, uattr_ptr
);
212 if (num_given_buckets
<= 0)
215 attr_bundle
->num_buckets
= num_given_buckets
;
216 ret
= uverbs_validate_kernel_mandatory(method_spec
, attr_bundle
);
220 ret
= method_spec
->handler(ibdev
, ufile
, attr_bundle
);
222 finalize_ret
= uverbs_finalize_objects(attr_bundle
,
223 method_spec
->attr_buckets
,
224 attr_bundle
->num_buckets
,
227 return ret
? ret
: finalize_ret
;
230 #define UVERBS_OPTIMIZE_USING_STACK_SZ 256
231 static long ib_uverbs_cmd_verbs(struct ib_device
*ib_dev
,
232 struct ib_uverbs_file
*file
,
233 struct ib_uverbs_ioctl_hdr
*hdr
,
236 const struct uverbs_object_spec
*object_spec
;
237 const struct uverbs_method_spec
*method_spec
;
241 struct ib_uverbs_attr
*uattrs
;
242 struct uverbs_attr_bundle
*uverbs_attr_bundle
;
244 struct uverbs_attr
*curr_attr
;
245 unsigned long *curr_bitmap
;
247 uintptr_t data
[UVERBS_OPTIMIZE_USING_STACK_SZ
/ sizeof(uintptr_t)];
249 object_spec
= uverbs_get_object(ib_dev
, hdr
->object_id
);
251 return -EPROTONOSUPPORT
;
253 method_spec
= uverbs_get_method(object_spec
, hdr
->method_id
);
255 return -EPROTONOSUPPORT
;
257 if ((method_spec
->flags
& UVERBS_ACTION_FLAG_CREATE_ROOT
) ^ !file
->ucontext
)
260 ctx_size
= sizeof(*ctx
) +
261 sizeof(struct uverbs_attr_bundle
) +
262 sizeof(struct uverbs_attr_bundle_hash
) * method_spec
->num_buckets
+
263 sizeof(*ctx
->uattrs
) * hdr
->num_attrs
+
264 sizeof(*ctx
->uverbs_attr_bundle
->hash
[0].attrs
) *
265 method_spec
->num_child_attrs
+
266 sizeof(*ctx
->uverbs_attr_bundle
->hash
[0].valid_bitmap
) *
267 (method_spec
->num_child_attrs
/ BITS_PER_LONG
+
268 method_spec
->num_buckets
);
270 if (ctx_size
<= UVERBS_OPTIMIZE_USING_STACK_SZ
)
273 ctx
= kmalloc(ctx_size
, GFP_KERNEL
);
277 ctx
->uverbs_attr_bundle
= (void *)ctx
+ sizeof(*ctx
);
278 ctx
->uattrs
= (void *)(ctx
->uverbs_attr_bundle
+ 1) +
279 (sizeof(ctx
->uverbs_attr_bundle
->hash
[0]) *
280 method_spec
->num_buckets
);
281 curr_attr
= (void *)(ctx
->uattrs
+ hdr
->num_attrs
);
282 curr_bitmap
= (void *)(curr_attr
+ method_spec
->num_child_attrs
);
285 * We just fill the pointers and num_attrs here. The data itself will be
286 * filled at a later stage (uverbs_process_attr)
288 for (i
= 0; i
< method_spec
->num_buckets
; i
++) {
289 unsigned int curr_num_attrs
= method_spec
->attr_buckets
[i
]->num_attrs
;
291 ctx
->uverbs_attr_bundle
->hash
[i
].attrs
= curr_attr
;
292 curr_attr
+= curr_num_attrs
;
293 ctx
->uverbs_attr_bundle
->hash
[i
].num_attrs
= curr_num_attrs
;
294 ctx
->uverbs_attr_bundle
->hash
[i
].valid_bitmap
= curr_bitmap
;
295 bitmap_zero(curr_bitmap
, curr_num_attrs
);
296 curr_bitmap
+= BITS_TO_LONGS(curr_num_attrs
);
299 err
= copy_from_user(ctx
->uattrs
, buf
,
300 sizeof(*ctx
->uattrs
) * hdr
->num_attrs
);
306 err
= uverbs_handle_method(buf
, ctx
->uattrs
, hdr
->num_attrs
, ib_dev
,
307 file
, method_spec
, ctx
->uverbs_attr_bundle
);
310 * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
311 * not invoke the method because the request is not supported. No
312 * other cases should return this code.
314 if (unlikely(err
== -EPROTONOSUPPORT
)) {
315 WARN_ON_ONCE(err
== -EPROTONOSUPPORT
);
319 if (ctx
!= (void *)data
)
324 #define IB_UVERBS_MAX_CMD_SZ 4096
326 long ib_uverbs_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
328 struct ib_uverbs_file
*file
= filp
->private_data
;
329 struct ib_uverbs_ioctl_hdr __user
*user_hdr
=
330 (struct ib_uverbs_ioctl_hdr __user
*)arg
;
331 struct ib_uverbs_ioctl_hdr hdr
;
332 struct ib_device
*ib_dev
;
336 srcu_key
= srcu_read_lock(&file
->device
->disassociate_srcu
);
337 ib_dev
= srcu_dereference(file
->device
->ib_dev
,
338 &file
->device
->disassociate_srcu
);
344 if (cmd
== RDMA_VERBS_IOCTL
) {
345 err
= copy_from_user(&hdr
, user_hdr
, sizeof(hdr
));
347 if (err
|| hdr
.length
> IB_UVERBS_MAX_CMD_SZ
||
348 hdr
.length
!= sizeof(hdr
) + hdr
.num_attrs
* sizeof(struct ib_uverbs_attr
)) {
354 err
= -EPROTONOSUPPORT
;
358 err
= ib_uverbs_cmd_verbs(ib_dev
, file
, &hdr
,
359 (__user
void *)arg
+ sizeof(hdr
));
364 srcu_read_unlock(&file
->device
->disassociate_srcu
, srcu_key
);