.. | .. |
---|
57 | 57 | struct ib_uverbs_attr *uattrs; |
---|
58 | 58 | |
---|
59 | 59 | DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN); |
---|
| 60 | + DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN); |
---|
| 61 | + DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN); |
---|
60 | 62 | |
---|
61 | 63 | /* |
---|
62 | 64 | * Must be last. bundle ends in a flex array which overlaps |
---|
.. | .. |
---|
135 | 137 | static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, |
---|
136 | 138 | u16 len) |
---|
137 | 139 | { |
---|
138 | | - if (uattr->len > sizeof(((struct ib_uverbs_attr *)0)->data)) |
---|
| 140 | + if (uattr->len > sizeof_field(struct ib_uverbs_attr, data)) |
---|
139 | 141 | return ib_is_buffer_cleared(u64_to_user_ptr(uattr->data) + len, |
---|
140 | 142 | uattr->len - len); |
---|
141 | 143 | |
---|
142 | 144 | return !memchr_inv((const void *)&uattr->data + len, |
---|
143 | 145 | 0, uattr->len - len); |
---|
| 146 | +} |
---|
| 147 | + |
---|
| 148 | +static int uverbs_set_output(const struct uverbs_attr_bundle *bundle, |
---|
| 149 | + const struct uverbs_attr *attr) |
---|
| 150 | +{ |
---|
| 151 | + struct bundle_priv *pbundle = |
---|
| 152 | + container_of(bundle, struct bundle_priv, bundle); |
---|
| 153 | + u16 flags; |
---|
| 154 | + |
---|
| 155 | + flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags | |
---|
| 156 | + UVERBS_ATTR_F_VALID_OUTPUT; |
---|
| 157 | + if (put_user(flags, |
---|
| 158 | + &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags)) |
---|
| 159 | + return -EFAULT; |
---|
| 160 | + return 0; |
---|
| 161 | +} |
---|
| 162 | + |
---|
| 163 | +static int uverbs_process_idrs_array(struct bundle_priv *pbundle, |
---|
| 164 | + const struct uverbs_api_attr *attr_uapi, |
---|
| 165 | + struct uverbs_objs_arr_attr *attr, |
---|
| 166 | + struct ib_uverbs_attr *uattr, |
---|
| 167 | + u32 attr_bkey) |
---|
| 168 | +{ |
---|
| 169 | + const struct uverbs_attr_spec *spec = &attr_uapi->spec; |
---|
| 170 | + size_t array_len; |
---|
| 171 | + u32 *idr_vals; |
---|
| 172 | + int ret = 0; |
---|
| 173 | + size_t i; |
---|
| 174 | + |
---|
| 175 | + if (uattr->attr_data.reserved) |
---|
| 176 | + return -EINVAL; |
---|
| 177 | + |
---|
| 178 | + if (uattr->len % sizeof(u32)) |
---|
| 179 | + return -EINVAL; |
---|
| 180 | + |
---|
| 181 | + array_len = uattr->len / sizeof(u32); |
---|
| 182 | + if (array_len < spec->u2.objs_arr.min_len || |
---|
| 183 | + array_len > spec->u2.objs_arr.max_len) |
---|
| 184 | + return -EINVAL; |
---|
| 185 | + |
---|
| 186 | + attr->uobjects = |
---|
| 187 | + uverbs_alloc(&pbundle->bundle, |
---|
| 188 | + array_size(array_len, sizeof(*attr->uobjects))); |
---|
| 189 | + if (IS_ERR(attr->uobjects)) |
---|
| 190 | + return PTR_ERR(attr->uobjects); |
---|
| 191 | + |
---|
| 192 | + /* |
---|
| 193 | + * Since idr is 4B and *uobjects is >= 4B, we can use attr->uobjects |
---|
| 194 | + * to store idrs array and avoid additional memory allocation. The |
---|
| 195 | + * idrs array is offset to the end of the uobjects array so we will be |
---|
| 196 | + * able to read idr and replace with a pointer. |
---|
| 197 | + */ |
---|
| 198 | + idr_vals = (u32 *)(attr->uobjects + array_len) - array_len; |
---|
| 199 | + |
---|
| 200 | + if (uattr->len > sizeof(uattr->data)) { |
---|
| 201 | + ret = copy_from_user(idr_vals, u64_to_user_ptr(uattr->data), |
---|
| 202 | + uattr->len); |
---|
| 203 | + if (ret) |
---|
| 204 | + return -EFAULT; |
---|
| 205 | + } else { |
---|
| 206 | + memcpy(idr_vals, &uattr->data, uattr->len); |
---|
| 207 | + } |
---|
| 208 | + |
---|
| 209 | + for (i = 0; i != array_len; i++) { |
---|
| 210 | + attr->uobjects[i] = uverbs_get_uobject_from_file( |
---|
| 211 | + spec->u2.objs_arr.obj_type, spec->u2.objs_arr.access, |
---|
| 212 | + idr_vals[i], &pbundle->bundle); |
---|
| 213 | + if (IS_ERR(attr->uobjects[i])) { |
---|
| 214 | + ret = PTR_ERR(attr->uobjects[i]); |
---|
| 215 | + break; |
---|
| 216 | + } |
---|
| 217 | + } |
---|
| 218 | + |
---|
| 219 | + attr->len = i; |
---|
| 220 | + __set_bit(attr_bkey, pbundle->spec_finalize); |
---|
| 221 | + return ret; |
---|
| 222 | +} |
---|
| 223 | + |
---|
| 224 | +static void uverbs_free_idrs_array(const struct uverbs_api_attr *attr_uapi, |
---|
| 225 | + struct uverbs_objs_arr_attr *attr, |
---|
| 226 | + bool commit, |
---|
| 227 | + struct uverbs_attr_bundle *attrs) |
---|
| 228 | +{ |
---|
| 229 | + const struct uverbs_attr_spec *spec = &attr_uapi->spec; |
---|
| 230 | + size_t i; |
---|
| 231 | + |
---|
| 232 | + for (i = 0; i != attr->len; i++) |
---|
| 233 | + uverbs_finalize_object(attr->uobjects[i], |
---|
| 234 | + spec->u2.objs_arr.access, false, commit, |
---|
| 235 | + attrs); |
---|
144 | 236 | } |
---|
145 | 237 | |
---|
146 | 238 | static int uverbs_process_attr(struct bundle_priv *pbundle, |
---|
.. | .. |
---|
167 | 259 | return -EOPNOTSUPP; |
---|
168 | 260 | |
---|
169 | 261 | e->ptr_attr.enum_id = uattr->attr_data.enum_data.elem_id; |
---|
170 | | - /* fall through */ |
---|
| 262 | + fallthrough; |
---|
171 | 263 | case UVERBS_ATTR_TYPE_PTR_IN: |
---|
172 | 264 | /* Ensure that any data provided by userspace beyond the known |
---|
173 | 265 | * struct is zero. Userspace that knows how to use some future |
---|
.. | .. |
---|
179 | 271 | !uverbs_is_attr_cleared(uattr, val_spec->u.ptr.len)) |
---|
180 | 272 | return -EOPNOTSUPP; |
---|
181 | 273 | |
---|
182 | | - /* fall through */ |
---|
| 274 | + fallthrough; |
---|
183 | 275 | case UVERBS_ATTR_TYPE_PTR_OUT: |
---|
184 | 276 | if (uattr->len < val_spec->u.ptr.min_len || |
---|
185 | 277 | (!val_spec->zero_trailing && |
---|
.. | .. |
---|
228 | 320 | * IDR implementation today rejects negative IDs |
---|
229 | 321 | */ |
---|
230 | 322 | o_attr->uobject = uverbs_get_uobject_from_file( |
---|
231 | | - spec->u.obj.obj_type, |
---|
232 | | - pbundle->bundle.ufile, |
---|
233 | | - spec->u.obj.access, |
---|
234 | | - uattr->data_s64); |
---|
| 323 | + spec->u.obj.obj_type, spec->u.obj.access, |
---|
| 324 | + uattr->data_s64, &pbundle->bundle); |
---|
235 | 325 | if (IS_ERR(o_attr->uobject)) |
---|
236 | 326 | return PTR_ERR(o_attr->uobject); |
---|
237 | 327 | __set_bit(attr_bkey, pbundle->uobj_finalize); |
---|
.. | .. |
---|
246 | 336 | } |
---|
247 | 337 | |
---|
248 | 338 | break; |
---|
| 339 | + |
---|
| 340 | + case UVERBS_ATTR_TYPE_IDRS_ARRAY: |
---|
| 341 | + return uverbs_process_idrs_array(pbundle, attr_uapi, |
---|
| 342 | + &e->objs_arr_attr, uattr, |
---|
| 343 | + attr_bkey); |
---|
249 | 344 | default: |
---|
250 | 345 | return -EOPNOTSUPP; |
---|
251 | 346 | } |
---|
.. | .. |
---|
300 | 395 | return -EPROTONOSUPPORT; |
---|
301 | 396 | return 0; |
---|
302 | 397 | } |
---|
303 | | - attr = srcu_dereference( |
---|
304 | | - *slot, &pbundle->bundle.ufile->device->disassociate_srcu); |
---|
| 398 | + attr = rcu_dereference_protected(*slot, true); |
---|
305 | 399 | |
---|
306 | 400 | /* Reject duplicate attributes from user-space */ |
---|
307 | 401 | if (test_bit(attr_bkey, pbundle->bundle.attr_present)) |
---|
.. | .. |
---|
319 | 413 | static int ib_uverbs_run_method(struct bundle_priv *pbundle, |
---|
320 | 414 | unsigned int num_attrs) |
---|
321 | 415 | { |
---|
322 | | - int (*handler)(struct ib_uverbs_file *ufile, |
---|
323 | | - struct uverbs_attr_bundle *ctx); |
---|
| 416 | + int (*handler)(struct uverbs_attr_bundle *attrs); |
---|
324 | 417 | size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs); |
---|
325 | 418 | unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey; |
---|
326 | 419 | unsigned int i; |
---|
.. | .. |
---|
351 | 444 | pbundle->method_elm->key_bitmap_len))) |
---|
352 | 445 | return -EINVAL; |
---|
353 | 446 | |
---|
| 447 | + if (pbundle->method_elm->has_udata) |
---|
| 448 | + uverbs_fill_udata(&pbundle->bundle, |
---|
| 449 | + &pbundle->bundle.driver_udata, |
---|
| 450 | + UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT); |
---|
| 451 | + else |
---|
| 452 | + pbundle->bundle.driver_udata = (struct ib_udata){}; |
---|
| 453 | + |
---|
354 | 454 | if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) { |
---|
355 | 455 | struct uverbs_obj_attr *destroy_attr = |
---|
356 | 456 | &pbundle->bundle.attrs[destroy_bkey].obj_attr; |
---|
357 | 457 | |
---|
358 | | - ret = uobj_destroy(destroy_attr->uobject); |
---|
| 458 | + ret = uobj_destroy(destroy_attr->uobject, &pbundle->bundle); |
---|
359 | 459 | if (ret) |
---|
360 | 460 | return ret; |
---|
361 | 461 | __clear_bit(destroy_bkey, pbundle->uobj_finalize); |
---|
362 | 462 | |
---|
363 | | - ret = handler(pbundle->bundle.ufile, &pbundle->bundle); |
---|
| 463 | + ret = handler(&pbundle->bundle); |
---|
364 | 464 | uobj_put_destroy(destroy_attr->uobject); |
---|
365 | 465 | } else { |
---|
366 | | - ret = handler(pbundle->bundle.ufile, &pbundle->bundle); |
---|
| 466 | + ret = handler(&pbundle->bundle); |
---|
| 467 | + } |
---|
| 468 | + |
---|
| 469 | + /* |
---|
| 470 | + * Until the drivers are revised to use the bundle directly we have to |
---|
| 471 | + * assume that the driver wrote to its UHW_OUT and flag userspace |
---|
| 472 | + * appropriately. |
---|
| 473 | + */ |
---|
| 474 | + if (!ret && pbundle->method_elm->has_udata) { |
---|
| 475 | + const struct uverbs_attr *attr = |
---|
| 476 | + uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT); |
---|
| 477 | + |
---|
| 478 | + if (!IS_ERR(attr)) |
---|
| 479 | + ret = uverbs_set_output(&pbundle->bundle, attr); |
---|
367 | 480 | } |
---|
368 | 481 | |
---|
369 | 482 | /* |
---|
.. | .. |
---|
377 | 490 | return ret; |
---|
378 | 491 | } |
---|
379 | 492 | |
---|
380 | | -static int bundle_destroy(struct bundle_priv *pbundle, bool commit) |
---|
| 493 | +static void bundle_destroy(struct bundle_priv *pbundle, bool commit) |
---|
381 | 494 | { |
---|
382 | 495 | unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len; |
---|
383 | 496 | struct bundle_alloc_head *memblock; |
---|
384 | 497 | unsigned int i; |
---|
385 | | - int ret = 0; |
---|
386 | 498 | |
---|
| 499 | + /* fast path for simple uobjects */ |
---|
387 | 500 | i = -1; |
---|
388 | 501 | while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len, |
---|
389 | 502 | i + 1)) < key_bitmap_len) { |
---|
390 | 503 | struct uverbs_attr *attr = &pbundle->bundle.attrs[i]; |
---|
391 | | - int current_ret; |
---|
392 | 504 | |
---|
393 | | - current_ret = uverbs_finalize_object( |
---|
| 505 | + uverbs_finalize_object( |
---|
394 | 506 | attr->obj_attr.uobject, |
---|
395 | | - attr->obj_attr.attr_elm->spec.u.obj.access, commit); |
---|
396 | | - if (!ret) |
---|
397 | | - ret = current_ret; |
---|
| 507 | + attr->obj_attr.attr_elm->spec.u.obj.access, |
---|
| 508 | + test_bit(i, pbundle->uobj_hw_obj_valid), |
---|
| 509 | + commit, |
---|
| 510 | + &pbundle->bundle); |
---|
| 511 | + } |
---|
| 512 | + |
---|
| 513 | + i = -1; |
---|
| 514 | + while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len, |
---|
| 515 | + i + 1)) < key_bitmap_len) { |
---|
| 516 | + struct uverbs_attr *attr = &pbundle->bundle.attrs[i]; |
---|
| 517 | + const struct uverbs_api_attr *attr_uapi; |
---|
| 518 | + void __rcu **slot; |
---|
| 519 | + |
---|
| 520 | + slot = uapi_get_attr_for_method( |
---|
| 521 | + pbundle, |
---|
| 522 | + pbundle->method_key | uapi_bkey_to_key_attr(i)); |
---|
| 523 | + if (WARN_ON(!slot)) |
---|
| 524 | + continue; |
---|
| 525 | + |
---|
| 526 | + attr_uapi = rcu_dereference_protected(*slot, true); |
---|
| 527 | + |
---|
| 528 | + if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) { |
---|
| 529 | + uverbs_free_idrs_array(attr_uapi, &attr->objs_arr_attr, |
---|
| 530 | + commit, &pbundle->bundle); |
---|
| 531 | + } |
---|
398 | 532 | } |
---|
399 | 533 | |
---|
400 | 534 | for (memblock = pbundle->allocated_mem; memblock;) { |
---|
.. | .. |
---|
403 | 537 | memblock = memblock->next; |
---|
404 | 538 | kvfree(tmp); |
---|
405 | 539 | } |
---|
406 | | - |
---|
407 | | - return ret; |
---|
408 | 540 | } |
---|
409 | 541 | |
---|
410 | 542 | static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile, |
---|
.. | .. |
---|
417 | 549 | struct bundle_priv *pbundle; |
---|
418 | 550 | struct bundle_priv onstack; |
---|
419 | 551 | void __rcu **slot; |
---|
420 | | - int destroy_ret; |
---|
421 | 552 | int ret; |
---|
422 | 553 | |
---|
423 | 554 | if (unlikely(hdr->driver_id != uapi->driver_id)) |
---|
.. | .. |
---|
429 | 560 | uapi_key_ioctl_method(hdr->method_id)); |
---|
430 | 561 | if (unlikely(!slot)) |
---|
431 | 562 | return -EPROTONOSUPPORT; |
---|
432 | | - method_elm = srcu_dereference(*slot, &ufile->device->disassociate_srcu); |
---|
| 563 | + method_elm = rcu_dereference_protected(*slot, true); |
---|
433 | 564 | |
---|
434 | 565 | if (!method_elm->use_stack) { |
---|
435 | 566 | pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL); |
---|
.. | .. |
---|
450 | 581 | pbundle->method_elm = method_elm; |
---|
451 | 582 | pbundle->method_key = attrs_iter.index; |
---|
452 | 583 | pbundle->bundle.ufile = ufile; |
---|
| 584 | + pbundle->bundle.context = NULL; /* only valid if bundle has uobject */ |
---|
453 | 585 | pbundle->radix = &uapi->radix; |
---|
454 | 586 | pbundle->radix_slots = slot; |
---|
455 | 587 | pbundle->radix_slots_len = radix_tree_chunk_size(&attrs_iter); |
---|
.. | .. |
---|
461 | 593 | memset(pbundle->bundle.attr_present, 0, |
---|
462 | 594 | sizeof(pbundle->bundle.attr_present)); |
---|
463 | 595 | memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize)); |
---|
| 596 | + memset(pbundle->spec_finalize, 0, sizeof(pbundle->spec_finalize)); |
---|
| 597 | + memset(pbundle->uobj_hw_obj_valid, 0, |
---|
| 598 | + sizeof(pbundle->uobj_hw_obj_valid)); |
---|
464 | 599 | |
---|
465 | 600 | ret = ib_uverbs_run_method(pbundle, hdr->num_attrs); |
---|
466 | | - destroy_ret = bundle_destroy(pbundle, ret == 0); |
---|
467 | | - if (unlikely(destroy_ret && !ret)) |
---|
468 | | - return destroy_ret; |
---|
469 | | - |
---|
| 601 | + bundle_destroy(pbundle, ret == 0); |
---|
470 | 602 | return ret; |
---|
471 | 603 | } |
---|
472 | 604 | |
---|
.. | .. |
---|
551 | 683 | EXPORT_SYMBOL(uverbs_get_flags32); |
---|
552 | 684 | |
---|
553 | 685 | /* |
---|
554 | | - * This is for ease of conversion. The purpose is to convert all drivers to |
---|
555 | | - * use uverbs_attr_bundle instead of ib_udata. Assume attr == 0 is input and |
---|
556 | | - * attr == 1 is output. |
---|
| 686 | + * Fill a ib_udata struct (core or uhw) using the given attribute IDs. |
---|
| 687 | + * This is primarily used to convert the UVERBS_ATTR_UHW() into the |
---|
| 688 | + * ib_udata format used by the drivers. |
---|
557 | 689 | */ |
---|
558 | | -void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata) |
---|
| 690 | +void uverbs_fill_udata(struct uverbs_attr_bundle *bundle, |
---|
| 691 | + struct ib_udata *udata, unsigned int attr_in, |
---|
| 692 | + unsigned int attr_out) |
---|
559 | 693 | { |
---|
560 | 694 | struct bundle_priv *pbundle = |
---|
561 | 695 | container_of(bundle, struct bundle_priv, bundle); |
---|
562 | | - const struct uverbs_attr *uhw_in = |
---|
563 | | - uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN); |
---|
564 | | - const struct uverbs_attr *uhw_out = |
---|
565 | | - uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT); |
---|
| 696 | + const struct uverbs_attr *in = |
---|
| 697 | + uverbs_attr_get(&pbundle->bundle, attr_in); |
---|
| 698 | + const struct uverbs_attr *out = |
---|
| 699 | + uverbs_attr_get(&pbundle->bundle, attr_out); |
---|
566 | 700 | |
---|
567 | | - if (!IS_ERR(uhw_in)) { |
---|
568 | | - udata->inlen = uhw_in->ptr_attr.len; |
---|
569 | | - if (uverbs_attr_ptr_is_inline(uhw_in)) |
---|
| 701 | + if (!IS_ERR(in)) { |
---|
| 702 | + udata->inlen = in->ptr_attr.len; |
---|
| 703 | + if (uverbs_attr_ptr_is_inline(in)) |
---|
570 | 704 | udata->inbuf = |
---|
571 | | - &pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx] |
---|
| 705 | + &pbundle->user_attrs[in->ptr_attr.uattr_idx] |
---|
572 | 706 | .data; |
---|
573 | 707 | else |
---|
574 | | - udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); |
---|
| 708 | + udata->inbuf = u64_to_user_ptr(in->ptr_attr.data); |
---|
575 | 709 | } else { |
---|
576 | 710 | udata->inbuf = NULL; |
---|
577 | 711 | udata->inlen = 0; |
---|
578 | 712 | } |
---|
579 | 713 | |
---|
580 | | - if (!IS_ERR(uhw_out)) { |
---|
581 | | - udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); |
---|
582 | | - udata->outlen = uhw_out->ptr_attr.len; |
---|
| 714 | + if (!IS_ERR(out)) { |
---|
| 715 | + udata->outbuf = u64_to_user_ptr(out->ptr_attr.data); |
---|
| 716 | + udata->outlen = out->ptr_attr.len; |
---|
583 | 717 | } else { |
---|
584 | 718 | udata->outbuf = NULL; |
---|
585 | 719 | udata->outlen = 0; |
---|
.. | .. |
---|
589 | 723 | int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx, |
---|
590 | 724 | const void *from, size_t size) |
---|
591 | 725 | { |
---|
592 | | - struct bundle_priv *pbundle = |
---|
593 | | - container_of(bundle, struct bundle_priv, bundle); |
---|
594 | 726 | const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); |
---|
595 | | - u16 flags; |
---|
596 | 727 | size_t min_size; |
---|
597 | 728 | |
---|
598 | 729 | if (IS_ERR(attr)) |
---|
.. | .. |
---|
602 | 733 | if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) |
---|
603 | 734 | return -EFAULT; |
---|
604 | 735 | |
---|
605 | | - flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags | |
---|
606 | | - UVERBS_ATTR_F_VALID_OUTPUT; |
---|
607 | | - if (put_user(flags, |
---|
608 | | - &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags)) |
---|
609 | | - return -EFAULT; |
---|
| 736 | + return uverbs_set_output(bundle, attr); |
---|
| 737 | +} |
---|
| 738 | +EXPORT_SYMBOL(uverbs_copy_to); |
---|
| 739 | + |
---|
| 740 | + |
---|
| 741 | +/* |
---|
| 742 | + * This is only used if the caller has directly used copy_to_use to write the |
---|
| 743 | + * data. It signals to user space that the buffer is filled in. |
---|
| 744 | + */ |
---|
| 745 | +int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx) |
---|
| 746 | +{ |
---|
| 747 | + const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); |
---|
| 748 | + |
---|
| 749 | + if (IS_ERR(attr)) |
---|
| 750 | + return PTR_ERR(attr); |
---|
| 751 | + |
---|
| 752 | + return uverbs_set_output(bundle, attr); |
---|
| 753 | +} |
---|
| 754 | + |
---|
| 755 | +int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, |
---|
| 756 | + size_t idx, s64 lower_bound, u64 upper_bound, |
---|
| 757 | + s64 *def_val) |
---|
| 758 | +{ |
---|
| 759 | + const struct uverbs_attr *attr; |
---|
| 760 | + |
---|
| 761 | + attr = uverbs_attr_get(attrs_bundle, idx); |
---|
| 762 | + if (IS_ERR(attr)) { |
---|
| 763 | + if ((PTR_ERR(attr) != -ENOENT) || !def_val) |
---|
| 764 | + return PTR_ERR(attr); |
---|
| 765 | + |
---|
| 766 | + *to = *def_val; |
---|
| 767 | + } else { |
---|
| 768 | + *to = attr->ptr_attr.data; |
---|
| 769 | + } |
---|
| 770 | + |
---|
| 771 | + if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound)) |
---|
| 772 | + return -EINVAL; |
---|
610 | 773 | |
---|
611 | 774 | return 0; |
---|
612 | 775 | } |
---|
613 | | -EXPORT_SYMBOL(uverbs_copy_to); |
---|
| 776 | +EXPORT_SYMBOL(_uverbs_get_const); |
---|
| 777 | + |
---|
| 778 | +int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, |
---|
| 779 | + size_t idx, const void *from, size_t size) |
---|
| 780 | +{ |
---|
| 781 | + const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); |
---|
| 782 | + |
---|
| 783 | + if (IS_ERR(attr)) |
---|
| 784 | + return PTR_ERR(attr); |
---|
| 785 | + |
---|
| 786 | + if (size < attr->ptr_attr.len) { |
---|
| 787 | + if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size, |
---|
| 788 | + attr->ptr_attr.len - size)) |
---|
| 789 | + return -EFAULT; |
---|
| 790 | + } |
---|
| 791 | + return uverbs_copy_to(bundle, idx, from, size); |
---|
| 792 | +} |
---|
| 793 | +EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero); |
---|
| 794 | + |
---|
| 795 | +/* Once called an abort will call through to the type's destroy_hw() */ |
---|
| 796 | +void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle, |
---|
| 797 | + u16 idx) |
---|
| 798 | +{ |
---|
| 799 | + struct bundle_priv *pbundle = |
---|
| 800 | + container_of(bundle, struct bundle_priv, bundle); |
---|
| 801 | + |
---|
| 802 | + __set_bit(uapi_bkey_attr(uapi_key_attr(idx)), |
---|
| 803 | + pbundle->uobj_hw_obj_valid); |
---|
| 804 | +} |
---|
| 805 | +EXPORT_SYMBOL(uverbs_finalize_uobj_create); |
---|