summaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_znode.c
diff options
context:
space:
mode:
authorTim Chase <[email protected]>2014-01-18 13:00:53 -0600
committerBrian Behlendorf <[email protected]>2014-01-29 15:50:44 -0800
commit6d111134c0d1eb9b179eb9fddf26a31d5d45ae22 (patch)
tree58b2ef03d95ddcc6721574651ea223e7150c1763 /module/zfs/zfs_znode.c
parent2278381ce2a820afe76dd9650298858d7037a01b (diff)
Implement relatime.
Add the "relatime" property. When set to "on", a file's atime will only be updated if the existing atime at least a day old or if the existing ctime or mtime has been updated since the last access. This behavior is compatible with the Linux "relatime" mount option. Signed-off-by: Tim Chase <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #2064 Closes #1917
Diffstat (limited to 'module/zfs/zfs_znode.c')
-rw-r--r--module/zfs/zfs_znode.c82
1 files changed, 73 insertions, 9 deletions
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c
index 2a4b1c648..5e9941034 100644
--- a/module/zfs/zfs_znode.c
+++ b/module/zfs/zfs_znode.c
@@ -1109,25 +1109,89 @@ zfs_zinactive(znode_t *zp)
ZFS_OBJ_HOLD_EXIT(zsb, z_id);
}
+static inline int
+zfs_compare_timespec(struct timespec *t1, struct timespec *t2)
+{
+ if (t1->tv_sec < t2->tv_sec)
+ return (-1);
+
+ if (t1->tv_sec > t2->tv_sec)
+ return (1);
+
+ return (t1->tv_nsec - t2->tv_nsec);
+}
+
+/*
+ * Determine whether the znode's atime must be updated. The logic mostly
+ * duplicates the Linux kernel's relatime_need_update() functionality.
+ * This function is only called if the underlying filesystem actually has
+ * atime updates enabled.
+ */
+static inline boolean_t
+zfs_atime_need_update(znode_t *zp, timestruc_t *now)
+{
+ if (!ZTOZSB(zp)->z_relatime)
+ return (B_TRUE);
+
+ /*
+ * In relatime mode, only update the atime if the previous atime
+ * is earlier than either the ctime or mtime or if at least a day
+ * has passed since the last update of atime.
+ */
+ if (zfs_compare_timespec(&ZTOI(zp)->i_mtime, &ZTOI(zp)->i_atime) >= 0)
+ return (B_TRUE);
+
+ if (zfs_compare_timespec(&ZTOI(zp)->i_ctime, &ZTOI(zp)->i_atime) >= 0)
+ return (B_TRUE);
+
+ if ((long)now->tv_sec - ZTOI(zp)->i_atime.tv_sec >= 24*60*60)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+/*
+ * Prepare to update znode time stamps.
+ *
+ * IN: zp - znode requiring timestamp update
+ * flag - ATTR_MTIME, ATTR_CTIME, ATTR_ATIME flags
+ * have_tx - true of caller is creating a new txg
+ *
+ * OUT: zp - new atime (via underlying inode's i_atime)
+ * mtime - new mtime
+ * ctime - new ctime
+ *
+ * NOTE: The arguments are somewhat redundant. The following condition
+ * is always true:
+ *
+ * have_tx == !(flag & ATTR_ATIME)
+ */
void
zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
uint64_t ctime[2], boolean_t have_tx)
{
timestruc_t now;
+ ASSERT(have_tx == !(flag & ATTR_ATIME));
gethrestime(&now);
- if (have_tx) { /* will sa_bulk_update happen really soon? */
+ /*
+ * NOTE: The following test intentionally does not update z_atime_dirty
+ * in the case where an ATIME update has been requested but for which
+ * the update is omitted due to relatime logic. The rationale being
+ * that if the flag was set somewhere else, we should leave it alone
+ * here.
+ */
+ if (flag & ATTR_ATIME) {
+ if (zfs_atime_need_update(zp, &now)) {
+ ZFS_TIME_ENCODE(&now, zp->z_atime);
+ ZTOI(zp)->i_atime.tv_sec = zp->z_atime[0];
+ ZTOI(zp)->i_atime.tv_nsec = zp->z_atime[1];
+ zp->z_atime_dirty = 1;
+ }
+ } else {
zp->z_atime_dirty = 0;
zp->z_seq++;
- } else {
- zp->z_atime_dirty = 1;
- }
-
- if (flag & ATTR_ATIME) {
- ZFS_TIME_ENCODE(&now, zp->z_atime);
- ZTOI(zp)->i_atime.tv_sec = zp->z_atime[0];
- ZTOI(zp)->i_atime.tv_nsec = zp->z_atime[1];
}
if (flag & ATTR_MTIME) {