[PATCH] fuse: use jiffies_64
authorMiklos Szeredi <miklos@szeredi.hu>
Sun, 30 Jul 2006 10:04:10 +0000 (03:04 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 31 Jul 2006 20:28:43 +0000 (13:28 -0700)
It is entirely possible (though rare) that jiffies half-wraps around, while a
dentry/inode remains in the cache.  This could mean that the dentry/inode is
not invalidated for another half wraparound-time.

To get around this problem, use 64-bit jiffies.  The only problem with this is
that dentry->d_time is 32 bits on 32-bit archs.  So use d_fsdata as the high
32 bits.  This is an ugly hack, but far simpler, than having to allocate
private data just for this purpose.

Since 64-bit jiffies can be assumed never to wrap around, simple comparison
can be used, and a zero time value can represent "invalid".

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 6db66ec386aef2d61873d3cacea3509a55c2741e..409ce6a7cca4ccd2e53f46693a5e4301bef87245 100644 (file)
 #include <linux/sched.h>
 #include <linux/namei.h>
 
+#if BITS_PER_LONG >= 64
+static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
+{
+       entry->d_time = time;
+}
+
+static inline u64 fuse_dentry_time(struct dentry *entry)
+{
+       return entry->d_time;
+}
+#else
+/*
+ * On 32 bit archs store the high 32 bits of time in d_fsdata
+ */
+static void fuse_dentry_settime(struct dentry *entry, u64 time)
+{
+       entry->d_time = time;
+       entry->d_fsdata = (void *) (unsigned long) (time >> 32);
+}
+
+static u64 fuse_dentry_time(struct dentry *entry)
+{
+       return (u64) entry->d_time +
+               ((u64) (unsigned long) entry->d_fsdata << 32);
+}
+#endif
+
 /*
  * FUSE caches dentries and attributes with separate timeout.  The
  * time in jiffies until the dentry/attributes are valid is stored in
 /*
  * Calculate the time in jiffies until a dentry/attributes are valid
  */
-static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
+static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
 {
        if (sec || nsec) {
                struct timespec ts = {sec, nsec};
-               return jiffies + timespec_to_jiffies(&ts);
+               return get_jiffies_64() + timespec_to_jiffies(&ts);
        } else
-               return jiffies - 1;
+               return 0;
 }
 
 /*
@@ -38,7 +65,8 @@ static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
  */
 static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
 {
-       entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
+       fuse_dentry_settime(entry,
+               time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
        if (entry->d_inode)
                get_fuse_inode(entry->d_inode)->i_time =
                        time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
@@ -50,7 +78,7 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
  */
 void fuse_invalidate_attr(struct inode *inode)
 {
-       get_fuse_inode(inode)->i_time = jiffies - 1;
+       get_fuse_inode(inode)->i_time = 0;
 }
 
 /*
@@ -63,7 +91,7 @@ void fuse_invalidate_attr(struct inode *inode)
  */
 static void fuse_invalidate_entry_cache(struct dentry *entry)
 {
-       entry->d_time = jiffies - 1;
+       fuse_dentry_settime(entry, 0);
 }
 
 /*
@@ -105,7 +133,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 
        if (inode && is_bad_inode(inode))
                return 0;
-       else if (time_after(jiffies, entry->d_time)) {
+       else if (fuse_dentry_time(entry) < get_jiffies_64()) {
                int err;
                struct fuse_entry_out outarg;
                struct fuse_conn *fc;
@@ -669,7 +697,7 @@ static int fuse_revalidate(struct dentry *entry)
        if (!fuse_allow_task(fc, current))
                return -EACCES;
        if (get_node_id(inode) != FUSE_ROOT_ID &&
-           time_before_eq(jiffies, fi->i_time))
+           fi->i_time >= get_jiffies_64())
                return 0;
 
        return fuse_do_getattr(inode);
index 0dbf96621841506f94ed62ae32260fd077ae19d5..69c7750d55b8e59cfd95a0322f45557a74c0fdfe 100644 (file)
@@ -59,7 +59,7 @@ struct fuse_inode {
        struct fuse_req *forget_req;
 
        /** Time in jiffies until the file attributes are valid */
-       unsigned long i_time;
+       u64 i_time;
 };
 
 /** FUSE specific file data */
index dcaaabd3b9c450ad546b86c54d475c5b8ff0f0ed..7d25092262ae71d3eb0af390b60b8e8a0c587a9e 100644 (file)
@@ -51,7 +51,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
                return NULL;
 
        fi = get_fuse_inode(inode);
-       fi->i_time = jiffies - 1;
+       fi->i_time = 0;
        fi->nodeid = 0;
        fi->nlookup = 0;
        fi->forget_req = fuse_request_alloc();