[1/2] dma-buf: make reservation_object_copy_fences rcu save

Submitted by Christian König on Sept. 4, 2017, 7:02 p.m.

Details

Message ID 1504551766-5093-1-git-send-email-deathsimple@vodafone.de
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in AMD X.Org drivers

Browsing this patch as part of:
"Series without cover letter" rev 1 in AMD X.Org drivers
<< prev patch [1/2] next patch >>

Commit Message

Christian König Sept. 4, 2017, 7:02 p.m.
From: Christian König <christian.koenig@amd.com>

Stop requiring that the src reservation object is locked for this operation.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/dma-buf/reservation.c | 56 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 14 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index dec3a81..b44d9d7 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -266,8 +266,7 @@  EXPORT_SYMBOL(reservation_object_add_excl_fence);
 * @dst: the destination reservation object
 * @src: the source reservation object
 *
-* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
-* held.
+* Copy all fences from src to dst. dst-lock must be held.
 */
 int reservation_object_copy_fences(struct reservation_object *dst,
 				   struct reservation_object *src)
@@ -277,33 +276,62 @@  int reservation_object_copy_fences(struct reservation_object *dst,
 	size_t size;
 	unsigned i;
 
-	src_list = reservation_object_get_list(src);
+	rcu_read_lock();
+	src_list = rcu_dereference(src->fence);
 
+retry:
 	if (src_list) {
-		size = offsetof(typeof(*src_list),
-				shared[src_list->shared_count]);
+		unsigned shared_count = src_list->shared_count;
+
+		size = offsetof(typeof(*src_list), shared[shared_count]);
+		rcu_read_unlock();
+
 		dst_list = kmalloc(size, GFP_KERNEL);
 		if (!dst_list)
 			return -ENOMEM;
 
-		dst_list->shared_count = src_list->shared_count;
-		dst_list->shared_max = src_list->shared_count;
-		for (i = 0; i < src_list->shared_count; ++i)
-			dst_list->shared[i] =
-				dma_fence_get(src_list->shared[i]);
+		rcu_read_lock();
+		src_list = rcu_dereference(src->fence);
+		if (!src_list || src_list->shared_count > shared_count) {
+			kfree(dst_list);
+			goto retry;
+		}
+
+		dst_list->shared_count = 0;
+		dst_list->shared_max = shared_count;
+		for (i = 0; i < src_list->shared_count; ++i) {
+			struct dma_fence *fence;
+
+			fence = rcu_dereference(src_list->shared[i]);
+			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+				     &fence->flags))
+				continue;
+
+			if (!dma_fence_get_rcu(fence)) {
+				kfree(dst_list);
+				src_list = rcu_dereference(src->fence);
+				goto retry;
+			}
+
+			if (dma_fence_is_signaled(fence)) {
+				dma_fence_put(fence);
+				continue;
+			}
+
+			dst_list->shared[dst_list->shared_count++] = fence;
+		}
 	} else {
 		dst_list = NULL;
 	}
 
+	new = dma_fence_get_rcu_safe(&src->fence_excl);
+	rcu_read_unlock();
+
 	kfree(dst->staged);
 	dst->staged = NULL;
 
 	src_list = reservation_object_get_list(dst);
-
 	old = reservation_object_get_excl(dst);
-	new = reservation_object_get_excl(src);
-
-	dma_fence_get(new);
 
 	preempt_disable();
 	write_seqcount_begin(&dst->seq);

Comments

Ping? David can you take a look?

Alex is on vacation and that is a rather important bug fix.

Thanks,
Christian.

Am 04.09.2017 um 21:02 schrieb Christian König:
> From: Christian König <christian.koenig@amd.com>
>
> Stop requiring that the src reservation object is locked for this operation.
>
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>   drivers/dma-buf/reservation.c | 56 ++++++++++++++++++++++++++++++++-----------
>   1 file changed, 42 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
> index dec3a81..b44d9d7 100644
> --- a/drivers/dma-buf/reservation.c
> +++ b/drivers/dma-buf/reservation.c
> @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence);
>   * @dst: the destination reservation object
>   * @src: the source reservation object
>   *
> -* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
> -* held.
> +* Copy all fences from src to dst. dst-lock must be held.
>   */
>   int reservation_object_copy_fences(struct reservation_object *dst,
>   				   struct reservation_object *src)
> @@ -277,33 +276,62 @@ int reservation_object_copy_fences(struct reservation_object *dst,
>   	size_t size;
>   	unsigned i;
>   
> -	src_list = reservation_object_get_list(src);
> +	rcu_read_lock();
> +	src_list = rcu_dereference(src->fence);
>   
> +retry:
>   	if (src_list) {
> -		size = offsetof(typeof(*src_list),
> -				shared[src_list->shared_count]);
> +		unsigned shared_count = src_list->shared_count;
> +
> +		size = offsetof(typeof(*src_list), shared[shared_count]);
> +		rcu_read_unlock();
> +
>   		dst_list = kmalloc(size, GFP_KERNEL);
>   		if (!dst_list)
>   			return -ENOMEM;
>   
> -		dst_list->shared_count = src_list->shared_count;
> -		dst_list->shared_max = src_list->shared_count;
> -		for (i = 0; i < src_list->shared_count; ++i)
> -			dst_list->shared[i] =
> -				dma_fence_get(src_list->shared[i]);
> +		rcu_read_lock();
> +		src_list = rcu_dereference(src->fence);
> +		if (!src_list || src_list->shared_count > shared_count) {
> +			kfree(dst_list);
> +			goto retry;
> +		}
> +
> +		dst_list->shared_count = 0;
> +		dst_list->shared_max = shared_count;
> +		for (i = 0; i < src_list->shared_count; ++i) {
> +			struct dma_fence *fence;
> +
> +			fence = rcu_dereference(src_list->shared[i]);
> +			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
> +				     &fence->flags))
> +				continue;
> +
> +			if (!dma_fence_get_rcu(fence)) {
> +				kfree(dst_list);
> +				src_list = rcu_dereference(src->fence);
> +				goto retry;
> +			}
> +
> +			if (dma_fence_is_signaled(fence)) {
> +				dma_fence_put(fence);
> +				continue;
> +			}
> +
> +			dst_list->shared[dst_list->shared_count++] = fence;
> +		}
>   	} else {
>   		dst_list = NULL;
>   	}
>   
> +	new = dma_fence_get_rcu_safe(&src->fence_excl);
> +	rcu_read_unlock();
> +
>   	kfree(dst->staged);
>   	dst->staged = NULL;
>   
>   	src_list = reservation_object_get_list(dst);
> -
>   	old = reservation_object_get_excl(dst);
> -	new = reservation_object_get_excl(src);
> -
> -	dma_fence_get(new);
>   
>   	preempt_disable();
>   	write_seqcount_begin(&dst->seq);
On 2017年09月07日 15:13, Christian König wrote:
> Ping? David can you take a look?
>
> Alex is on vacation and that is a rather important bug fix.
>
> Thanks,
> Christian.
>
> Am 04.09.2017 um 21:02 schrieb Christian König:
>> From: Christian König <christian.koenig@amd.com>
>>
>> Stop requiring that the src reservation object is locked for this 
>> operation.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
>> ---
>>   drivers/dma-buf/reservation.c | 56 
>> ++++++++++++++++++++++++++++++++-----------
>>   1 file changed, 42 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/dma-buf/reservation.c 
>> b/drivers/dma-buf/reservation.c
>> index dec3a81..b44d9d7 100644
>> --- a/drivers/dma-buf/reservation.c
>> +++ b/drivers/dma-buf/reservation.c
>> @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence);
>>   * @dst: the destination reservation object
>>   * @src: the source reservation object
>>   *
>> -* Copy all fences from src to dst. Both src->lock as well as 
>> dst-lock must be
>> -* held.
>> +* Copy all fences from src to dst. dst-lock must be held.
>>   */
>>   int reservation_object_copy_fences(struct reservation_object *dst,
>>                      struct reservation_object *src)
>> @@ -277,33 +276,62 @@ int reservation_object_copy_fences(struct 
>> reservation_object *dst,
>>       size_t size;
>>       unsigned i;
>>   -    src_list = reservation_object_get_list(src);
>> +    rcu_read_lock();
>> +    src_list = rcu_dereference(src->fence);
>>   +retry:
>>       if (src_list) {
>> -        size = offsetof(typeof(*src_list),
>> -                shared[src_list->shared_count]);
>> +        unsigned shared_count = src_list->shared_count;
>> +
>> +        size = offsetof(typeof(*src_list), shared[shared_count]);
>> +        rcu_read_unlock();
>> +
>>           dst_list = kmalloc(size, GFP_KERNEL);
>>           if (!dst_list)
>>               return -ENOMEM;
>>   -        dst_list->shared_count = src_list->shared_count;
>> -        dst_list->shared_max = src_list->shared_count;
>> -        for (i = 0; i < src_list->shared_count; ++i)
>> -            dst_list->shared[i] =
>> -                dma_fence_get(src_list->shared[i]);
>> +        rcu_read_lock();
>> +        src_list = rcu_dereference(src->fence);
>> +        if (!src_list || src_list->shared_count > shared_count) {
>> +            kfree(dst_list);
>> +            goto retry;
>> +        }
>> +
>> +        dst_list->shared_count = 0;
>> +        dst_list->shared_max = shared_count;
>> +        for (i = 0; i < src_list->shared_count; ++i) {
>> +            struct dma_fence *fence;
>> +
>> +            fence = rcu_dereference(src_list->shared[i]);
>> +            if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
>> +                     &fence->flags))
seems here is duplicated with the below dma_fence_is_signaled, can it be 
removed?

And I'm not sure the locking, but it looks good, so Acked-by: Chunming 
Zhou <david1.zhou@amd.com>
>> +                continue;
>> +
>> +            if (!dma_fence_get_rcu(fence)) {
>> +                kfree(dst_list);
>> +                src_list = rcu_dereference(src->fence);
>> +                goto retry;
>> +            }
>> +
>> +            if (dma_fence_is_signaled(fence)) {
>> +                dma_fence_put(fence);
>> +                continue;
>> +            }
>> +
>> +            dst_list->shared[dst_list->shared_count++] = fence;
>> +        }
>>       } else {
>>           dst_list = NULL;
>>       }
>>   +    new = dma_fence_get_rcu_safe(&src->fence_excl);
>> +    rcu_read_unlock();
>> +
>>       kfree(dst->staged);
>>       dst->staged = NULL;
>>         src_list = reservation_object_get_list(dst);
>> -
>>       old = reservation_object_get_excl(dst);
>> -    new = reservation_object_get_excl(src);
>> -
>> -    dma_fence_get(new);
>>         preempt_disable();
>>       write_seqcount_begin(&dst->seq);
>
>
On Thu, Sep 07, 2017 at 09:13:32AM +0200, Christian König wrote:
> Ping? David can you take a look?
> 
> Alex is on vacation and that is a rather important bug fix.

Works better when you cc Gustavo/Maarten/Sumits/Chris I think, for
anything dma-buf review needing.
-Daniel

> 
> Thanks,
> Christian.
> 
> Am 04.09.2017 um 21:02 schrieb Christian König:
> > From: Christian König <christian.koenig@amd.com>
> > 
> > Stop requiring that the src reservation object is locked for this operation.
> > 
> > Signed-off-by: Christian König <christian.koenig@amd.com>
> > ---
> >   drivers/dma-buf/reservation.c | 56 ++++++++++++++++++++++++++++++++-----------
> >   1 file changed, 42 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
> > index dec3a81..b44d9d7 100644
> > --- a/drivers/dma-buf/reservation.c
> > +++ b/drivers/dma-buf/reservation.c
> > @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence);
> >   * @dst: the destination reservation object
> >   * @src: the source reservation object
> >   *
> > -* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
> > -* held.
> > +* Copy all fences from src to dst. dst-lock must be held.
> >   */
> >   int reservation_object_copy_fences(struct reservation_object *dst,
> >   				   struct reservation_object *src)
> > @@ -277,33 +276,62 @@ int reservation_object_copy_fences(struct reservation_object *dst,
> >   	size_t size;
> >   	unsigned i;
> > -	src_list = reservation_object_get_list(src);
> > +	rcu_read_lock();
> > +	src_list = rcu_dereference(src->fence);
> > +retry:
> >   	if (src_list) {
> > -		size = offsetof(typeof(*src_list),
> > -				shared[src_list->shared_count]);
> > +		unsigned shared_count = src_list->shared_count;
> > +
> > +		size = offsetof(typeof(*src_list), shared[shared_count]);
> > +		rcu_read_unlock();
> > +
> >   		dst_list = kmalloc(size, GFP_KERNEL);
> >   		if (!dst_list)
> >   			return -ENOMEM;
> > -		dst_list->shared_count = src_list->shared_count;
> > -		dst_list->shared_max = src_list->shared_count;
> > -		for (i = 0; i < src_list->shared_count; ++i)
> > -			dst_list->shared[i] =
> > -				dma_fence_get(src_list->shared[i]);
> > +		rcu_read_lock();
> > +		src_list = rcu_dereference(src->fence);
> > +		if (!src_list || src_list->shared_count > shared_count) {
> > +			kfree(dst_list);
> > +			goto retry;
> > +		}
> > +
> > +		dst_list->shared_count = 0;
> > +		dst_list->shared_max = shared_count;
> > +		for (i = 0; i < src_list->shared_count; ++i) {
> > +			struct dma_fence *fence;
> > +
> > +			fence = rcu_dereference(src_list->shared[i]);
> > +			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
> > +				     &fence->flags))
> > +				continue;
> > +
> > +			if (!dma_fence_get_rcu(fence)) {
> > +				kfree(dst_list);
> > +				src_list = rcu_dereference(src->fence);
> > +				goto retry;
> > +			}
> > +
> > +			if (dma_fence_is_signaled(fence)) {
> > +				dma_fence_put(fence);
> > +				continue;
> > +			}
> > +
> > +			dst_list->shared[dst_list->shared_count++] = fence;
> > +		}
> >   	} else {
> >   		dst_list = NULL;
> >   	}
> > +	new = dma_fence_get_rcu_safe(&src->fence_excl);
> > +	rcu_read_unlock();
> > +
> >   	kfree(dst->staged);
> >   	dst->staged = NULL;
> >   	src_list = reservation_object_get_list(dst);
> > -
> >   	old = reservation_object_get_excl(dst);
> > -	new = reservation_object_get_excl(src);
> > -
> > -	dma_fence_get(new);
> >   	preempt_disable();
> >   	write_seqcount_begin(&dst->seq);
> 
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Op 04-09-17 om 21:02 schreef Christian König:
> From: Christian König <christian.koenig@amd.com>
>
> Stop requiring that the src reservation object is locked for this operation.
>
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>  drivers/dma-buf/reservation.c | 56 ++++++++++++++++++++++++++++++++-----------
>  1 file changed, 42 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
> index dec3a81..b44d9d7 100644
> --- a/drivers/dma-buf/reservation.c
> +++ b/drivers/dma-buf/reservation.c
> @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence);
>  * @dst: the destination reservation object
>  * @src: the source reservation object
>  *
> -* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
> -* held.
> +* Copy all fences from src to dst. dst-lock must be held.
>  */
>  int reservation_object_copy_fences(struct reservation_object *dst,
>  				   struct reservation_object *src)
Could this be implemented using reservation_object_get_fences_rcu? You're essentially duplicating its functionality.

Cheers,
Maarten
Am 10.09.2017 um 09:30 schrieb Maarten Lankhorst:
> Op 04-09-17 om 21:02 schreef Christian König:
>> From: Christian König <christian.koenig@amd.com>
>>
>> Stop requiring that the src reservation object is locked for this operation.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
>> ---
>>   drivers/dma-buf/reservation.c | 56 ++++++++++++++++++++++++++++++++-----------
>>   1 file changed, 42 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
>> index dec3a81..b44d9d7 100644
>> --- a/drivers/dma-buf/reservation.c
>> +++ b/drivers/dma-buf/reservation.c
>> @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence);
>>   * @dst: the destination reservation object
>>   * @src: the source reservation object
>>   *
>> -* Copy all fences from src to dst. Both src->lock as well as dst-lock must be
>> -* held.
>> +* Copy all fences from src to dst. dst-lock must be held.
>>   */
>>   int reservation_object_copy_fences(struct reservation_object *dst,
>>   				   struct reservation_object *src)
> Could this be implemented using reservation_object_get_fences_rcu? You're essentially duplicating its functionality.

I've considered this as well, but reservation_object_get_fences_rcu() 
returns an array and here we need an reservation_object_list.

Regards,
Christian.

>
> Cheers,
> Maarten
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx