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
@ -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);
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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 @@ retry:
|
|||||||
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 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@ retry:
|
|||||||
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 @@ retry:
|
|||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user