]> git.neil.brown.name Git - LaFS.git/commitdiff
accesstime: load delta from atime file and apply when loading inode.
authorNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 23:44:22 +0000 (10:44 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 23:44:22 +0000 (10:44 +1100)
Signed-off-by: NeilBrown <neilb@suse.de>
inode.c
lafs.h
state.h

diff --git a/inode.c b/inode.c
index fd8ab773db85e3d42a3f8a9204b8eee73be332cf..681b8fe701f6189cd1ec2039941fca3d3f774e8c 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -14,6 +14,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 
+static void check_atime_ref(struct inode *ino, int async);
+
 /* Supporting an async 'iget' - as required by the cleaner -
  * is slightly non-trivial.
  * iget*_locked will normally wait for any inode with one
@@ -139,8 +141,10 @@ lafs_iget(struct super_block *sb, ino_t inum, int async)
 
        if (!(ino->i_state & I_NEW)) {
                putdref(b, MKREF(iget));
-               if (ino->i_mode)
+               if (ino->i_mode) {
+                       check_atime_ref(ino, async);
                        return ino;
+               }
                iput(ino);
                return ERR_PTR(-ENOENT);
        }
@@ -185,6 +189,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async)
                        printk("lafs_import_inode failed %d\n", err);
                goto err;
        }
+       check_atime_ref(ino, async);
        unlock_new_inode(ino);
 out:
        if (b && test_and_clear_bit(B_Async, &b->b.flags)) {
@@ -389,8 +394,9 @@ lafs_import_inode(struct inode *ino, struct datablock *b)
                decode_time(&ino->i_mtime, le64_to_cpu(l->modifytime));
                decode_time(&ino->i_ctime, le64_to_cpu(l->ctime));
                decode_time(&i->i_accesstime, le64_to_cpu(l->accesstime));
-               ino->i_atime = i->i_accesstime; /* FIXME load from
-                                                * accesstime file */
+               ino->i_atime = i->i_accesstime;
+               i->atime_offset = 0; /* Will be filled-in later probably */
+               lafs_add_atime_offset(&ino->i_atime, i->atime_offset);
                ino->i_size = le64_to_cpu(l->size);
                i->parent = le32_to_cpu(l->parent);
                ino->i_nlink = le32_to_cpu(l->linkcount);
@@ -468,6 +474,75 @@ out:
        return err;
 }
 
+static void check_atime_ref(struct inode *ino, int async)
+{
+       /* If there is an time file in this filesystem the inode
+        * should hold a reference to the relevant block in
+        * that file.
+        */
+       struct inode *root, *at;
+       u32 bnum;
+       struct datablock *b;
+       if (async)
+               /* Never bother for async lookups */
+               return;
+       if (LAFSI(ino)->type < TypeBase)
+               return;
+       if (test_bit(I_AccessTime, &LAFSI(ino)->iflags))
+               return;
+       root = ino_from_sb(ino->i_sb);
+       at = LAFSI(root)->md.fs.accesstime;
+       if (at == NULL)
+               return;
+
+       if (LAFSI(ino)->md.file.atime_offset)
+               LAFSI(ino)->md.file.atime_offset = 0;
+
+       /* "* 2" to get byte number, then shift to get block
+        * number
+        */
+       bnum = ino->i_ino >> (at->i_blkbits-1);
+       b = lafs_get_block(at, bnum, NULL, GFP_NOFS, MKREF(atime));
+       if (b) {
+               if (lafs_read_block(b) == 0) {
+                       u16 *atp;
+                       int i;
+                       atp = map_dblock(b);
+                       i = (ino->i_ino * 2) & ((1<<at->i_blkbits)-1);
+                       LAFSI(ino)->md.file.atime_offset = le16_to_cpu(atp[i]);
+                       set_bit(I_AccessTime, &LAFSI(ino)->iflags);
+                       unmap_dblock(b, atp);
+                       lafs_add_atime_offset(&ino->i_atime,
+                                             LAFSI(ino)->md.file.atime_offset);
+               } else
+                       putdref(b, MKREF(atime));
+       }
+}
+
+void lafs_add_atime_offset(struct timespec *atime, int offset)
+{
+       int expon;
+       time_t mantissa;
+       if (offset == 0)
+               return;
+
+       expon = offset & 0x1f;
+       if (expon)
+               mantissa = (offset >> 5) | 0x800;
+       else
+               mantissa = (offset >> 5);
+       if (expon >= 11) {
+               /* seconds */
+               mantissa <<= expon-11;
+               atime->tv_sec += mantissa;
+       } else {
+               /* milliseconds */
+               if (expon)
+                       mantissa <<= expon-1;
+               timespec_add_ns(atime, (s64)mantissa * 1000000);
+       }
+}
+
 void lafs_inode_checkpin(struct inode *ino)
 {
        /* Make sure I_Pinned is set correctly.
diff --git a/lafs.h b/lafs.h
index c8c76848dcdcb7bd1e070379d964c27aed4a85e3..b9b7804fc53a6cb6b66a8facff4369d7cf155bf4 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -136,6 +136,7 @@ void lafs_super_write(struct fs *fs, int dev, u64 addr, char *buf, int size);
 int lafs_super_wait(struct fs *fs);
 
 /* inode.c */
+void lafs_add_atime_offset(struct timespec *atime, int offset);
 int __must_check lafs_mount(struct fs *fs);
 struct inode *lafs_iget(struct super_block *fs, ino_t inum, int async);
 struct inode *lafs_iget_fs(struct fs *fs, int fsnum, int inum, int async);
diff --git a/state.h b/state.h
index ecbc996cdd834632a01cae0eb8aeb35777b3df07..8f278411bfc8b378d862861c853eeafca4ba2396 100644 (file)
--- a/state.h
+++ b/state.h
@@ -571,6 +571,9 @@ struct lafs_inode {
 #define        I_Pinned 6      /* InoIdx is pinned, i_nlink is non-zero, and consequently
                         * we own an extra ref to the inode and superblock.
                         */
+#define I_AccessTime 7 /* Set if this inode holds a reference to the block
+                        * in the accesstime file that holds our atime
+                        */
 /* next three indicate if we hold a reference on the relevant qent */
 #define        I_QUid  8
 #define        I_QGid  9
@@ -617,6 +620,7 @@ struct lafs_inode {
                        u32     table_size;     /* (blocks) */
                } segmentusage;
                struct file_md {
+                       u16     atime_offset; /* value stored in atime file */
                        u16     flags;
 /*                     u16     mode; */
 /*                     u32     uid; */