#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
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);
}
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)) {
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);
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.