From: Li RongQing lirongqing@baidu.com
[ Upstream commit 7dbe6442487743ad492d9143f1f404c1f4a05e0e ]
The original commit be2ff42c5d6e ("fuse: Use hash table to link processing request") converted fuse_pqueue->processing to a hash table, but virtio_fs_enqueue_req() was not updated to use it correctly. So use fuse_pqueue->processing as a hash table, this make the code more coherent
Co-developed-by: Fushuai Wang wangfushuai@baidu.com Signed-off-by: Fushuai Wang wangfushuai@baidu.com Signed-off-by: Li RongQing lirongqing@baidu.com Reviewed-by: Stefan Hajnoczi stefanha@redhat.com Signed-off-by: Miklos Szeredi mszeredi@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
**Why This Is A Bugfix** - The earlier change “fuse: Use hash table to link processing request” (be2ff42c5d6e) converted `fuse_pqueue->processing` from a single list to a hash table. You can see the hash table parameters and the data structure: - `FUSE_PQ_HASH_BITS` and `FUSE_PQ_HASH_SIZE`: fs/fuse/fuse_i.h:546 - `struct fuse_pqueue { struct list_head *processing; }`: fs/fuse/fuse_i.h:556 - Allocation as an array of `list_head` buckets: fs/fuse/inode.c:1622 - Responses are looked up by hashing the request ID and searching only that bucket: - `fuse_request_find()` iterates `&fpq->processing[hash]`: fs/fuse/dev.c:2131 - Before this fix, `virtio_fs_enqueue_req()` added every request to the list head pointer (effectively bucket 0) instead of the hashed bucket. That makes replies unfindable for non-zero buckets, leading to -ENOENT on reply processing and stuck/hung requests.
**What The Patch Changes** - Export the hash function so virtio-fs can use it: - `fuse_req_hash()` now exported: fs/fuse/dev.c:321 - Ensure virtio-fs adds requests to the correct bucket: - Include FUSE device internals: fs/fuse/virtio_fs.c:23 - Compute the bucket: `hash = fuse_req_hash(req->in.h.unique);`: fs/fuse/virtio_fs.c:1445 - Enqueue into the correct bucket: `list_add_tail(&req->list, &fpq->processing[hash]);`: fs/fuse/virtio_fs.c:1447 - Function definition location for context: fs/fuse/virtio_fs.c:1370
**Impact and Risk** - User-visible bugfix: Without this, replies cannot be matched to requests (except those hashing to bucket 0), causing request completion failures and potential hangs in virtio-fs workloads. - Small and contained: Two files touched; logic change is limited to correctly hashing and inserting into the right bucket, plus exporting a helper symbol. - No architectural changes: Keeps the existing hash-table design; simply uses it correctly. - Stable-friendly: Minimal risk of regression, no new features, fixes incorrect behavior.
**Backport Conditions** - This should be backported to any stable series that already includes the conversion of `processing` to a hash table (be2ff42c5d6e). If a stable series predates that change (i.e., `processing` is still a single list), this patch is not applicable. - The export `EXPORT_SYMBOL_GPL(fuse_req_hash)` (fs/fuse/dev.c:321) is required so `virtio_fs` can link against it. This is an internal, GPL- only symbol used by in-tree code and is appropriate for stable.
fs/fuse/dev.c | 1 + fs/fuse/virtio_fs.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index dbf53c7bc8535..612d4da6d7d91 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -322,6 +322,7 @@ unsigned int fuse_req_hash(u64 unique) { return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS); } +EXPORT_SYMBOL_GPL(fuse_req_hash);
/* * A new request is available, wake fiq->waitq diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 76c8fd0bfc75d..1751cd6e3d42b 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -20,6 +20,7 @@ #include <linux/cleanup.h> #include <linux/uio.h> #include "fuse_i.h" +#include "fuse_dev_i.h"
/* Used to help calculate the FUSE connection's max_pages limit for a request's * size. Parts of the struct fuse_req are sliced into scattergather lists in @@ -1384,7 +1385,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, unsigned int out_sgs = 0; unsigned int in_sgs = 0; unsigned int total_sgs; - unsigned int i; + unsigned int i, hash; int ret; bool notify; struct fuse_pqueue *fpq; @@ -1444,8 +1445,9 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
/* Request successfully sent. */ fpq = &fsvq->fud->pq; + hash = fuse_req_hash(req->in.h.unique); spin_lock(&fpq->lock); - list_add_tail(&req->list, fpq->processing); + list_add_tail(&req->list, &fpq->processing[hash]); spin_unlock(&fpq->lock); set_bit(FR_SENT, &req->flags); /* matches barrier in request_wait_answer() */