summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-05-10 11:33:45 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-05-10 11:33:45 -0700
commit390f9933178d247961a7e290baff3371d689de6c (patch)
tree38c6b2db2f8fd76344f897d243038fd015fa5d1c
parent6e5dae3ae1af25ac48b005ccfb2cf7e033d312ce (diff)
parentc7e6dca7572cd8e882c76a668911d33a980f5a75 (diff)
Merge "soc: qcom: hab: hold the message when the read buffer is smaller"
-rw-r--r--drivers/soc/qcom/hab/hab.c50
-rw-r--r--drivers/soc/qcom/hab/hab.h12
-rw-r--r--drivers/soc/qcom/hab/hab_msg.c28
-rw-r--r--drivers/soc/qcom/hab/khab.c18
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);