file->f_path.dentry->d_name.name, io->ci_designated_mirror);
}
+/*
+ * This is relatime_need_update() from Linux 5.17, which is not exported.
+ */
+static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
+ struct timespec64 now)
+{
+
+ if (!(mnt->mnt_flags & MNT_RELATIME))
+ return 1;
+ /*
+ * Is mtime younger than atime? If yes, update atime:
+ */
+ if (timespec64_compare(&inode->i_mtime, &inode->i_atime) >= 0)
+ return 1;
+ /*
+ * Is ctime younger than atime? If yes, update atime:
+ */
+ if (timespec64_compare(&inode->i_ctime, &inode->i_atime) >= 0)
+ return 1;
+
+ /*
+ * Is the previous atime value older than a day? If yes,
+ * update atime:
+ */
+ if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60)
+ return 1;
+ /*
+ * Good, we can skip the atime update:
+ */
+ return 0;
+}
+
+/*
+ * Very similar to kernel function: !__atime_needs_update()
+ */
static bool file_is_noatime(const struct file *file)
{
- const struct vfsmount *mnt = file->f_path.mnt;
- const struct inode *inode = file_inode((struct file *)file);
+ struct vfsmount *mnt = file->f_path.mnt;
+ struct inode *inode = file_inode((struct file *)file);
+ struct timespec64 now;
- /* Adapted from file_accessed() and touch_atime().*/
if (file->f_flags & O_NOATIME)
return true;
if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode))
return true;
+ now = current_time(inode);
+
+ if (!relatime_need_update(mnt, inode, now))
+ return true;
+
return false;
}
}
run_test 39q "close won't zero out atime"
+test_39s() {
+ local atime0
+ local atime1
+ local atime2
+ local atime3
+ local atime4
+
+ umount_client $MOUNT
+ mount_client $MOUNT relatime
+
+ dd if=/dev/zero of=$DIR/$tfile bs=4096 count=1 status=noxfer conv=fsync
+ atime0=$(stat -c %X $DIR/$tfile)
+
+ # First read updates atime
+ sleep 1
+ cat $DIR/$tfile >/dev/null
+ atime1=$(stat -c %X $DIR/$tfile) # (atime = atime0 + 1)
+
+ # Next reads do not update atime
+ sleep 1
+ cat $DIR/$tfile >/dev/null
+ atime2=$(stat -c %X $DIR/$tfile) # (atime = atime0 + 1)
+
+ # If mtime is greater than atime, atime is updated
+ sleep 1
+ touch -m $DIR/$tfile # (mtime = now)
+ sleep 1
+ cat $DIR/$tfile >/dev/null # (atime is updated because atime < mtime)
+ atime3=$(stat -c %X $DIR/$tfile) # (atime = mtime = atime0 + 3)
+
+ # Next reads do not update atime
+ sleep 1
+ cat $DIR/$tfile >/dev/null
+ atime4=$(stat -c %X $DIR/$tfile)
+
+ # Remount the client to clear 'relatime' option
+ remount_client $MOUNT
+
+ if (( MDS1_VERSION >= $(version_code 2.15.50) )); then
+ # The full test lasted less than default atime_diff
+ # Client was remounted to clear 'relatime' option for next tests
+ # and to confirm atime was written to disk
+ local atime5=$(stat -c %X $DIR/$tfile)
+ (( atime3 == atime5 )) ||
+ error "atime3 $atime3 != atime5 $atime5"
+ fi
+
+ (( atime0 < atime1 )) ||
+ error "atime $atime0 should be smaller than $atime1"
+ (( atime1 == atime2 )) ||
+ error "atime $atime1 was updated to $atime2"
+ (( atime1 < atime3 )) || error "atime1 $atime1 != atime3 $atime3"
+ (( atime3 == atime4 )) || error "atime3 $atime3 != atime4 $atime4"
+}
+run_test 39s "relatime is supported"
+
test_40() {
dd if=/dev/zero of=$DIR/$tfile bs=4096 count=1
$RUNAS $OPENFILE -f O_WRONLY:O_TRUNC $DIR/$tfile &&