examples: enable io_uring single-issuer mode

These example filesystems always send their reply from the per-queue
io-uring worker thread. The ones that run a helper thread use it only
for cache-invalidation notifications over /dev/fuse, not ring
submissions, so they too satisfy the io_uring_single_issuer contract.

Call fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER) in their
init() handlers so they take the lock-free, registered-ring-fd fast
path. It is harmless when io-uring is not in use.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This commit is contained in:
Bernd Schubert
2026-06-20 17:25:57 +02:00
parent 1615ff35af
commit 2ad90f04dc
15 changed files with 41 additions and 6 deletions
+3 -1
View File
@@ -55,7 +55,9 @@ static const struct fuse_opt option_spec[] = {
static void *hello_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
cfg->kernel_cache = 1;
/* Test setting flags the old way */
+3
View File
@@ -61,6 +61,9 @@ static void hello_ll_init(void *userdata, struct fuse_conn_info *conn)
{
(void)userdata;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
conn->no_interrupt = 1;
+2 -1
View File
@@ -72,7 +72,8 @@ static const struct fuse_opt option_spec[] = {
static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
{
(void) conn;
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
cfg->entry_timeout = NO_TIMEOUT;
cfg->attr_timeout = NO_TIMEOUT;
cfg->negative_timeout = 0;
+3 -1
View File
@@ -109,7 +109,9 @@ static int fioc_stat(fuse_ino_t ino, struct stat *stbuf)
static void fioc_ll_init(void *userdata, struct fuse_conn_info *conn)
{
(void)userdata;
(void)conn;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
}
static void fioc_ll_getattr(fuse_req_t req, fuse_ino_t ino,
+4
View File
@@ -833,6 +833,10 @@ static void memfs_releasedir(fuse_req_t req, [[maybe_unused]] fuse_ino_t ino,
static void memfs_init(void *userdata, struct fuse_conn_info *conn)
{
(void)userdata;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
if (memfs_cfg.writeback_cache)
fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE);
}
+2
View File
@@ -152,6 +152,8 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
static void tfs_init(void *userdata, struct fuse_conn_info *conn) {
(void)userdata;
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
conn->no_interrupt = 1;
}
+2
View File
@@ -126,6 +126,8 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
static void tfs_init(void *userdata, struct fuse_conn_info *conn) {
(void)userdata;
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
conn->no_interrupt = 1;
}
+2
View File
@@ -137,6 +137,8 @@ static void tfs_init(void *userdata, struct fuse_conn_info *conn)
{
(void)userdata;
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
conn->no_interrupt = 1;
}
+2
View File
@@ -135,6 +135,8 @@ static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
static void tfs_init(void *userdata, struct fuse_conn_info *conn) {
(void)userdata;
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
/* Disable the receiving and processing of FUSE_INTERRUPT requests */
conn->no_interrupt = 1;
}
+3 -1
View File
@@ -53,7 +53,9 @@ static int readdir_zero_ino;
static void *xmp_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
cfg->use_ino = !readdir_zero_ino;
/* parallel_direct_writes feature depends on direct_io features.
+3 -1
View File
@@ -52,7 +52,9 @@
static void *xmp_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
cfg->use_ino = 1;
cfg->nullpath_ok = 1;
+3
View File
@@ -205,6 +205,9 @@ static void sfs_init(void *userdata, fuse_conn_info *conn)
{
(void)userdata;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
if (!fuse_set_feature_flag(conn, FUSE_CAP_PASSTHROUGH))
fs.passthrough = false;
+3
View File
@@ -167,6 +167,9 @@ static void lo_init(void *userdata,
struct lo_data *lo = (struct lo_data *)userdata;
bool has_flag;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
if (lo->writeback) {
has_flag = fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE);
if (lo->debug && has_flag)
+3 -1
View File
@@ -88,7 +88,9 @@ static struct service_hl hl = { };
static void *service_hl_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
(void) conn;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
cfg->kernel_cache = 1;
return NULL;
+3
View File
@@ -85,6 +85,9 @@ static void service_ll_init(void *userdata, struct fuse_conn_info *conn)
{
(void)userdata;
/* Always replies inline on the io-uring worker thread */
fuse_set_conn_flag(conn, FUSE_CONN_FLAG_SINGLE_ISSUER);
conn->time_gran = 1;
}