mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 17:59:32 +00:00
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: Christian König <christian.koenig@amd.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/322031/?series=64786&rev=1
This commit is contained in:
parent
93505ee7d0
commit
96e95496b0
1 changed files with 46 additions and 19 deletions
|
@ -55,6 +55,47 @@ EXPORT_SYMBOL(reservation_seqcount_class);
|
|||
const char reservation_seqcount_string[] = "reservation_seqcount";
|
||||
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
|
||||
* @obj: the reservation object
|
||||
|
@ -76,7 +117,6 @@ EXPORT_SYMBOL(reservation_object_init);
|
|||
*/
|
||||
void reservation_object_fini(struct reservation_object *obj)
|
||||
{
|
||||
int i;
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_fence *excl;
|
||||
|
||||
|
@ -89,13 +129,7 @@ void reservation_object_fini(struct reservation_object *obj)
|
|||
dma_fence_put(excl);
|
||||
|
||||
fobj = rcu_dereference_protected(obj->fence, 1);
|
||||
if (fobj) {
|
||||
for (i = 0; i < fobj->shared_count; ++i)
|
||||
dma_fence_put(rcu_dereference_protected(fobj->shared[i], 1));
|
||||
|
||||
kfree(fobj);
|
||||
}
|
||||
|
||||
reservation_object_list_free(fobj);
|
||||
ww_mutex_destroy(&obj->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(reservation_object_fini);
|
||||
|
@ -132,7 +166,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
|
|||
max = 4;
|
||||
}
|
||||
|
||||
new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL);
|
||||
new = reservation_object_list_alloc(max);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -153,9 +187,6 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
|
|||
RCU_INIT_POINTER(new->shared[j++], fence);
|
||||
}
|
||||
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
|
||||
|
@ -286,7 +317,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
|
|||
{
|
||||
struct reservation_object_list *src_list, *dst_list;
|
||||
struct dma_fence *old, *new;
|
||||
size_t size;
|
||||
unsigned i;
|
||||
|
||||
reservation_object_assert_held(dst);
|
||||
|
@ -298,10 +328,9 @@ int reservation_object_copy_fences(struct reservation_object *dst,
|
|||
if (src_list) {
|
||||
unsigned shared_count = src_list->shared_count;
|
||||
|
||||
size = offsetof(typeof(*src_list), shared[shared_count]);
|
||||
rcu_read_unlock();
|
||||
|
||||
dst_list = kmalloc(size, GFP_KERNEL);
|
||||
dst_list = reservation_object_list_alloc(shared_count);
|
||||
if (!dst_list)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -313,7 +342,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
|
|||
}
|
||||
|
||||
dst_list->shared_count = 0;
|
||||
dst_list->shared_max = shared_count;
|
||||
for (i = 0; i < src_list->shared_count; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
|
@ -323,7 +351,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
|
|||
continue;
|
||||
|
||||
if (!dma_fence_get_rcu(fence)) {
|
||||
kfree(dst_list);
|
||||
reservation_object_list_free(dst_list);
|
||||
src_list = rcu_dereference(src->fence);
|
||||
goto retry;
|
||||
}
|
||||
|
@ -353,8 +381,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
|
|||
write_seqcount_end(&dst->seq);
|
||||
preempt_enable();
|
||||
|
||||
if (src_list)
|
||||
kfree_rcu(src_list, rcu);
|
||||
reservation_object_list_free(src_list);
|
||||
dma_fence_put(old);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue