* 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,
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;
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;
write_lock(&ctx->ctx_lock);
list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
if (vchan->id == vcid) {
+ vchan->closed = 1;
write_unlock(&ctx->ctx_lock);
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;
- hab_vchan_stop_notify(vchan);
- }
+ /* unblocking blocked in-calls */
+ hab_vchan_stop_notify(vchan);
hab_vchan_put(vchan); /* there is a lock inside */
write_lock(&ctx->ctx_lock);
break;
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;
+ /* for the missing local vchan close */
write_unlock(&ctx->ctx_lock);
hab_vchan_put(vchan); /* there is a lock inside */
write_lock(&ctx->ctx_lock);
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;
}
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,
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;
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;
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;
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);
{
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;
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)
{
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;
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;
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;
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;
empty = list_empty(&pchan->vchannels);
if (!empty) {
struct virtual_channel *vchan;
+ int vcnt = pchan->vcnt;
list_for_each_entry(vchan, &pchan->vchannels, pnode) {
- pr_err("vchan %pK id %x remote id %x session %d ref %d closed %d remote close %d\n",
- vchan, vchan->id, vchan->otherend_id,
- vchan->session_id,
- get_refcnt(vchan->refcount), vchan->closed,
- vchan->otherend_closed);
+ /* discount open-pending unpaired vchan */
+ if (!vchan->session_id)
+ vcnt--;
+ else
+ pr_err("vchan %pK %x rm %x sn %d rf %d clsd %d rm clsd %d\n",
+ vchan, vchan->id,
+ vchan->otherend_id,
+ vchan->session_id,
+ get_refcnt(vchan->refcount),
+ vchan->closed, vchan->otherend_closed);
}
-
+ if (!vcnt)
+ empty = 1;/* unpaired vchan can exist at init time */
}
read_unlock(&pchan->vchans_lock);
int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids,
char *names, size_t name_size, uint32_t flags)
{
- struct virtual_channel *vchan = hab_get_vchan_fromvcid(vcid, ctx);
+ struct virtual_channel *vchan;
+
+ vchan = hab_get_vchan_fromvcid(vcid, ctx, 1);
if (!vchan)
return -EINVAL;
return -EAGAIN; /* not enough free space */
}
+ header->sequence = pchan->sequence_tx + 1;
header->signature = HAB_HEAD_SIGNATURE;
if (hab_pipe_write(dev->pipe_ep,
hab_pipe_write_commit(dev->pipe_ep);
spin_unlock_bh(&dev->io_lock);
habhyp_notify(dev);
-
+ ++pchan->sequence_tx;
return 0;
}
header.sequence);
}
+ pchan->sequence_rx = header.sequence;
+
hab_msg_recv(pchan, &header);
}
spin_unlock_bh(&pchan->rxbuf_lock);