mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 06:42:32 +08:00
misc/rpmsgdev: fix block mode read/write bug in rpmsgdev
Rpmsg dev server always open the real char device with nonblock mode, so let client try to read/wrtie the read device every read/write operation. Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
+50
-62
@@ -404,20 +404,6 @@ static ssize_t rpmsgdev_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
priv = filep->f_priv;
|
priv = filep->f_priv;
|
||||||
DEBUGASSERT(dev != NULL && priv != NULL);
|
DEBUGASSERT(dev != NULL && priv != NULL);
|
||||||
|
|
||||||
/* If the open flags is not nonblock, should poll the device for
|
|
||||||
* read ready first to avoid the server rptun thread blocked in
|
|
||||||
* device read operation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (priv->nonblock == false)
|
|
||||||
{
|
|
||||||
ret = rpmsgdev_wait(filep, POLLIN);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the host to perform the read */
|
/* Call the host to perform the read */
|
||||||
|
|
||||||
read.iov_base = buffer;
|
read.iov_base = buffer;
|
||||||
@@ -428,8 +414,27 @@ static ssize_t rpmsgdev_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
command = dev->flags & RPMSGDEV_NOFRAG_READ ?
|
command = dev->flags & RPMSGDEV_NOFRAG_READ ?
|
||||||
RPMSGDEV_READ_NOFRAG : RPMSGDEV_READ;
|
RPMSGDEV_READ_NOFRAG : RPMSGDEV_READ;
|
||||||
|
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
ret = rpmsgdev_send_recv(dev, command, true, &msg.header,
|
ret = rpmsgdev_send_recv(dev, command, true, &msg.header,
|
||||||
sizeof(msg) - 1, &read);
|
sizeof(msg) - 1, &read);
|
||||||
|
if (ret != -EAGAIN || priv->nonblock)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If open with block mode and return -EAGAIN, should wait the
|
||||||
|
* perr device ready and try again until read success or some
|
||||||
|
* other errors occur.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = rpmsgdev_wait(filep, POLLIN);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
rpmsgdeverr("read wait failed, ret=%d\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return read.iov_len ? read.iov_len : ret;
|
return read.iov_len ? read.iov_len : ret;
|
||||||
}
|
}
|
||||||
@@ -459,10 +464,9 @@ static ssize_t rpmsgdev_write(FAR struct file *filep, const char *buffer,
|
|||||||
FAR struct rpmsgdev_s *dev;
|
FAR struct rpmsgdev_s *dev;
|
||||||
FAR struct rpmsgdev_priv_s *priv;
|
FAR struct rpmsgdev_priv_s *priv;
|
||||||
FAR struct rpmsgdev_write_s *msg;
|
FAR struct rpmsgdev_write_s *msg;
|
||||||
struct rpmsgdev_cookie_s cookie;
|
|
||||||
uint32_t space;
|
uint32_t space;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
{
|
{
|
||||||
@@ -475,81 +479,60 @@ static ssize_t rpmsgdev_write(FAR struct file *filep, const char *buffer,
|
|||||||
priv = filep->f_priv;
|
priv = filep->f_priv;
|
||||||
DEBUGASSERT(dev != NULL && priv != NULL);
|
DEBUGASSERT(dev != NULL && priv != NULL);
|
||||||
|
|
||||||
/* If the open flags is not nonblock, should poll the device for
|
|
||||||
* write ready first to avoid the server rptun thread blocked in
|
|
||||||
* device write operation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (priv->nonblock == false)
|
|
||||||
{
|
|
||||||
ret = rpmsgdev_wait(filep, POLLOUT);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Perform the rpmsg write */
|
/* Perform the rpmsg write */
|
||||||
|
|
||||||
memset(&cookie, 0, sizeof(cookie));
|
|
||||||
nxsem_init(&cookie.sem, 0, 0);
|
|
||||||
|
|
||||||
while (written < buflen)
|
while (written < buflen)
|
||||||
{
|
{
|
||||||
msg = rpmsgdev_get_tx_payload_buffer(dev, &space);
|
msg = rpmsgdev_get_tx_payload_buffer(dev, &space);
|
||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
{
|
{
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
space -= sizeof(*msg) - 1;
|
space -= sizeof(*msg) - 1;
|
||||||
if (space >= buflen - written)
|
if (space >= buflen - written)
|
||||||
{
|
{
|
||||||
/* Send complete, set cookie is valid, need ack */
|
|
||||||
|
|
||||||
space = buflen - written;
|
space = buflen - written;
|
||||||
msg->header.cookie = (uintptr_t)&cookie;
|
|
||||||
}
|
}
|
||||||
else if ((dev->flags & RPMSGDEV_NOFRAG_WRITE) != 0)
|
else if ((dev->flags & RPMSGDEV_NOFRAG_WRITE) != 0)
|
||||||
{
|
{
|
||||||
rpmsg_release_tx_buffer(&dev->ept, msg);
|
rpmsg_release_tx_buffer(&dev->ept, msg);
|
||||||
ret = -EMSGSIZE;
|
ret = -EMSGSIZE;
|
||||||
goto out;
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Not send complete, set cookie invalid, do not need ack */
|
|
||||||
|
|
||||||
msg->header.cookie = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->header.command = RPMSGDEV_WRITE;
|
|
||||||
msg->header.result = -ENXIO;
|
|
||||||
msg->filep = priv->filep;
|
msg->filep = priv->filep;
|
||||||
msg->count = space;
|
msg->count = space;
|
||||||
memcpy(msg->buf, buffer + written, space);
|
memcpy(msg->buf, buffer + written, space);
|
||||||
|
|
||||||
ret = rpmsg_send_nocopy(&dev->ept, msg, sizeof(*msg) - 1 + space);
|
ret = rpmsgdev_send_recv(dev, RPMSGDEV_WRITE, false, &msg->header,
|
||||||
|
sizeof(*msg) - 1 + space, NULL);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
written += ret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != -EAGAIN || priv->nonblock || written != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If open with block mode and return -EAGAIN and no data
|
||||||
|
* written to this device, should wait peer device ready and
|
||||||
|
* try again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = rpmsgdev_wait(filep, POLLOUT);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
goto out;
|
rpmsgerr("write wait failed, ret=%d\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
written += space;
|
return written != 0 ? written : ret;
|
||||||
}
|
|
||||||
|
|
||||||
ret = rpmsg_wait(&dev->ept, &cookie.sem);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = cookie.result;
|
|
||||||
|
|
||||||
out:
|
|
||||||
nxsem_destroy(&cookie.sem);
|
|
||||||
return ret < 0 ? ret : buflen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -838,6 +821,11 @@ static int rpmsgdev_send_recv(FAR struct rpmsgdev_s *priv,
|
|||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
if (copy == false)
|
||||||
|
{
|
||||||
|
rpmsg_release_tx_buffer(&priv->ept, msg);
|
||||||
|
}
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -272,11 +272,16 @@ static int rpmsgdev_write_handler(FAR struct rpmsg_endpoint *ept,
|
|||||||
written += ret;
|
written += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->header.cookie != 0)
|
if (written != 0)
|
||||||
{
|
{
|
||||||
msg->header.result = ret < 0 ? ret : written;
|
msg->header.result = written;
|
||||||
rpmsg_send(ept, msg, sizeof(*msg) - 1);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg->header.result = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpmsg_send(ept, msg, sizeof(*msg) - 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user