| .. 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. | |
| ``fuse_uring_cmd_req.flags`` must be 0. Submitting this command with | |
| ``IORING_URING_CMD_FIXED`` marks the pool as registered, which avoids per | |
| i/o pinning/unpinning and mapping overhead (see `Buffer pools`_). | |
| ``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``. | |
| ``bufpool.reserved`` Must be 0, 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 | |
| ============ | |
| 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. | |
| To use registered buffers, the server registers the pool region with io_uring | |
| and submits ``ADD_BUFPOOL`` with ``IORING_URING_CMD_FIXED`` set in | |
| ``sqe->uring_cmd_flags`` and the index of the registered bufpool in | |
| ``sqe->buf_index``. Every SQE the server submits afterwards must follow the | |
| same fixed-buffer protocol, carrying ``IORING_URING_CMD_FIXED`` and that same | |
| ``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``). | |
| Zero-copy | |
| ========= | |
| Requirements: | |
| * The server must be privileged (``CAP_SYS_ADMIN``). | |
| * 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``. |