Skip to content

Commit

Permalink
Enable lazytime semantic for atime
Browse files Browse the repository at this point in the history
Linux 4.0 introduces lazytime. The idea is that when we update the atime, we
delay writing it to disk for as long as it is reasonably possible.

When lazytime is enabled, dirty_inode will be called with only I_DIRTY_TIME
flag whenever i_atime is updated. So under such condition, we will set
z_atime_dirty. We will only write it to disk if file is closed, inode is
evicted or setattr is called. Ideally, we should also write it whenever SA
is going to be updated, but it is left for future improvement.

There's one thing that we should take care of now that we allow i_atime to be
dirty. In original implementation, whenever SA is modified, zfs_inode_update
will be called to overwrite every thing in inode. This will cause dirty
i_atime to be discarded. We fix this by don't overwrite i_atime in
zfs_inode_update. We only overwrite i_atime when allocating new inode or doing
zfs_rezget with zfs_inode_update_new.

Signed-off-by: Chunwei Chen <david.chen@osnexus.com>
  • Loading branch information
Chunwei Chen committed Apr 1, 2016
1 parent 1d583bd commit 231f9ff
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 8 deletions.
23 changes: 20 additions & 3 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -3006,8 +3006,9 @@ zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
}


if (mask & ATTR_ATIME) {
ZFS_TIME_ENCODE(&vap->va_atime, atime);
if ((mask & ATTR_ATIME) || zp->z_atime_dirty) {
zp->z_atime_dirty = 0;
ZFS_TIME_ENCODE(&ip->i_atime, atime);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
&atime, sizeof (atime));
}
Expand Down Expand Up @@ -4131,7 +4132,7 @@ zfs_dirty_inode(struct inode *ip, int flags)
dmu_tx_t *tx;
uint64_t mode, atime[2], mtime[2], ctime[2];
sa_bulk_attr_t bulk[4];
int error;
int error = 0;
int cnt = 0;

if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os))
Expand All @@ -4140,6 +4141,20 @@ zfs_dirty_inode(struct inode *ip, int flags)
ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);

#ifdef I_DIRTY_TIME
/*
* This is the lazytime semantic indroduced in Linux 4.0
* This flag will only be called from update_time when lazytime is set.
* (Note, I_DIRTY_SYNC will also set if not lazytime)
* Fortunately mtime and ctime are managed within ZFS itself, so we
* only need to dirty atime.
*/
if (flags == I_DIRTY_TIME) {
zp->z_atime_dirty = 1;
goto out;
}
#endif

tx = dmu_tx_create(zsb->z_os);

dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
Expand All @@ -4152,6 +4167,8 @@ zfs_dirty_inode(struct inode *ip, int flags)
}

mutex_enter(&zp->z_lock);
zp->z_atime_dirty = 0;

SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(zsb), NULL, &mode, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
Expand Down
30 changes: 25 additions & 5 deletions module/zfs/zfs_znode.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
}
}

static void zfs_inode_update_new(znode_t *zp);

/*
* Construct a znode+inode and initialize.
*
Expand Down Expand Up @@ -567,7 +569,7 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz,
}

ip->i_ino = obj;
zfs_inode_update(zp);
zfs_inode_update_new(zp);
zfs_inode_set_ops(zsb, ip);

/*
Expand Down Expand Up @@ -620,8 +622,8 @@ zfs_set_inode_flags(znode_t *zp, struct inode *ip)
* inode has the correct field it should be used, and the ZFS code
* updated to access the inode. This can be done incrementally.
*/
void
zfs_inode_update(znode_t *zp)
static void
__zfs_inode_update(znode_t *zp, int new)
{
zfs_sb_t *zsb;
struct inode *ip;
Expand Down Expand Up @@ -653,14 +655,31 @@ zfs_inode_update(znode_t *zp)
ip->i_blkbits = SPA_MINBLOCKSHIFT;
ip->i_blocks = i_blocks;

ZFS_TIME_DECODE(&ip->i_atime, atime);
/*
* Only read atime if we are new inode (or rezget), otherwise i_atime
* might be dirty.
*/
if (new)
ZFS_TIME_DECODE(&ip->i_atime, atime);
ZFS_TIME_DECODE(&ip->i_mtime, mtime);
ZFS_TIME_DECODE(&ip->i_ctime, ctime);

i_size_write(ip, zp->z_size);
spin_unlock(&ip->i_lock);
}

static void
zfs_inode_update_new(znode_t *zp)
{
__zfs_inode_update(zp, 1);
}

void
zfs_inode_update(znode_t *zp)
{
__zfs_inode_update(zp, 0);
}

/*
* Safely mark an inode dirty. Inodes which are part of a read-only
* file system or snapshot may not be dirtied.
Expand Down Expand Up @@ -1220,7 +1239,8 @@ zfs_rezget(znode_t *zp)

zp->z_unlinked = (zp->z_links == 0);
zp->z_blksz = doi.doi_data_block_size;
zfs_inode_update(zp);
zp->z_atime_dirty = 0;
zfs_inode_update_new(zp);

zfs_znode_hold_exit(zsb, zh);

Expand Down
3 changes: 3 additions & 0 deletions module/zfs/zpl_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
vap->va_mtime = ia->ia_mtime;
vap->va_ctime = ia->ia_ctime;

if (vap->va_mask & ATTR_ATIME)
ip->i_atime = ia->ia_atime;

cookie = spl_fstrans_mark();
error = -zfs_setattr(ip, vap, 0, cr);
if (!error && (ia->ia_valid & ATTR_MODE))
Expand Down

0 comments on commit 231f9ff

Please sign in to comment.