The payload of each uring entry serves as the buffer holding file data for read/write operations. In this patch, fuse_co_write is refactored to support using different buffer sources for write operations in legacy and io_uring modes.
Suggested-by: Kevin Wolf <[email protected]> Suggested-by: Stefan Hajnoczi <[email protected]> Signed-off-by: Brian Song <[email protected]> --- block/export/fuse.c | 55 ++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index ae7490b2a1..867752555a 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -1299,6 +1299,9 @@ fuse_co_read(FuseExport *exp, void **bufptr, uint64_t offset, uint32_t size) * Data in @in_place_buf is assumed to be overwritten after yielding, so will * be copied to a bounce buffer beforehand. @spillover_buf in contrast is * assumed to be exclusively owned and will be used as-is. + * In FUSE-over-io_uring mode, the actual req_payload content is stored in + * @spillover_buf. To ensure this buffer is used for writing, @in_place_buf + * is explicitly set to NULL. * Return the number of bytes written to *out on success, and -errno on error. */ static ssize_t coroutine_fn @@ -1306,8 +1309,8 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out, uint64_t offset, uint32_t size, const void *in_place_buf, const void *spillover_buf) { - size_t in_place_size; - void *copied; + size_t in_place_size = 0; + void *copied = NULL; int64_t blk_len; int ret; struct iovec iov[2]; @@ -1322,10 +1325,12 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out, return -EACCES; } - /* Must copy to bounce buffer before potentially yielding */ - in_place_size = MIN(size, FUSE_IN_PLACE_WRITE_BYTES); - copied = blk_blockalign(exp->common.blk, in_place_size); - memcpy(copied, in_place_buf, in_place_size); + if (in_place_buf) { + /* Must copy to bounce buffer before potentially yielding */ + in_place_size = MIN(size, FUSE_IN_PLACE_WRITE_BYTES); + copied = blk_blockalign(exp->common.blk, in_place_size); + memcpy(copied, in_place_buf, in_place_size); + } /** * Clients will expect short writes at EOF, so we have to limit @@ -1349,26 +1354,38 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out, } } - iov[0] = (struct iovec) { - .iov_base = copied, - .iov_len = in_place_size, - }; - if (size > FUSE_IN_PLACE_WRITE_BYTES) { - assert(size - FUSE_IN_PLACE_WRITE_BYTES <= FUSE_SPILLOVER_BUF_SIZE); - iov[1] = (struct iovec) { - .iov_base = (void *)spillover_buf, - .iov_len = size - FUSE_IN_PLACE_WRITE_BYTES, + if (in_place_buf) { + iov[0] = (struct iovec) { + .iov_base = copied, + .iov_len = in_place_size, }; - qemu_iovec_init_external(&qiov, iov, 2); + if (size > FUSE_IN_PLACE_WRITE_BYTES) { + assert(size - FUSE_IN_PLACE_WRITE_BYTES <= FUSE_SPILLOVER_BUF_SIZE); + iov[1] = (struct iovec) { + .iov_base = (void *)spillover_buf, + .iov_len = size - FUSE_IN_PLACE_WRITE_BYTES, + }; + qemu_iovec_init_external(&qiov, iov, 2); + } else { + qemu_iovec_init_external(&qiov, iov, 1); + } } else { + /* fuse over io_uring */ + iov[0] = (struct iovec) { + .iov_base = (void *)spillover_buf, + .iov_len = size, + }; qemu_iovec_init_external(&qiov, iov, 1); } + ret = blk_co_pwritev(exp->common.blk, offset, size, &qiov, 0); if (ret < 0) { goto fail_free_buffer; } - qemu_vfree(copied); + if (in_place_buf) { + qemu_vfree(copied); + } *out = (struct fuse_write_out) { .size = size, @@ -1376,7 +1393,9 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out, return sizeof(*out); fail_free_buffer: - qemu_vfree(copied); + if (in_place_buf) { + qemu_vfree(copied); + } return ret; } -- 2.43.0
