From 386a7f67abe051067887a9d84443eccf353dbb2c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 7 Feb 2005 16:12:46 +0000 Subject: cleanup --- ChangeLog | 4 + Makefile.am | 2 +- cache.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cache.h | 21 ++++++ sshfs.c | 179 +++++++++----------------------------------- 5 files changed, 304 insertions(+), 146 deletions(-) create mode 100644 cache.c create mode 100644 cache.h diff --git a/ChangeLog b/ChangeLog index 9b4b4a4..7d0e25f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2005-02-07 Miklos Szeredi + + * Separate attribute caching to a separate layer + 2005-02-03 Miklos Szeredi Fix PKG_CONFIG_PATH setting in configure.ac (reported by Alpar diff --git a/Makefile.am b/Makefile.am index e8c3665..4f75792 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ ## Process this file with automake to produce Makefile.in bin_PROGRAMS = sshfs -sshfs_SOURCES = sshfs.c +sshfs_SOURCES = sshfs.c cache.c diff --git a/cache.c b/cache.c new file mode 100644 index 0000000..0ef110d --- /dev/null +++ b/cache.c @@ -0,0 +1,244 @@ +/* + Caching file system proxy + Copyright (C) 2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#define FUSE_USE_VERSION 22 +#include "cache.h" +#include +#include +#include +#include + +#define CACHE_TIMEOUT 20 +#define MAX_CACHE_SIZE 10000 +#define CACHE_CLEAN_INTERVAL 60 + +struct node_attr { + struct stat stat; + time_t stat_valid; + time_t valid; +}; + +struct fuse_cache_dirhandle { + const char *path; + fuse_dirh_t h; + fuse_dirfil_t filler; +}; + +static struct fuse_cache_operations *next_oper; +static GHashTable *cache; +static pthread_mutex_t cache_lock; +static time_t last_cleaned; + +static int cache_clean_entry(void *_key, struct node_attr *node, time_t *now) +{ + (void) _key; + if (*now > node->valid) + return TRUE; + else + return FALSE; +} + +static void cache_clean(void) +{ + time_t now = time(NULL); + if (g_hash_table_size(cache) > MAX_CACHE_SIZE || + now > last_cleaned + CACHE_CLEAN_INTERVAL) { + g_hash_table_foreach_remove(cache, (GHRFunc) cache_clean_entry, &now); + last_cleaned = now; + } +} + +static struct node_attr *cache_lookup(const char *path) +{ + return (struct node_attr *) g_hash_table_lookup(cache, path); +} + +static void cache_remove(const char *path) +{ + pthread_mutex_lock(&cache_lock); + g_hash_table_remove(cache, path); + pthread_mutex_unlock(&cache_lock); +} + +static void cache_invalidate(const char *path) +{ + cache_remove(path); +} + +static void cache_do_rename(const char *from, const char *to) +{ + cache_remove(from); + cache_remove(to); +} + +static struct node_attr *cache_get(const char *path) +{ + struct node_attr *node = cache_lookup(path); + if (node == NULL) { + char *pathcopy = g_strdup(path); + node = g_new0(struct node_attr, 1); + g_hash_table_insert(cache, pathcopy, node); + } + return node; +} + +static void cache_add_attr(const char *path, const struct stat *stbuf) +{ + struct node_attr *node; + time_t now; + + pthread_mutex_lock(&cache_lock); + node = cache_get(path); + now = time(NULL); + node->stat = *stbuf; + node->stat_valid = time(NULL) + CACHE_TIMEOUT; + if (node->stat_valid > node->valid) + node->valid = node->stat_valid; + cache_clean(); + pthread_mutex_unlock(&cache_lock); +} + +static int cache_getattr(const char *path, struct stat *stbuf) +{ + struct node_attr *node; + int err; + + pthread_mutex_lock(&cache_lock); + node = cache_lookup(path); + if (node != NULL) { + time_t now = time(NULL); + if (node->valid - now >= 0) { + *stbuf = node->stat; + pthread_mutex_unlock(&cache_lock); + return 0; + } + } + pthread_mutex_unlock(&cache_lock); + err = next_oper->oper.getattr(path, stbuf); + if (!err) + cache_add_attr(path, stbuf); + + return err; +} + +static int cache_dirfill(fuse_cache_dirh_t ch, const char *name, + const struct stat *stbuf) +{ + int err = ch->filler(ch->h, name, 0, 0); + if (!err) { + char *fullpath = g_strdup_printf("%s/%s", + !ch->path[1] ? "" : ch->path, name); + cache_add_attr(fullpath, stbuf); + g_free(fullpath); + } + return err; +} + +static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) +{ + struct fuse_cache_dirhandle ch; + ch.path = path; + ch.h = h; + ch.filler = filler; + return next_oper->cache_getdir(path, &ch, cache_dirfill); +} + +static int cache_unlink(const char *path) +{ + int err = next_oper->oper.unlink(path); + if (!err) + cache_remove(path); + return err; +} + +static int cache_rmdir(const char *path) +{ + int err = next_oper->oper.rmdir(path); + if (!err) + cache_remove(path); + return err; +} + +static int cache_rename(const char *from, const char *to) +{ + int err = next_oper->oper.rename(from, to); + if (!err) + cache_do_rename(from, to); + return err; +} + +static int cache_chmod(const char *path, mode_t mode) +{ + int err = next_oper->oper.chmod(path, mode); + if (!err) + cache_invalidate(path); + return err; +} + +static int cache_chown(const char *path, uid_t uid, gid_t gid) +{ + int err = next_oper->oper.chown(path, uid, gid); + if (!err) + cache_invalidate(path); + return err; +} + +static int cache_truncate(const char *path, off_t size) +{ + int err = next_oper->oper.truncate(path, size); + if (!err) + cache_invalidate(path); + return err; +} + +static int cache_utime(const char *path, struct utimbuf *buf) +{ + int err = next_oper->oper.utime(path, buf); + if (!err) + cache_invalidate(path); + return err; +} + + +struct fuse_operations *cache_init(struct fuse_cache_operations *oper) +{ + static struct fuse_operations cache_oper; + next_oper = oper; + + cache_oper.getattr = oper->oper.getattr ? cache_getattr : NULL; + cache_oper.readlink = oper->oper.readlink; + cache_oper.getdir = oper->cache_getdir ? cache_getdir : oper->oper.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_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_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.open = oper->oper.open; + cache_oper.read = oper->oper.read; + cache_oper.write = oper->oper.write; + cache_oper.statfs = oper->oper.statfs; + cache_oper.release = oper->oper.release; + cache_oper.fsync = oper->oper.fsync; + cache_oper.setxattr = oper->oper.setxattr; + cache_oper.getxattr = oper->oper.getxattr; + cache_oper.listxattr = oper->oper.listxattr; + cache_oper.removexattr = oper->oper.removexattr; + pthread_mutex_init(&cache_lock, NULL); + cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + if (cache == NULL) { + fprintf(stderr, "failed to create cache\n"); + return NULL; + } + return &cache_oper; +} diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..1466a1b --- /dev/null +++ b/cache.h @@ -0,0 +1,21 @@ +/* + Caching file system proxy + Copyright (C) 2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include + +typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t; +typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name, + const struct stat *stbuf); + +struct fuse_cache_operations { + struct fuse_operations oper; + int (*cache_getdir) (const char *, fuse_cache_dirh_t, fuse_cache_dirfil_t); + +}; + +struct fuse_operations *cache_init(struct fuse_cache_operations *oper); diff --git a/sshfs.c b/sshfs.c index dc68653..48eb7f3 100644 --- a/sshfs.c +++ b/sshfs.c @@ -23,6 +23,8 @@ #include #include +#include "cache.h" + #define SSH_FXP_INIT 1 #define SSH_FXP_VERSION 2 #define SSH_FXP_OPEN 3 @@ -79,9 +81,6 @@ #define MY_EOF 1 #define MAX_REPLY_LEN (1 << 17) -#define CACHE_TIMEOUT 20 -#define MAX_CACHE_SIZE 10000 -#define CACHE_CLEAN_INTERVAL 60 static int infd; static int outfd; @@ -110,18 +109,11 @@ struct openfile { struct buffer write_handle; }; -struct node_attr { - struct stat stat; - time_t updated; -}; - struct sshfs_file { struct buffer handle; }; static GHashTable *reqtab; -static GHashTable *cache; -static time_t last_cleaned; static pthread_mutex_t lock; static int processing_thread_started; @@ -379,75 +371,8 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf) return 0; } -static int cache_clean_entry(void *_key, struct node_attr *node, time_t *now) -{ - (void) _key; - if (*now > node->updated + CACHE_TIMEOUT) - return TRUE; - else - return FALSE; -} - -static void cache_clean(void) -{ - time_t now = time(NULL); - if (g_hash_table_size(cache) > MAX_CACHE_SIZE || - now > last_cleaned + CACHE_CLEAN_INTERVAL) { - g_hash_table_foreach_remove(cache, (GHRFunc) cache_clean_entry, &now); - last_cleaned = now; - } -} - -static struct node_attr *cache_lookup(const char *path) -{ - return (struct node_attr *) g_hash_table_lookup(cache, path); -} - -static void cache_remove(const char *path) -{ - pthread_mutex_lock(&lock); - g_hash_table_remove(cache, path); - pthread_mutex_unlock(&lock); -} - -static void cache_invalidate(const char *path) -{ - cache_remove(path); -} - -static void cache_rename(const char *from, const char *to) -{ - cache_remove(from); - cache_remove(to); -} - -static struct node_attr *cache_get(const char *path) -{ - struct node_attr *node = cache_lookup(path); - if (node == NULL) { - char *pathcopy = g_strdup(path); - node = g_new0(struct node_attr, 1); - g_hash_table_insert(cache, pathcopy, node); - } - return node; -} - -static void cache_add_attr(const char *path, const struct stat *stbuf) -{ - struct node_attr *node; - time_t now; - - pthread_mutex_lock(&lock); - node = cache_get(path); - now = time(NULL); - node->stat = *stbuf; - node->updated = time(NULL); - cache_clean(); - pthread_mutex_unlock(&lock); -} - -static int buf_get_entries(struct buffer *buf, fuse_dirh_t h, - fuse_dirfil_t filler, const char *path) +static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h, + fuse_cache_dirfil_t filler) { uint32_t count; unsigned i; @@ -465,11 +390,7 @@ static int buf_get_entries(struct buffer *buf, fuse_dirh_t h, if (buf_get_string(buf, &longname) != -1) { free(longname); if (buf_get_attrs(buf, &stbuf) != -1) { - char *fullpath; - filler(h, name, stbuf.st_mode >> 12, 0); - fullpath = g_strdup_printf("%s/%s", !path[1] ? "" : path, name); - cache_add_attr(fullpath, &stbuf); - g_free(fullpath); + filler(h, name, &stbuf); err = 0; } } @@ -780,7 +701,7 @@ static int sftp_request(uint8_t type, const struct buffer *buf, } -static int sshfs_send_getattr(const char *path, struct stat *stbuf) +static int sshfs_getattr(const char *path, struct stat *stbuf) { int err; struct buffer buf; @@ -794,29 +715,9 @@ static int sshfs_send_getattr(const char *path, struct stat *stbuf) buf_free(&outbuf); } buf_free(&buf); - if (!err) - cache_add_attr(path, stbuf); return err; } -static int sshfs_getattr(const char *path, struct stat *stbuf) -{ - struct node_attr *node; - - pthread_mutex_lock(&lock); - node = cache_lookup(path); - if (node != NULL) { - time_t now = time(NULL); - if (now - node->updated < CACHE_TIMEOUT) { - *stbuf = node->stat; - pthread_mutex_unlock(&lock); - return 0; - } - } - pthread_mutex_unlock(&lock); - return sshfs_send_getattr(path, stbuf); -} - static int sshfs_readlink(const char *path, char *linkbuf, size_t size) { int err; @@ -842,7 +743,8 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size) return err; } -static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) +static int sshfs_getdir(const char *path, fuse_cache_dirh_t h, + fuse_cache_dirfil_t filler) { int err; struct buffer buf; @@ -857,7 +759,7 @@ static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) struct buffer name; err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name); if (!err) { - if (buf_get_entries(&name, h, filler, path) == -1) + if (buf_get_entries(&name, h, filler) == -1) err = -EPROTO; buf_free(&name); } @@ -935,8 +837,6 @@ static int sshfs_unlink(const char *path) buf_init(&buf, 0); buf_add_path(&buf, path); err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_remove(path); buf_free(&buf); return err; } @@ -948,8 +848,6 @@ static int sshfs_rmdir(const char *path) buf_init(&buf, 0); buf_add_path(&buf, path); err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_remove(path); buf_free(&buf); return err; } @@ -962,8 +860,6 @@ static int sshfs_rename(const char *from, const char *to) buf_add_path(&buf, from); buf_add_path(&buf, to); err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_rename(from, to); buf_free(&buf); return err; } @@ -977,8 +873,6 @@ static int sshfs_chmod(const char *path, mode_t mode) buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS); buf_add_uint32(&buf, mode); err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_invalidate(path); buf_free(&buf); return err; } @@ -1006,8 +900,6 @@ static int sshfs_truncate(const char *path, off_t size) buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE); buf_add_uint64(&buf, size); err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_invalidate(path); buf_free(&buf); return err; } @@ -1016,15 +908,12 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf) { int err; struct buffer buf; - cache_remove(path); buf_init(&buf, 0); buf_add_path(&buf, path); buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME); buf_add_uint32(&buf, ubuf->actime); buf_add_uint32(&buf, ubuf->modtime); err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_invalidate(path); buf_free(&buf); return err; } @@ -1110,6 +999,7 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size, struct buffer data; struct sshfs_file *sf = (struct sshfs_file *) fi->fh; struct buffer *handle = &sf->handle; + (void) path; data.p = (uint8_t *) wbuf; data.len = size; buf_init(&buf, 0); @@ -1117,8 +1007,6 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size, buf_add_uint64(&buf, offset); buf_add_data(&buf, &data); err = sftp_request(SSH_FXP_WRITE, &buf, SSH_FXP_STATUS, NULL); - if (!err) - cache_invalidate(path); buf_free(&buf); return err ? err : (int) size; } @@ -1157,32 +1045,33 @@ static int processing_init(void) { pthread_mutex_init(&lock, NULL); reqtab = g_hash_table_new(NULL, NULL); - cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - if (!reqtab || !cache) { - fprintf(stderr, "failed to create hash tables\n"); + if (!reqtab) { + fprintf(stderr, "failed to create hash table\n"); return -1; } return 0; } -static struct fuse_operations sshfs_oper = { - .getattr = sshfs_getattr, - .readlink = sshfs_readlink, - .getdir = sshfs_getdir, - .mknod = sshfs_mknod, - .mkdir = sshfs_mkdir, - .symlink = sshfs_symlink, - .unlink = sshfs_unlink, - .rmdir = sshfs_rmdir, - .rename = sshfs_rename, - .chmod = sshfs_chmod, - .chown = sshfs_chown, - .truncate = sshfs_truncate, - .utime = sshfs_utime, - .open = sshfs_open, - .release = sshfs_release, - .read = sshfs_read, - .write = sshfs_write, +static struct fuse_cache_operations sshfs_oper = { + .oper = { + .getattr = sshfs_getattr, + .readlink = sshfs_readlink, + .mknod = sshfs_mknod, + .mkdir = sshfs_mkdir, + .symlink = sshfs_symlink, + .unlink = sshfs_unlink, + .rmdir = sshfs_rmdir, + .rename = sshfs_rename, + .chmod = sshfs_chmod, + .chown = sshfs_chown, + .truncate = sshfs_truncate, + .utime = sshfs_utime, + .open = sshfs_open, + .release = sshfs_release, + .read = sshfs_read, + .write = sshfs_write, + }, + .cache_getdir = sshfs_getdir, }; static void usage(const char *progname) @@ -1196,7 +1085,7 @@ static void usage(const char *progname) " -p port remote port\n" " -c port directly connect to port bypassing ssh\n" "\n", progname); - fuse_main(2, (char **) fusehelp, &sshfs_oper); + fuse_main(2, (char **) fusehelp, NULL); exit(1); } @@ -1278,5 +1167,5 @@ int main(int argc, char *argv[]) newargv[newargc++] = g_strdup_printf("-ofsname=sshfs#%s", fsname); g_free(fsname); newargv[newargc] = NULL; - return fuse_main(newargc, newargv, &sshfs_oper); + return fuse_main(newargc, newargv, cache_init(&sshfs_oper)); } -- cgit v1.2.3