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

dma-buf: Use sequence counter with associated wound/wait mutex

A sequence counter write side critical section must be protected by some
form of locking to serialize writers. If the serialization primitive is
not disabling preemption implicitly, preemption has to be explicitly
disabled before entering the sequence counter write side critical
section.

The dma-buf reservation subsystem uses plain sequence counters to manage
updates to reservations. Writer serialization is accomplished through a
wound/wait mutex.

Acquiring a wound/wait mutex does not disable preemption, so this needs
to be done manually before and after the write side critical section.

Use the newly-added seqcount_ww_mutex_t instead:

- It associates the ww_mutex with the sequence count, which enables
lockdep to validate that the write side critical section is properly
serialized.

- It removes the need to explicitly add preempt_disable/enable()
around the write side critical section because the write_begin/end()
functions for this new data type automatically do this.

If lockdep is disabled this ww_mutex lock association is compiled out
and has neither storage size nor runtime overhead.

Signed-off-by: Ahmed S. Darwish <a.darwish@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://lkml.kernel.org/r/20200720155530.1173732-13-a.darwish@linutronix.de

authored by

Ahmed S. Darwish and committed by
Peter Zijlstra
cd29f220 318ce71f

+2 -10
+1 -7
drivers/dma-buf/dma-resv.c
··· 129 129 void dma_resv_init(struct dma_resv *obj) 130 130 { 131 131 ww_mutex_init(&obj->lock, &reservation_ww_class); 132 - seqcount_init(&obj->seq); 132 + seqcount_ww_mutex_init(&obj->seq, &obj->lock); 133 133 134 134 RCU_INIT_POINTER(obj->fence, NULL); 135 135 RCU_INIT_POINTER(obj->fence_excl, NULL); ··· 260 260 fobj = dma_resv_get_list(obj); 261 261 count = fobj->shared_count; 262 262 263 - preempt_disable(); 264 263 write_seqcount_begin(&obj->seq); 265 264 266 265 for (i = 0; i < count; ++i) { ··· 281 282 smp_store_mb(fobj->shared_count, count); 282 283 283 284 write_seqcount_end(&obj->seq); 284 - preempt_enable(); 285 285 dma_fence_put(old); 286 286 } 287 287 EXPORT_SYMBOL(dma_resv_add_shared_fence); ··· 307 309 if (fence) 308 310 dma_fence_get(fence); 309 311 310 - preempt_disable(); 311 312 write_seqcount_begin(&obj->seq); 312 313 /* write_seqcount_begin provides the necessary memory barrier */ 313 314 RCU_INIT_POINTER(obj->fence_excl, fence); 314 315 if (old) 315 316 old->shared_count = 0; 316 317 write_seqcount_end(&obj->seq); 317 - preempt_enable(); 318 318 319 319 /* inplace update, no shared fences */ 320 320 while (i--) ··· 390 394 src_list = dma_resv_get_list(dst); 391 395 old = dma_resv_get_excl(dst); 392 396 393 - preempt_disable(); 394 397 write_seqcount_begin(&dst->seq); 395 398 /* write_seqcount_begin provides the necessary memory barrier */ 396 399 RCU_INIT_POINTER(dst->fence_excl, new); 397 400 RCU_INIT_POINTER(dst->fence, dst_list); 398 401 write_seqcount_end(&dst->seq); 399 - preempt_enable(); 400 402 401 403 dma_resv_list_free(src_list); 402 404 dma_fence_put(old);
-2
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
··· 258 258 new->shared_count = k; 259 259 260 260 /* Install the new fence list, seqcount provides the barriers */ 261 - preempt_disable(); 262 261 write_seqcount_begin(&resv->seq); 263 262 RCU_INIT_POINTER(resv->fence, new); 264 263 write_seqcount_end(&resv->seq); 265 - preempt_enable(); 266 264 267 265 /* Drop the references to the removed fences or move them to ef_list */ 268 266 for (i = j, k = 0; i < old->shared_count; ++i) {
+1 -1
include/linux/dma-resv.h
··· 69 69 */ 70 70 struct dma_resv { 71 71 struct ww_mutex lock; 72 - seqcount_t seq; 72 + seqcount_ww_mutex_t seq; 73 73 74 74 struct dma_fence __rcu *fence_excl; 75 75 struct dma_resv_list __rcu *fence;