xref: /linux/Documentation/filesystems/fuse/fuse-io-uring.rst (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1.. SPDX-License-Identifier: GPL-2.0
2
3=======================================
4FUSE-over-io-uring design documentation
5=======================================
6
7This documentation covers basic details how the fuse
8kernel/userspace communication through io-uring is configured
9and works. For generic details about FUSE see fuse.rst.
10
11This document also covers the current interface, which is
12still in development and might change.
13
14For the userspace protocol, see
15Documentation/filesystems/fuse/uapi/fuse-uapi-io-uring.rst.
16
17Limitations
18===========
19As of now not all requests types are supported through io-uring, userspace
20is required to also handle requests through /dev/fuse after io-uring setup
21is complete. Specifically notifications (initiated from the daemon side)
22and interrupts.
23
24Fuse io-uring configuration
25===========================
26
27Fuse kernel requests are queued through the classical /dev/fuse
28read/write interface - until io-uring setup is complete.
29
30In order to set up fuse-over-io-uring fuse-server (user-space)
31needs to submit SQEs (opcode = IORING_OP_URING_CMD) to the /dev/fuse
32connection file descriptor. Initial submit is with the sub command
33FUSE_URING_REQ_REGISTER, which will just register entries to be
34available in the kernel.
35
36Once at least one entry per queue is submitted, kernel starts
37to enqueue to ring queues.
38Note, every CPU core has its own fuse-io-uring queue.
39Userspace handles the CQE/fuse-request and submits the result as
40subcommand FUSE_URING_REQ_COMMIT_AND_FETCH - kernel completes
41the requests and also marks the entry available again. If there are
42pending requests waiting the request will be immediately submitted
43to the daemon again.
44
45Initial SQE
46-----------::
47
48 |                                    |  FUSE filesystem daemon
49 |                                    |
50 |                                    |  >io_uring_submit()
51 |                                    |   IORING_OP_URING_CMD /
52 |                                    |   FUSE_URING_CMD_REGISTER
53 |                                    |  [wait cqe]
54 |                                    |   >io_uring_wait_cqe() or
55 |                                    |   >io_uring_submit_and_wait()
56 |                                    |
57 |  >fuse_uring_cmd()                 |
58 |   >fuse_uring_register()           |
59
60
61Sending requests with CQEs
62--------------------------::
63
64 |                                           |  FUSE filesystem daemon
65 |                                           |  [waiting for CQEs]
66 |  "rm /mnt/fuse/file"                      |
67 |                                           |
68 |  >sys_unlink()                            |
69 |    >fuse_unlink()                         |
70 |      [allocate request]                   |
71 |      >fuse_send_one()                     |
72 |        ...                                |
73 |       >fuse_uring_queue_fuse_req          |
74 |        [queue request on fg queue]        |
75 |         >fuse_uring_add_req_to_ring_ent() |
76 |         ...                               |
77 |          >fuse_uring_copy_to_ring()       |
78 |          >io_uring_cmd_done()             |
79 |       >request_wait_answer()              |
80 |         [sleep on req->waitq]             |
81 |                                           |  [receives and handles CQE]
82 |                                           |  [submit result and fetch next]
83 |                                           |  >io_uring_submit()
84 |                                           |   IORING_OP_URING_CMD/
85 |                                           |   FUSE_URING_CMD_COMMIT_AND_FETCH
86 |  >fuse_uring_cmd()                        |
87 |   >fuse_uring_commit_fetch()              |
88 |    >fuse_uring_commit()                   |
89 |     >fuse_uring_copy_from_ring()          |
90 |      [ copy the result to the fuse req]   |
91 |     >fuse_uring_req_end()                 |
92 |      >fuse_request_end()                  |
93 |       [wake up req->waitq]                |
94 |    >fuse_uring_next_fuse_req              |
95 |       [wait or handle next req]           |
96 |                                           |
97 |       [req->waitq woken up]               |
98 |    <fuse_unlink()                         |
99 |  <sys_unlink()                            |
100
101Buffer pools
102============
103
104Without a buffer pool, every entry needs to pass a dedicated payload buffer
105large enough for the maximum payload size. A buffer pool decouples entries
106from payload buffers. The server hands the kernel one contiguous buffer pool
107of memory and when the kernel sends the server a request, it indicates the
108offset into the pool for that request's payload. Internally, the kernel is
109able to manage/optimize the buffer pool memory however it likes.
110
111A server may also register the pool region with io_uring as a fixed buffer.
112The backing pages are then pinned once, avoiding per-request pinning and
113address translation. This also allows servers to use the same registered
114buffers for subsequent backing store I/O through io-uring, keeping data
115in the same pinned pages without additional pinning / mapping overhead.
116
117Zero-copy
118=========
119
120Zero-copy lets the server read from / write to the client's pages (pinned
121user pages for direct I/O, or page-cache folios for buffered I/O) without an
122intermediary payload copy. This requires CAP_SYS_ADMIN privileges.
123
124When a fuse request arrives for a file that opted into zero-copy, the kernel
125registers the relevant pages (pinned user pages for direct i/o or underlying
126page cache folios for buffered i/o) into a sparse slot in the server's
127io_uring registered buffer table. The server can then operate on these pages
128directly using io-uring fixed buffer operations (eg read_fixed / write_fixed)
129and the kernel unregisters these pages when the request completes.
130Non-page-backed args (eg op out headers) will go through the payload buffer as
131normal.
132