diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2018-05-10 11:33:45 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2018-05-10 11:33:45 -0700 |
commit | 390f9933178d247961a7e290baff3371d689de6c (patch) | |
tree | 38c6b2db2f8fd76344f897d243038fd015fa5d1c | |
parent | 6e5dae3ae1af25ac48b005ccfb2cf7e033d312ce (diff) | |
parent | c7e6dca7572cd8e882c76a668911d33a980f5a75 (diff) |
Merge "soc: qcom: hab: hold the message when the read buffer is smaller"
-rw-r--r-- | drivers/soc/qcom/hab/hab.c | 50 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab.h | 12 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/hab_msg.c | 28 | ||||
-rw-r--r-- | drivers/soc/qcom/hab/khab.c | 18 |
4 files changed, 57 insertions, 51 deletions
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index 3294fc34bdf8..37afe025a97a 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -356,18 +356,21 @@ err: return ret; } -struct hab_message *hab_vchan_recv(struct uhab_context *ctx, +int hab_vchan_recv(struct uhab_context *ctx, + struct hab_message **message, int vcid, + int *rsize, unsigned int flags) { struct virtual_channel *vchan; - struct hab_message *message; int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; vchan = hab_get_vchan_fromvcid(vcid, ctx); - if (!vchan) - return ERR_PTR(-ENODEV); + if (!vchan) { + pr_err("vcid %X, vchan %p ctx %p\n", vcid, vchan, ctx); + return -ENODEV; + } if (nonblocking_flag) { /* @@ -378,18 +381,18 @@ struct hab_message *hab_vchan_recv(struct uhab_context *ctx, physical_channel_rx_dispatch((unsigned long) vchan->pchan); } - message = hab_msg_dequeue(vchan, flags); - if (!message) { + ret = hab_msg_dequeue(vchan, message, rsize, flags); + if (!(*message)) { if (nonblocking_flag) ret = -EAGAIN; else if (vchan->otherend_closed) ret = -ENODEV; - else - ret = -EPIPE; + else if (ret == -ERESTARTSYS) + ret = -EINTR; } hab_vchan_put(vchan); - return ret ? ERR_PTR(ret) : message; + return ret; } bool hab_is_loopback(void) @@ -843,29 +846,22 @@ static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) break; } - msg = hab_vchan_recv(ctx, recv_param->vcid, recv_param->flags); - - if (IS_ERR(msg)) { - recv_param->sizebytes = 0; - ret = PTR_ERR(msg); - break; - } + ret = hab_vchan_recv(ctx, &msg, recv_param->vcid, + &recv_param->sizebytes, recv_param->flags); - if (recv_param->sizebytes < msg->sizebytes) { - recv_param->sizebytes = 0; - ret = -EINVAL; - } else if (copy_to_user((void __user *)recv_param->data, + if (ret == 0 && msg) { + if (copy_to_user((void __user *)recv_param->data, msg->data, msg->sizebytes)) { - pr_err("copy_to_user failed: vc=%x size=%d\n", - recv_param->vcid, (int)msg->sizebytes); - recv_param->sizebytes = 0; - ret = -EFAULT; - } else { - recv_param->sizebytes = msg->sizebytes; + pr_err("copy_to_user failed: vc=%x size=%d\n", + recv_param->vcid, (int)msg->sizebytes); + recv_param->sizebytes = 0; + ret = -EFAULT; + } } - hab_msg_free(msg); + if (msg) + hab_msg_free(msg); break; case IOCTL_HAB_VC_EXPORT: ret = hab_mem_export(ctx, (struct hab_export *)data, 0); diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index ffb0637055d4..2a07da728e00 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -373,9 +373,11 @@ long hab_vchan_send(struct uhab_context *ctx, size_t sizebytes, void *data, unsigned int flags); -struct hab_message *hab_vchan_recv(struct uhab_context *ctx, - int vcid, - unsigned int flags); +int hab_vchan_recv(struct uhab_context *ctx, + struct hab_message **msg, + int vcid, + int *rsize, + unsigned int flags); void hab_vchan_stop(struct virtual_channel *vchan); void hab_vchans_stop(struct physical_channel *pchan); void hab_vchan_stop_notify(struct virtual_channel *vchan); @@ -422,8 +424,8 @@ int habmem_imp_hyp_mmap(struct file *flip, struct vm_area_struct *vma); void hab_msg_free(struct hab_message *message); -struct hab_message *hab_msg_dequeue(struct virtual_channel *vchan, - unsigned int flags); +int hab_msg_dequeue(struct virtual_channel *vchan, + struct hab_message **msg, int *rsize, unsigned int flags); void hab_msg_recv(struct physical_channel *pchan, struct hab_header *header); diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index d5c625e8c1c9..d904cdee838c 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -42,8 +42,9 @@ void hab_msg_free(struct hab_message *message) kfree(message); } -struct hab_message * -hab_msg_dequeue(struct virtual_channel *vchan, unsigned int flags) +int +hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, + int *rsize, unsigned int flags) { struct hab_message *message = NULL; int ret = 0; @@ -64,15 +65,30 @@ hab_msg_dequeue(struct virtual_channel *vchan, unsigned int flags) } /* return all the received messages before the remote close */ - if (!ret && !hab_rx_queue_empty(vchan)) { + if ((!ret || (ret == -ERESTARTSYS)) && !hab_rx_queue_empty(vchan)) { spin_lock_bh(&vchan->rx_lock); message = list_first_entry(&vchan->rx_list, struct hab_message, node); - list_del(&message->node); + if (message) { + if (*rsize >= message->sizebytes) { + /* msg can be safely retrieved in full */ + list_del(&message->node); + ret = 0; + *rsize = message->sizebytes; + } else { + pr_err("rcv buffer too small %d < %zd\n", + *rsize, message->sizebytes); + *rsize = 0; + message = NULL; + ret = -EINVAL; + } + } spin_unlock_bh(&vchan->rx_lock); - } + } else + *rsize = 0; - return message; + *msg = message; + return ret; } static void hab_msg_queue(struct virtual_channel *vchan, diff --git a/drivers/soc/qcom/hab/khab.c b/drivers/soc/qcom/hab/khab.c index 3fdd11f7daf7..ba77e5e9cca2 100644 --- a/drivers/soc/qcom/hab/khab.c +++ b/drivers/soc/qcom/hab/khab.c @@ -51,22 +51,14 @@ int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes, if (!size_bytes || !dst_buff) return -EINVAL; - msg = hab_vchan_recv(hab_driver.kctx, handle, flags); + ret = hab_vchan_recv(hab_driver.kctx, &msg, handle, size_bytes, flags); - if (IS_ERR(msg)) { - *size_bytes = 0; - return PTR_ERR(msg); - } - - if (*size_bytes < msg->sizebytes) { - *size_bytes = 0; - ret = -EINVAL; - } else { + if (ret == 0 && msg) memcpy(dst_buff, msg->data, msg->sizebytes); - *size_bytes = msg->sizebytes; - } - hab_msg_free(msg); + if (msg) + hab_msg_free(msg); + return ret; } EXPORT_SYMBOL(habmm_socket_recv); |