From: Li RongQing <[email protected]>
[ 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 <[email protected]>
Signed-off-by: Fushuai Wang <[email protected]>
Signed-off-by: Li RongQing <[email protected]>
Reviewed-by: Stefan Hajnoczi <[email protected]>
Signed-off-by: Miklos Szeredi <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
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() */
--
2.51.0