Re: [PATCH v6 1/6] fuse: decouple fuse_ring creation from ent registration
Bernd Schubert <[email protected]>
| Newsgroups | dev.linux.lists.fuse-devel |
|---|---|
| Message-ID | <[email protected]> |
On 7/16/26 19:59, Joanne Koong wrote: > Currently, the connection's fuse_ring is created lazily on the first > FUSE_IO_URING_CMD_REGISTER command. A server registers entries from one > thread per queue (one per CPU) and those threads issue their first > REGISTER command concurrently. They then race to create the single > per-connection fuse_ring, which required open-coded handling in > fuse_uring_create() to detect and protect against concurrent creations. > > Decouple fuse_ring creation from ent registration and move it to > FUSE_INIT reply processing after a server has negotiated and set > FUSE_OVER_IO_URING. The ring is published before the connection is > marked initialized. fuse_uring_register() no longer creates the ring and > it instead uses the ring set up at init time. > > Signed-off-by: Joanne Koong <[email protected]> > --- > fs/fuse/dev.c | 8 +++----- > fs/fuse/dev.h | 2 +- > fs/fuse/dev_uring.c | 26 ++++++++++---------------- > fs/fuse/dev_uring_i.h | 5 +++++ > fs/fuse/inode.c | 4 +++- > 5 files changed, 22 insertions(+), 23 deletions(-) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index 8b68b24af9d7..d50792162d8b 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -75,6 +75,9 @@ void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *pa > fch->minor = param->minor; > fch->max_write = param->max_write; > fch->max_pages = param->max_pages; > + > + if (param->io_uring_enabled) > + fuse_uring_conn_init(fch); > } > > /* Pairs with smp_load_acquire() readers of fch->initialized */ > @@ -411,11 +414,6 @@ void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc) > fch->conn = fc; > } > > -void fuse_chan_io_uring_enable(struct fuse_chan *fch) > -{ > - fch->io_uring = 1; > -} > - > void fuse_pqueue_init(struct fuse_pqueue *fpq) > { > spin_lock_init(&fpq->lock); > diff --git a/fs/fuse/dev.h b/fs/fuse/dev.h > index aed69fd14c41..8d25378c0918 100644 > --- a/fs/fuse/dev.h > +++ b/fs/fuse/dev.h > @@ -22,6 +22,7 @@ struct fuse_chan_param { > unsigned int minor; > unsigned int max_write; > unsigned int max_pages; > + bool io_uring_enabled; > }; > > struct fuse_chan *fuse_chan_new(void); > @@ -34,7 +35,6 @@ void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val); > unsigned int fuse_chan_num_waiting(struct fuse_chan *fch); > void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc); > void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *param); > -void fuse_chan_io_uring_enable(struct fuse_chan *fch); > ssize_t fuse_chan_send(struct fuse_chan *fch, struct fuse_args *args); > int fuse_chan_send_bg(struct fuse_chan *fch, struct fuse_args *args, gfp_t gfp_flags); > int fuse_chan_send_notify_reply(struct fuse_chan *fch, struct fuse_args *args, u64 unique); > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c > index bf9d51f2a508..b7c6100c4176 100644 > --- a/fs/fuse/dev_uring.c > +++ b/fs/fuse/dev_uring.c > @@ -238,7 +238,6 @@ static struct fuse_ring *fuse_uring_create(struct fuse_chan *fch) > { > struct fuse_ring *ring; > size_t nr_queues = num_possible_cpus(); > - struct fuse_ring *res = NULL; > size_t max_payload_size; > > ring = kzalloc_obj(*ring, GFP_KERNEL_ACCOUNT); > @@ -258,12 +257,6 @@ static struct fuse_ring *fuse_uring_create(struct fuse_chan *fch) > spin_unlock(&fch->lock); > goto out_err; > } > - if (fch->ring) { > - /* race, another thread created the ring in the meantime */ > - spin_unlock(&fch->lock); > - res = fch->ring; > - goto out_err; > - } > > init_waitqueue_head(&ring->stop_waitq); > > @@ -278,7 +271,13 @@ static struct fuse_ring *fuse_uring_create(struct fuse_chan *fch) > out_err: > kfree(ring->queues); > kfree(ring); > - return res; > + return NULL; > +} > + > +void fuse_uring_conn_init(struct fuse_chan *fch) > +{ > + if (fuse_uring_create(fch)) > + fch->io_uring = 1; > } > > static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring, > @@ -1178,15 +1177,10 @@ static int fuse_uring_register(struct io_uring_cmd *cmd, > struct fuse_ring *ring = smp_load_acquire(&fch->ring); > struct fuse_ring_queue *queue; > struct fuse_ring_ent *ent; > - int err; > unsigned int qid = READ_ONCE(cmd_req->qid); > > - err = -ENOMEM; > - if (!ring) { > - ring = fuse_uring_create(fch); > - if (!ring) > - return err; > - } > + if (!ring) > + return -EINVAL; > > if (qid >= ring->nr_queues) { > pr_info_ratelimited("fuse: Invalid ring qid %u\n", qid); > @@ -1197,7 +1191,7 @@ static int fuse_uring_register(struct io_uring_cmd *cmd, > if (!queue) { > queue = fuse_uring_create_queue(ring, qid); > if (!queue) > - return err; > + return -ENOMEM; > } > > /* > diff --git a/fs/fuse/dev_uring_i.h b/fs/fuse/dev_uring_i.h > index 55f8d04e4b0b..d721a4fc0215 100644 > --- a/fs/fuse/dev_uring_i.h > +++ b/fs/fuse/dev_uring_i.h > @@ -135,6 +135,7 @@ struct fuse_ring { > bool ready; > }; > > +void fuse_uring_conn_init(struct fuse_chan *fch); > void fuse_uring_stop_queues(struct fuse_ring *ring); > void fuse_uring_abort_end_requests(struct fuse_ring *ring); > int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags); > @@ -174,6 +175,10 @@ static inline bool fuse_uring_ready(struct fuse_chan *fch) > > #else /* CONFIG_FUSE_IO_URING */ > > +static inline void fuse_uring_conn_init(struct fuse_chan *fch) > +{ > +} > + > static inline void fuse_uring_abort(struct fuse_chan *fch) > { > } > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index d975073c6029..ce4891a04a37 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -1272,6 +1272,7 @@ static void process_init_reply(struct fuse_args *args, int error) > struct fuse_mount *fm = ia->fm; > struct fuse_conn *fc = fm->fc; > struct fuse_init_out *arg = &ia->out; > + bool io_uring_enabled = false; > bool ok = true; > > if (error || arg->major != FUSE_KERNEL_VERSION) > @@ -1402,7 +1403,7 @@ static void process_init_reply(struct fuse_args *args, int error) > ok = false; > } > if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled()) > - fuse_chan_io_uring_enable(fc->chan); > + io_uring_enabled = true; > > if (flags & FUSE_REQUEST_TIMEOUT) > timeout = arg->request_timeout; > @@ -1432,6 +1433,7 @@ static void process_init_reply(struct fuse_args *args, int error) > .minor = fc->minor, > .max_write = fc->max_write, > .max_pages = fc->max_pages, > + .io_uring_enabled = io_uring_enabled, > }; > fuse_chan_set_initialized(fc->chan, &cp); > } Thanks, I should have done that from the beginning! Reviewed-by: Bernd Schubert <[email protected]>