From c10c6eeb37dd553166367b96369dca25183ace3b Mon Sep 17 00:00:00 2001 From: Aurelien Degremont Date: Thu, 7 Apr 2022 12:58:00 +0000 Subject: [PATCH] LU-15728 llite: fix relatime support 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 Change-Id: I7a26f39841300a60c015944f9e544115b4446ead Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/47017 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Shaun Tancheff Reviewed-by: Oleg Drokin Reviewed-by: Yang Sheng Reviewed-by: Andreas Dilger --- lustre/llite/file.c | 46 +++++++++++++++++++++++++++++++++++++--- lustre/mdd/mdd_object.c | 1 + lustre/tests/sanity.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 0a7a88d..692e3e5 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -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; } diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index 0144b28..8f7ad59 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -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; diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 42aca2b..f7d0741 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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 && -- 1.8.3.1