fuse_uring: restore inline-reply batching, add single-issuer fast path

Part 1 dropped cqe_processing and made the serving loop wait-only, so
the default path now issues one io_uring_submit() per inline reply
instead of coalescing a cqe batch into a single submit.

Restore the batching: the loop splits submit_and_wait so the flush
stays under ring_lock (part 1's race fix), and cqe_processing - now an
_Atomic bool set lock-free around handle_cqes() - again gates the
per-reply submit. The SQ stays serialised, so a batched reply is always
flushed before the next wait, never stranded.

Add a conn flag, io_uring_single_issuer, for a filesystem that replies
only from the per-queue uring thread: it skips ring_lock entirely and
runs the combined io_uring_submit_and_wait() loop, sound because only
that thread touches the ring. The flag reuses a reserved padding bit
(ABI unchanged; flag 0 keeps the multi-issuer path) and is mirrored
into the ring pool after op.init(), before serving starts.

A filesystem enables it with fuse_set_conn_flag(conn,
FUSE_CONN_FLAG_SINGLE_ISSUER), a new exported setter modelled on
fuse_set_feature_flag(); the io_uring_single_issuer bitfield is the
internal storage.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This commit is contained in:
Bernd Schubert
2026-06-20 17:18:54 +02:00
parent 6910b07ade
commit 670f938336
4 changed files with 107 additions and 29 deletions
+28 -1
View File
@@ -698,8 +698,19 @@ struct fuse_conn_info {
*/
uint32_t no_interrupt : 1;
/**
* Only meaningful with io-uring (FUSE_CAP_OVER_IO_URING).
* The filesystem promises that every reply to an io-uring request is
* sent from the same thread that received the request (the per-queue
* io-uring worker), i.e. replies are never deferred to another thread.
* The flag is used for io-uring optimizations.
*
*/
uint32_t io_uring_single_issuer : 1;
/* reserved bits for future use */
uint32_t padding : 31;
uint32_t padding : 30;
/**
* Extended capability flags that the kernel supports (read-only)
@@ -1140,6 +1151,22 @@ void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag);
*/
bool fuse_get_feature_flag(const struct fuse_conn_info *conn, uint64_t flag);
/* The file system replies to requests from the same thread that received them,
* allowing io-uring optimizations
*/
#define FUSE_CONN_FLAG_SINGLE_ISSUER (1u << 0)
/**
* Set a libfuse connection flag (a FUSE_CONN_FLAG_* value). Unlike
* fuse_set_feature_flag(), these are libfuse-side hints, not negotiated
* with the kernel.
*
* @param conn connection information
* @param flag a single FUSE_CONN_FLAG_* value
* @return true if the flag is known to this libfuse and was set, false otherwise
*/
bool fuse_set_conn_flag(struct fuse_conn_info *conn, uint64_t flag);
/*
* DO NOT USE: Not part of public API, for internal test use only.
* The function signature or any use of it is not guaranteeed to