[Devel] [PATCH RHEL7 COMMIT] fuse: Use hash table to link processing request
Konstantin Khorenko
khorenko at virtuozzo.com
Thu Oct 4 12:04:52 MSK 2018
The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.14.4.vz7.72.2
------>
commit db9c952b06c92ddadd504cbfc7f5dbaa4b93f704
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date: Thu Oct 4 11:57:53 2018 +0300
fuse: Use hash table to link processing request
(this is going to ms)
We noticed the performance bottle neck in FUSE running our
Virtuozzo storage over rdma. On some types of workload
we observe 20% of times pent in request_find() in profiler.
This function is iterating over long requests list, and it
scales bad.
The patch introduces hash table to reduce the number
of iterations, we do in this function. Hash generating
algorithm is taken from hash_add() function, while
512 lines table is used to store pending requests.
This fixes problem and improves the performance.
https://pmc.acronis.com/browse/VSTOR-14760
Reported-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
fs/fuse/dev.c | 32 ++++++++++++++++++++++++++++----
fs/fuse/fuse_i.h | 8 +++++---
fs/fuse/inode.c | 9 +++++++--
3 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 22e0cf689b75..ba21fe75e82c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -21,6 +21,7 @@
#include <linux/splice.h>
#include <linux/aio.h>
#include <linux/sched.h>
+#include <linux/hashtable.h>
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
@@ -353,6 +354,20 @@ static u64 fuse_get_unique(struct fuse_iqueue *fiq)
return fiq->reqctr;
}
+static unsigned int __fuse_req_hash(u64 unique)
+{
+ unique &= ~FUSE_INT_REQ_BIT;
+
+ /* Borrowed from hash_add() */
+ return hash_min(unique,
+ HASH_BITS(((struct fuse_pqueue *)0)->processing));
+}
+
+static unsigned int fuse_req_hash(struct fuse_req *req)
+{
+ return __fuse_req_hash(req->in.h.unique);
+}
+
static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req)
{
req->in.h.len = sizeof(struct fuse_in_header) +
@@ -1362,7 +1377,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
err = reqsize;
goto out_end;
}
- list_move_tail(&req->list, &fpq->processing);
+ list_move_tail(&req->list, &fpq->processing[fuse_req_hash(req)]);
spin_unlock(&fpq->lock);
set_bit(FR_SENT, &req->flags);
/* matches barrier in request_wait_answer() */
@@ -1907,10 +1922,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
static struct fuse_req *request_find(struct fuse_pqueue *fpq, u64 unique)
{
struct fuse_req *req;
+ unsigned int hash;
unique &= ~FUSE_INT_REQ_BIT;
+ hash = __fuse_req_hash(unique);
- list_for_each_entry(req, &fpq->processing, list) {
+ list_for_each_entry(req, &fpq->processing[hash], list) {
if (req->in.h.unique == unique)
return req;
}
@@ -2232,6 +2249,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
struct fuse_req *req, *next;
LIST_HEAD(to_end1);
LIST_HEAD(to_end2);
+ int i;
fc->connected = 0;
fc->blocked = 0;
@@ -2251,7 +2269,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
}
spin_unlock(&req->waitq.lock);
}
- list_splice_init(&fpq->processing, &to_end2);
+ for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+ list_splice_tail_init(&fpq->processing[i],
+ &to_end2);
spin_unlock(&fpq->lock);
}
if (fc->kio.op)
@@ -2290,9 +2310,13 @@ int fuse_dev_release(struct inode *inode, struct file *file)
if (fud) {
struct fuse_conn *fc = fud->fc;
struct fuse_pqueue *fpq = &fud->pq;
+ LIST_HEAD(to_end);
+ int i;
WARN_ON(!list_empty(&fpq->io));
- end_requests(fc, &fpq->processing);
+ for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+ list_splice_init(&fpq->processing[i], &to_end);
+ end_requests(fc, &to_end);
/* Are we the last open device? */
if (atomic_dec_and_test(&fc->dev_count)) {
WARN_ON(fud->fiq->fasync != NULL);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 14f7a2af0a90..45d1026dea27 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -464,6 +464,8 @@ struct fuse_iqueue {
struct fasync_struct *fasync;
};
+#define FUSE_PQ_HASH_SIZE 256
+
struct fuse_pqueue {
/** Connection established */
unsigned connected;
@@ -471,11 +473,11 @@ struct fuse_pqueue {
/** Lock protecting accessess to members of this structure */
spinlock_t lock;
- /** The list of requests being processed */
- struct list_head processing;
-
/** The list of requests under I/O */
struct list_head io;
+
+ /** The lists of requests being processed */
+ struct list_head processing[FUSE_PQ_HASH_SIZE];
};
/**
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 7a81025e3979..6b374324f84f 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -432,8 +432,10 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)
list_for_each_entry(fud, &fc->devices, entry) {
struct fuse_pqueue *fpq = &fud->pq;
struct fuse_iqueue *fiq = fud->fiq;
+ int i;
spin_lock(&fpq->lock);
- fuse_kill_requests(fc, inode, &fpq->processing);
+ for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+ fuse_kill_requests(fc, inode, &fpq->processing[i]);
fuse_kill_requests(fc, inode, &fiq->pending);
fuse_kill_requests(fc, inode, &fpq->io);
spin_unlock(&fpq->lock);
@@ -780,9 +782,12 @@ static void fuse_iqueue_init(struct fuse_iqueue *fiq)
static void fuse_pqueue_init(struct fuse_pqueue *fpq)
{
+ int i;
+
memset(fpq, 0, sizeof(struct fuse_pqueue));
spin_lock_init(&fpq->lock);
- INIT_LIST_HEAD(&fpq->processing);
+ for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&fpq->processing[i]);
INIT_LIST_HEAD(&fpq->io);
fpq->connected = 1;
}
More information about the Devel
mailing list