aboutsummaryrefslogtreecommitdiff
path: root/cache.c
diff options
context:
space:
mode:
authorNikolaus Rath <Nikolaus@rath.org>2017-06-21 10:59:13 -0700
committerNikolaus Rath <Nikolaus@rath.org>2017-07-08 00:34:01 +0200
commitc711bf738f7e78ecb05acc6097088ea07646d3c0 (patch)
tree91502ee0e1305d11f939a633bda0ed8142b412f7 /cache.c
parent493081e8f64c3fedb430704485aebbe32edf8ac1 (diff)
downloadsshfs-c711bf738f7e78ecb05acc6097088ea07646d3c0.tar
sshfs-c711bf738f7e78ecb05acc6097088ea07646d3c0.tar.gz
sshfs-c711bf738f7e78ecb05acc6097088ea07646d3c0.tar.bz2
sshfs-c711bf738f7e78ecb05acc6097088ea07646d3c0.zip
Re-enabled cache support.
Diffstat (limited to 'cache.c')
-rw-r--r--cache.c263
1 files changed, 138 insertions, 125 deletions
diff --git a/cache.c b/cache.c
index 6a17106..4d9cb0b 100644
--- a/cache.c
+++ b/cache.c
@@ -8,6 +8,7 @@
#include "cache.h"
#include <stdio.h>
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -27,7 +28,7 @@ struct cache {
unsigned int max_size;
unsigned int clean_interval_secs;
unsigned int min_clean_interval_secs;
- struct fuse_cache_operations *next_oper;
+ struct fuse_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
@@ -46,14 +47,22 @@ struct node {
time_t valid;
};
-struct fuse_cache_dirhandle {
+struct readdir_handle {
const char *path;
- fuse_dirh_t h;
- fuse_dirfil_t filler;
+ void *buf;
+ fuse_fill_dir_t filler;
GPtrArray *dir;
uint64_t wrctr;
};
+struct file_handle {
+ /* Did we send an open request to the underlying fs? */
+ int is_open;
+
+ /* If so, this will hold its handle */
+ unsigned long fs_fh;
+};
+
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
@@ -108,15 +117,12 @@ static void cache_purge_parent(const char *path)
void cache_invalidate(const char *path)
{
- if (!cache.on)
- return;
-
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache.lock);
}
-void cache_invalidate_write(const char *path)
+static void cache_invalidate_write(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
@@ -168,9 +174,6 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
{
struct node *node;
- if (!cache.on)
- return;
-
pthread_mutex_lock(&cache.lock);
if (wrctr == cache.write_ctr) {
node = cache_get(path);
@@ -253,7 +256,7 @@ static int cache_getattr(const char *path, struct stat *stbuf)
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
- err = cache.next_oper->oper.getattr(path, stbuf);
+ err = cache.next_oper->getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
@@ -277,17 +280,52 @@ static int cache_readlink(const char *path, char *buf, size_t size)
}
}
pthread_mutex_unlock(&cache.lock);
- err = cache.next_oper->oper.readlink(path, buf, size);
+ err = cache.next_oper->readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
return err;
}
-static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
- const struct stat *stbuf)
+
+static int cache_opendir(const char *path, struct fuse_file_info *fi)
+{
+ (void) path;
+ struct file_handle *cfi;
+
+ cfi = malloc(sizeof(struct file_handle));
+ if(cfi == NULL)
+ return -ENOMEM;
+ cfi->is_open = 0;
+ fi->fh = (unsigned long) cfi;
+ return 0;
+}
+
+static int cache_releasedir(const char *path, struct fuse_file_info *fi)
+{
+ int err;
+ struct file_handle *cfi;
+
+ cfi = (struct file_handle*) fi->fh;
+
+ if(cfi->is_open) {
+ fi->fh = cfi->fs_fh;
+ err = cache.next_oper->releasedir(path, fi);
+ } else
+ err = 0;
+
+ free(cfi);
+ return err;
+}
+
+static int cache_dirfill (void *buf, const char *name,
+ const struct stat *stbuf, off_t off)
{
- int err = ch->filler(ch->h, name, 0, 0);
+ int err;
+ struct readdir_handle *ch;
+
+ ch = (struct readdir_handle*) buf;
+ err = ch->filler(ch->buf, name, stbuf, off);
if (!err) {
g_ptr_array_add(ch->dir, g_strdup(name));
if (stbuf->st_mode & S_IFMT) {
@@ -302,61 +340,65 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
return err;
}
-static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
{
- struct fuse_cache_dirhandle ch;
+ struct readdir_handle ch;
+ struct file_handle *cfi;
int err;
char **dir;
struct node *node;
+ assert(offset == 0);
+
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL && node->dir != NULL) {
time_t now = time(NULL);
if (node->dir_valid - now >= 0) {
for(dir = node->dir; *dir != NULL; dir++)
- filler(h, *dir, 0, 0);
+ // FIXME: What about st_mode?
+ filler(buf, *dir, 0, 0);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
+ cfi = (struct file_handle*) fi->fh;
+ if(cfi->is_open)
+ fi->fh = cfi->fs_fh;
+ else {
+ if(cache.next_oper->opendir) {
+ err = cache.next_oper->opendir(path, fi);
+ if(err)
+ return err;
+ }
+ cfi->is_open = 1;
+ cfi->fs_fh = fi->fh;
+ }
+
ch.path = path;
- ch.h = h;
+ ch.buf = buf;
ch.filler = filler;
ch.dir = g_ptr_array_new();
ch.wrctr = cache_get_write_ctr();
- err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
+ err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
- if (!err)
+ if (!err) {
cache_add_dir(path, dir);
- else
+ } else {
g_strfreev(dir);
+ }
g_ptr_array_free(ch.dir, FALSE);
- return err;
-}
-static int cache_unity_dirfill(fuse_cache_dirh_t ch, const char *name,
- const struct stat *stbuf)
-{
- (void) stbuf;
- return ch->filler(ch->h, name, 0, 0);
-}
-
-static int cache_unity_getdir(const char *path, fuse_dirh_t h,
- fuse_dirfil_t filler)
-{
- struct fuse_cache_dirhandle ch;
- ch.h = h;
- ch.filler = filler;
- return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
+ return err;
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
- int err = cache.next_oper->oper.mknod(path, mode, rdev);
+ int err = cache.next_oper->mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -364,7 +406,7 @@ static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
static int cache_mkdir(const char *path, mode_t mode)
{
- int err = cache.next_oper->oper.mkdir(path, mode);
+ int err = cache.next_oper->mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -372,7 +414,7 @@ static int cache_mkdir(const char *path, mode_t mode)
static int cache_unlink(const char *path)
{
- int err = cache.next_oper->oper.unlink(path);
+ int err = cache.next_oper->unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -380,7 +422,7 @@ static int cache_unlink(const char *path)
static int cache_rmdir(const char *path)
{
- int err = cache.next_oper->oper.rmdir(path);
+ int err = cache.next_oper->rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -388,7 +430,7 @@ static int cache_rmdir(const char *path)
static int cache_symlink(const char *from, const char *to)
{
- int err = cache.next_oper->oper.symlink(from, to);
+ int err = cache.next_oper->symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
@@ -396,7 +438,7 @@ static int cache_symlink(const char *from, const char *to)
static int cache_rename(const char *from, const char *to)
{
- int err = cache.next_oper->oper.rename(from, to);
+ int err = cache.next_oper->rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
@@ -404,7 +446,7 @@ static int cache_rename(const char *from, const char *to)
static int cache_link(const char *from, const char *to)
{
- int err = cache.next_oper->oper.link(from, to);
+ int err = cache.next_oper->link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
@@ -414,7 +456,7 @@ static int cache_link(const char *from, const char *to)
static int cache_chmod(const char *path, mode_t mode)
{
- int err = cache.next_oper->oper.chmod(path, mode);
+ int err = cache.next_oper->chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
@@ -422,7 +464,7 @@ static int cache_chmod(const char *path, mode_t mode)
static int cache_chown(const char *path, uid_t uid, gid_t gid)
{
- int err = cache.next_oper->oper.chown(path, uid, gid);
+ int err = cache.next_oper->chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
@@ -430,7 +472,7 @@ static int cache_chown(const char *path, uid_t uid, gid_t gid)
static int cache_truncate(const char *path, off_t size)
{
- int err = cache.next_oper->oper.truncate(path, size);
+ int err = cache.next_oper->truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
@@ -438,7 +480,7 @@ static int cache_truncate(const char *path, off_t size)
static int cache_utime(const char *path, struct utimbuf *buf)
{
- int err = cache.next_oper->oper.utime(path, buf);
+ int err = cache.next_oper->utime(path, buf);
if (!err)
cache_invalidate(path);
return err;
@@ -447,7 +489,7 @@ static int cache_utime(const char *path, struct utimbuf *buf)
static int cache_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
- int res = cache.next_oper->oper.write(path, buf, size, offset, fi);
+ int res = cache.next_oper->write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate_write(path);
return res;
@@ -456,7 +498,7 @@ static int cache_write(const char *path, const char *buf, size_t size,
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
- int err = cache.next_oper->oper.create(path, mode, fi);
+ int err = cache.next_oper->create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -465,7 +507,7 @@ static int cache_create(const char *path, mode_t mode,
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
- int err = cache.next_oper->oper.ftruncate(path, size, fi);
+ int err = cache.next_oper->ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
@@ -477,97 +519,69 @@ static int cache_fgetattr(const char *path, struct stat *stbuf,
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
- err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
+ err = cache.next_oper->fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
return err;
}
-static void cache_unity_fill(struct fuse_cache_operations *oper,
- struct fuse_operations *cache_oper)
-{
- cache_oper->init = oper->oper.init;
- cache_oper->getattr = oper->oper.getattr;
- cache_oper->access = oper->oper.access;
- cache_oper->readlink = oper->oper.readlink;
- cache_oper->getdir = cache_unity_getdir;
- cache_oper->mknod = oper->oper.mknod;
- cache_oper->mkdir = oper->oper.mkdir;
- cache_oper->symlink = oper->oper.symlink;
- cache_oper->unlink = oper->oper.unlink;
- cache_oper->rmdir = oper->oper.rmdir;
- cache_oper->rename = oper->oper.rename;
- cache_oper->link = oper->oper.link;
- cache_oper->chmod = oper->oper.chmod;
- cache_oper->chown = oper->oper.chown;
- cache_oper->truncate = oper->oper.truncate;
- cache_oper->utime = oper->oper.utime;
- cache_oper->open = oper->oper.open;
- cache_oper->read = oper->oper.read;
- cache_oper->write = oper->oper.write;
- cache_oper->flush = oper->oper.flush;
- cache_oper->release = oper->oper.release;
- cache_oper->fsync = oper->oper.fsync;
- cache_oper->statfs = oper->oper.statfs;
- cache_oper->setxattr = oper->oper.setxattr;
- cache_oper->getxattr = oper->oper.getxattr;
- cache_oper->listxattr = oper->oper.listxattr;
- cache_oper->removexattr = oper->oper.removexattr;
- cache_oper->create = oper->oper.create;
- cache_oper->ftruncate = oper->oper.ftruncate;
- cache_oper->fgetattr = oper->oper.fgetattr;
- cache_oper->flag_nullpath_ok = oper->oper.flag_nullpath_ok;
- cache_oper->flag_nopath = oper->oper.flag_nopath;
-}
-
-static void cache_fill(struct fuse_cache_operations *oper,
+static void cache_fill(struct fuse_operations *oper,
struct fuse_operations *cache_oper)
{
- cache_oper->getattr = oper->oper.getattr ? cache_getattr : NULL;
- cache_oper->readlink = oper->oper.readlink ? cache_readlink : NULL;
- cache_oper->getdir = oper->cache_getdir ? cache_getdir : NULL;
- cache_oper->mknod = oper->oper.mknod ? cache_mknod : NULL;
- cache_oper->mkdir = oper->oper.mkdir ? cache_mkdir : NULL;
- cache_oper->symlink = oper->oper.symlink ? cache_symlink : NULL;
- cache_oper->unlink = oper->oper.unlink ? cache_unlink : NULL;
- cache_oper->rmdir = oper->oper.rmdir ? cache_rmdir : NULL;
- cache_oper->rename = oper->oper.rename ? cache_rename : NULL;
- cache_oper->link = oper->oper.link ? cache_link : NULL;
- cache_oper->chmod = oper->oper.chmod ? cache_chmod : NULL;
- cache_oper->chown = oper->oper.chown ? cache_chown : NULL;
- cache_oper->truncate = oper->oper.truncate ? cache_truncate : NULL;
- cache_oper->utime = oper->oper.utime ? cache_utime : NULL;
- cache_oper->write = oper->oper.write ? cache_write : NULL;
- cache_oper->create = oper->oper.create ? cache_create : NULL;
- cache_oper->ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
- cache_oper->fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
+ cache_oper->access = oper->access;
+ cache_oper->chmod = oper->chmod ? cache_chmod : NULL;
+ cache_oper->chown = oper->chown ? cache_chown : NULL;
+ cache_oper->create = oper->create ? cache_create : NULL;
+ cache_oper->fgetattr = oper->fgetattr ? cache_fgetattr : NULL;
+ cache_oper->flush = oper->flush;
+ cache_oper->fsync = oper->fsync;
+ cache_oper->ftruncate = oper->ftruncate ? cache_ftruncate : NULL;
+ cache_oper->getattr = oper->getattr ? cache_getattr : NULL;
+ cache_oper->getxattr = oper->getxattr;
+ cache_oper->init = oper->init;
+ cache_oper->link = oper->link ? cache_link : NULL;
+ cache_oper->listxattr = oper->listxattr;
+ cache_oper->mkdir = oper->mkdir ? cache_mkdir : NULL;
+ cache_oper->mknod = oper->mknod ? cache_mknod : NULL;
+ cache_oper->open = oper->open;
+ cache_oper->opendir = cache_opendir;
+ cache_oper->read = oper->read;
+ cache_oper->readdir = oper->readdir ? cache_readdir : NULL;
+ cache_oper->readlink = oper->readlink ? cache_readlink : NULL;
+ cache_oper->release = oper->release;
+ cache_oper->releasedir = cache_releasedir;
+ cache_oper->removexattr = oper->removexattr;
+ cache_oper->rename = oper->rename ? cache_rename : NULL;
+ cache_oper->rmdir = oper->rmdir ? cache_rmdir : NULL;
+ cache_oper->setxattr = oper->setxattr;
+ cache_oper->statfs = oper->statfs;
+ cache_oper->symlink = oper->symlink ? cache_symlink : NULL;
+ cache_oper->truncate = oper->truncate ? cache_truncate : NULL;
+ cache_oper->unlink = oper->unlink ? cache_unlink : NULL;
+ cache_oper->utime = oper->utime ? cache_utime : NULL;
+ cache_oper->write = oper->write ? cache_write : NULL;
+ cache_oper->flag_nopath = 0;
cache_oper->flag_nullpath_ok = 0;
- cache_oper->flag_nopath = 0;
}
-struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
+struct fuse_operations *cache_init(struct fuse_operations *oper)
{
static struct fuse_operations cache_oper;
cache.next_oper = oper;
- cache_unity_fill(oper, &cache_oper);
- if (cache.on) {
- cache_fill(oper, &cache_oper);
- pthread_mutex_init(&cache.lock, NULL);
- cache.table = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, free_node);
- if (cache.table == NULL) {
- fprintf(stderr, "failed to create cache\n");
- return NULL;
- }
+ cache_fill(oper, &cache_oper);
+ pthread_mutex_init(&cache.lock, NULL);
+ cache.table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, free_node);
+ if (cache.table == NULL) {
+ fprintf(stderr, "failed to create cache\n");
+ return NULL;
}
return &cache_oper;
}
static const struct fuse_opt cache_opts[] = {
- { "cache=yes", offsetof(struct cache, on), 1 },
- { "cache=no", offsetof(struct cache, on), 0 },
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
@@ -590,7 +604,6 @@ int cache_parse_options(struct fuse_args *args)
cache.max_size = DEFAULT_MAX_CACHE_SIZE;
cache.clean_interval_secs = DEFAULT_CACHE_CLEAN_INTERVAL_SECS;
cache.min_clean_interval_secs = DEFAULT_MIN_CACHE_CLEAN_INTERVAL_SECS;
- cache.on = 1;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}