| @@ -269,6 +269,175 @@ umem_kfree: · 268 unmodified lines |
| 269 | 269 | return ret ? ERR_PTR(ret) : umem; |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | +/** |
| 273 | + * ib_umem_get_desc - Pin a umem from a buffer descriptor. |
| 274 | + * @device: IB device. |
| 275 | + * @desc: buffer descriptor (VA or DMABUF). |
| 276 | + * @access: IB access flags. |
| 277 | + * |
| 278 | + * Return: caller-owned umem on success, ERR_PTR(...) on error. |
| 279 | + */ |
| 280 | +struct ib_umem *ib_umem_get_desc(struct ib_device *device, |
| 281 | + const struct ib_uverbs_buffer_desc *desc, |
| 282 | + int access) |
| 283 | +{ |
| 284 | + struct ib_umem_dmabuf *umem_dmabuf; |
| 285 | + |
| 286 | + if (desc->flags & ~IB_UVERBS_BUFFER_DESC_FLAGS_KNOWN_MASK) |
| 287 | + return ERR_PTR(-EINVAL); |
| 288 | + |
| 289 | + if (overflows_type(desc->addr, unsigned long) || |
| 290 | + overflows_type(desc->length, size_t)) |
| 291 | + return ERR_PTR(-EOVERFLOW); |
| 292 | + |
| 293 | + switch (desc->type) { |
| 294 | + case IB_UVERBS_BUFFER_TYPE_DMABUF: |
| 295 | + umem_dmabuf = ib_umem_dmabuf_get_pinned(device, desc->addr, |
| 296 | + desc->length, desc->fd, |
| 297 | + access); |
| 298 | + if (IS_ERR(umem_dmabuf)) |
| 299 | + return ERR_CAST(umem_dmabuf); |
| 300 | + return &umem_dmabuf->umem; |
| 301 | + case IB_UVERBS_BUFFER_TYPE_VA: |
| 302 | + return __ib_umem_get_va(device, desc->addr, desc->length, |
| 303 | + access); |
| 304 | + default: |
| 305 | + return ERR_PTR(-EINVAL); |
| 306 | + } |
| 307 | +} |
| 308 | +EXPORT_SYMBOL(ib_umem_get_desc); |
| 309 | + |
| 310 | +/* |
| 311 | + * Per-command legacy buffer-desc filler. |
| 312 | + * Returns 0 on success (desc filled), -ENODATA if no legacy attrs apply, |
| 313 | + * negative errno on validation failure. |
| 314 | + */ |
| 315 | +typedef int (*ib_umem_buf_desc_filler_t)(const struct uverbs_attr_bundle *attrs, |
| 316 | + struct ib_uverbs_buffer_desc *desc); |
| 317 | + |
| 318 | +/* |
| 319 | + * ib_umem_resolve_desc - Resolve a buffer descriptor from a per-command UMEM |
| 320 | + * attribute and/or a legacy attr filler. |
| 321 | + * |
| 322 | + * Return: |
| 323 | + * 0 @desc filled. |
| 324 | + * -ENOENT no source produced a buffer. |
| 325 | + * -EINVAL both the UMEM attribute and the legacy filler produced a buffer. |
| 326 | + * -errno propagated from attr read / filler validation. |
| 327 | + */ |
| 328 | +static int ib_umem_resolve_desc(const struct uverbs_attr_bundle *attrs, |
| 329 | + u16 attr_id, |
| 330 | + ib_umem_buf_desc_filler_t legacy_filler, |
| 331 | + struct ib_uverbs_buffer_desc *desc) |
| 332 | +{ |
| 333 | + bool have_desc = false; |
| 334 | + int ret; |
| 335 | + |
| 336 | + if (!attrs) |
| 337 | + return -ENOENT; |
| 338 | + |
| 339 | + ret = uverbs_get_buffer_desc(attrs, attr_id, desc); |
| 340 | + if (!ret) |
| 341 | + have_desc = true; |
| 342 | + else if (ret != -ENOENT) |
| 343 | + return ret; |
| 344 | + |
| 345 | + if (legacy_filler) { |
| 346 | + struct ib_uverbs_buffer_desc legacy_desc = {}; |
| 347 | + |
| 348 | + ret = legacy_filler(attrs, &legacy_desc); |
| 349 | + if (!ret) { |
| 350 | + if (have_desc) |
| 351 | + return -EINVAL; |
| 352 | + *desc = legacy_desc; |
| 353 | + have_desc = true; |
| 354 | + } else if (ret != -ENODATA) { |
| 355 | + return ret; |
| 356 | + } |
| 357 | + } |
| 358 | + |
| 359 | + return have_desc ? 0 : -ENOENT; |
| 360 | +} |
| 361 | + |
| 362 | +/* |
| 363 | + * ib_umem_get_desc_check - Pin a umem from @desc and verify it meets |
| 364 | + * @min_size. |
| 365 | + */ |
| 366 | +static struct ib_umem * |
| 367 | +ib_umem_get_desc_check(struct ib_device *device, |
| 368 | + const struct ib_uverbs_buffer_desc *desc, |
| 369 | + size_t min_size, int access) |
| 370 | +{ |
| 371 | + struct ib_umem *umem; |
| 372 | + |
| 373 | + umem = ib_umem_get_desc(device, desc, access); |
| 374 | + if (IS_ERR(umem)) |
| 375 | + return umem; |
| 376 | + if (umem->length < min_size) { |
| 377 | + ib_umem_release(umem); |
| 378 | + return ERR_PTR(-EINVAL); |
| 379 | + } |
| 380 | + return umem; |
| 381 | +} |
| 382 | + |
| 383 | +/* |
| 384 | + * ib_umem_get_from_attrs - Pin a umem from a per-command UMEM attribute |
| 385 | + * and/or a legacy attr filler. |
| 386 | + * |
| 387 | + * Return: caller-owned umem on success; NULL when no source supplied a |
| 388 | + * buffer; ERR_PTR(...) on error. |
| 389 | + */ |
| 390 | +static struct ib_umem * |
| 391 | +ib_umem_get_from_attrs(struct ib_device *device, |
| 392 | + const struct uverbs_attr_bundle *attrs, |
| 393 | + u16 attr_id, ib_umem_buf_desc_filler_t legacy_filler, |
| 394 | + size_t size, int access) |
| 395 | +{ |
| 396 | + struct ib_uverbs_buffer_desc desc = {}; |
| 397 | + int ret; |
| 398 | + |
| 399 | + ret = ib_umem_resolve_desc(attrs, attr_id, legacy_filler, &desc); |
| 400 | + if (ret == -ENOENT) |
| 401 | + return NULL; |
| 402 | + if (ret) |
| 403 | + return ERR_PTR(ret); |
| 404 | + return ib_umem_get_desc_check(device, &desc, size, access); |
| 405 | +} |
| 406 | + |
| 407 | +/* |
| 408 | + * ib_umem_get_from_attrs_or_va - Pin a umem from a per-command UMEM |
| 409 | + * attribute and/or a legacy attr filler, |
| 410 | + * falling back to a UHW VA when no source |
| 411 | + * matched. |
| 412 | + * |
| 413 | + * @size is always consumed: it is the length to pin on the VA fallback |
| 414 | + * path AND the post-pin minimum-length check on the attr / legacy paths. |
| 415 | + * Callers must always pass a meaningful, validated value. |
| 416 | + * |
| 417 | + * Return: caller-owned umem on success, ERR_PTR(...) on error. |
| 418 | + */ |
| 419 | +static struct ib_umem * |
| 420 | +ib_umem_get_from_attrs_or_va(struct ib_device *device, |
| 421 | + const struct uverbs_attr_bundle *attrs, |
| 422 | + u16 attr_id, |
| 423 | + ib_umem_buf_desc_filler_t legacy_filler, |
| 424 | + u64 addr, size_t size, int access) |
| 425 | +{ |
| 426 | + struct ib_uverbs_buffer_desc desc = {}; |
| 427 | + int ret; |
| 428 | + |
| 429 | + ret = ib_umem_resolve_desc(attrs, attr_id, legacy_filler, &desc); |
| 430 | + if (ret == -ENOENT) |
| 431 | + desc = (struct ib_uverbs_buffer_desc){ |
| 432 | + .type = IB_UVERBS_BUFFER_TYPE_VA, |
| 433 | + .addr = addr, |
| 434 | + .length = size, |
| 435 | + }; |
| 436 | + else if (ret) |
| 437 | + return ERR_PTR(ret); |
| 438 | + return ib_umem_get_desc_check(device, &desc, size, access); |
| 439 | +} |
| 440 | + |
| 272 | 441 | /** |
| 273 | 442 | * ib_umem_get_va - Pin and DMA map userspace memory. |
| 274 | 443 | * |
| @@ -284,6 +453,65 @@ struct ib_umem *ib_umem_get_va(struct ib_device *device, unsigned long addr, · 9 unmodified lines |
| 284 | 453 | } |
| 285 | 454 | EXPORT_SYMBOL(ib_umem_get_va); |
| 286 | 455 | |
| 456 | +/** |
| 457 | + * ib_umem_get_attr - Pin a umem from a per-command UMEM attribute. |
| 458 | + * @device: IB device. |
| 459 | + * @attrs: uverbs attribute bundle (may be NULL). |
| 460 | + * @attr_id: per-command UMEM attribute id. |
| 461 | + * @size: minimum required umem length. |
| 462 | + * @access: IB access flags. |
| 463 | + * |
| 464 | + * Return: caller-owned umem on success; NULL when no source supplied |
| 465 | + * a buffer; ERR_PTR(...) on error. |
| 466 | + */ |
| 467 | +struct ib_umem *ib_umem_get_attr(struct ib_device *device, |
| 468 | + const struct uverbs_attr_bundle *attrs, |
| 469 | + u16 attr_id, size_t size, int access) |
| 470 | +{ |
| 471 | + return ib_umem_get_from_attrs(device, attrs, attr_id, NULL, size, |
| 472 | + access); |
| 473 | +} |
| 474 | +EXPORT_SYMBOL(ib_umem_get_attr); |
| 475 | + |
| 476 | +/** |
| 477 | + * ib_umem_get_attr_or_va - Pin a umem from a per-command UMEM attribute, |
| 478 | + * falling back to a UHW VA. |
| 479 | + * @device: IB device. |
| 480 | + * @attrs: uverbs attribute bundle (may be NULL). |
| 481 | + * @attr_id: per-command UMEM attribute id. |
| 482 | + * @addr: UHW user VA used when no per-command attribute matched. |
| 483 | + * @size: on the attr / legacy paths, the minimum required umem length |
| 484 | + * validated post-pin; on the VA fallback path, the length to pin. |
| 485 | + * @access: IB access flags. |
| 486 | + * |
| 487 | + * Like ib_umem_get_attr(), but pins @addr/@size when no per-command |
| 488 | + * UMEM attribute is supplied. |
| 489 | + * |
| 490 | + * IMPORTANT: @size is always consumed. On the attr / legacy paths it is |
| 491 | + * used as the post-pin minimum-length check; on the VA fallback path it |
| 492 | + * is the length to pin. Callers MUST pass a meaningful, validated value |
| 493 | + * even when they expect an attribute-supplied buffer to be used. |
| 494 | + * |
| 495 | + * Every in-tree caller passes the same value for the two roles of @size |
| 496 | + * because no driver today distinguishes a user-passed buffer length from |
| 497 | + * a driver-computed minimum. Drivers that currently accept a user-supplied |
| 498 | + * length without cross-checking it against a driver minimum (vmw_pvrdma |
| 499 | + * CQ/QP/SRQ, qedr CQ/QP/SRQ, mana WQ/QP, ionic CQ/QP), once tightened to |
| 500 | + * compute and check a real minimum, will want to introduce a separate |
| 501 | + * helper that passes these as distinct values. |
| 502 | + * |
| 503 | + * Return: caller-owned umem on success, ERR_PTR(...) on error. |
| 504 | + */ |
| 505 | +struct ib_umem *ib_umem_get_attr_or_va(struct ib_device *device, |
| 506 | + const struct uverbs_attr_bundle *attrs, |
| 507 | + u16 attr_id, u64 addr, size_t size, |
| 508 | + int access) |
| 509 | +{ |
| 510 | + return ib_umem_get_from_attrs_or_va(device, attrs, attr_id, NULL, addr, |
| 511 | + size, access); |
| 512 | +} |
| 513 | +EXPORT_SYMBOL(ib_umem_get_attr_or_va); |
| 514 | + |
| 287 | 515 | /** |
| 288 | 516 | * ib_umem_release - release pinned memory |
| 289 | 517 | * @umem: umem struct to release |