qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] Demo for integration coroutin into fuse export
@ 2025-03-12  6:22 saz97
  2025-03-13  8:39 ` Stefan Hajnoczi
  0 siblings, 1 reply; 2+ messages in thread
From: saz97 @ 2025-03-12  6:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, qemu-block, hreitz, stefanha, saz97

Signed-off-by: Changzhi Xie <sa.z@qq.com>
---
 block/export/fuse.c | 167 ++++++++++++++++++++++++++++++--------------
 1 file changed, 114 insertions(+), 53 deletions(-)

diff --git a/block/export/fuse.c b/block/export/fuse.c
index 465cc9891d..f47117a00d 100644
--- a/block/export/fuse.c
+++ b/block/export/fuse.c
@@ -64,6 +64,16 @@ typedef struct FuseExport {
     gid_t st_gid;
 } FuseExport;
 
+typedef struct FuseIORequest {
+    fuse_req_t req;
+    fuse_ino_t inode;
+    size_t size;
+    off_t offset;
+    struct fuse_file_info *fi;
+    FuseExport *exp;
+    char *write_buf;
+} FuseIORequest;
+
 static GHashTable *exports;
 static const struct fuse_lowlevel_ops fuse_ops;
 
@@ -570,102 +580,153 @@ static void fuse_open(fuse_req_t req, fuse_ino_t inode,
     fuse_reply_open(req, fi);
 }
 
-/**
- * Handle client reads from the exported image.
- */
-static void fuse_read(fuse_req_t req, fuse_ino_t inode,
-                      size_t size, off_t offset, struct fuse_file_info *fi)
+static void coroutine_fn fuse_read_coroutine(void *opaque)
 {
-    FuseExport *exp = fuse_req_userdata(req);
+    FuseIORequest *io_req = opaque;
+    FuseExport *exp = io_req->exp;
     int64_t length;
-    void *buf;
+    void *buffer;
     int ret;
 
-    /* Limited by max_read, should not happen */
-    if (size > FUSE_MAX_BOUNCE_BYTES) {
-        fuse_reply_err(req, EINVAL);
-        return;
+    if (io_req->size > FUSE_MAX_BOUNCE_BYTES) {
+        fuse_reply_err(io_req->req, EINVAL);
+        goto cleanup;
     }
 
-    /**
-     * Clients will expect short reads at EOF, so we have to limit
-     * offset+size to the image length.
-     */
     length = blk_getlength(exp->common.blk);
     if (length < 0) {
-        fuse_reply_err(req, -length);
-        return;
+        fuse_reply_err(io_req->req, -length);
+        goto cleanup;
     }
 
-    if (offset + size > length) {
-        size = length - offset;
+    if (io_req->offset + io_req->size > length) {
+        io_req->size = length - io_req->offset;
     }
 
-    buf = qemu_try_blockalign(blk_bs(exp->common.blk), size);
-    if (!buf) {
-        fuse_reply_err(req, ENOMEM);
-        return;
+    if (io_req->size == 0) {
+        fuse_reply_buf(io_req->req, NULL, 0);
+        goto cleanup;
+    }
+
+    buffer = qemu_try_blockalign(blk_bs(exp->common.blk), io_req->size);
+    if (!buffer) {
+        fuse_reply_err(io_req->req, ENOMEM);
+        goto cleanup;
     }
 
-    ret = blk_pread(exp->common.blk, offset, size, buf, 0);
+    ret = blk_co_pread(exp->common.blk, io_req->offset,
+                       io_req->size, buffer, 0);
     if (ret >= 0) {
-        fuse_reply_buf(req, buf, size);
+        fuse_reply_buf(io_req->req, buffer, io_req->size);
     } else {
-        fuse_reply_err(req, -ret);
+        fuse_reply_err(io_req->req, -ret);
     }
 
-    qemu_vfree(buf);
+    qemu_vfree(buffer);
+
+cleanup:
+    g_free(io_req);
 }
 
-/**
- * Handle client writes to the exported image.
- */
-static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
-                       size_t size, off_t offset, struct fuse_file_info *fi)
+static void coroutine_fn fuse_write_coroutine(void *opaque)
 {
-    FuseExport *exp = fuse_req_userdata(req);
+    FuseIORequest *io_req = opaque;
+    FuseExport *exp = io_req->exp;
     int64_t length;
     int ret;
 
-    /* Limited by max_write, should not happen */
-    if (size > BDRV_REQUEST_MAX_BYTES) {
-        fuse_reply_err(req, EINVAL);
-        return;
+    if (io_req->size > BDRV_REQUEST_MAX_BYTES) {
+        fuse_reply_err(io_req->req, EINVAL);
+        goto cleanup;
     }
 
     if (!exp->writable) {
-        fuse_reply_err(req, EACCES);
-        return;
+        fuse_reply_err(io_req->req, EACCES);
+        goto cleanup;
     }
 
-    /**
-     * Clients will expect short writes at EOF, so we have to limit
-     * offset+size to the image length.
-     */
     length = blk_getlength(exp->common.blk);
     if (length < 0) {
-        fuse_reply_err(req, -length);
-        return;
+        fuse_reply_err(io_req->req, -length);
+        goto cleanup;
     }
 
-    if (offset + size > length) {
+    if (io_req->offset + io_req->size > length) {
         if (exp->growable) {
-            ret = fuse_do_truncate(exp, offset + size, true, PREALLOC_MODE_OFF);
+            ret = fuse_do_truncate(exp, io_req->offset + io_req->size,
+                                   true, PREALLOC_MODE_OFF);
             if (ret < 0) {
-                fuse_reply_err(req, -ret);
-                return;
+                fuse_reply_err(io_req->req, -ret);
+                goto cleanup;
             }
         } else {
-            size = length - offset;
+            io_req->size = MAX(0, length - io_req->offset);
+            if (io_req->size == 0) {
+                fuse_reply_write(io_req->req, 0);
+                goto cleanup;
+            }
         }
     }
 
-    ret = blk_pwrite(exp->common.blk, offset, size, buf, 0);
+    ret = blk_co_pwrite(exp->common.blk, io_req->offset, io_req->size,
+                        io_req->write_buf, 0);
     if (ret >= 0) {
-        fuse_reply_write(req, size);
+        fuse_reply_write(io_req->req, io_req->size);
     } else {
-        fuse_reply_err(req, -ret);
+        fuse_reply_err(io_req->req, -ret);
     }
+
+cleanup:
+    g_free(io_req->write_buf);
+    g_free(io_req);
+}
+
+/**
+ * Handle client reads from the exported image.
+ */
+static void fuse_read(fuse_req_t req, fuse_ino_t inode,
+                      size_t size, off_t offset, struct fuse_file_info *fi)
+{
+    FuseExport *exp = fuse_req_userdata(req);
+    FuseIORequest *io_req = g_new(FuseIORequest, 1);
+    io_req->req = req;
+    io_req->inode = inode;
+    io_req->size = size;
+    io_req->offset = offset;
+    io_req->fi = fi;
+    io_req->exp = exp;
+
+    Coroutine *co = qemu_coroutine_create(fuse_read_coroutine, io_req);
+    qemu_coroutine_enter(co);
+}
+
+
+/**
+ * Handle client writes to the exported image.
+ */
+static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
+                       size_t size, off_t offset, struct fuse_file_info *fi)
+{
+    FuseExport *exp = fuse_req_userdata(req);
+    FuseIORequest *io_req = g_new(FuseIORequest, 1);
+
+    io_req->write_buf = g_try_malloc(size);
+    if (!io_req->write_buf) {
+        fuse_reply_err(req, ENOMEM);
+        g_free(io_req);
+        return;
+    }
+    memcpy(io_req->write_buf, buf, size);
+
+    io_req->req = req;
+    io_req->inode = inode;
+    io_req->size = size;
+    io_req->offset = offset;
+    io_req->fi = fi;
+    io_req->exp = exp;
+
+    Coroutine *co = qemu_coroutine_create(fuse_write_coroutine, io_req);
+    qemu_coroutine_enter(co);
 }
 
 /**
-- 
2.34.1


From 3d2d317a49eb4cbf401294c6e19c72533eeeefad Mon Sep 17 00:00:00 2001
From: saz97 <sa.z@qq.com>
Date: Wed, 12 Mar 2025 13:47:01 +0800
Subject: [PATCH 2/2] allocate independent fuse_buffor each coroutine and store
 fuse_file_info copy instead of pointerin FuseIORequest

Signed-off-by: Changzhi Xie <sa.z@qq.com>
---
 block/export/fuse.c | 45 ++++++++++++++++++++++++---------------------
 1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/block/export/fuse.c b/block/export/fuse.c
index f47117a00d..69ffe4f0ca 100644
--- a/block/export/fuse.c
+++ b/block/export/fuse.c
@@ -69,7 +69,7 @@ typedef struct FuseIORequest {
     fuse_ino_t inode;
     size_t size;
     off_t offset;
-    struct fuse_file_info *fi;
+    struct fuse_file_info fi;
     FuseExport *exp;
     char *write_buf;
 } FuseIORequest;
@@ -298,6 +298,10 @@ fail:
 static void read_from_fuse_export(void *opaque)
 {
     FuseExport *exp = opaque;
+    struct fuse_buf buf = {
+        .mem = g_malloc(FUSE_MAX_BOUNCE_BYTES),
+        .size = FUSE_MAX_BOUNCE_BYTES,
+    };
     int ret;
 
     blk_exp_ref(&exp->common);
@@ -314,6 +318,7 @@ static void read_from_fuse_export(void *opaque)
     fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf);
 
 out:
+    g_free(buf.mem);
     if (qatomic_fetch_dec(&exp->in_flight) == 1) {
         aio_wait_kick(); /* wake AIO_WAIT_WHILE() */
     }
@@ -689,12 +694,15 @@ static void fuse_read(fuse_req_t req, fuse_ino_t inode,
 {
     FuseExport *exp = fuse_req_userdata(req);
     FuseIORequest *io_req = g_new(FuseIORequest, 1);
-    io_req->req = req;
-    io_req->inode = inode;
-    io_req->size = size;
-    io_req->offset = offset;
-    io_req->fi = fi;
-    io_req->exp = exp;
+
+    *io_req = (FuseIORequest) {
+        .req = req,
+        .inode = inode,
+        .size = size,
+        .offset = offset,
+        .exp = exp,
+        .fi = *fi,
+    };
 
     Coroutine *co = qemu_coroutine_create(fuse_read_coroutine, io_req);
     qemu_coroutine_enter(co);
@@ -710,20 +718,15 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
     FuseExport *exp = fuse_req_userdata(req);
     FuseIORequest *io_req = g_new(FuseIORequest, 1);
 
-    io_req->write_buf = g_try_malloc(size);
-    if (!io_req->write_buf) {
-        fuse_reply_err(req, ENOMEM);
-        g_free(io_req);
-        return;
-    }
-    memcpy(io_req->write_buf, buf, size);
-
-    io_req->req = req;
-    io_req->inode = inode;
-    io_req->size = size;
-    io_req->offset = offset;
-    io_req->fi = fi;
-    io_req->exp = exp;
+    *io_req = (FuseIORequest) {
+        .req = req,
+        .inode = inode,
+        .size = size,
+        .offset = offset,
+        .exp = exp,
+        .fi = *fi,
+        .write_buf = g_memdup2_qemu(buf, size),
+    };
 
     Coroutine *co = qemu_coroutine_create(fuse_write_coroutine, io_req);
     qemu_coroutine_enter(co);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 1/2] Demo for integration coroutin into fuse export
  2025-03-12  6:22 [PATCH 1/2] Demo for integration coroutin into fuse export saz97
@ 2025-03-13  8:39 ` Stefan Hajnoczi
  0 siblings, 0 replies; 2+ messages in thread
From: Stefan Hajnoczi @ 2025-03-13  8:39 UTC (permalink / raw)
  To: saz97; +Cc: qemu-devel, kwolf, qemu-block, hreitz

[-- Attachment #1: Type: text/plain, Size: 12859 bytes --]

On Wed, Mar 12, 2025 at 02:22:05PM +0800, saz97 wrote:

The email subject says [PATCH 1/2] but I only see one patch email. The
second patch is at the bottom of this email. Please send each patch in a
separate email with email threading (this is what git-send-email(1) does
by default) in the future.

There is a website with useful git-send-email(1) setup advice here:
https://git-send-email.io/. You can test your patch emails by sending
them to yourself with `git send-email --to sa.z@qq.com ...`.

It would be nice to actually merge this once code review discussion has
completed. It will be necessary to have a commit description for each
patch to explains its purpose. Performance results demonstrating the
advantage of supporting higher queue depths are also needed.

> Signed-off-by: Changzhi Xie <sa.z@qq.com>
> ---
>  block/export/fuse.c | 167 ++++++++++++++++++++++++++++++--------------
>  1 file changed, 114 insertions(+), 53 deletions(-)
> 
> diff --git a/block/export/fuse.c b/block/export/fuse.c
> index 465cc9891d..f47117a00d 100644
> --- a/block/export/fuse.c
> +++ b/block/export/fuse.c
> @@ -64,6 +64,16 @@ typedef struct FuseExport {
>      gid_t st_gid;
>  } FuseExport;
>  
> +typedef struct FuseIORequest {
> +    fuse_req_t req;
> +    fuse_ino_t inode;
> +    size_t size;
> +    off_t offset;
> +    struct fuse_file_info *fi;
> +    FuseExport *exp;
> +    char *write_buf;
> +} FuseIORequest;
> +
>  static GHashTable *exports;
>  static const struct fuse_lowlevel_ops fuse_ops;
>  
> @@ -570,102 +580,153 @@ static void fuse_open(fuse_req_t req, fuse_ino_t inode,
>      fuse_reply_open(req, fi);
>  }
>  
> -/**
> - * Handle client reads from the exported image.
> - */
> -static void fuse_read(fuse_req_t req, fuse_ino_t inode,
> -                      size_t size, off_t offset, struct fuse_file_info *fi)
> +static void coroutine_fn fuse_read_coroutine(void *opaque)
>  {
> -    FuseExport *exp = fuse_req_userdata(req);
> +    FuseIORequest *io_req = opaque;
> +    FuseExport *exp = io_req->exp;
>      int64_t length;
> -    void *buf;
> +    void *buffer;
>      int ret;
>  
> -    /* Limited by max_read, should not happen */
> -    if (size > FUSE_MAX_BOUNCE_BYTES) {
> -        fuse_reply_err(req, EINVAL);
> -        return;
> +    if (io_req->size > FUSE_MAX_BOUNCE_BYTES) {
> +        fuse_reply_err(io_req->req, EINVAL);
> +        goto cleanup;
>      }
>  
> -    /**
> -     * Clients will expect short reads at EOF, so we have to limit
> -     * offset+size to the image length.
> -     */
>      length = blk_getlength(exp->common.blk);
>      if (length < 0) {
> -        fuse_reply_err(req, -length);
> -        return;
> +        fuse_reply_err(io_req->req, -length);
> +        goto cleanup;
>      }
>  
> -    if (offset + size > length) {
> -        size = length - offset;
> +    if (io_req->offset + io_req->size > length) {
> +        io_req->size = length - io_req->offset;
>      }
>  
> -    buf = qemu_try_blockalign(blk_bs(exp->common.blk), size);
> -    if (!buf) {
> -        fuse_reply_err(req, ENOMEM);
> -        return;
> +    if (io_req->size == 0) {
> +        fuse_reply_buf(io_req->req, NULL, 0);
> +        goto cleanup;
> +    }
> +
> +    buffer = qemu_try_blockalign(blk_bs(exp->common.blk), io_req->size);
> +    if (!buffer) {
> +        fuse_reply_err(io_req->req, ENOMEM);
> +        goto cleanup;
>      }
>  
> -    ret = blk_pread(exp->common.blk, offset, size, buf, 0);
> +    ret = blk_co_pread(exp->common.blk, io_req->offset,
> +                       io_req->size, buffer, 0);
>      if (ret >= 0) {
> -        fuse_reply_buf(req, buf, size);
> +        fuse_reply_buf(io_req->req, buffer, io_req->size);
>      } else {
> -        fuse_reply_err(req, -ret);
> +        fuse_reply_err(io_req->req, -ret);
>      }
>  
> -    qemu_vfree(buf);
> +    qemu_vfree(buffer);
> +
> +cleanup:
> +    g_free(io_req);
>  }
>  
> -/**
> - * Handle client writes to the exported image.
> - */
> -static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
> -                       size_t size, off_t offset, struct fuse_file_info *fi)
> +static void coroutine_fn fuse_write_coroutine(void *opaque)
>  {
> -    FuseExport *exp = fuse_req_userdata(req);
> +    FuseIORequest *io_req = opaque;
> +    FuseExport *exp = io_req->exp;
>      int64_t length;
>      int ret;
>  
> -    /* Limited by max_write, should not happen */
> -    if (size > BDRV_REQUEST_MAX_BYTES) {
> -        fuse_reply_err(req, EINVAL);
> -        return;
> +    if (io_req->size > BDRV_REQUEST_MAX_BYTES) {
> +        fuse_reply_err(io_req->req, EINVAL);
> +        goto cleanup;
>      }
>  
>      if (!exp->writable) {
> -        fuse_reply_err(req, EACCES);
> -        return;
> +        fuse_reply_err(io_req->req, EACCES);
> +        goto cleanup;
>      }
>  
> -    /**
> -     * Clients will expect short writes at EOF, so we have to limit
> -     * offset+size to the image length.
> -     */
>      length = blk_getlength(exp->common.blk);
>      if (length < 0) {
> -        fuse_reply_err(req, -length);
> -        return;
> +        fuse_reply_err(io_req->req, -length);
> +        goto cleanup;
>      }
>  
> -    if (offset + size > length) {
> +    if (io_req->offset + io_req->size > length) {
>          if (exp->growable) {
> -            ret = fuse_do_truncate(exp, offset + size, true, PREALLOC_MODE_OFF);
> +            ret = fuse_do_truncate(exp, io_req->offset + io_req->size,
> +                                   true, PREALLOC_MODE_OFF);
>              if (ret < 0) {
> -                fuse_reply_err(req, -ret);
> -                return;
> +                fuse_reply_err(io_req->req, -ret);
> +                goto cleanup;
>              }
>          } else {
> -            size = length - offset;
> +            io_req->size = MAX(0, length - io_req->offset);
> +            if (io_req->size == 0) {
> +                fuse_reply_write(io_req->req, 0);
> +                goto cleanup;
> +            }
>          }
>      }
>  
> -    ret = blk_pwrite(exp->common.blk, offset, size, buf, 0);
> +    ret = blk_co_pwrite(exp->common.blk, io_req->offset, io_req->size,
> +                        io_req->write_buf, 0);
>      if (ret >= 0) {
> -        fuse_reply_write(req, size);
> +        fuse_reply_write(io_req->req, io_req->size);
>      } else {
> -        fuse_reply_err(req, -ret);
> +        fuse_reply_err(io_req->req, -ret);
>      }
> +
> +cleanup:
> +    g_free(io_req->write_buf);
> +    g_free(io_req);
> +}
> +
> +/**
> + * Handle client reads from the exported image.
> + */
> +static void fuse_read(fuse_req_t req, fuse_ino_t inode,
> +                      size_t size, off_t offset, struct fuse_file_info *fi)
> +{
> +    FuseExport *exp = fuse_req_userdata(req);
> +    FuseIORequest *io_req = g_new(FuseIORequest, 1);
> +    io_req->req = req;
> +    io_req->inode = inode;
> +    io_req->size = size;
> +    io_req->offset = offset;
> +    io_req->fi = fi;
> +    io_req->exp = exp;
> +
> +    Coroutine *co = qemu_coroutine_create(fuse_read_coroutine, io_req);
> +    qemu_coroutine_enter(co);
> +}
> +
> +
> +/**
> + * Handle client writes to the exported image.
> + */
> +static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
> +                       size_t size, off_t offset, struct fuse_file_info *fi)
> +{
> +    FuseExport *exp = fuse_req_userdata(req);
> +    FuseIORequest *io_req = g_new(FuseIORequest, 1);
> +
> +    io_req->write_buf = g_try_malloc(size);
> +    if (!io_req->write_buf) {
> +        fuse_reply_err(req, ENOMEM);
> +        g_free(io_req);
> +        return;
> +    }
> +    memcpy(io_req->write_buf, buf, size);
> +
> +    io_req->req = req;
> +    io_req->inode = inode;
> +    io_req->size = size;
> +    io_req->offset = offset;
> +    io_req->fi = fi;
> +    io_req->exp = exp;
> +
> +    Coroutine *co = qemu_coroutine_create(fuse_write_coroutine, io_req);
> +    qemu_coroutine_enter(co);
>  }
>  
>  /**
> -- 
> 2.34.1
> 
> 
> From 3d2d317a49eb4cbf401294c6e19c72533eeeefad Mon Sep 17 00:00:00 2001
> From: saz97 <sa.z@qq.com>
> Date: Wed, 12 Mar 2025 13:47:01 +0800
> Subject: [PATCH 2/2] allocate independent fuse_buffor each coroutine and store
>  fuse_file_info copy instead of pointerin FuseIORequest

Reviewers appreciate it when a patch series is a sequence of logical
changes without intermediate steps (like "fix typo", etc) modifying
earlier code changes. That way reviewers don't spend time reviewing and
commenting on code that will be replaced immediately.

Please squash this patch into the previous one. This can be done with
`git rebase -i` and its "squash" command.

> 
> Signed-off-by: Changzhi Xie <sa.z@qq.com>
> ---
>  block/export/fuse.c | 45 ++++++++++++++++++++++++---------------------
>  1 file changed, 24 insertions(+), 21 deletions(-)
> 
> diff --git a/block/export/fuse.c b/block/export/fuse.c
> index f47117a00d..69ffe4f0ca 100644
> --- a/block/export/fuse.c
> +++ b/block/export/fuse.c
> @@ -69,7 +69,7 @@ typedef struct FuseIORequest {
>      fuse_ino_t inode;
>      size_t size;
>      off_t offset;
> -    struct fuse_file_info *fi;
> +    struct fuse_file_info fi;
>      FuseExport *exp;
>      char *write_buf;
>  } FuseIORequest;
> @@ -298,6 +298,10 @@ fail:
>  static void read_from_fuse_export(void *opaque)
>  {
>      FuseExport *exp = opaque;
> +    struct fuse_buf buf = {
> +        .mem = g_malloc(FUSE_MAX_BOUNCE_BYTES),
> +        .size = FUSE_MAX_BOUNCE_BYTES,
> +    };

libfuse's lib/fuse_lowlevel.c:_fuse_session_receive_buf() allocates the
memory as needed. It should be freed using fuse_buf_free(). Is it
possible to use just `struct fuse_buf buf = {};` and let libfuse
automatically allocate memory?

>      int ret;
>  
>      blk_exp_ref(&exp->common);
> @@ -314,6 +318,7 @@ static void read_from_fuse_export(void *opaque)
>      fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf);
>  
>  out:
> +    g_free(buf.mem);

fuse_session_process_buf() can return while the coroutine still exists,
so it's not safe to free the buffer here.

>      if (qatomic_fetch_dec(&exp->in_flight) == 1) {
>          aio_wait_kick(); /* wake AIO_WAIT_WHILE() */
>      }

This assumes the request has already completed, but now there's a
coroutine that might still exist. Please take a look at
read_from_fuse_export() and think about how to put the in_flight
decrement and blk_exp_unref() into the coroutine so it only happens when
the request finishes.

> @@ -689,12 +694,15 @@ static void fuse_read(fuse_req_t req, fuse_ino_t inode,
>  {
>      FuseExport *exp = fuse_req_userdata(req);
>      FuseIORequest *io_req = g_new(FuseIORequest, 1);
> -    io_req->req = req;
> -    io_req->inode = inode;
> -    io_req->size = size;
> -    io_req->offset = offset;
> -    io_req->fi = fi;
> -    io_req->exp = exp;
> +
> +    *io_req = (FuseIORequest) {
> +        .req = req,
> +        .inode = inode,
> +        .size = size,
> +        .offset = offset,
> +        .exp = exp,
> +        .fi = *fi,
> +    };

I'm not sure if FuseIORequest is necessary. If read_from_fuse_export()
creates a coroutine that reads and processes the next request, then it
should be possible to implement the request directly in
fuse_write()/fuse_write() without an intermediate request struct. That
would be simpler, avoid the io_req heap allocation, and require less
code.

>  
>      Coroutine *co = qemu_coroutine_create(fuse_read_coroutine, io_req);
>      qemu_coroutine_enter(co);
> @@ -710,20 +718,15 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
>      FuseExport *exp = fuse_req_userdata(req);
>      FuseIORequest *io_req = g_new(FuseIORequest, 1);
>  
> -    io_req->write_buf = g_try_malloc(size);
> -    if (!io_req->write_buf) {
> -        fuse_reply_err(req, ENOMEM);
> -        g_free(io_req);
> -        return;
> -    }
> -    memcpy(io_req->write_buf, buf, size);
> -
> -    io_req->req = req;
> -    io_req->inode = inode;
> -    io_req->size = size;
> -    io_req->offset = offset;
> -    io_req->fi = fi;
> -    io_req->exp = exp;
> +    *io_req = (FuseIORequest) {
> +        .req = req,
> +        .inode = inode,
> +        .size = size,
> +        .offset = offset,
> +        .exp = exp,
> +        .fi = *fi,
> +        .write_buf = g_memdup2_qemu(buf, size),
> +    };
>  
>      Coroutine *co = qemu_coroutine_create(fuse_write_coroutine, io_req);
>      qemu_coroutine_enter(co);
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-03-13  8:40 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-12  6:22 [PATCH 1/2] Demo for integration coroutin into fuse export saz97
2025-03-13  8:39 ` Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).