<div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jan 17, 2022 at 5:26 AM Christian König <<a href="mailto:ckoenig.leichtzumerken@gmail.com">ckoenig.leichtzumerken@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Am 14.01.22 um 17:31 schrieb Daniel Vetter:<br>
> On Mon, Jan 03, 2022 at 12:13:41PM +0100, Christian König wrote:<br>
>> Am 22.12.21 um 22:21 schrieb Daniel Vetter:<br>
>>> On Tue, Dec 07, 2021 at 01:33:51PM +0100, Christian König wrote:<br>
>>>> Add a function to simplify getting a single fence for all the fences in<br>
>>>> the dma_resv object.<br>
>>>><br>
>>>> v2: fix ref leak in error handling<br>
>>>><br>
>>>> Signed-off-by: Christian König <<a href="mailto:christian.koenig@amd.com" target="_blank">christian.koenig@amd.com</a>><br>
>>>> ---<br>
>>>>    drivers/dma-buf/dma-resv.c | 52 ++++++++++++++++++++++++++++++++++++++<br>
>>>>    include/linux/dma-resv.h   |  2 ++<br>
>>>>    2 files changed, 54 insertions(+)<br>
>>>><br>
>>>> diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c<br>
>>>> index 480c305554a1..694716a3d66d 100644<br>
>>>> --- a/drivers/dma-buf/dma-resv.c<br>
>>>> +++ b/drivers/dma-buf/dma-resv.c<br>
>>>> @@ -34,6 +34,7 @@<br>
>>>>     */<br>
>>>>    #include <linux/dma-resv.h><br>
>>>> +#include <linux/dma-fence-array.h><br>
>>>>    #include <linux/export.h><br>
>>>>    #include <linux/mm.h><br>
>>>>    #include <linux/sched/mm.h><br>
>>>> @@ -657,6 +658,57 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,<br>
>>>>    }<br>
>>>>    EXPORT_SYMBOL_GPL(dma_resv_get_fences);<br>
>>>> +/**<br>
>>>> + * dma_resv_get_singleton - Get a single fence for all the fences<br>
>>>> + * @obj: the reservation object<br>
>>>> + * @write: true if we should return all fences<br>
>>>> + * @fence: the resulting fence<br>
>>>> + *<br>
>>>> + * Get a single fence representing all the fences inside the resv object.<br>
>>>> + * Returns either 0 for success or -ENOMEM.<br>
>>>> + *<br>
>>>> + * Warning: This can't be used like this when adding the fence back to the resv<br>
>>>> + * object since that can lead to stack corruption when finalizing the<br>
>>>> + * dma_fence_array.<br>
>>> Uh I don't get this one? I thought the only problem with nested fences is<br>
>>> the signalling recursion, which we work around with the irq_work?<br>
>> Nope, the main problem is finalizing the dma_fence_array.<br>
>><br>
>> E.g. imagine that you build up a chain of dma_fence_array objects like this:<br>
>> a<-b<-c<-d<-e<-f.....<br>
>><br>
>> With each one referencing the previous dma_fence_array and then you call<br>
>> dma_fence_put() on the last one. That in turn will cause calling<br>
>> dma_fence_put() on the previous one, which in turn will cause<br>
>> dma_fence_put() one the one before the previous one etc....<br>
>><br>
>> In other words you recurse because each dma_fence_array instance drops the<br>
>> last reference of it's predecessor.<br>
>><br>
>> What we could do is to delegate dropping the reference to the containing<br>
>> fences in a dma_fence_array as well, but that would require some changes to<br>
>> the irq_work_run_list() function to be halve way efficient.o<br>
>><br>
>>> Also if there's really an issue with dma_fence_array fences, then that<br>
>>> warning should be on the dma_resv kerneldoc, not somewhere hidden like<br>
>>> this. And finally I really don't see what can go wrong, sure we'll end up<br>
>>> with the same fence once in the dma_resv_list and then once more in the<br>
>>> fence array. But they're all refcounted, so really shouldn't matter.<br>
>>><br>
>>> The code itself looks correct, but me not understanding what even goes<br>
>>> wrong here freaks me out a bit.<br>
>> Yeah, IIRC we already discussed that with Jason in length as well.<br>
>><br>
>> Essentially what you can't do is to put a dma_fence_array into another<br>
>> dma_fence_array without causing issues.<br>
>><br>
>> So I think we should maybe just add a WARN_ON() into dma_fence_array_init()<br>
>> to make sure that this never happens.<br>
> Yeah I think this would be much clearer instead of sprinkling half the<br>
> story as a scary&confusing warning over all kinds of users which<br>
> internally use dma fence arrays.<br></blockquote><div><br></div><div>Agreed.  WARN_ON in dma_fence_array_init() would be better for everyone, I think.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> And then if it goes boom I guess we could fix it internally in<br>
> dma_fence_array_init by flattening fences down again. But only if actually<br>
> needed.<br>
<br>
Ok, going to do that first then.<br></blockquote><div><br></div><div>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.</div><div><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
> What confused me is why dma_resv is special, and from your reply it sounds<br>
> like it really isn't.<br>
<br>
Well, it isn't special in any way. It's just something very obvious <br>
which could go wrong.<br>
<br>
Regards,<br>
Christian.<br>
<br>
> -Daniel<br>
><br>
><br>
>> Regards,<br>
>> Christian.<br>
>><br>
>>> I guess something to figure out next year, I kinda hoped I could squeeze a<br>
>>> review in before I disappear :-/<br>
>>> -Daniel<br>
>>><br>
>>>> + */<br>
>>>> +int dma_resv_get_singleton(struct dma_resv *obj, bool write,<br>
>>>> +                     struct dma_fence **fence)<br>
>>>> +{<br>
>>>> +  struct dma_fence_array *array;<br>
>>>> +  struct dma_fence **fences;<br>
>>>> +  unsigned count;<br>
>>>> +  int r;<br>
>>>> +<br>
>>>> +  r = dma_resv_get_fences(obj, write, &count, &fences);<br>
>>>> +        if (r)<br>
>>>> +          return r;<br>
>>>> +<br>
>>>> +  if (count == 0) {<br>
>>>> +          *fence = NULL;<br>
>>>> +          return 0;<br>
>>>> +  }<br>
>>>> +<br>
>>>> +  if (count == 1) {<br>
>>>> +          *fence = fences[0];<br>
>>>> +          kfree(fences);<br>
>>>> +          return 0;<br>
>>>> +  }<br>
>>>> +<br>
>>>> +  array = dma_fence_array_create(count, fences,<br>
>>>> +                                 dma_fence_context_alloc(1),<br>
>>>> +                                 1, false);<br>
>>>> +  if (!array) {<br>
>>>> +          while (count--)<br>
>>>> +                  dma_fence_put(fences[count]);<br>
>>>> +          kfree(fences);<br>
>>>> +          return -ENOMEM;<br>
>>>> +  }<br>
>>>> +<br>
>>>> +  *fence = &array->base;<br>
>>>> +  return 0;<br>
>>>> +}<br>
>>>> +EXPORT_SYMBOL_GPL(dma_resv_get_singleton);<br>
>>>> +<br>
>>>>    /**<br>
>>>>     * dma_resv_wait_timeout - Wait on reservation's objects<br>
>>>>     * shared and/or exclusive fences.<br>
>>>> diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h<br>
>>>> index fa2002939b19..cdfbbda6f600 100644<br>
>>>> --- a/include/linux/dma-resv.h<br>
>>>> +++ b/include/linux/dma-resv.h<br>
>>>> @@ -438,6 +438,8 @@ void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,<br>
>>>>    void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence);<br>
>>>>    int dma_resv_get_fences(struct dma_resv *obj, bool write,<br>
>>>>                            unsigned int *num_fences, struct dma_fence ***fences);<br>
>>>> +int dma_resv_get_singleton(struct dma_resv *obj, bool write,<br>
>>>> +                     struct dma_fence **fence);<br>
>>>>    int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src);<br>
>>>>    long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,<br>
>>>>                               unsigned long timeout);<br>
>>>> -- <br>
>>>> 2.25.1<br>
>>>><br>
<br>
</blockquote></div></div>