[PATCH 04/24] dma-buf: add dma_resv_get_singleton v2

Jason Ekstrand jason at jlekstrand.net
Wed Mar 2 17:39:36 UTC 2022


On Mon, Jan 17, 2022 at 5:26 AM Christian König <
ckoenig.leichtzumerken at gmail.com> wrote:

> Am 14.01.22 um 17:31 schrieb Daniel Vetter:
> > On Mon, Jan 03, 2022 at 12:13:41PM +0100, Christian König wrote:
> >> Am 22.12.21 um 22:21 schrieb Daniel Vetter:
> >>> On Tue, Dec 07, 2021 at 01:33:51PM +0100, Christian König wrote:
> >>>> Add a function to simplify getting a single fence for all the fences
> in
> >>>> the dma_resv object.
> >>>>
> >>>> v2: fix ref leak in error handling
> >>>>
> >>>> Signed-off-by: Christian König <christian.koenig at amd.com>
> >>>> ---
> >>>>    drivers/dma-buf/dma-resv.c | 52
> ++++++++++++++++++++++++++++++++++++++
> >>>>    include/linux/dma-resv.h   |  2 ++
> >>>>    2 files changed, 54 insertions(+)
> >>>>
> >>>> diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
> >>>> index 480c305554a1..694716a3d66d 100644
> >>>> --- a/drivers/dma-buf/dma-resv.c
> >>>> +++ b/drivers/dma-buf/dma-resv.c
> >>>> @@ -34,6 +34,7 @@
> >>>>     */
> >>>>    #include <linux/dma-resv.h>
> >>>> +#include <linux/dma-fence-array.h>
> >>>>    #include <linux/export.h>
> >>>>    #include <linux/mm.h>
> >>>>    #include <linux/sched/mm.h>
> >>>> @@ -657,6 +658,57 @@ int dma_resv_get_fences(struct dma_resv *obj,
> bool write,
> >>>>    }
> >>>>    EXPORT_SYMBOL_GPL(dma_resv_get_fences);
> >>>> +/**
> >>>> + * dma_resv_get_singleton - Get a single fence for all the fences
> >>>> + * @obj: the reservation object
> >>>> + * @write: true if we should return all fences
> >>>> + * @fence: the resulting fence
> >>>> + *
> >>>> + * Get a single fence representing all the fences inside the resv
> object.
> >>>> + * Returns either 0 for success or -ENOMEM.
> >>>> + *
> >>>> + * Warning: This can't be used like this when adding the fence back
> to the resv
> >>>> + * object since that can lead to stack corruption when finalizing the
> >>>> + * dma_fence_array.
> >>> Uh I don't get this one? I thought the only problem with nested fences
> is
> >>> the signalling recursion, which we work around with the irq_work?
> >> Nope, the main problem is finalizing the dma_fence_array.
> >>
> >> E.g. imagine that you build up a chain of dma_fence_array objects like
> this:
> >> a<-b<-c<-d<-e<-f.....
> >>
> >> With each one referencing the previous dma_fence_array and then you call
> >> dma_fence_put() on the last one. That in turn will cause calling
> >> dma_fence_put() on the previous one, which in turn will cause
> >> dma_fence_put() one the one before the previous one etc....
> >>
> >> In other words you recurse because each dma_fence_array instance drops
> the
> >> last reference of it's predecessor.
> >>
> >> What we could do is to delegate dropping the reference to the containing
> >> fences in a dma_fence_array as well, but that would require some
> changes to
> >> the irq_work_run_list() function to be halve way efficient.o
> >>
> >>> Also if there's really an issue with dma_fence_array fences, then that
> >>> warning should be on the dma_resv kerneldoc, not somewhere hidden like
> >>> this. And finally I really don't see what can go wrong, sure we'll end
> up
> >>> with the same fence once in the dma_resv_list and then once more in the
> >>> fence array. But they're all refcounted, so really shouldn't matter.
> >>>
> >>> The code itself looks correct, but me not understanding what even goes
> >>> wrong here freaks me out a bit.
> >> Yeah, IIRC we already discussed that with Jason in length as well.
> >>
> >> Essentially what you can't do is to put a dma_fence_array into another
> >> dma_fence_array without causing issues.
> >>
> >> So I think we should maybe just add a WARN_ON() into
> dma_fence_array_init()
> >> to make sure that this never happens.
> > Yeah I think this would be much clearer instead of sprinkling half the
> > story as a scary&confusing warning over all kinds of users which
> > internally use dma fence arrays.
>

Agreed.  WARN_ON in dma_fence_array_init() would be better for everyone, I
think.


> > And then if it goes boom I guess we could fix it internally in
> > dma_fence_array_init by flattening fences down again. But only if
> actually
> > needed.
>
> Ok, going to do that first then.
>

Sounds good.  This patch looks pretty reasonable to me.  I do have a bit of
a concern with how it's being used to replace calls to
dma_resv_excl_fence() in later patches, though.  In particular, this may
allocate memory whereas dma_resv_excl_fence() does not so we need to be
really careful in each of the replacements that doing so is safe.  That's a
job for the per-driver reviewers but I thought I'd drop a note here so
we're all aware of and watching for it.

--Jason


> >
> > What confused me is why dma_resv is special, and from your reply it
> sounds
> > like it really isn't.
>
> Well, it isn't special in any way. It's just something very obvious
> which could go wrong.
>
> Regards,
> Christian.
>
> > -Daniel
> >
> >
> >> Regards,
> >> Christian.
> >>
> >>> I guess something to figure out next year, I kinda hoped I could
> squeeze a
> >>> review in before I disappear :-/
> >>> -Daniel
> >>>
> >>>> + */
> >>>> +int dma_resv_get_singleton(struct dma_resv *obj, bool write,
> >>>> +                     struct dma_fence **fence)
> >>>> +{
> >>>> +  struct dma_fence_array *array;
> >>>> +  struct dma_fence **fences;
> >>>> +  unsigned count;
> >>>> +  int r;
> >>>> +
> >>>> +  r = dma_resv_get_fences(obj, write, &count, &fences);
> >>>> +        if (r)
> >>>> +          return r;
> >>>> +
> >>>> +  if (count == 0) {
> >>>> +          *fence = NULL;
> >>>> +          return 0;
> >>>> +  }
> >>>> +
> >>>> +  if (count == 1) {
> >>>> +          *fence = fences[0];
> >>>> +          kfree(fences);
> >>>> +          return 0;
> >>>> +  }
> >>>> +
> >>>> +  array = dma_fence_array_create(count, fences,
> >>>> +                                 dma_fence_context_alloc(1),
> >>>> +                                 1, false);
> >>>> +  if (!array) {
> >>>> +          while (count--)
> >>>> +                  dma_fence_put(fences[count]);
> >>>> +          kfree(fences);
> >>>> +          return -ENOMEM;
> >>>> +  }
> >>>> +
> >>>> +  *fence = &array->base;
> >>>> +  return 0;
> >>>> +}
> >>>> +EXPORT_SYMBOL_GPL(dma_resv_get_singleton);
> >>>> +
> >>>>    /**
> >>>>     * dma_resv_wait_timeout - Wait on reservation's objects
> >>>>     * shared and/or exclusive fences.
> >>>> diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
> >>>> index fa2002939b19..cdfbbda6f600 100644
> >>>> --- a/include/linux/dma-resv.h
> >>>> +++ b/include/linux/dma-resv.h
> >>>> @@ -438,6 +438,8 @@ void dma_resv_replace_fences(struct dma_resv
> *obj, uint64_t context,
> >>>>    void dma_resv_add_excl_fence(struct dma_resv *obj, struct
> dma_fence *fence);
> >>>>    int dma_resv_get_fences(struct dma_resv *obj, bool write,
> >>>>                            unsigned int *num_fences, struct dma_fence
> ***fences);
> >>>> +int dma_resv_get_singleton(struct dma_resv *obj, bool write,
> >>>> +                     struct dma_fence **fence);
> >>>>    int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv
> *src);
> >>>>    long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all,
> bool intr,
> >>>>                               unsigned long timeout);
> >>>> --
> >>>> 2.25.1
> >>>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20220302/c1ca9ac1/attachment-0001.htm>


More information about the dri-devel mailing list