From 4b28b15c34f0969e47fbbfd81c4f63e6e6f16203 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 6 May 2008 15:10:28 +0000 Subject: Fix bug in caching which could cause file corruption for append mode writes --- ChangeLog | 11 +++++++++++ cache.c | 50 ++++++++++++++++++++++++++++++++++++++------------ cache.h | 3 ++- sshfs.c | 13 ++++++++++++- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index b871aa7..0d89652 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-05-06 Miklos Szeredi + + * Fix bug in caching which could cause file corruption for append + mode writes. Reported by Jose Alonso + +2008-05-05 Miklos Szeredi + + * Fix compile on OS X. Original patch from Michael G Schwern + + * Fix compile on Solaris. Reported by Jean-Jacques Sarton + 2008-04-23 Miklos Szeredi * Released 2.0 diff --git a/cache.c b/cache.c index 8908835..c6be742 100644 --- a/cache.c +++ b/cache.c @@ -28,6 +28,7 @@ struct cache { GHashTable *table; pthread_mutex_t lock; time_t last_cleaned; + uint64_t write_ctr; }; static struct cache cache; @@ -47,6 +48,7 @@ struct fuse_cache_dirhandle { fuse_dirh_t h; fuse_dirfil_t filler; GPtrArray *dir; + uint64_t wrctr; }; static void free_node(gpointer node_) @@ -108,6 +110,14 @@ void cache_invalidate(const char *path) pthread_mutex_unlock(&cache.lock); } +void cache_invalidate_write(const char *path) +{ + pthread_mutex_lock(&cache.lock); + cache_purge(path); + cache.write_ctr++; + pthread_mutex_unlock(&cache.lock); +} + static void cache_invalidate_dir(const char *path) { pthread_mutex_lock(&cache.lock); @@ -148,19 +158,21 @@ static struct node *cache_get(const char *path) return node; } -void cache_add_attr(const char *path, const struct stat *stbuf) +void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr) { struct node *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.stat_timeout; - if (node->stat_valid > node->valid) - node->valid = node->stat_valid; - cache_clean(); + if (wrctr == cache.write_ctr) { + node = cache_get(path); + now = time(NULL); + node->stat = *stbuf; + node->stat_valid = time(NULL) + cache.stat_timeout; + if (node->stat_valid > node->valid) + node->valid = node->stat_valid; + cache_clean(); + } pthread_mutex_unlock(&cache.lock); } @@ -222,13 +234,25 @@ static int cache_get_attr(const char *path, struct stat *stbuf) return err; } +uint64_t cache_get_write_ctr(void) +{ + uint64_t res; + + pthread_mutex_lock(&cache.lock); + res = cache.write_ctr; + pthread_mutex_unlock(&cache.lock); + + return res; +} + 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); if (!err) - cache_add_attr(path, stbuf); + cache_add_attr(path, stbuf, wrctr); } return err; } @@ -268,7 +292,7 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name, const char *basepath = !ch->path[1] ? "" : ch->path; fullpath = g_strdup_printf("%s/%s", basepath, name); - cache_add_attr(fullpath, stbuf); + cache_add_attr(fullpath, stbuf, ch->wrctr); g_free(fullpath); } } @@ -299,6 +323,7 @@ static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) ch.h = h; 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); g_ptr_array_add(ch.dir, NULL); dir = (char **) ch.dir->pdata; @@ -421,7 +446,7 @@ static int cache_write(const char *path, const char *buf, size_t size, { int res = cache.next_oper->oper.write(path, buf, size, offset, fi); if (res >= 0) - cache_invalidate(path); + cache_invalidate_write(path); return res; } @@ -449,9 +474,10 @@ 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); if (!err) - cache_add_attr(path, stbuf); + cache_add_attr(path, stbuf, wrctr); } return err; } diff --git a/cache.h b/cache.h index 3a121fc..cec9ca4 100644 --- a/cache.h +++ b/cache.h @@ -24,5 +24,6 @@ struct fuse_cache_operations { struct fuse_operations *cache_init(struct fuse_cache_operations *oper); int cache_parse_options(struct fuse_args *args); -void cache_add_attr(const char *path, const struct stat *stbuf); +void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr); void cache_invalidate(const char *path); +uint64_t cache_get_write_ctr(void); diff --git a/sshfs.c b/sshfs.c index 39eec48..6f5c256 100644 --- a/sshfs.c +++ b/sshfs.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,15 @@ #include "cache.h" +#ifndef MAP_LOCKED +#define MAP_LOCKED 0 +#endif + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + + #if FUSE_VERSION >= 23 #define SSHFS_USE_INIT #endif @@ -2116,6 +2126,7 @@ static int sshfs_open_common(const char *path, mode_t mode, uint32_t pflags = 0; struct iovec iov; uint8_t type; + uint64_t wrctr = cache_get_write_ctr(); if ((fi->flags & O_ACCMODE) == O_RDONLY) pflags = SSH_FXF_READ; @@ -2171,7 +2182,7 @@ static int sshfs_open_common(const char *path, mode_t mode, } if (!err) { - cache_add_attr(path, &stbuf); + cache_add_attr(path, &stbuf, wrctr); buf_finish(&sf->handle); fi->fh = (unsigned long) sf; } else { -- cgit v1.2.3