From: Jeff Layton <jlayton@kernel.org>
To: Joanne Koong <joannelkoong@gmail.com>, miklos@szeredi.hu
Cc: bernd@bsbernd.com, axboe@kernel.dk, linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH v2 13/14] fuse: add zero-copy over io-uring
Date: Thu, 30 Apr 2026 13:56:34 +0100 [thread overview]
Message-ID: <f8201c9c18a3317cf41d6112f39f7885fb0f64c5.camel@kernel.org> (raw)
In-Reply-To: <20260402162840.2989717-14-joannelkoong@gmail.com>
On Thu, 2026-04-02 at 09:28 -0700, Joanne Koong wrote:
> Implement zero-copy data transfer for fuse over io-uring, eliminating
> memory copies between userspace, the kernel, and the fuse server for
> page-backed read/write operations.
>
> When the FUSE_URING_ZERO_COPY flag is set alongside FUSE_URING_BUFRING,
> the kernel registers the client's underlying pages as a sparse buffer at
> the entry's fixed id via io_buffer_register_bvec(). The fuse server can
> then perform io_uring read/write operations directly on these pages.
> Non-page-backed args (eg out headers) go through the payload buffer as
> normal.
>
> This requires CAP_SYS_ADMIN and buffer rings with pinned headers and
> buffers. Gating on pinned headers and buffers keeps the configuration
> space small and avoids partially-optimized modes that are unlikely to be
> useful in practice. Pages are unregistered when the request completes.
>
> The request flow for the zero-copy write path (client writes data,
> server reads it) is as follows:
> =======================================================================
> > Kernel | FUSE server
> > |
> > "write(fd, buf, 1MB)" |
> > |
> > >sys_write() |
> > >fuse_file_write_iter() |
> > >fuse_send_one() |
> > [req->args->in_pages = true] |
> > [folios hold client write data] |
> > |
> > >fuse_uring_copy_to_ring() |
> > >copy_header_to_ring(IN_OUT) |
> > [memcpy fuse_in_header to |
> > pinned headers buf via kaddr] |
> > >copy_header_to_ring(OP) |
> > [memcpy write_in header] |
> > |
> > >fuse_uring_args_to_ring() |
> > >setup_fuse_copy_state() |
> > [is_kaddr = true] |
> > [skip_folio_copy = true] |
> > |
> > >fuse_uring_set_up_zero_copy() |
> > [folio_get for each client folio] |
> > [build bio_vec array from folios] |
> > >io_buffer_register_bvec() |
> > [register pages at ent->id] |
> > [ent->zero_copied = true] |
> > |
> > >fuse_copy_args() |
> > [skip_folio_copy => return 0 |
> > for page arg, skip data copy] |
> > |
> > >copy_header_to_ring(RING_ENT) |
> > [memcpy ent_in_out] |
> > >io_uring_cmd_done() |
> > |
> > | [CQE received]
> > |
> > | [issue io_uring READ at
> > | ent->id]
> > | [reads directly from
> > |client's pages (ZERO_COPY)]
> > |
> > | [write data to backing
> > | store]
> > | [submit COMMIT AND FETCH]
> > |
> > >fuse_uring_commit_fetch() |
> > >fuse_uring_commit() |
> > >fuse_uring_copy_from_ring() |
> > >fuse_uring_req_end() |
> > >io_buffer_unregister(ent->id) |
> > [unregister sparse buffer] |
> > >fuse_zero_copy_release() |
> > [folio_put for each folio] |
> > [ent->zero_copied = false] |
> > >fuse_request_end() |
> > [wake up client] |
>
> The zero-copy read path is analogous.
>
> Some requests may have both page-backed args and non-page-backed args.
> For these requests, the page-backed args are zero-copied while the
> non-page-backed args are copied to the buffer selected from the buffer
> ring:
> zero-copy: pages registered via io_buffer_register_bvec()
> non-page-backed: copied to payload buffer via fuse_copy_args()
>
> For a request whose payload is zero-copied, the
> registration/unregistration path looks like:
>
> register: fuse_uring_set_up_zero_copy()
> folio_get() for each folio
> io_buffer_register_bvec(ent->id)
>
> [server accesses pages via io_uring fixed buf at ent->id]
>
> unregister: fuse_uring_req_end()
> io_buffer_unregister(ent->id)
> -> fuse_zero_copy_release() callback
> folio_put() for each folio
>
> The throughput improvement from zero-copy depends on how much of the
> per-request latency is spent on data copying vs backing I/O. When
> backing I/O dominates, the saved memcpy is a negligible fraction of
> overall latency. Please also note that for the server to read/write
> into the zero-copied pages, the read/write must go through io-uring
> as an IORING_OP_READ_FIXED / IORING_OP_WRITE_FIXED operation. If the
> server's backing I/O is instantaneous (eg served from cache), the
> overhead of the additional io_uring operation may negate the savings
> from eliminating the memcpy.
>
> In benchmarks using passthrough_hp on a high-performance NVMe-backed
> system, zero-copy showed around a 35% throughput improvement for direct
> randreads (~2150 MiB/s to ~2900 MiB/s), a 15% improvement for direct
> sequential reads (~2510 MiB/s to ~2900 MiB/s), a 15% improvement for
> buffered randreads (~2100 MiB/s to ~2470 MiB/s), and a 10% improvement
> for buffered sequential reads (~2500 MiB/s to ~2750 MiB/s).
>
> The benchmarks were run using:
> fio --name=test_run --ioengine=sync --rw=rand{read,write} --bs=1M
> --size=1G --numjobs=2 --ramp_time=30 --group_reporting=1
>
> Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> ---
> fs/fuse/dev.c | 7 +-
> fs/fuse/dev_uring.c | 167 +++++++++++++++++++++++++++++++++-----
> fs/fuse/dev_uring_i.h | 4 +
> fs/fuse/fuse_dev_i.h | 1 +
> include/uapi/linux/fuse.h | 5 ++
> 5 files changed, 160 insertions(+), 24 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index a87939eaa103..cd326e61831b 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1233,10 +1233,13 @@ int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
>
> for (i = 0; !err && i < numargs; i++) {
> struct fuse_arg *arg = &args[i];
> - if (i == numargs - 1 && argpages)
> + if (i == numargs - 1 && argpages) {
> + if (cs->skip_folio_copy)
> + return 0;
> err = fuse_copy_folios(cs, arg->size, zeroing);
> - else
> + } else {
> err = fuse_copy_one(cs, arg->value, arg->size);
> + }
> }
> return err;
> }
> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c
> index 06d3d8dc1c82..d9f1ee4beaf3 100644
> --- a/fs/fuse/dev_uring.c
> +++ b/fs/fuse/dev_uring.c
> @@ -31,6 +31,11 @@ struct fuse_uring_pdu {
> struct fuse_ring_ent *ent;
> };
>
> +struct fuse_zero_copy_bvs {
> + unsigned int nr_bvs;
> + struct bio_vec bvs[];
> +};
> +
> static const struct fuse_iqueue_ops fuse_io_uring_ops;
>
> enum fuse_uring_header_type {
> @@ -57,6 +62,11 @@ static inline bool bufring_pinned_buffers(struct fuse_ring_queue *queue)
> return queue->bufring->use_pinned_buffers;
> }
>
> +static inline bool bufring_zero_copy(struct fuse_ring_queue *queue)
> +{
> + return queue->bufring->use_zero_copy;
> +}
> +
> static void uring_cmd_set_ring_ent(struct io_uring_cmd *cmd,
> struct fuse_ring_ent *ring_ent)
> {
> @@ -102,8 +112,18 @@ static void fuse_uring_flush_bg(struct fuse_ring_queue *queue)
> }
> }
>
> +static bool can_zero_copy_req(struct fuse_ring_ent *ent, struct fuse_req *req)
> +{
> + struct fuse_args *args = req->args;
> +
> + if (!bufring_enabled(ent->queue) || !bufring_zero_copy(ent->queue))
> + return false;
> +
> + return args->in_pages || args->out_pages;
> +}
> +
> static void fuse_uring_req_end(struct fuse_ring_ent *ent, struct fuse_req *req,
> - int error)
> + int error, unsigned int issue_flags)
> {
> struct fuse_ring_queue *queue = ent->queue;
> struct fuse_ring *ring = queue->ring;
> @@ -122,6 +142,11 @@ static void fuse_uring_req_end(struct fuse_ring_ent *ent, struct fuse_req *req,
>
> spin_unlock(&queue->lock);
>
> + if (ent->zero_copied) {
> + io_buffer_unregister(ent->cmd, ent->id, issue_flags);
> + ent->zero_copied = false;
> + }
> +
> if (error)
> req->out.h.error = error;
>
> @@ -485,6 +510,7 @@ static int fuse_uring_bufring_setup(struct io_uring_cmd *cmd,
> struct iovec iov[FUSE_URING_IOV_SEGS];
> bool pinned_headers = init_flags & FUSE_URING_PINNED_HEADERS;
> bool pinned_bufs = init_flags & FUSE_URING_PINNED_BUFFERS;
> + bool zero_copy = init_flags & FUSE_URING_ZERO_COPY;
> void __user *payload, *headers;
> size_t headers_size, payload_size, ring_size;
> struct fuse_bufring *br;
> @@ -508,7 +534,7 @@ static int fuse_uring_bufring_setup(struct io_uring_cmd *cmd,
> if (headers_size < queue_depth * sizeof(struct fuse_uring_req_header))
> return -EINVAL;
>
> - if (buf_size < queue->ring->max_payload_sz)
> + if (!zero_copy && buf_size < queue->ring->max_payload_sz)
> return -EINVAL;
>
> nr_bufs = payload_size / buf_size;
> @@ -521,6 +547,7 @@ static int fuse_uring_bufring_setup(struct io_uring_cmd *cmd,
> if (!br)
> return -ENOMEM;
>
> + br->use_zero_copy = zero_copy;
> br->queue_depth = queue_depth;
> if (pinned_headers) {
> err = fuse_bufring_pin_mem(&br->pinned_headers, headers,
> @@ -580,6 +607,7 @@ static bool queue_init_flags_consistent(struct fuse_ring_queue *queue,
> bool bufring = init_flags & FUSE_URING_BUFRING;
> bool pinned_headers = init_flags & FUSE_URING_PINNED_HEADERS;
> bool pinned_bufs = init_flags & FUSE_URING_PINNED_BUFFERS;
> + bool zero_copy = init_flags & FUSE_URING_ZERO_COPY;
>
> if (bufring_enabled(queue) != bufring)
> return false;
> @@ -588,7 +616,8 @@ static bool queue_init_flags_consistent(struct fuse_ring_queue *queue,
> return true;
>
> return bufring_pinned_headers(queue) == pinned_headers &&
> - bufring_pinned_buffers(queue) == pinned_bufs;
> + bufring_pinned_buffers(queue) == pinned_bufs &&
> + bufring_zero_copy(queue) == zero_copy;
> }
>
> static struct fuse_ring_queue *
> @@ -1063,6 +1092,7 @@ static int setup_fuse_copy_state(struct fuse_copy_state *cs,
> cs->is_kaddr = true;
> cs->kaddr = (void *)ent->payload_buf.addr;
> cs->len = ent->payload_buf.len;
> + cs->skip_folio_copy = ent->zero_copied;
> }
>
> cs->is_uring = true;
> @@ -1095,11 +1125,70 @@ static int fuse_uring_copy_from_ring(struct fuse_ring *ring,
> return err;
> }
>
> +static void fuse_zero_copy_release(void *priv)
> +{
> + struct fuse_zero_copy_bvs *zc_bvs = priv;
> + unsigned int i;
> +
> + for (i = 0; i < zc_bvs->nr_bvs; i++)
> + folio_put(page_folio(zc_bvs->bvs[i].bv_page));
> +
> + kfree(zc_bvs);
> +}
> +
> +static int fuse_uring_set_up_zero_copy(struct fuse_ring_ent *ent,
> + struct fuse_req *req,
> + unsigned int issue_flags)
> +{
> + struct fuse_args_pages *ap;
> + int err, i, ddir = 0;
> + struct fuse_zero_copy_bvs *zc_bvs;
> + struct bio_vec *bvs;
> +
> + /* out_pages indicates a read, in_pages indicates a write */
> + if (req->args->out_pages)
> + ddir |= IO_BUF_DEST;
> + if (req->args->in_pages)
> + ddir |= IO_BUF_SOURCE;
> +
> + WARN_ON_ONCE(!ddir);
> +
> + ap = container_of(req->args, typeof(*ap), args);
> +
> + zc_bvs = kmalloc(struct_size(zc_bvs, bvs, ap->num_folios),
> + GFP_KERNEL_ACCOUNT);
> + if (!zc_bvs)
> + return -ENOMEM;
> +
> + zc_bvs->nr_bvs = ap->num_folios;
> + bvs = zc_bvs->bvs;
> + for (i = 0; i < ap->num_folios; i++) {
> + bvs[i].bv_page = folio_page(ap->folios[i], 0);
> + bvs[i].bv_offset = ap->descs[i].offset;
> + bvs[i].bv_len = ap->descs[i].length;
> + folio_get(ap->folios[i]);
> + }
> +
> + err = io_buffer_register_bvec(ent->cmd, bvs, ap->num_folios,
> + fuse_zero_copy_release, zc_bvs,
> + ddir, ent->id,
> + issue_flags);
> + if (err) {
> + fuse_zero_copy_release(zc_bvs);
> + return err;
> + }
> +
> + ent->zero_copied = true;
> +
> + return 0;
> +}
> +
> /*
> * Copy data from the req to the ring buffer
> */
> static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req,
> - struct fuse_ring_ent *ent)
> + struct fuse_ring_ent *ent,
> + unsigned int issue_flags)
> {
> struct fuse_copy_state cs;
> struct fuse_args *args = req->args;
> @@ -1112,8 +1201,15 @@ static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req,
> .commit_id = req->in.h.unique,
> };
>
> - if (bufring_enabled(ent->queue))
> + if (bufring_enabled(ent->queue)) {
> ent_in_out.buf_id = ent->payload_buf.id;
> + if (can_zero_copy_req(ent, req)) {
> + ent_in_out.flags |= FUSE_URING_ENT_ZERO_COPY;
> + err = fuse_uring_set_up_zero_copy(ent, req, issue_flags);
> + if (err)
> + return err;
> + }
> + }
>
> err = setup_fuse_copy_state(&cs, ring, req, ent, ITER_DEST, &iter);
> if (err)
> @@ -1145,12 +1241,17 @@ static int fuse_uring_args_to_ring(struct fuse_ring *ring, struct fuse_req *req,
> }
>
> ent_in_out.payload_sz = cs.ring.copied_sz;
> + if (cs.skip_folio_copy && args->in_pages)
> + ent_in_out.payload_sz +=
> + args->in_args[args->in_numargs - 1].size;
> +
> return copy_header_to_ring(ent, FUSE_URING_HEADER_RING_ENT,
> &ent_in_out, sizeof(ent_in_out));
> }
>
> static int fuse_uring_copy_to_ring(struct fuse_ring_ent *ent,
> - struct fuse_req *req)
> + struct fuse_req *req,
> + unsigned int issue_flags)
> {
> struct fuse_ring_queue *queue = ent->queue;
> struct fuse_ring *ring = queue->ring;
> @@ -1168,7 +1269,7 @@ static int fuse_uring_copy_to_ring(struct fuse_ring_ent *ent,
> return err;
>
> /* copy the request */
> - err = fuse_uring_args_to_ring(ring, req, ent);
> + err = fuse_uring_args_to_ring(ring, req, ent, issue_flags);
> if (unlikely(err)) {
> pr_info_ratelimited("Copy to ring failed: %d\n", err);
> return err;
> @@ -1179,11 +1280,25 @@ static int fuse_uring_copy_to_ring(struct fuse_ring_ent *ent,
> sizeof(req->in.h));
> }
>
> -static bool fuse_uring_req_has_payload(struct fuse_req *req)
> +static bool fuse_uring_req_has_copyable_payload(struct fuse_ring_ent *ent,
> + struct fuse_req *req)
> {
> struct fuse_args *args = req->args;
>
> - return args->in_numargs > 1 || args->out_numargs;
> + if (!can_zero_copy_req(ent, req))
> + return args->in_numargs > 1 || args->out_numargs;
> +
> + /*
> + * the asymmetry between in_numargs > 2 and out_numargs > 1 is because
> + * the per-op header is extracted before fuse_copy_args() for inargs but
> + * not for outargs
> + */
> + if ((args->in_numargs > 1) && (!args->in_pages || args->in_numargs > 2))
> + return true;
> + if (args->out_numargs && (!args->out_pages || args->out_numargs > 1))
> + return true;
> +
> + return false;
> }
>
> static int fuse_uring_select_buffer(struct fuse_ring_ent *ent)
> @@ -1245,7 +1360,7 @@ static int fuse_uring_next_req_update_buffer(struct fuse_ring_ent *ent,
> return 0;
>
> buffer_selected = !!ent->payload_buf.addr;
> - has_payload = fuse_uring_req_has_payload(req);
> + has_payload = fuse_uring_req_has_copyable_payload(ent, req);
>
> if (has_payload && !buffer_selected)
> return fuse_uring_select_buffer(ent);
> @@ -1263,22 +1378,23 @@ static int fuse_uring_prep_buffer(struct fuse_ring_ent *ent,
> return 0;
>
> /* no payload to copy, can skip selecting a buffer */
> - if (!fuse_uring_req_has_payload(req))
> + if (!fuse_uring_req_has_copyable_payload(ent, req))
> return 0;
>
> return fuse_uring_select_buffer(ent);
> }
>
> static int fuse_uring_prepare_send(struct fuse_ring_ent *ent,
> - struct fuse_req *req)
> + struct fuse_req *req,
> + unsigned int issue_flags)
> {
> int err;
>
> - err = fuse_uring_copy_to_ring(ent, req);
> + err = fuse_uring_copy_to_ring(ent, req, issue_flags);
> if (!err)
> set_bit(FR_SENT, &req->flags);
> else
> - fuse_uring_req_end(ent, req, err);
> + fuse_uring_req_end(ent, req, err, issue_flags);
>
> return err;
> }
> @@ -1386,7 +1502,7 @@ static void fuse_uring_commit(struct fuse_ring_ent *ent, struct fuse_req *req,
>
> err = fuse_uring_copy_from_ring(ring, req, ent);
> out:
> - fuse_uring_req_end(ent, req, err);
> + fuse_uring_req_end(ent, req, err, issue_flags);
> }
>
> /*
> @@ -1396,7 +1512,8 @@ static void fuse_uring_commit(struct fuse_ring_ent *ent, struct fuse_req *req,
> * Else, there is no next fuse request and this returns false.
> */
> static bool fuse_uring_get_next_fuse_req(struct fuse_ring_ent *ent,
> - struct fuse_ring_queue *queue)
> + struct fuse_ring_queue *queue,
> + unsigned int issue_flags)
> {
> int err;
> struct fuse_req *req;
> @@ -1408,7 +1525,7 @@ static bool fuse_uring_get_next_fuse_req(struct fuse_ring_ent *ent,
> spin_unlock(&queue->lock);
>
> if (req) {
> - err = fuse_uring_prepare_send(ent, req);
> + err = fuse_uring_prepare_send(ent, req, issue_flags);
> if (err)
> goto retry;
> }
> @@ -1523,7 +1640,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags,
> * no-op and the next request will be serviced when a buffer becomes
> * available.
> */
> - if (fuse_uring_get_next_fuse_req(ent, queue))
> + if (fuse_uring_get_next_fuse_req(ent, queue, issue_flags))
> fuse_uring_send(ent, cmd, 0, issue_flags);
> return 0;
> }
> @@ -1645,12 +1762,17 @@ static bool init_flags_valid(u64 init_flags)
> {
> u64 valid_flags =
> FUSE_URING_BUFRING | FUSE_URING_PINNED_HEADERS |
> - FUSE_URING_PINNED_BUFFERS;
> + FUSE_URING_PINNED_BUFFERS | FUSE_URING_ZERO_COPY;
> bool bufring = init_flags & FUSE_URING_BUFRING;
> bool pinned_headers = init_flags & FUSE_URING_PINNED_HEADERS;
> bool pinned_buffers = init_flags & FUSE_URING_PINNED_BUFFERS;
> + bool zero_copy = init_flags & FUSE_URING_ZERO_COPY;
> +
> + if (!bufring && (pinned_headers || pinned_buffers || zero_copy))
> + return false;
>
> - if (!bufring && (pinned_headers || pinned_buffers))
> + if (zero_copy &&
> + (!capable(CAP_SYS_ADMIN) || !pinned_headers || !pinned_buffers))
> return false;
>
> return !(init_flags & ~valid_flags);
> @@ -1795,9 +1917,10 @@ static void fuse_uring_send_in_task(struct io_tw_req tw_req, io_tw_token_t tw)
> int err;
>
> if (!tw.cancel) {
> - err = fuse_uring_prepare_send(ent, ent->fuse_req);
> + err = fuse_uring_prepare_send(ent, ent->fuse_req, issue_flags);
> if (err) {
> - if (!fuse_uring_get_next_fuse_req(ent, queue))
> + if (!fuse_uring_get_next_fuse_req(ent, queue,
> + issue_flags))
> return;
> err = 0;
> }
> diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h
> index 859ee4e6ba03..0546f719fc65 100644
> --- a/fs/fuse/dev_uring_i.h
> +++ b/fs/fuse/dev_uring_i.h
> @@ -58,6 +58,8 @@ struct fuse_bufring_pinned {
> struct fuse_bufring {
> bool use_pinned_headers: 1;
> bool use_pinned_buffers: 1;
> + /* this is only allowed on privileged servers */
> + bool use_zero_copy: 1;
> unsigned int queue_depth;
>
> union {
> @@ -96,6 +98,8 @@ struct fuse_ring_ent {
> */
> unsigned int id;
> struct fuse_bufring_buf payload_buf;
> + /* true if the request's pages are being zero-copied */
> + bool zero_copied;
> };
> };
>
> diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h
> index aa1d25421054..67b5bed451fe 100644
> --- a/fs/fuse/fuse_dev_i.h
> +++ b/fs/fuse/fuse_dev_i.h
> @@ -39,6 +39,7 @@ struct fuse_copy_state {
> bool is_uring:1;
> /* if set, use kaddr; otherwise use pg */
> bool is_kaddr:1;
> + bool skip_folio_copy:1;
> struct {
> unsigned int copied_sz; /* copied size into the user buffer */
> } ring;
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 51ecb66dd6eb..c2e53886cf06 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -246,6 +246,7 @@
> * - add fuse_uring_cmd_req init struct
> * - add FUSE_URING_PINNED_HEADERS flag
> * - add FUSE_URING_PINNED_BUFFERS flag
> + * - add FUSE_URING_ZERO_COPY flag
> */
>
> #ifndef _LINUX_FUSE_H
> @@ -1257,6 +1258,9 @@ struct fuse_supp_groups {
> #define FUSE_URING_IN_OUT_HEADER_SZ 128
> #define FUSE_URING_OP_IN_OUT_SZ 128
>
> +/* Set if the ent's payload is zero-copied */
> +#define FUSE_URING_ENT_ZERO_COPY (1 << 0)
> +
> /* Used as part of the fuse_uring_req_header */
> struct fuse_uring_ent_in_out {
> uint64_t flags;
> @@ -1310,6 +1314,7 @@ enum fuse_uring_cmd {
> #define FUSE_URING_BUFRING (1 << 0)
> #define FUSE_URING_PINNED_HEADERS (1 << 1)
> #define FUSE_URING_PINNED_BUFFERS (1 << 2)
> +#define FUSE_URING_ZERO_COPY (1 << 3)
>
> /**
> * In the 80B command area of the SQE.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2026-04-30 12:56 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 16:28 [PATCH v2 00/14] fuse: add io-uring buffer rings and zero-copy Joanne Koong
2026-04-02 16:28 ` [PATCH v2 01/14] fuse: separate next request fetching from sending logic Joanne Koong
2026-04-29 11:52 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 02/14] fuse: refactor io-uring header copying to ring Joanne Koong
2026-04-29 12:05 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 03/14] fuse: refactor io-uring header copying from ring Joanne Koong
2026-04-29 12:06 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 04/14] fuse: use enum types for header copying Joanne Koong
2026-04-30 8:04 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 05/14] fuse: refactor setting up copy state for payload copying Joanne Koong
2026-04-30 8:06 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 06/14] fuse: support buffer copying for kernel addresses Joanne Koong
2026-04-30 8:19 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 07/14] fuse: use named constants for io-uring iovec indices Joanne Koong
2026-04-15 9:36 ` Bernd Schubert
2026-04-30 8:20 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 08/14] fuse: move fuse_uring_abort() from header to dev_uring.c Joanne Koong
2026-04-15 9:40 ` Bernd Schubert
2026-04-30 8:21 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 09/14] fuse: rearrange io-uring iovec and ent allocation logic Joanne Koong
2026-04-15 9:45 ` Bernd Schubert
2026-04-30 8:24 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 10/14] fuse: add io-uring buffer rings Joanne Koong
2026-04-15 9:48 ` Bernd Schubert
2026-04-15 21:40 ` Joanne Koong
2026-04-30 11:08 ` Jeff Layton
2026-04-30 12:44 ` Joanne Koong
2026-05-05 22:47 ` Bernd Schubert
2026-04-02 16:28 ` [PATCH v2 11/14] fuse: add pinned headers capability for " Joanne Koong
2026-04-14 12:47 ` Bernd Schubert
2026-04-15 0:48 ` Joanne Koong
2026-05-05 22:51 ` Bernd Schubert
2026-04-30 11:22 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 12/14] fuse: add pinned payload buffers " Joanne Koong
2026-04-30 11:29 ` Jeff Layton
2026-04-02 16:28 ` [PATCH v2 13/14] fuse: add zero-copy over io-uring Joanne Koong
2026-04-30 11:42 ` Jeff Layton
2026-04-30 12:35 ` Joanne Koong
2026-04-30 12:55 ` Jeff Layton
2026-05-05 22:55 ` Bernd Schubert
2026-04-30 12:56 ` Jeff Layton [this message]
2026-05-05 23:45 ` Bernd Schubert
2026-04-02 16:28 ` [PATCH v2 14/14] docs: fuse: add io-uring bufring and zero-copy documentation Joanne Koong
2026-04-14 21:05 ` Bernd Schubert
2026-04-15 1:10 ` Joanne Koong
2026-04-15 10:55 ` Bernd Schubert
2026-04-15 22:40 ` Joanne Koong
2026-04-30 12:57 ` Jeff Layton
2026-04-30 12:59 ` [PATCH v2 00/14] fuse: add io-uring buffer rings and zero-copy Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f8201c9c18a3317cf41d6112f39f7885fb0f64c5.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=axboe@kernel.dk \
--cc=bernd@bsbernd.com \
--cc=joannelkoong@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=miklos@szeredi.hu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox