212 lines
6.7 KiB
Diff
212 lines
6.7 KiB
Diff
|
From 44f4434b1305f6ff47b4f63fafcf39bcea9e4ceb Mon Sep 17 00:00:00 2001
|
||
|
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||
|
Date: Mon, 27 Jan 2020 19:01:52 +0100
|
||
|
Subject: [PATCH 081/116] virtiofsd: passthrough_ll: use hashtable
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||
|
Message-id: <20200127190227.40942-78-dgilbert@redhat.com>
|
||
|
Patchwork-id: 93528
|
||
|
O-Subject: [RHEL-AV-8.2 qemu-kvm PATCH 077/112] virtiofsd: passthrough_ll: use hashtable
|
||
|
Bugzilla: 1694164
|
||
|
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||
|
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
|
||
|
|
||
|
From: Miklos Szeredi <mszeredi@redhat.com>
|
||
|
|
||
|
Improve performance of inode lookup by using a hash table.
|
||
|
|
||
|
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
||
|
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||
|
Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
|
||
|
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||
|
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||
|
(cherry picked from commit bfc50a6e06b10b2f9dbaf6c1a89dd523322e016f)
|
||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||
|
---
|
||
|
tools/virtiofsd/passthrough_ll.c | 81 ++++++++++++++++++++++------------------
|
||
|
1 file changed, 45 insertions(+), 36 deletions(-)
|
||
|
|
||
|
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
|
||
|
index b40f287..b176a31 100644
|
||
|
--- a/tools/virtiofsd/passthrough_ll.c
|
||
|
+++ b/tools/virtiofsd/passthrough_ll.c
|
||
|
@@ -84,13 +84,15 @@ struct lo_map {
|
||
|
ssize_t freelist;
|
||
|
};
|
||
|
|
||
|
+struct lo_key {
|
||
|
+ ino_t ino;
|
||
|
+ dev_t dev;
|
||
|
+};
|
||
|
+
|
||
|
struct lo_inode {
|
||
|
- struct lo_inode *next; /* protected by lo->mutex */
|
||
|
- struct lo_inode *prev; /* protected by lo->mutex */
|
||
|
int fd;
|
||
|
bool is_symlink;
|
||
|
- ino_t ino;
|
||
|
- dev_t dev;
|
||
|
+ struct lo_key key;
|
||
|
uint64_t refcount; /* protected by lo->mutex */
|
||
|
fuse_ino_t fuse_ino;
|
||
|
};
|
||
|
@@ -119,7 +121,8 @@ struct lo_data {
|
||
|
int timeout_set;
|
||
|
int readdirplus_set;
|
||
|
int readdirplus_clear;
|
||
|
- struct lo_inode root; /* protected by lo->mutex */
|
||
|
+ struct lo_inode root;
|
||
|
+ GHashTable *inodes; /* protected by lo->mutex */
|
||
|
struct lo_map ino_map; /* protected by lo->mutex */
|
||
|
struct lo_map dirp_map; /* protected by lo->mutex */
|
||
|
struct lo_map fd_map; /* protected by lo->mutex */
|
||
|
@@ -573,7 +576,7 @@ retry:
|
||
|
}
|
||
|
goto fail_unref;
|
||
|
}
|
||
|
- if (stat.st_dev != inode->dev || stat.st_ino != inode->ino) {
|
||
|
+ if (stat.st_dev != inode->key.dev || stat.st_ino != inode->key.ino) {
|
||
|
if (!retries) {
|
||
|
fuse_log(FUSE_LOG_WARNING,
|
||
|
"%s: failed to match last\n", __func__);
|
||
|
@@ -753,19 +756,20 @@ out_err:
|
||
|
static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
|
||
|
{
|
||
|
struct lo_inode *p;
|
||
|
- struct lo_inode *ret = NULL;
|
||
|
+ struct lo_key key = {
|
||
|
+ .ino = st->st_ino,
|
||
|
+ .dev = st->st_dev,
|
||
|
+ };
|
||
|
|
||
|
pthread_mutex_lock(&lo->mutex);
|
||
|
- for (p = lo->root.next; p != &lo->root; p = p->next) {
|
||
|
- if (p->ino == st->st_ino && p->dev == st->st_dev) {
|
||
|
- assert(p->refcount > 0);
|
||
|
- ret = p;
|
||
|
- ret->refcount++;
|
||
|
- break;
|
||
|
- }
|
||
|
+ p = g_hash_table_lookup(lo->inodes, &key);
|
||
|
+ if (p) {
|
||
|
+ assert(p->refcount > 0);
|
||
|
+ p->refcount++;
|
||
|
}
|
||
|
pthread_mutex_unlock(&lo->mutex);
|
||
|
- return ret;
|
||
|
+
|
||
|
+ return p;
|
||
|
}
|
||
|
|
||
|
static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||
|
@@ -810,8 +814,6 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||
|
close(newfd);
|
||
|
newfd = -1;
|
||
|
} else {
|
||
|
- struct lo_inode *prev, *next;
|
||
|
-
|
||
|
saverr = ENOMEM;
|
||
|
inode = calloc(1, sizeof(struct lo_inode));
|
||
|
if (!inode) {
|
||
|
@@ -822,17 +824,12 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||
|
inode->refcount = 1;
|
||
|
inode->fd = newfd;
|
||
|
newfd = -1;
|
||
|
- inode->ino = e->attr.st_ino;
|
||
|
- inode->dev = e->attr.st_dev;
|
||
|
+ inode->key.ino = e->attr.st_ino;
|
||
|
+ inode->key.dev = e->attr.st_dev;
|
||
|
|
||
|
pthread_mutex_lock(&lo->mutex);
|
||
|
inode->fuse_ino = lo_add_inode_mapping(req, inode);
|
||
|
- prev = &lo->root;
|
||
|
- next = prev->next;
|
||
|
- next->prev = inode;
|
||
|
- inode->next = next;
|
||
|
- inode->prev = prev;
|
||
|
- prev->next = inode;
|
||
|
+ g_hash_table_insert(lo->inodes, &inode->key, inode);
|
||
|
pthread_mutex_unlock(&lo->mutex);
|
||
|
}
|
||
|
e->ino = inode->fuse_ino;
|
||
|
@@ -1162,14 +1159,8 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
|
||
|
assert(inode->refcount >= n);
|
||
|
inode->refcount -= n;
|
||
|
if (!inode->refcount) {
|
||
|
- struct lo_inode *prev, *next;
|
||
|
-
|
||
|
- prev = inode->prev;
|
||
|
- next = inode->next;
|
||
|
- next->prev = prev;
|
||
|
- prev->next = next;
|
||
|
-
|
||
|
lo_map_remove(&lo->ino_map, inode->fuse_ino);
|
||
|
+ g_hash_table_remove(lo->inodes, &inode->key);
|
||
|
pthread_mutex_unlock(&lo->mutex);
|
||
|
close(inode->fd);
|
||
|
free(inode);
|
||
|
@@ -1369,7 +1360,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
|
||
|
|
||
|
/* Hide root's parent directory */
|
||
|
if (dinode == &lo->root && strcmp(name, "..") == 0) {
|
||
|
- e.attr.st_ino = lo->root.ino;
|
||
|
+ e.attr.st_ino = lo->root.key.ino;
|
||
|
e.attr.st_mode = DT_DIR << 12;
|
||
|
}
|
||
|
|
||
|
@@ -2370,11 +2361,26 @@ static void setup_root(struct lo_data *lo, struct lo_inode *root)
|
||
|
|
||
|
root->is_symlink = false;
|
||
|
root->fd = fd;
|
||
|
- root->ino = stat.st_ino;
|
||
|
- root->dev = stat.st_dev;
|
||
|
+ root->key.ino = stat.st_ino;
|
||
|
+ root->key.dev = stat.st_dev;
|
||
|
root->refcount = 2;
|
||
|
}
|
||
|
|
||
|
+static guint lo_key_hash(gconstpointer key)
|
||
|
+{
|
||
|
+ const struct lo_key *lkey = key;
|
||
|
+
|
||
|
+ return (guint)lkey->ino + (guint)lkey->dev;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean lo_key_equal(gconstpointer a, gconstpointer b)
|
||
|
+{
|
||
|
+ const struct lo_key *la = a;
|
||
|
+ const struct lo_key *lb = b;
|
||
|
+
|
||
|
+ return la->ino == lb->ino && la->dev == lb->dev;
|
||
|
+}
|
||
|
+
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||
|
@@ -2392,7 +2398,7 @@ int main(int argc, char *argv[])
|
||
|
umask(0);
|
||
|
|
||
|
pthread_mutex_init(&lo.mutex, NULL);
|
||
|
- lo.root.next = lo.root.prev = &lo.root;
|
||
|
+ lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
|
||
|
lo.root.fd = -1;
|
||
|
lo.root.fuse_ino = FUSE_ROOT_ID;
|
||
|
lo.cache = CACHE_AUTO;
|
||
|
@@ -2522,6 +2528,9 @@ err_out2:
|
||
|
err_out1:
|
||
|
fuse_opt_free_args(&args);
|
||
|
|
||
|
+ if (lo.inodes) {
|
||
|
+ g_hash_table_destroy(lo.inodes);
|
||
|
+ }
|
||
|
lo_map_destroy(&lo.fd_map);
|
||
|
lo_map_destroy(&lo.dirp_map);
|
||
|
lo_map_destroy(&lo.ino_map);
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|