diff options
author | Yong Ding <yongding@codeaurora.org> | 2018-11-01 15:59:49 +0800 |
---|---|---|
committer | Yong Ding <yongding@codeaurora.org> | 2018-11-01 17:37:29 +0800 |
commit | cf41f3e0d3c2e5025f401a61cfaa7a79d27cc586 (patch) | |
tree | 5acba8bc863f07e48e501022e51bf5a5e3aafec8 /drivers/soc/qcom/hab | |
parent | 67b38b0496484ac2b862c9514cff40b82a92a622 (diff) |
soc: qcom: hab: refine hab virtual channel's resource free
Whenever a vchan is locally closed in hab_vchan_close or hab_free,
4 actions should be taken immediately, including,
- remove it from the local hab context
- mark its local closed flag
- notify remote side and unblock local blocking calls over it
- decrease the refcnt on the vchan
Change-Id: I3fbde9464f6405b6dadac248768a5fd857a29128
Signed-off-by: Yong Ding <yongding@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/hab')
-rw-r--r-- | drivers/soc/qcom/hab/hab.c | 33 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_vchan.c | 40 |
2 files changed, 17 insertions, 56 deletions
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index 7d53e6162172..24461d2c957b 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -720,11 +720,18 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) write_lock(&ctx->ctx_lock); list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { if (vchan->id == vcid) { + /* local close starts */ vchan->closed = 1; - write_unlock(&ctx->ctx_lock); + + /* vchan is not in this ctx anymore */ + list_del(&vchan->node); + ctx->vcnt--; + pr_debug("vcid %x remote %x session %d refcnt %d\n", vchan->id, vchan->otherend_id, vchan->session_id, get_refcnt(vchan->refcount)); + + write_unlock(&ctx->ctx_lock); /* unblocking blocked in-calls */ hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ @@ -1069,28 +1076,14 @@ static int hab_release(struct inode *inodep, struct file *filep) write_lock(&ctx->ctx_lock); /* notify remote side on vchan closing */ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { - list_del(&vchan->node); /* vchan is not in this ctx anymore */ + /* local close starts */ + vchan->closed = 1; - if (!vchan->closed) { /* locally hasn't closed yet */ - if (!kref_get_unless_zero(&vchan->refcount)) { - pr_err("vchan %x %x refcnt %d mismanaged closed %d remote closed %d\n", - vchan->id, - vchan->otherend_id, - get_refcnt(vchan->refcount), - vchan->closed, vchan->otherend_closed); - continue; /* vchan is already being freed */ - } else { - write_unlock(&ctx->ctx_lock); - hab_vchan_stop_notify(vchan); - /* put for notify. shouldn't cause free */ - hab_vchan_put(vchan); - write_lock(&ctx->ctx_lock); - } - } else - continue; + list_del(&vchan->node); /* vchan is not in this ctx anymore */ + ctx->vcnt--; - /* for the missing local vchan close */ write_unlock(&ctx->ctx_lock); + hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); } diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index 770c6ba3dadd..a95d6c7451c9 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -85,9 +85,6 @@ hab_vchan_free(struct kref *ref) } spin_unlock_bh(&vchan->rx_lock); - /* the release vchan from ctx was done earlier in vchan close() */ - hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */ - /* release vchan from pchan. no more msg for this vchan */ write_lock_bh(&pchan->vchans_lock); list_for_each_entry_safe(vc, vc_tmp, &pchan->vchannels, pnode) { @@ -100,6 +97,9 @@ hab_vchan_free(struct kref *ref) } write_unlock_bh(&pchan->vchans_lock); + /* the release vchan from ctx was done earlier in vchan close() */ + hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */ + /* release idr at the last so same idr will not be used early */ spin_lock_bh(&pchan->vid_lock); idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id)); @@ -274,42 +274,10 @@ int hab_vchan_find_domid(struct virtual_channel *vchan) return vchan ? vchan->pchan->dom_id : -1; } -/* this sould be only called once after refcnt is zero */ -static void hab_vchan_schedule_free(struct kref *ref) -{ - struct virtual_channel *vchanin = - container_of(ref, struct virtual_channel, refcount); - struct uhab_context *ctx = vchanin->ctx; - struct virtual_channel *vchan, *tmp; - int bnotify = 0; - - /* - * similar logic is in ctx free. if ctx free runs first, - * this is skipped - */ - write_lock_bh(&ctx->ctx_lock); - list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { - if (vchan == vchanin) { - pr_debug("vchan free refcnt = %d\n", - get_refcnt(vchan->refcount)); - ctx->vcnt--; - list_del(&vchan->node); - bnotify = 1; - break; - } - } - write_unlock_bh(&ctx->ctx_lock); - - if (bnotify) - hab_vchan_stop_notify(vchan); - - hab_vchan_free(ref); -} - void hab_vchan_put(struct virtual_channel *vchan) { if (vchan) - kref_put(&vchan->refcount, hab_vchan_schedule_free); + kref_put(&vchan->refcount, hab_vchan_free); } int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids, |