Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89520007 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: hab: refine hab virtual channel's resource free"

parents e8e7047a cf41f3e0
Loading
Loading
Loading
Loading
+21 −41
Original line number Diff line number Diff line
@@ -209,14 +209,15 @@ void hab_ctx_free(struct kref *ref)
 * the local ioctl access based on ctx
 */
struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
		struct uhab_context *ctx)
		struct uhab_context *ctx, int ignore_remote)
{
	struct virtual_channel *vchan;

	read_lock(&ctx->ctx_lock);
	list_for_each_entry(vchan, &ctx->vchannels, node) {
		if (vcid == vchan->id) {
			if (vchan->otherend_closed || vchan->closed ||
			if ((ignore_remote ? 0 : vchan->otherend_closed) ||
				vchan->closed ||
				!kref_get_unless_zero(&vchan->refcount)) {
				pr_debug("failed to inc vcid %x remote %x session %d refcnt %d close_flg remote %d local %d\n",
					vchan->id, vchan->otherend_id,
@@ -550,7 +551,7 @@ long hab_vchan_send(struct uhab_context *ctx,
		return -EINVAL;
	}

	vchan = hab_get_vchan_fromvcid(vcid, ctx);
	vchan = hab_get_vchan_fromvcid(vcid, ctx, 0);
	if (!vchan || vchan->otherend_closed) {
		ret = -ENODEV;
		goto err;
@@ -597,7 +598,7 @@ int hab_vchan_recv(struct uhab_context *ctx,
	int ret = 0;
	int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING;

	vchan = hab_get_vchan_fromvcid(vcid, ctx);
	vchan = hab_get_vchan_fromvcid(vcid, ctx, 1);
	if (!vchan) {
		pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx);
		return -ENODEV;
@@ -719,24 +720,20 @@ 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) {
			write_unlock(&ctx->ctx_lock);
			/* local close starts */
			vchan->closed = 1;

			/* 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));
			/*
			 * only set when vc close is called locally by user
			 * explicity. Used to block remote msg. if forked once
			 * before, this local close is skipped due to child
			 * usage. if forked but not closed locally, the local
			 * context could NOT be closed, vchan can be prolonged
			 * by arrived remote msgs
			 */
			if (vchan->forked)
				vchan->forked = 0;
			else {
				vchan->closed = 1;

			write_unlock(&ctx->ctx_lock);
			/* unblocking blocked in-calls */
			hab_vchan_stop_notify(vchan);
			}
			hab_vchan_put(vchan); /* there is a lock inside */
			write_lock(&ctx->ctx_lock);
			break;
@@ -1079,25 +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 {
				hab_vchan_stop_notify(vchan);
				/* put for notify. shouldn't cause free */
				hab_vchan_put(vchan);
			}
		} else
			continue;
		list_del(&vchan->node); /* vchan is not in this ctx anymore */
		ctx->vcnt--;

		write_unlock(&ctx->ctx_lock);
		hab_vchan_stop_notify(vchan);
		hab_vchan_put(vchan); /* there is a lock inside */
		write_lock(&ctx->ctx_lock);
	}
@@ -1117,12 +1103,6 @@ static int hab_release(struct inode *inodep, struct file *filep)
	hab_ctx_put(ctx);
	filep->private_data = NULL;

	/* ctx leak check */
	if (get_refcnt(ctx->refcount))
		pr_warn("pending ctx release owner %d refcnt %d total %d\n",
				ctx->owner, get_refcnt(ctx->refcount),
				hab_driver.ctx_cnt);

	return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -494,7 +494,7 @@ struct virtual_channel *hab_vchan_get(struct physical_channel *pchan,
void hab_vchan_put(struct virtual_channel *vchan);

struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
		struct uhab_context *ctx);
		struct uhab_context *ctx, int ignore_remote);
struct physical_channel *hab_pchan_alloc(struct hab_device *habdev,
		int otherend_id);
struct physical_channel *hab_pchan_find_domid(struct hab_device *dev,
+4 −4
Original line number Diff line number Diff line
@@ -246,7 +246,7 @@ int hab_mem_export(struct uhab_context *ctx,
	if (!ctx || !param || !param->buffer)
		return -EINVAL;

	vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
	vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0);
	if (!vchan || !vchan->pchan) {
		ret = -ENODEV;
		goto err;
@@ -313,7 +313,7 @@ int hab_mem_unexport(struct uhab_context *ctx,
		return -EINVAL;

	/* refcnt on the access */
	vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
	vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1);
	if (!vchan || !vchan->pchan) {
		ret = -ENODEV;
		goto err_novchan;
@@ -360,7 +360,7 @@ int hab_mem_import(struct uhab_context *ctx,
	if (!ctx || !param)
		return -EINVAL;

	vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
	vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0);
	if (!vchan || !vchan->pchan) {
		ret = -ENODEV;
		goto err_imp;
@@ -420,7 +420,7 @@ int hab_mem_unimport(struct uhab_context *ctx,
	if (!ctx || !param)
		return -EINVAL;

	vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
	vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1);
	if (!vchan || !vchan->pchan) {
		if (vchan)
			hab_vchan_put(vchan);
+23 −0
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@ hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes)
{
	struct hab_message *message;

	if (sizebytes > HAB_HEADER_SIZE_MASK) {
		pr_err("pchan %s send size too large %zd\n",
			pchan->name, sizebytes);
		return NULL;
	}

	message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC);
	if (!message)
		return NULL;
@@ -153,6 +159,12 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan,
		pr_err("exp ack size %zu is not as arrived %zu\n",
				  sizeof(ack_recvd->ack), sizebytes);

	if (sizebytes > HAB_HEADER_SIZE_MASK) {
		pr_err("pchan %s read size too large %zd\n",
			pchan->name, sizebytes);
		return -EINVAL;
	}

	if (physical_channel_read(pchan,
		&ack_recvd->ack,
		sizebytes) != sizebytes)
@@ -169,6 +181,11 @@ static void hab_msg_drop(struct physical_channel *pchan, size_t sizebytes)
{
	uint8_t *data = NULL;

	if (sizebytes > HAB_HEADER_SIZE_MASK) {
		pr_err("%s read size too large %zd\n", pchan->name, sizebytes);
		return;
	}

	data = kmalloc(sizebytes, GFP_ATOMIC);
	if (data == NULL)
		return;
@@ -275,6 +292,12 @@ int hab_msg_recv(struct physical_channel *pchan,
		break;

	case HAB_PAYLOAD_TYPE_EXPORT:
		if (sizebytes > HAB_HEADER_SIZE_MASK) {
			pr_err("%s exp size too large %zd\n",
					pchan->name, sizebytes);
			break;
		}

		exp_desc = kzalloc(sizebytes, GFP_ATOMIC);
		if (!exp_desc)
			break;
+12 −0
Original line number Diff line number Diff line
@@ -47,6 +47,12 @@ int hab_open_request_add(struct physical_channel *pchan,
	struct hab_open_request *request;
	struct timeval tv;

	if (sizebytes > HAB_HEADER_SIZE_MASK) {
		pr_err("pchan %s request size too large %zd\n",
			pchan->name, sizebytes);
		return -EINVAL;
	}

	node = kzalloc(sizeof(*node), GFP_ATOMIC);
	if (!node)
		return -ENOMEM;
@@ -187,6 +193,12 @@ int hab_open_receive_cancel(struct physical_channel *pchan,
	int bfound = 0;
	struct timeval tv;

	if (sizebytes > HAB_HEADER_SIZE_MASK) {
		pr_err("pchan %s cancel size too large %zd\n",
			pchan->name, sizebytes);
		return -EINVAL;
	}

	if (physical_channel_read(pchan, &data, sizebytes) != sizebytes)
		return -EIO;

Loading