diff options
author | Ruofei Ma <ruofeim@google.com> | 2022-04-25 14:40:43 -0700 |
---|---|---|
committer | Ruofei Ma <ruofeim@google.com> | 2022-04-26 20:14:37 +0000 |
commit | 92c4f3604ce672275fe17de6fd988bf9c32140f1 (patch) | |
tree | e052c5255279e307d52b5b420c8029ebf695eb87 | |
parent | 5036de9318c5ebe18636fc78b1c9103e28024db4 (diff) | |
download | gchips-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.c | 22 |
1 files changed, 11 insertions, 11 deletions
@@ -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; } |