FUSE-over-io-uring 设计文档

本文档涵盖了 FUSE 内核/用户空间通过 io-uring 进行通信的配置和工作原理。有关 FUSE 的通用详细信息,请参阅FUSE

本文档还涵盖了当前仍在开发中且可能更改的接口。

限制

截至目前,并非所有请求类型都通过 io-uring 支持,用户空间在 io-uring 设置完成后仍需通过 /dev/fuse 处理请求。特别是通知(由守护进程发起)和中断。

Fuse io-uring 配置

Fuse 内核请求通过经典的 /dev/fuse 读/写接口排队——直到 io-uring 设置完成。

为了设置 fuse-over-io-uring,fuse-server(用户空间)需要向 /dev/fuse 连接文件描述符提交 SQE(操作码 = IORING_OP_URING_CMD)。首次提交使用子命令 FUSE_URING_REQ_REGISTER,这将只是注册条目以使其在内核中可用。

一旦每个队列至少提交一个条目,内核就开始向环形队列入队。请注意,每个 CPU 核心都有自己的 fuse-io-uring 队列。用户空间处理 CQE/fuse 请求,并将结果作为子命令 FUSE_URING_REQ_COMMIT_AND_FETCH 提交——内核完成请求并再次标记条目可用。如果有挂起的请求等待,该请求将立即再次提交给守护进程。

初始 SQE -----------

|                                    |  FUSE filesystem daemon
|                                    |
|                                    |  >io_uring_submit()
|                                    |   IORING_OP_URING_CMD /
|                                    |   FUSE_URING_CMD_REGISTER
|                                    |  [wait cqe]
|                                    |   >io_uring_wait_cqe() or
|                                    |   >io_uring_submit_and_wait()
|                                    |
|  >fuse_uring_cmd()                 |
|   >fuse_uring_register()           |

使用 CQE 发送请求 --------------------------

|                                           |  FUSE filesystem daemon
|                                           |  [waiting for CQEs]
|  "rm /mnt/fuse/file"                      |
|                                           |
|  >sys_unlink()                            |
|    >fuse_unlink()                         |
|      [allocate request]                   |
|      >fuse_send_one()                     |
|        ...                                |
|       >fuse_uring_queue_fuse_req          |
|        [queue request on fg queue]        |
|         >fuse_uring_add_req_to_ring_ent() |
|         ...                               |
|          >fuse_uring_copy_to_ring()       |
|          >io_uring_cmd_done()             |
|       >request_wait_answer()              |
|         [sleep on req->waitq]             |
|                                           |  [receives and handles CQE]
|                                           |  [submit result and fetch next]
|                                           |  >io_uring_submit()
|                                           |   IORING_OP_URING_CMD/
|                                           |   FUSE_URING_CMD_COMMIT_AND_FETCH
|  >fuse_uring_cmd()                        |
|   >fuse_uring_commit_fetch()              |
|    >fuse_uring_commit()                   |
|     >fuse_uring_copy_from_ring()          |
|      [ copy the result to the fuse req]   |
|     >fuse_uring_req_end()                 |
|      >fuse_request_end()                  |
|       [wake up req->waitq]                |
|    >fuse_uring_next_fuse_req              |
|       [wait or handle next req]           |
|                                           |
|       [req->waitq woken up]               |
|    <fuse_unlink()                         |
|  <sys_unlink()                            |