virtiofsd: passthrough_ll: use hashtable

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>
This commit is contained in:
Miklos Szeredi 2018-11-15 15:29:51 +01:00 committed by Dr. David Alan Gilbert
parent 230e777b5e
commit bfc50a6e06
1 changed files with 46 additions and 37 deletions

View File

@ -84,13 +84,15 @@ struct lo_map {
ssize_t freelist; ssize_t freelist;
}; };
struct lo_inode { struct lo_key {
struct lo_inode *next; /* protected by lo->mutex */
struct lo_inode *prev; /* protected by lo->mutex */
int fd;
bool is_symlink;
ino_t ino; ino_t ino;
dev_t dev; dev_t dev;
};
struct lo_inode {
int fd;
bool is_symlink;
struct lo_key key;
uint64_t refcount; /* protected by lo->mutex */ uint64_t refcount; /* protected by lo->mutex */
fuse_ino_t fuse_ino; fuse_ino_t fuse_ino;
}; };
@ -119,7 +121,8 @@ struct lo_data {
int timeout_set; int timeout_set;
int readdirplus_set; int readdirplus_set;
int readdirplus_clear; 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 ino_map; /* protected by lo->mutex */
struct lo_map dirp_map; /* protected by lo->mutex */ struct lo_map dirp_map; /* protected by lo->mutex */
struct lo_map fd_map; /* protected by lo->mutex */ struct lo_map fd_map; /* protected by lo->mutex */
@ -573,7 +576,7 @@ retry:
} }
goto fail_unref; 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) { if (!retries) {
fuse_log(FUSE_LOG_WARNING, fuse_log(FUSE_LOG_WARNING,
"%s: failed to match last\n", __func__); "%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) static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
{ {
struct lo_inode *p; 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); pthread_mutex_lock(&lo->mutex);
for (p = lo->root.next; p != &lo->root; p = p->next) { p = g_hash_table_lookup(lo->inodes, &key);
if (p->ino == st->st_ino && p->dev == st->st_dev) { if (p) {
assert(p->refcount > 0); assert(p->refcount > 0);
ret = p; p->refcount++;
ret->refcount++;
break;
}
} }
pthread_mutex_unlock(&lo->mutex); 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, 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); close(newfd);
newfd = -1; newfd = -1;
} else { } else {
struct lo_inode *prev, *next;
saverr = ENOMEM; saverr = ENOMEM;
inode = calloc(1, sizeof(struct lo_inode)); inode = calloc(1, sizeof(struct lo_inode));
if (!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->refcount = 1;
inode->fd = newfd; inode->fd = newfd;
newfd = -1; newfd = -1;
inode->ino = e->attr.st_ino; inode->key.ino = e->attr.st_ino;
inode->dev = e->attr.st_dev; inode->key.dev = e->attr.st_dev;
pthread_mutex_lock(&lo->mutex); pthread_mutex_lock(&lo->mutex);
inode->fuse_ino = lo_add_inode_mapping(req, inode); inode->fuse_ino = lo_add_inode_mapping(req, inode);
prev = &lo->root; g_hash_table_insert(lo->inodes, &inode->key, inode);
next = prev->next;
next->prev = inode;
inode->next = next;
inode->prev = prev;
prev->next = inode;
pthread_mutex_unlock(&lo->mutex); pthread_mutex_unlock(&lo->mutex);
} }
e->ino = inode->fuse_ino; 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); assert(inode->refcount >= n);
inode->refcount -= n; inode->refcount -= n;
if (!inode->refcount) { 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); lo_map_remove(&lo->ino_map, inode->fuse_ino);
g_hash_table_remove(lo->inodes, &inode->key);
pthread_mutex_unlock(&lo->mutex); pthread_mutex_unlock(&lo->mutex);
close(inode->fd); close(inode->fd);
free(inode); 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 */ /* Hide root's parent directory */
if (dinode == &lo->root && strcmp(name, "..") == 0) { 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; 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->is_symlink = false;
root->fd = fd; root->fd = fd;
root->ino = stat.st_ino; root->key.ino = stat.st_ino;
root->dev = stat.st_dev; root->key.dev = stat.st_dev;
root->refcount = 2; 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[]) int main(int argc, char *argv[])
{ {
struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
@ -2392,7 +2398,7 @@ int main(int argc, char *argv[])
umask(0); umask(0);
pthread_mutex_init(&lo.mutex, NULL); 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.fd = -1;
lo.root.fuse_ino = FUSE_ROOT_ID; lo.root.fuse_ino = FUSE_ROOT_ID;
lo.cache = CACHE_AUTO; lo.cache = CACHE_AUTO;
@ -2522,6 +2528,9 @@ err_out2:
err_out1: err_out1:
fuse_opt_free_args(&args); fuse_opt_free_args(&args);
if (lo.inodes) {
g_hash_table_destroy(lo.inodes);
}
lo_map_destroy(&lo.fd_map); lo_map_destroy(&lo.fd_map);
lo_map_destroy(&lo.dirp_map); lo_map_destroy(&lo.dirp_map);
lo_map_destroy(&lo.ino_map); lo_map_destroy(&lo.ino_map);