summaryrefslogtreecommitdiff
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:53:38 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:53:38 +0200
commit5895db67c12464003afd16c08049b73aa09e58ea (patch)
treec3855a7ab889dffc2a02460f65abbbe6b800b6e6 /fs/fuse/dev.c
parent1c5f3df9481bb6275aeb079a8312d037da69715b (diff)
parentf89c296854b755a66657065c35b05406fc18264d (diff)
Merge v6.18.39linux-rolling-lts
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 527f60f7ad7b..77c3982bca3d 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -148,6 +148,7 @@ static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags)
static void fuse_request_free(struct fuse_req *req)
{
+ WARN_ON(!list_empty(&req->intr_entry));
kmem_cache_free(fuse_req_cachep, req);
}
@@ -447,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
@@ -479,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 {
@@ -1106,7 +1114,7 @@ static int fuse_ref_folio(struct fuse_copy_state *cs, struct folio *folio,
cs->nr_segs++;
cs->len = 0;
- return 0;
+ return lock_request(cs->req);
}
/*
@@ -2039,6 +2047,14 @@ static void fuse_resend(struct fuse_conn *fc)
fuse_dev_end_requests(&to_queue);
return;
}
+ /*
+ * Remove interrupt entries for resent requests to prevent stale
+ * intr_entry on fiq->interrupts after the request is re-queued.
+ */
+ list_for_each_entry(req, &to_queue, list) {
+ if (test_bit(FR_INTERRUPTED, &req->flags))
+ list_del_init(&req->intr_entry);
+ }
/* iq and pq requests are both oldest to newest */
list_splice(&to_queue, &fiq->pending);
fuse_dev_wake_and_unlock(fiq);
@@ -2082,7 +2098,7 @@ static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size,
if (err)
return err;
- if (size - sizeof(outarg) != outarg.count * sizeof(u64))
+ if (size - sizeof(outarg) != array_size(outarg.count, sizeof(u64)))
return -EINVAL;
for (; outarg.count; outarg.count -= num) {