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
This commit is contained in:
parent
318ce71f3e
commit
cd29f22019
|
@ -129,7 +129,7 @@ subsys_initcall(dma_resv_lockdep);
|
||||||
void dma_resv_init(struct dma_resv *obj)
|
void dma_resv_init(struct dma_resv *obj)
|
||||||
{
|
{
|
||||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||||
seqcount_init(&obj->seq);
|
seqcount_ww_mutex_init(&obj->seq, &obj->lock);
|
||||||
|
|
||||||
RCU_INIT_POINTER(obj->fence, NULL);
|
RCU_INIT_POINTER(obj->fence, NULL);
|
||||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||||
|
@ -260,7 +260,6 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||||
fobj = dma_resv_get_list(obj);
|
fobj = dma_resv_get_list(obj);
|
||||||
count = fobj->shared_count;
|
count = fobj->shared_count;
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&obj->seq);
|
write_seqcount_begin(&obj->seq);
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
|
@ -282,7 +281,6 @@ replace:
|
||||||
smp_store_mb(fobj->shared_count, count);
|
smp_store_mb(fobj->shared_count, count);
|
||||||
|
|
||||||
write_seqcount_end(&obj->seq);
|
write_seqcount_end(&obj->seq);
|
||||||
preempt_enable();
|
|
||||||
dma_fence_put(old);
|
dma_fence_put(old);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||||
|
@ -309,14 +307,12 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||||
if (fence)
|
if (fence)
|
||||||
dma_fence_get(fence);
|
dma_fence_get(fence);
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&obj->seq);
|
write_seqcount_begin(&obj->seq);
|
||||||
/* write_seqcount_begin provides the necessary memory barrier */
|
/* write_seqcount_begin provides the necessary memory barrier */
|
||||||
RCU_INIT_POINTER(obj->fence_excl, fence);
|
RCU_INIT_POINTER(obj->fence_excl, fence);
|
||||||
if (old)
|
if (old)
|
||||||
old->shared_count = 0;
|
old->shared_count = 0;
|
||||||
write_seqcount_end(&obj->seq);
|
write_seqcount_end(&obj->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
/* inplace update, no shared fences */
|
/* inplace update, no shared fences */
|
||||||
while (i--)
|
while (i--)
|
||||||
|
@ -394,13 +390,11 @@ retry:
|
||||||
src_list = dma_resv_get_list(dst);
|
src_list = dma_resv_get_list(dst);
|
||||||
old = dma_resv_get_excl(dst);
|
old = dma_resv_get_excl(dst);
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&dst->seq);
|
write_seqcount_begin(&dst->seq);
|
||||||
/* write_seqcount_begin provides the necessary memory barrier */
|
/* write_seqcount_begin provides the necessary memory barrier */
|
||||||
RCU_INIT_POINTER(dst->fence_excl, new);
|
RCU_INIT_POINTER(dst->fence_excl, new);
|
||||||
RCU_INIT_POINTER(dst->fence, dst_list);
|
RCU_INIT_POINTER(dst->fence, dst_list);
|
||||||
write_seqcount_end(&dst->seq);
|
write_seqcount_end(&dst->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
dma_resv_list_free(src_list);
|
dma_resv_list_free(src_list);
|
||||||
dma_fence_put(old);
|
dma_fence_put(old);
|
||||||
|
|
|
@ -258,11 +258,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||||
new->shared_count = k;
|
new->shared_count = k;
|
||||||
|
|
||||||
/* Install the new fence list, seqcount provides the barriers */
|
/* Install the new fence list, seqcount provides the barriers */
|
||||||
preempt_disable();
|
|
||||||
write_seqcount_begin(&resv->seq);
|
write_seqcount_begin(&resv->seq);
|
||||||
RCU_INIT_POINTER(resv->fence, new);
|
RCU_INIT_POINTER(resv->fence, new);
|
||||||
write_seqcount_end(&resv->seq);
|
write_seqcount_end(&resv->seq);
|
||||||
preempt_enable();
|
|
||||||
|
|
||||||
/* Drop the references to the removed fences or move them to ef_list */
|
/* Drop the references to the removed fences or move them to ef_list */
|
||||||
for (i = j, k = 0; i < old->shared_count; ++i) {
|
for (i = j, k = 0; i < old->shared_count; ++i) {
|
||||||
|
|
|
@ -69,7 +69,7 @@ struct dma_resv_list {
|
||||||
*/
|
*/
|
||||||
struct dma_resv {
|
struct dma_resv {
|
||||||
struct ww_mutex lock;
|
struct ww_mutex lock;
|
||||||
seqcount_t seq;
|
seqcount_ww_mutex_t seq;
|
||||||
|
|
||||||
struct dma_fence __rcu *fence_excl;
|
struct dma_fence __rcu *fence_excl;
|
||||||
struct dma_resv_list __rcu *fence;
|
struct dma_resv_list __rcu *fence;
|
||||||
|
|
Loading…
Reference in New Issue