On Mon, Aug 29, 2016 at 08:08:30AM +0100, Chris Wilson wrote:
> In order to be completely generic, we have to double check the read
> seqlock after acquiring a reference to the fence. If the driver is
> allocating fences from a SLAB_DESTROY_BY_RCU, or similar freelist, then
> within an RCU grace period a fence may be freed and reallocated. The RCU
> read side critical section does not prevent this reallocation, instead
> we have to inspect the reservation's seqlock to double check if the
> fences have been reassigned as we were acquiring our reference.
> 
> Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
> Cc: Daniel Vetter <daniel.vet...@ffwll.ch>
> Cc: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
> Cc: Christian König <christian.koe...@amd.com>
> Cc: Alex Deucher <alexander.deuc...@amd.com>
> Cc: Sumit Semwal <sumit.sem...@linaro.org>
> Cc: linux-me...@vger.kernel.org
> Cc: dri-de...@lists.freedesktop.org
> Cc: linaro-mm-...@lists.linaro.org
> ---
>  drivers/dma-buf/reservation.c | 71 
> +++++++++++++++++++------------------------
>  1 file changed, 31 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
> index 723d8af988e5..10fd441dd4ed 100644
> --- a/drivers/dma-buf/reservation.c
> +++ b/drivers/dma-buf/reservation.c
> @@ -280,18 +280,24 @@ int reservation_object_get_fences_rcu(struct 
> reservation_object *obj,
>                                     unsigned *pshared_count,
>                                     struct fence ***pshared)
>  {
> -     unsigned shared_count = 0;
> -     unsigned retry = 1;
> -     struct fence **shared = NULL, *fence_excl = NULL;
> -     int ret = 0;
> +     struct fence **shared = NULL;
> +     struct fence *fence_excl;
> +     unsigned shared_count;
> +     int ret = 1;

Personally I'd go with ret = -EBUSY here, but that's a bikeshed.

Reviewed-by: Daniel Vetter <daniel.vet...@ffwll.ch>
>  
> -     while (retry) {
> +     do {
>               struct reservation_object_list *fobj;
>               unsigned seq;
> +             unsigned i;
>  
> -             seq = read_seqcount_begin(&obj->seq);
> +             shared_count = i = 0;
>  
>               rcu_read_lock();
> +             seq = read_seqcount_begin(&obj->seq);
> +
> +             fence_excl = rcu_dereference(obj->fence_excl);
> +             if (fence_excl && !fence_get_rcu(fence_excl))
> +                     goto unlock;
>  
>               fobj = rcu_dereference(obj->fence);
>               if (fobj) {
> @@ -309,52 +315,37 @@ int reservation_object_get_fences_rcu(struct 
> reservation_object *obj,
>                               }
>  
>                               ret = -ENOMEM;
> -                             shared_count = 0;
>                               break;
>                       }
>                       shared = nshared;
> -                     memcpy(shared, fobj->shared, sz);
>                       shared_count = fobj->shared_count;
> -             } else
> -                     shared_count = 0;
> -             fence_excl = rcu_dereference(obj->fence_excl);
> -
> -             retry = read_seqcount_retry(&obj->seq, seq);
> -             if (retry)
> -                     goto unlock;
> -
> -             if (!fence_excl || fence_get_rcu(fence_excl)) {
> -                     unsigned i;
>  
>                       for (i = 0; i < shared_count; ++i) {
> -                             if (fence_get_rcu(shared[i]))
> -                                     continue;
> -
> -                             /* uh oh, refcount failed, abort and retry */
> -                             while (i--)
> -                                     fence_put(shared[i]);
> -
> -                             if (fence_excl) {
> -                                     fence_put(fence_excl);
> -                                     fence_excl = NULL;
> -                             }
> -
> -                             retry = 1;
> -                             break;
> +                             shared[i] = rcu_dereference(fobj->shared[i]);
> +                             if (!fence_get_rcu(shared[i]))
> +                                     break;
>                       }
> -             } else
> -                     retry = 1;
> +             }
> +
> +             if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
> +                     while (i--)
> +                             fence_put(shared[i]);
> +                     fence_put(fence_excl);
> +                     goto unlock;
> +             }
>  
> +             ret = 0;
>  unlock:
>               rcu_read_unlock();
> -     }
> -     *pshared_count = shared_count;
> -     if (shared_count)
> -             *pshared = shared;
> -     else {
> -             *pshared = NULL;
> +     } while (ret);
> +
> +     if (!shared_count) {
>               kfree(shared);
> +             shared = NULL;
>       }
> +
> +     *pshared_count = shared_count;
> +     *pshared = shared;
>       *pfence_excl = fence_excl;
>  
>       return ret;
> -- 
> 2.9.3
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to