summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuofei Ma <ruofeim@google.com>2022-04-25 14:40:43 -0700
committerRuofei Ma <ruofeim@google.com>2022-04-26 20:14:37 +0000
commit92c4f3604ce672275fe17de6fd988bf9c32140f1 (patch)
treee052c5255279e307d52b5b420c8029ebf695eb87
parent5036de9318c5ebe18636fc78b1c9103e28024db4 (diff)
downloadgchips-92c4f3604ce672275fe17de6fd988bf9c32140f1.tar.gz
Fix a potential thread dead lock issue
When bigo_worker_thread does kref_put on an instance, if the refcount changes from 1 to 0, bigo_close will be invoked. If this is the last instance, on_last_inst_close will be invoked and it will wait for bigo_worker_thread to exit. It is a dead loop that bigo_worker_thread is waiting for itself to exit. The fix is to make sure the worker thread is stopped before closing the last instance. Bug: 229580907 Signed-off-by: Ruofei Ma <ruofeim@google.com> Change-Id: I0950a07e072c6d10ab76389bd10ff697c3d1fc79
-rw-r--r--bigo.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/bigo.c b/bigo.c
index 8895c81..5b613bf 100644
--- a/bigo.c
+++ b/bigo.c
@@ -108,16 +108,11 @@ exit:
static inline void on_last_inst_close(struct bigo_core *core)
{
- int rc;
#if IS_ENABLED(CONFIG_PM)
if (pm_runtime_put_sync_suspend(core->dev))
pr_warn("failed to suspend\n");
#endif
bigo_pt_client_disable(core);
-
- rc = kthread_stop(core->worker_thread);
- if(rc)
- pr_err("failed to stop worker thread rc = %d\n", rc);
}
static inline int bigo_count_inst(struct bigo_core *core)
@@ -199,13 +194,8 @@ static void bigo_close(struct kref *ref)
return;
}
bigo_unmap_all(inst);
- mutex_lock(&core->lock);
- list_del(&inst->list);
kfree(inst->job.regs);
kfree(inst);
- if (list_empty(&core->instances))
- on_last_inst_close(core);
- mutex_unlock(&core->lock);
bigo_update_qos(core);
pr_info("closed instance\n");
}
@@ -213,10 +203,20 @@ static void bigo_close(struct kref *ref)
static int bigo_release(struct inode *inode, struct file *file)
{
struct bigo_inst *inst = file->private_data;
+ struct bigo_core *core = inst->core;
- if (!inst)
+ if (!inst || !core)
return -EINVAL;
+ mutex_lock(&core->lock);
+ list_del(&inst->list);
+ if (list_empty(&core->instances))
+ {
+ kthread_stop(core->worker_thread);
+ on_last_inst_close(core);
+ }
+ mutex_unlock(&core->lock);
+
kref_put(&inst->refcount, bigo_close);
return 0;
}