Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dma-buf: detach fence ops on signal v3

When neither a release nor a wait backend ops is specified it is possible
to let the dma_fence live on independently of the module who issued it.

This makes it possible to unload drivers and only wait for all their
fences to signal.

v2: fix typo in comment
v3: fix sparse rcu warnings

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: Philipp Stanner <phasta@kernel.org>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/r/20260219160822.1529-3-christian.koenig@amd.com

+16 -6
+14 -4
drivers/dma-buf/dma-fence.c
··· 362 362 void dma_fence_signal_timestamp_locked(struct dma_fence *fence, 363 363 ktime_t timestamp) 364 364 { 365 + const struct dma_fence_ops *ops; 365 366 struct dma_fence_cb *cur, *tmp; 366 367 struct list_head cb_list; 367 368 ··· 371 370 if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, 372 371 &fence->flags))) 373 372 return; 373 + 374 + /* 375 + * When neither a release nor a wait operation is specified set the ops 376 + * pointer to NULL to allow the fence structure to become independent 377 + * from who originally issued it. 378 + */ 379 + ops = rcu_dereference_protected(fence->ops, true); 380 + if (!ops->release && !ops->wait) 381 + RCU_INIT_POINTER(fence->ops, NULL); 374 382 375 383 /* Stash the cb_list before replacing it with the timestamp */ 376 384 list_replace(&fence->cb_list, &cb_list); ··· 547 537 rcu_read_lock(); 548 538 ops = rcu_dereference(fence->ops); 549 539 trace_dma_fence_wait_start(fence); 550 - if (ops->wait) { 540 + if (ops && ops->wait) { 551 541 /* 552 542 * Implementing the wait ops is deprecated and not supported for 553 543 * issuers of fences who need their lifetime to be independent ··· 613 603 } 614 604 615 605 ops = rcu_dereference(fence->ops); 616 - if (ops->release) 606 + if (ops && ops->release) 617 607 ops->release(fence); 618 608 else 619 609 dma_fence_free(fence); ··· 649 639 650 640 rcu_read_lock(); 651 641 ops = rcu_dereference(fence->ops); 652 - if (!was_set && ops->enable_signaling) { 642 + if (!was_set && ops && ops->enable_signaling) { 653 643 trace_dma_fence_enable_signal(fence); 654 644 655 645 if (!ops->enable_signaling(fence)) { ··· 1035 1025 1036 1026 rcu_read_lock(); 1037 1027 ops = rcu_dereference(fence->ops); 1038 - if (ops->set_deadline && !dma_fence_is_signaled(fence)) 1028 + if (ops && ops->set_deadline && !dma_fence_is_signaled(fence)) 1039 1029 ops->set_deadline(fence, deadline); 1040 1030 rcu_read_unlock(); 1041 1031 }
+2 -2
include/linux/dma-fence.h
··· 472 472 473 473 rcu_read_lock(); 474 474 ops = rcu_dereference(fence->ops); 475 - if (ops->signaled && ops->signaled(fence)) { 475 + if (ops && ops->signaled && ops->signaled(fence)) { 476 476 rcu_read_unlock(); 477 477 dma_fence_signal_locked(fence); 478 478 return true; ··· 508 508 509 509 rcu_read_lock(); 510 510 ops = rcu_dereference(fence->ops); 511 - if (ops->signaled && ops->signaled(fence)) { 511 + if (ops && ops->signaled && ops->signaled(fence)) { 512 512 rcu_read_unlock(); 513 513 dma_fence_signal(fence); 514 514 return true;