Commit 96e95496 authored by Christian König's avatar Christian König

dma-buf: fix shared fence list handling in reservation_object_copy_fences

Add some helpers to correctly allocate/free reservation_object_lists.

Otherwise we might forget to drop dma_fence references on list destruction.
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/322031/?series=64786&rev=1
parent 93505ee7
...@@ -55,6 +55,47 @@ EXPORT_SYMBOL(reservation_seqcount_class); ...@@ -55,6 +55,47 @@ EXPORT_SYMBOL(reservation_seqcount_class);
const char reservation_seqcount_string[] = "reservation_seqcount"; const char reservation_seqcount_string[] = "reservation_seqcount";
EXPORT_SYMBOL(reservation_seqcount_string); EXPORT_SYMBOL(reservation_seqcount_string);
/**
* reservation_object_list_alloc - allocate fence list
* @shared_max: number of fences we need space for
*
* Allocate a new reservation_object_list and make sure to correctly initialize
* shared_max.
*/
static struct reservation_object_list *
reservation_object_list_alloc(unsigned int shared_max)
{
struct reservation_object_list *list;
list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL);
if (!list)
return NULL;
list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
sizeof(*list->shared);
return list;
}
/**
* reservation_object_list_free - free fence list
* @list: list to free
*
* Free a reservation_object_list and make sure to drop all references.
*/
static void reservation_object_list_free(struct reservation_object_list *list)
{
unsigned int i;
if (!list)
return;
for (i = 0; i < list->shared_count; ++i)
dma_fence_put(rcu_dereference_protected(list->shared[i], true));
kfree_rcu(list, rcu);
}
/** /**
* reservation_object_init - initialize a reservation object * reservation_object_init - initialize a reservation object
* @obj: the reservation object * @obj: the reservation object
...@@ -76,7 +117,6 @@ EXPORT_SYMBOL(reservation_object_init); ...@@ -76,7 +117,6 @@ EXPORT_SYMBOL(reservation_object_init);
*/ */
void reservation_object_fini(struct reservation_object *obj) void reservation_object_fini(struct reservation_object *obj)
{ {
int i;
struct reservation_object_list *fobj; struct reservation_object_list *fobj;
struct dma_fence *excl; struct dma_fence *excl;
...@@ -89,13 +129,7 @@ void reservation_object_fini(struct reservation_object *obj) ...@@ -89,13 +129,7 @@ void reservation_object_fini(struct reservation_object *obj)
dma_fence_put(excl); dma_fence_put(excl);
fobj = rcu_dereference_protected(obj->fence, 1); fobj = rcu_dereference_protected(obj->fence, 1);
if (fobj) { reservation_object_list_free(fobj);
for (i = 0; i < fobj->shared_count; ++i)
dma_fence_put(rcu_dereference_protected(fobj->shared[i], 1));
kfree(fobj);
}
ww_mutex_destroy(&obj->lock); ww_mutex_destroy(&obj->lock);
} }
EXPORT_SYMBOL(reservation_object_fini); EXPORT_SYMBOL(reservation_object_fini);
...@@ -132,7 +166,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj, ...@@ -132,7 +166,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
max = 4; max = 4;
} }
new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL); new = reservation_object_list_alloc(max);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
...@@ -153,9 +187,6 @@ int reservation_object_reserve_shared(struct reservation_object *obj, ...@@ -153,9 +187,6 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
RCU_INIT_POINTER(new->shared[j++], fence); RCU_INIT_POINTER(new->shared[j++], fence);
} }
new->shared_count = j; new->shared_count = j;
new->shared_max =
(ksize(new) - offsetof(typeof(*new), shared)) /
sizeof(*new->shared);
/* /*
* We are not changing the effective set of fences here so can * We are not changing the effective set of fences here so can
...@@ -286,7 +317,6 @@ int reservation_object_copy_fences(struct reservation_object *dst, ...@@ -286,7 +317,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
{ {
struct reservation_object_list *src_list, *dst_list; struct reservation_object_list *src_list, *dst_list;
struct dma_fence *old, *new; struct dma_fence *old, *new;
size_t size;
unsigned i; unsigned i;
reservation_object_assert_held(dst); reservation_object_assert_held(dst);
...@@ -298,10 +328,9 @@ int reservation_object_copy_fences(struct reservation_object *dst, ...@@ -298,10 +328,9 @@ int reservation_object_copy_fences(struct reservation_object *dst,
if (src_list) { if (src_list) {
unsigned shared_count = src_list->shared_count; unsigned shared_count = src_list->shared_count;
size = offsetof(typeof(*src_list), shared[shared_count]);
rcu_read_unlock(); rcu_read_unlock();
dst_list = kmalloc(size, GFP_KERNEL); dst_list = reservation_object_list_alloc(shared_count);
if (!dst_list) if (!dst_list)
return -ENOMEM; return -ENOMEM;
...@@ -313,7 +342,6 @@ int reservation_object_copy_fences(struct reservation_object *dst, ...@@ -313,7 +342,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
} }
dst_list->shared_count = 0; dst_list->shared_count = 0;
dst_list->shared_max = shared_count;
for (i = 0; i < src_list->shared_count; ++i) { for (i = 0; i < src_list->shared_count; ++i) {
struct dma_fence *fence; struct dma_fence *fence;
...@@ -323,7 +351,7 @@ int reservation_object_copy_fences(struct reservation_object *dst, ...@@ -323,7 +351,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
continue; continue;
if (!dma_fence_get_rcu(fence)) { if (!dma_fence_get_rcu(fence)) {
kfree(dst_list); reservation_object_list_free(dst_list);
src_list = rcu_dereference(src->fence); src_list = rcu_dereference(src->fence);
goto retry; goto retry;
} }
...@@ -353,8 +381,7 @@ int reservation_object_copy_fences(struct reservation_object *dst, ...@@ -353,8 +381,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
write_seqcount_end(&dst->seq); write_seqcount_end(&dst->seq);
preempt_enable(); preempt_enable();
if (src_list) reservation_object_list_free(src_list);
kfree_rcu(src_list, rcu);
dma_fence_put(old); dma_fence_put(old);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment