diff options
| author | Joanne Koong <joannelkoong@gmail.com> | 2026-04-08 10:25:10 -0700 |
|---|---|---|
| committer | Miklos Szeredi <mszeredi@redhat.com> | 2026-06-15 14:06:15 +0200 |
| commit | 31da059891bd3be9c6e59280b8e1777ead90db34 (patch) | |
| tree | cc6d76fdb5779b0c326626bfa044462542585c0c /fs/fuse/dev.c | |
| parent | 9fa4f7a53406430ee9982f2f636a15b338185122 (diff) | |
| download | linux-next-31da059891bd3be9c6e59280b8e1777ead90db34.tar.gz linux-next-31da059891bd3be9c6e59280b8e1777ead90db34.zip | |
fuse: fix io-uring background queue dispatch on request completion
When a background request completes via the io_uring path, the
background queue gets flushed to dispatch pending background requests,
but this is done before the connection-level background counters
(fc->num_background, fc->active_background) are properly accounted,
which may reduce effective queue depth to one.
The connection-level counters are decremented in fuse_request_end(), but
flush_bg_queue() flushes the /dev/fuse path queue (fc->bg_queue), not
the io_uring per-queue bg one, which means pending uring background
requests on the queue are never dispatched in this path.
Fix this by accounting the connection-level background counters first
before flushing the queue's background queue. Since
fuse_request_bg_finish() clears FR_BACKGROUND, fuse_request_end() will
skip the background cleanup branch entirely, which avoids any
double-decrements; it will call the wake_up(&req->waitq) branch but this
is effectively a no-op as background requests have no waiters on
req->waitq.
Reviewed-by: Bernd Schubert <bernd@bsbernd.com>
Fixes: 857b0263f30e ("fuse: Allow to queue bg requests through io-uring")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse/dev.c')
| -rw-r--r-- | fs/fuse/dev.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 12b57a8c6024..916c214798ca 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -448,6 +448,29 @@ static void flush_bg_queue(struct fuse_conn *fc) } } +void fuse_request_bg_finish(struct fuse_conn *fc, struct fuse_req *req) +{ + lockdep_assert_held(&fc->bg_lock); + + clear_bit(FR_BACKGROUND, &req->flags); + if (fc->num_background == fc->max_background) { + fc->blocked = 0; + wake_up(&fc->blocked_waitq); + } else if (!fc->blocked) { + /* + * Wake up next waiter, if any. It's okay to use + * waitqueue_active(), as we've already synced up + * fc->blocked with waiters with the wake_up() call + * above. + */ + if (waitqueue_active(&fc->blocked_waitq)) + wake_up(&fc->blocked_waitq); + } + + fc->num_background--; + fc->active_background--; +} + /* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error @@ -480,23 +503,7 @@ void fuse_request_end(struct fuse_req *req) WARN_ON(test_bit(FR_SENT, &req->flags)); if (test_bit(FR_BACKGROUND, &req->flags)) { spin_lock(&fc->bg_lock); - clear_bit(FR_BACKGROUND, &req->flags); - if (fc->num_background == fc->max_background) { - fc->blocked = 0; - wake_up(&fc->blocked_waitq); - } else if (!fc->blocked) { - /* - * Wake up next waiter, if any. It's okay to use - * waitqueue_active(), as we've already synced up - * fc->blocked with waiters with the wake_up() call - * above. - */ - if (waitqueue_active(&fc->blocked_waitq)) - wake_up(&fc->blocked_waitq); - } - - fc->num_background--; - fc->active_background--; + fuse_request_bg_finish(fc, req); flush_bg_queue(fc); spin_unlock(&fc->bg_lock); } else { |
