Re: [PATCH v5 6/6] docs: fuse: document io-uring buffer pool and zero-copy uapi

Amir Goldstein <[email protected]> Wed, 1 Jul 2026 13:56:35 +0200
Newsgroups dev.linux.lists.fuse-devel
Message-ID <CAOQ4uxj8RU8X0V3+74rw9wjBc2w2TH8qaGXgLq6DdjPuQ8tivg@mail.gmail.com>
On Tue, Jun 30, 2026 at 11:17 PM Joanne Koong <[email protected]> wrote:
>
> Add documentation for fuse over io-uring usage of buffer pools and
> zero-copy.
>
> Signed-off-by: Joanne Koong <[email protected]>
> ---
>  .../filesystems/fuse/fuse-io-uring.rst        |   5 +-
>  Documentation/filesystems/fuse/index.rst      |   1 +
>  .../filesystems/fuse/uapi/io-uring.rst        | 143 ++++++++++++++++++
>  3 files changed, 148 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/filesystems/fuse/uapi/io-uring.rst
>
> diff --git a/Documentation/filesystems/fuse/fuse-io-uring.rst b/Documentation/filesystems/fuse/fuse-io-uring.rst
> index d73dd0dbd238..a92dee057d78 100644
> --- a/Documentation/filesystems/fuse/fuse-io-uring.rst
> +++ b/Documentation/filesystems/fuse/fuse-io-uring.rst
> @@ -95,5 +95,8 @@ Sending requests with CQEs
>   |    <fuse_unlink()                         |
>   |  <sys_unlink()                            |
>
> -
> +Buffer pools and zero-copy
> +==========================
> +For the userspace protocol used to set up buffer pools and zero-copy, see
> +Documentation/filesystems/fuse/uapi/io-uring.rst.

This dereference is not clear to me.

The name of the suggested doc is even more puzzling for me
io-uring.rst is really not an adequest standalone name for this doc
and fuse/uapi path is unconventional in Documentation.
The doc is not even pure uapi, it explains about buffer pools and zero copy.

Why not include the details inline in fuse-io-uring.rst?
It's not going to be a huge doc and all details seem to be intertwined.

Thanks,
Amir.

>
> diff --git a/Documentation/filesystems/fuse/index.rst b/Documentation/filesystems/fuse/index.rst
> index 393a845214da..0ee75d9df2dd 100644
> --- a/Documentation/filesystems/fuse/index.rst
> +++ b/Documentation/filesystems/fuse/index.rst
> @@ -12,3 +12,4 @@ FUSE (Filesystem in Userspace) Technical Documentation
>     fuse-io
>     fuse-io-uring
>     fuse-passthrough
> +   uapi/io-uring
> diff --git a/Documentation/filesystems/fuse/uapi/io-uring.rst b/Documentation/filesystems/fuse/uapi/io-uring.rst
> new file mode 100644
> index 000000000000..29f921782fed
> --- /dev/null
> +++ b/Documentation/filesystems/fuse/uapi/io-uring.rst
> @@ -0,0 +1,143 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +=====================================
> +FUSE-over-io-uring uapi documentation
> +=====================================
> +
> +Commands
> +========
> +
> +``enum fuse_uring_cmd``:
> +
> +``FUSE_IO_URING_CMD_ADD_QUEUE``
> +  Create a queue identified by ``fuse_uring_cmd_req.qid``. Queue-wide
> +  options are passed in ``fuse_uring_cmd_req.flags``:
> +
> +  ``FUSE_URING_ZERO_COPY``
> +    Enable zero-copy on this queue. Requires ``CAP_SYS_ADMIN`` and a buffer
> +    pool, which is added separately via ``ADD_BUFPOOL`` before registering
> +    entries (see `Zero-copy`_).
> +
> +``FUSE_IO_URING_CMD_ADD_BUFPOOL``
> +  Register the payload buffer pool for an existing queue. The server provides
> +  a single contiguous region in ``fuse_uring_cmd_req.bufpool.uaddr`` /
> +  ``.len``. This command must be issued after ``ADD_QUEUE`` and before
> +  registering any payload-carrying entries on that queue. Flags:
> +
> +  ``FUSE_URING_REGISTERED_BUFPOOL``
> +    The pool region is registered ahead of time with io_uring to avoid per i/o
> +    pinning/unpinning and mapping overhead.
> +
> +``FUSE_IO_URING_CMD_REGISTER``
> +  Register a ring entry (a long-lived SQE that carries the request header
> +  iovec). For a zero-copy queue, ``fuse_uring_cmd_req.ent_zero_copy_buf_index``
> +  indicates the reserved registered buffer table slot this entry uses for
> +  zero-copy (see `Zero-copy`_).
> +
> +``FUSE_IO_URING_CMD_COMMIT_AND_FETCH``
> +  Commit the reply for a completed request and fetch the next one. The
> +  request is identified by ``fuse_uring_cmd_req.commit_id`` (the value the
> +  kernel reported in ``fuse_uring_ent_in_out.commit_id``).
> +
> +Structures
> +==========
> +
> +``struct fuse_uring_cmd_req`` (80-byte SQE command area):
> +
> +============================  ==================================================
> +Field                         Meaning
> +============================  ==================================================
> +``flags``                     Command-specific flags (see each command).
> +``commit_id``                 Request id, for ``COMMIT_AND_FETCH``.
> +``qid``                       Queue index.
> +``bufpool.uaddr``             Pool base address, for ``ADD_BUFPOOL``.
> +``bufpool.len``               Pool length in bytes, for ``ADD_BUFPOOL``.
> +``ent_zero_copy_buf_index``   Per-entry zero-copy slot, for ``REGISTER``.
> +============================  ==================================================
> +
> +``struct fuse_uring_ent_in_out`` (reported by the kernel per request):
> +
> +============================  ==================================================
> +Field                         Meaning
> +============================  ==================================================
> +``flags``                     ``FUSE_URING_ENT_ZERO_COPY`` if zero-copied.
> +``commit_id``                 Id to echo back in ``COMMIT_AND_FETCH``.
> +``payload_sz``                Total payload size in bytes (see `Zero-copy`_).
> +``offset``                    Payload buffer offset within the pool.
> +============================  ==================================================
> +
> +Buffer pools
> +============
> +
> +Without a buffer pool, every entry needs to pass a dedicated payload buffer
> +large enough for the maximum payload size. A buffer pool decouples entries
> +from payload buffers. The server hands the kernel one contiguous region and
> +when the kernel sends the server a request, it indicates the offset into the
> +buffer pool for that request's payload.
> +
> +Setup:
> +
> +* Issue ``ADD_QUEUE`` for the qid.
> +* Issue ``ADD_BUFPOOL`` with ``bufpool.uaddr`` and ``bufpool.len`` pointing
> +  at the region.
> +* Register entries with ``REGISTER``.
> +
> +For every request that has a payload, the kernel reports where the payload
> +lives in ``struct fuse_uring_ent_in_out`` (part of
> +``struct fuse_uring_req_header``):
> +
> +``offset``
> +  Byte offset, within the pool region, for this request's payload buffer.
> +  The server adds this to the pool base address to locate the payload.
> +
> +``payload_sz``
> +  Number of payload bytes for this request.
> +
> +A server may register the pool region with io_uring as a fixed buffer. The
> +backing pages are then pinned once, avoiding per-request pinning and address
> +translation. The server should pass ``FUSE_URING_REGISTERED_BUFPOOL`` as a flag
> +to ``ADD_BUFPOOL`` and set ``IORING_URING_CMD_FIXED`` in
> +``sqe->uring_cmd_flags`` and put the index of the registered bufppol in
> +``sqe->buf_index``. The same registered buffer can be reused for the server's
> +backing-store I/O as well (e.g. ``IORING_OP_READ_FIXED`` /
> +``IORING_OP_WRITE_FIXED``).
> +
> +When using registered bufpools, every SQE the server submits must follow the
> +standard fixed-buffer protocol: set ``IORING_URING_CMD_FIXED`` in
> +``sqe->uring_cmd_flags`` and put the index of the registered bufpool in
> +``sqe->buf_index``.
> +
> +Zero-copy
> +=========
> +
> +Zero-copy lets the server read from / write to the client's pages (pinned
> +user pages for direct I/O, or page-cache folios for buffered I/O) without an
> +intermediary payload copy. Because it grants the server direct access to
> +those pages, it requires ``CAP_SYS_ADMIN``.
> +
> +Requirements:
> +
> +* A zero-copy queue: ``ADD_QUEUE`` with the ``FUSE_URING_ZERO_COPY`` flag set.
> +* A buffer pool: ``ADD_BUFPOOL``.
> +* For each entry, ``REGISTER`` with ``ent_zero_copy_buf_index`` set to the
> +  index this entry uses in the server's io_uring registered-buffer table.
> +  This is where the kernel registers the request's pages for the server to
> +  access (it is separate from the payload pool). On a non-zero-copy queue this
> +  field must be 0.
> +
> +Zero-copy is selected per open file. The server sets the open-file flag in
> +the ``FUSE_OPEN`` / ``FUSE_CREATE`` reply:
> +
> +``FOPEN_IO_URING_ZERO_COPY``
> +  Reads/writes on this open file should use zero-copy.
> +
> +For a request that is zero-copied, the kernel sets ``FUSE_URING_ENT_ZERO_COPY``
> +in ``fuse_uring_ent_in_out.flags`` and places the request's pages at the
> +entry's ``ent_zero_copy_buf_index``. The server then issues
> +``IORING_OP_READ_FIXED`` / ``IORING_OP_WRITE_FIXED`` against that index to
> +transfer the data directly to/from the client's pages.
> +
> +For such a request, ``payload_sz`` includes the zero-copied page bytes
> +(transferred via the registered buffer at ``ent_zero_copy_buf_index``). Any
> +non-page-backed args (e.g. op headers) are still copied through the pool
> +payload buffer at ``offset``.
> --
> 2.52.0
>
>