aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-08-04 23:50:17 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2019-08-04 23:50:17 -0700
commit8ea9ac46e6a737e1586683da03daa0bb639389fd (patch)
treecbcebeeabcc49ba4fbef844a45cb4c0e87fb52a5
parent304503b0c7ee3c56b6fe0f8bb0bfa7695aab14a2 (diff)
parent56ed6c6274a95aab36894570481f351d3fb06e67 (diff)
Merge "msm: kgsl: Fix race condition between drawobj and context destroy"LA.UM.7.9.r1-08000-sm6150.0
-rw-r--r--drivers/gpu/msm/kgsl_drawobj.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index 7e89ac16eeb6..ee75a204635c 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -223,8 +223,13 @@ static void drawobj_sync_func(struct kgsl_device *device,
trace_syncpoint_timestamp_expire(event->syncobj,
event->context, event->timestamp);
- drawobj_sync_expire(device, event);
- kgsl_context_put(event->context);
+ /*
+ * Put down the context ref count only if
+ * this thread successfully clears the pending bit mask.
+ */
+ if (drawobj_sync_expire(device, event))
+ kgsl_context_put(event->context);
+
kgsl_drawobj_put(&event->syncobj->base);
}
@@ -254,33 +259,24 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj)
static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
{
struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
- unsigned long pending = 0;
unsigned int i;
/* Zap the canary timer */
del_timer_sync(&syncobj->timer);
/*
- * Copy off the pending list and clear each pending event atomically -
- * this will render any subsequent asynchronous callback harmless.
- * This marks each event for deletion. If any pending fence callbacks
- * run between now and the actual cancel, the associated structures
- * are kfreed only in the cancel call.
- */
- for_each_set_bit(i, &syncobj->pending, KGSL_MAX_SYNCPOINTS) {
- if (test_and_clear_bit(i, &syncobj->pending))
- __set_bit(i, &pending);
- }
-
- /*
* Clear all pending events - this will render any subsequent async
* callbacks harmless
*/
for (i = 0; i < syncobj->numsyncs; i++) {
struct kgsl_drawobj_sync_event *event = &syncobj->synclist[i];
- /* Don't do anything if the event has already expired */
- if (!test_bit(i, &pending))
+ /*
+ * Don't do anything if the event has already expired.
+ * If this thread clears the pending bit mask then it is
+ * responsible for doing context put.
+ */
+ if (!test_and_clear_bit(i, &syncobj->pending))
continue;
switch (event->type) {
@@ -288,6 +284,11 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
kgsl_cancel_event(drawobj->device,
&event->context->events, event->timestamp,
drawobj_sync_func, event);
+ /*
+ * Do context put here to make sure the context is alive
+ * till this thread cancels kgsl event.
+ */
+ kgsl_context_put(event->context);
break;
case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
kgsl_sync_fence_async_cancel(event->handle);
@@ -300,7 +301,7 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj)
* If we cancelled an event, there's a good chance that the context is
* on a dispatcher queue, so schedule to get it removed.
*/
- if (!bitmap_empty(&pending, KGSL_MAX_SYNCPOINTS) &&
+ if (!bitmap_empty(&syncobj->pending, KGSL_MAX_SYNCPOINTS) &&
drawobj->device->ftbl->drawctxt_sched)
drawobj->device->ftbl->drawctxt_sched(drawobj->device,
drawobj->context);