}
}
+static int normalise(int *mantissa)
+{
+ /* Shift down until value can be stored in 12 bits:
+ * Top bit will be '1', so only 11 bits needed.
+ * Not used on values below 2048.
+ */
+ int shift = 0;
+ while (*mantissa >= 4096) {
+ *mantissa >>= 1;
+ shift ++;
+ }
+ return shift;
+}
+
+static int update_atime_delta(struct inode *ino)
+{
+ /* calculate new delta to show the difference between
+ * i_atime and i_accesstime
+ */
+ int rv;
+ if (timespec_compare(&ino->i_atime,
+ &LAFSI(ino)->md.file.i_accesstime) <= 0) {
+ /* We cannot store negative delta so if i_atime is in the
+ * past, just store zero
+ */
+ rv = 0;
+ } else {
+ struct timespec diff;
+ int shift;
+
+ diff = timespec_sub(ino->i_atime,
+ LAFSI(ino)->md.file.i_accesstime);
+ if (diff.tv_sec >= 2048) {
+ /* Just store the seconds */
+ rv = diff.tv_sec;
+ shift = normalise(&rv) + 11;
+ } else {
+ /* Store the milliseconds */
+ int rv = diff.tv_nsec / 1000000;
+ rv += diff.tv_sec * 1000;
+ if (rv >= 2048)
+ shift = normalise(&rv) + 1;
+ else
+ shift = 0;
+ }
+ if (shift > 31)
+ rv = 0xFFFF;
+ else {
+ rv &= 0x7ff;
+ rv <<= 5;
+ rv |= shift;
+ }
+ }
+ if (LAFSI(ino)->md.file.atime_offset == rv)
+ return 0;
+
+ LAFSI(ino)->md.file.atime_offset = rv;
+ return 1;
+}
+
+static void store_atime_delta(struct inode *ino)
+{
+ struct inode *at;
+ u32 bnum;
+ struct datablock *b;
+ u16 *atp;
+ int i;
+
+ if (!test_bit(I_AccessTime, &LAFSI(ino)->iflags))
+ /* sorry, nothing we can do here */
+ return;
+
+ /* We own a reference, so this lookup must succeed */
+ at = LAFSI(ino_from_sb(ino->i_sb))->md.fs.accesstime;
+ bnum = ino->i_ino >> (at->i_blkbits-1);
+ b = lafs_get_block(at, bnum, NULL, GFP_NOFS, MKREF(store_atime));
+ BUG_ON(!b);
+ atp = map_dblock(b);
+ i = (ino->i_ino * 2) & ((1<<at->i_blkbits)-1);
+ if (le16_to_cpu(atp[i]) != LAFSI(ino)->md.file.atime_offset) {
+ atp[i] = cpu_to_le16(LAFSI(ino)->md.file.atime_offset);
+ lafs_dirty_dblock(b);
+ }
+ unmap_dblock(b, atp);
+ putdref(b, MKREF(store_atime));
+}
+
void lafs_inode_checkpin(struct inode *ino)
{
/* Make sure I_Pinned is set correctly.
* 2/ by writeout before requesting a write - to update mtime
* 3/ by read to update atime
*
- * As we don't know which, there is not much we can do.
+ * We want to handle atime updates carefully as they may not change
+ * the stored inode itself.
+ * For all other updates, the inode dblock exists and is pinned.
+ * In those cases we will be updating the inode and so can store
+ * the atime exactly.
+ * For an atime update, the dblock may not exists, or may not be
+ * Pinned. If it isn't then we don't want to make the inode dirty
+ * but only want to update the delta stored in the atime file.
+ * The block for that should already be pinned.
+ *
+ *
* We mustn't update the data block as it could be in
* writeout and we cannot always wait safely.
* So require that anyone who really cares, dirties the datablock
*/
struct timespec now;
struct inode *filesys;
+ int atime_only = 1;
+
+ if (LAFSI(ino)->dblock) {
+ struct datablock *db;
+ spin_lock(&ino->i_data.private_lock);
+ db = LAFSI(ino)->dblock;
+ if (db && test_bit(B_Pinned, &db->b.flags))
+ atime_only = 0;
+ spin_unlock(&ino->i_data.private_lock);
+ }
+
+ if (atime_only) {
+ if (update_atime_delta(ino))
+ store_atime_delta(ino);
+ return;
+ }
+
+
set_bit(I_Dirty, &LAFSI(ino)->iflags);
ino->i_sb->s_dirt = 1;
+ LAFSI(ino)->md.file.i_accesstime = ino->i_atime;
+ if (LAFSI(ino)->md.file.atime_offset) {
+ LAFSI(ino)->md.file.atime_offset = 0;
+ store_atime_delta(ino);
+ }
now = current_fs_time(ino->i_sb);
filesys = ino_from_sb(ino->i_sb);
l->creationtime = cpu_to_le64(i->creationtime);
l->modifytime = cpu_to_le64(encode_time(&ino->i_mtime));
l->ctime = cpu_to_le64(encode_time(&ino->i_ctime));
- l->accesstime = cpu_to_le64(encode_time(&ino->i_atime));
- /* FIXME write 0 to accesstime file */
+ l->accesstime = cpu_to_le64(encode_time(&i->i_accesstime));
l->size = cpu_to_le64(ino->i_size);
l->parent = cpu_to_le32(i->parent);
l->linkcount = cpu_to_le32(ino->i_nlink);