| .. | .. |
|---|
| 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); |
|---|