Whamcloud - gitweb
LU-15728 llite: fix relatime support 17/47017/16
authorAurelien Degremont <degremoa@amazon.com>
Thu, 7 Apr 2022 12:58:00 +0000 (12:58 +0000)
committerOleg Drokin <green@whamcloud.com>
Wed, 8 Feb 2023 06:26:25 +0000 (06:26 +0000)
relatime behavior is properly managed by VFS, however
Lustre also stores acmtime on OST objects and atime
updates for OST objects should honor relatime behavior.

This patch updates 'ci_noatime' feature which was introduced to
properly honor noatime option for OST objects, to also support
'relatime'.
file_is_noatime() code already comes from upstream touch_atime().
Add missing parts from touch_atime() to also support relatime.

It also forces atime to disk on MDD if ondisk atime is older than
ondisk mtime/ctime to match relatime (even if relatime is not enabled)

Add a new test for relatime feature.

Signed-off-by: Aurelien Degremont <degremoa@amazon.com>
Change-Id: I7a26f39841300a60c015944f9e544115b4446ead
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/47017
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Shaun Tancheff <shaun.tancheff@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Yang Sheng <ys@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
lustre/llite/file.c
lustre/mdd/mdd_object.c
lustre/tests/sanity.sh

index 0a7a88d..692e3e5 100644 (file)
@@ -1529,12 +1529,47 @@ void ll_io_set_mirror(struct cl_io *io, const struct file *file)
               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;
 
@@ -1553,6 +1588,11 @@ static bool file_is_noatime(const struct file *file)
        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;
 }
 
index 0144b28..8f7ad59 100644 (file)
@@ -710,6 +710,7 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
                 * close RPCs.
                 */
                if (la->la_valid & LA_ATIME &&
+                   oattr->la_atime > max(oattr->la_ctime, oattr->la_mtime) &&
                    la->la_atime <= (oattr->la_atime +
                                mdd_obj2mdd_dev(obj)->mdd_atime_diff))
                        la->la_valid &= ~LA_ATIME;
index 42aca2b..f7d0741 100755 (executable)
@@ -5223,6 +5223,62 @@ test_39q() { # LU-8041
 }
 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 &&