[Virtio-fs] [PATCH 1/4] virtiofsd: send reply correctly on read failure

Liu Bo bo.liu at linux.alibaba.com
Tue Apr 16 19:08:55 UTC 2019


From: Eryu Guan <eguan at linux.alibaba.com>

Currently when a lo_read() operation fails, we don't send the failure
back to fuse client, and read(2) operation from guest kernel would hang
on waiting for the reply.

This is easily triggered by a direct read with non-aligned length.

Fix it by detecting preadv(2) error in virtio_send_data_iov(), and
teaching fuse_reply_data() to reply error on error case.

Reviewed-by: Liu Bo <bo.liu at linux.alibaba.com>
Signed-off-by: Eryu Guan <eguan at linux.alibaba.com>
---
 contrib/virtiofsd/fuse_lowlevel.c |  4 ++--
 contrib/virtiofsd/fuse_virtio.c   | 12 +++++++++---
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/contrib/virtiofsd/fuse_lowlevel.c b/contrib/virtiofsd/fuse_lowlevel.c
index 111c6e1..aeb5fe2 100644
--- a/contrib/virtiofsd/fuse_lowlevel.c
+++ b/contrib/virtiofsd/fuse_lowlevel.c
@@ -524,11 +524,11 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
 	out.error = 0;
 
 	res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
-	if (res <= 0) {
+	if (res >= 0) {
 		fuse_free_req(req);
 		return res;
 	} else {
-		return fuse_reply_err(req, res);
+		return fuse_reply_err(req, -res);
 	}
 }
 
diff --git a/contrib/virtiofsd/fuse_virtio.c b/contrib/virtiofsd/fuse_virtio.c
index ca988aa..0b5736d 100644
--- a/contrib/virtiofsd/fuse_virtio.c
+++ b/contrib/virtiofsd/fuse_virtio.c
@@ -333,8 +333,13 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
                 ret = preadv(buf->buf[0].fd, in_sg_ptr, in_sg_cpy_count, buf->buf[0].pos);
 
                 if (se->debug)
-                        fprintf(stderr, "%s: preadv_res=%d len=%zd\n",
-                                __func__, ret, len);
+                        fprintf(stderr, "%s: preadv_res=%d(%s) len=%zd\n",
+                                __func__, ret, strerror(errno), len);
+                if (ret == -1) {
+                        ret = -errno;
+                        free(in_sg_cpy);
+                        goto err;
+                }
                 if (ret < len && ret) {
                         if (se->debug)
                                 fprintf(stderr, "%s: ret < len\n", __func__);
@@ -379,7 +384,8 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
         vu_queue_notify(&se->virtio_dev->dev, q);
 
 err:
-        ch->qi->reply_sent = true;
+        if (!ret)
+                ch->qi->reply_sent = true;
 
         return ret;
 }
-- 
1.8.3.1




More information about the Virtio-fs mailing list