Re: [PATCH] drm: fix deadlock of syncobj

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 19.10.18 um 14:19 schrieb zhoucm1:


On 2018年10月19日 20:08, Koenig, Christian wrote:
Am 19.10.18 um 14:01 schrieb zhoucm1:

On 2018年10月19日 19:26, zhoucm1 wrote:

On 2018年10月19日 18:50, Chris Wilson wrote:
Quoting Chunming Zhou (2018-10-19 11:26:41)
Signed-off-by: Chunming Zhou <david1.zhou@xxxxxxx>
Cc: Daniel Vetter <daniel@xxxxxxxx>
Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx>
Cc: Christian König <christian.koenig@xxxxxxx>
---
   drivers/gpu/drm/drm_syncobj.c | 7 +++++--
   1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c
b/drivers/gpu/drm/drm_syncobj.c
index 57bf6006394d..2f3c14cb5156 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -344,13 +344,16 @@ void drm_syncobj_replace_fence(struct
drm_syncobj *syncobj,
          drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
          if (fence) {
                  struct drm_syncobj_cb *cur, *tmp;
+               struct list_head cb_list;
+               INIT_LIST_HEAD(&cb_list);
LIST_HEAD(cb_list); // does both in one

spin_lock(&syncobj->lock);
-               list_for_each_entry_safe(cur, tmp,
&syncobj->cb_list, node) {
+ list_splice_init(&syncobj->cb_list, &cb_list);
Steal the snapshot of the list under the lock, ok.

+ spin_unlock(&syncobj->lock);
+               list_for_each_entry_safe(cur, tmp, &cb_list, node) {
list_del_init(&cur->node);
Races against external caller of drm_syncobj_remove_callback().
However,
it looks like that race is just fine, but we don't guard against the
struct drm_syncobj_cb itself being freed, leading to all sort of fun
for
an interrupted drm_syncobj_array_wait_timeout.
Thanks quick review, I will use "while (!list_empty()) { e =
list_first_entry(); list_del(e)" to avoid deadlock.
this still cannot resolve freeing problem,  do you mind I change
spinlock to mutex?
How does that help?

What you could do is to merge the array of fences into the beginning of
the signal_pt, e.g. something like this:

struct drm_syncobj_signal_pt {
          struct dma_fence fences[2];
          struct dma_fence_array *fence_array;
          u64    value;
          struct list_head list;
};

This way the drm_syncobj_signal_pt is freed when the fence_array is
freed. That should be sufficient if we correctly reference count the
fence_array.
I'm not sure what problem you said, the deadlock reason is :
Cb func will call drm_syncobj_search_fence, which will need to grab the lock, otherwise deadlock.

But when we steal list or use "while (!list_empty()) { e = list_first_entry(); list_del(e)", both will encounter another freeing problem, that is syncobj_cb could be freed when wait timeout.

If we change to use mutex, then we can move lock inside of _search_fence out.

another way is we add a separate spinlock for signal_pt_list, not share one lock with cb_list.

Well of hand that sounds like the cleanest approach to me.

Christian.


Regards,
David

Christian.

Thanks,
David Zhou
will send v2 in one minute.

Regards,
David Zhou
That kfree seems to undermine the validity of stealing the list.
-Chris

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux