From d2f7cb7934a0b38fa9503e8257f2b70ed656c11d Mon Sep 17 00:00:00 2001 From: Qian Yingjin Date: Wed, 25 Sep 2019 17:14:12 +0800 Subject: [PATCH] LU-12026 mdt: MDS stores atime|mtime|ctime during close In order to make direct inode scanning on the MDT useful, in addition to storing the file size/blocks via LSOM on the MDT, we also need to store the atime/mtime/ctime on the MDT inodes. Currently the atime is already lazily updated on the MDS (at close time). In this patch, the final mtime/ctime are sent to the MDS at close time and updated on the MDT inode, and make MDT-only scanning workable. Signed-off-by: Qian Yingjin Change-Id: I4465281a03d70919c388cb241c16eebcb03e850f Reviewed-on: https://review.whamcloud.com/36286 Tested-by: jenkins Reviewed-by: Andreas Dilger Reviewed-by: Li Xi Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/include/uapi/linux/lustre/lustre_idl.h | 1 + lustre/mdd/mdd_object.c | 14 +++- lustre/mdt/mdt_open.c | 16 +++-- lustre/tests/sanityn.sh | 95 +++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 10 deletions(-) diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index 0cca401..db941b2 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1963,6 +1963,7 @@ enum mds_op_bias { MDS_CLOSE_LAYOUT_SPLIT = 1 << 17, MDS_TRUNC_KEEP_LEASE = 1 << 18, MDS_PCC_ATTACH = 1 << 19, + MDS_CLOSE_UPDATE_TIMES = 1 << 20, }; #define MDS_CLOSE_INTENT (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP | \ diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index 22355ab..0d83356 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -680,11 +680,19 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, RETURN(rc); } - if (la->la_valid == LA_ATIME) { - /* This is an atime-only attribute update for close RPCs. */ - if (la->la_atime < (oattr->la_atime + + if (flags & MDS_CLOSE_UPDATE_TIMES && + la->la_valid & (LA_ATIME | LA_MTIME | LA_CTIME)) { + /* This is an atime/mtime/ctime attribute update for + * close RPCs. + */ + if (la->la_valid & LA_ATIME && + la->la_atime <= (oattr->la_atime + mdd_obj2mdd_dev(obj)->mdd_atime_diff)) la->la_valid &= ~LA_ATIME; + if (la->la_valid & LA_CTIME && la->la_ctime <= oattr->la_ctime) + la->la_valid &= ~LA_CTIME; + if (la->la_valid & LA_MTIME && la->la_mtime <= oattr->la_mtime) + la->la_valid &= ~LA_MTIME; RETURN(0); } diff --git a/lustre/mdt/mdt_open.c b/lustre/mdt/mdt_open.c index c7cfc1a..b89abc9 100644 --- a/lustre/mdt/mdt_open.c +++ b/lustre/mdt/mdt_open.c @@ -2389,15 +2389,17 @@ int mdt_mfd_close(struct mdt_thread_info *info, struct mdt_file_data *mfd) else if (open_flags & MDS_FMODE_EXEC) mdt_write_allow(o); - /* Update atime on close only. */ + /* Update atime|mtime|ctime on close. */ if ((open_flags & MDS_FMODE_EXEC || open_flags & MDS_FMODE_READ || open_flags & MDS_FMODE_WRITE) && (ma->ma_valid & MA_INODE) && - (ma->ma_attr.la_valid & LA_ATIME)) { - /* Set the atime only. */ - ma->ma_valid = MA_INODE; - ma->ma_attr.la_valid = LA_ATIME; - rc = mo_attr_set(info->mti_env, next, ma); - } + (ma->ma_attr.la_valid & LA_ATIME || + ma->ma_attr.la_valid & LA_MTIME || + ma->ma_attr.la_valid & LA_CTIME)) { + ma->ma_valid = MA_INODE; + ma->ma_attr_flags |= MDS_CLOSE_UPDATE_TIMES; + ma->ma_attr.la_valid &= (LA_ATIME | LA_MTIME | LA_CTIME); + rc = mo_attr_set(info->mti_env, next, ma); + } /* If file data is modified, add the dirty flag. */ if (ma->ma_attr_flags & MDS_DATA_MODIFIED) diff --git a/lustre/tests/sanityn.sh b/lustre/tests/sanityn.sh index 736b742..f1d9b97 100755 --- a/lustre/tests/sanityn.sh +++ b/lustre/tests/sanityn.sh @@ -4793,6 +4793,101 @@ test_103() { } run_test 103 "Test size correctness with lockahead" +get_stat_xtimes() +{ + local xtimes + + xtimes=$(stat -c "%X %Y %Z" $DIR/$tfile) + + echo ${xtimes[*]} +} + +get_mdt_xtimes() +{ + local mdtdev=$1 + local output + local xtimes + + output=$(do_facet mds1 "$DEBUGFS -c -R 'stat ROOT/$tfile' $mdtdev") + ((xtimes[0]=$(awk -F ':' /atime/'{ print $2 }' <<< "$output"))) + ((xtimes[1]=$(awk -F ':' /mtime/'{ print $2 }' <<< "$output"))) + ((xtimes[2]=$(awk -F ':' /ctime/'{ print $2 }' <<< "$output"))) + + echo ${xtimes[*]} +} + +check_mdt_xtimes() +{ + local mdtdev=$1 + local xtimes=($(get_stat_xtimes)) + local mdt_xtimes=($(get_mdt_xtimes $mdtdev)) + + echo "STAT a|m|ctime ${xtimes[*]}" + echo "MDT a|m|ctime ${xtimes[*]}" + [[ ${xtimes[0]} == ${mdt_xtimes[0]} ]] || + error "$DIR/$tfile atime (${xtimes[0]}:${mdt_xtimes[0]}) diff" + [[ ${xtimes[1]} == ${mdt_xtimes[1]} ]] || + error "$DIR/$tfile mtime (${xtimes[1]}:${mdt_xtimes[1]}) diff" + [[ ${xtimes[2]} == ${mdt_xtimes[2]} ]] || + error "$DIR/$tfile ctime (${xtimes[2]}:${mdt_xtimes[2]}) diff" +} + +test_104() { + [ "$mds1_FSTYPE" == "ldiskfs" ] || skip_env "ldiskfs only test" + + local pid + local mdtdev=$(mdsdevname ${SINGLEMDS//mds/}) + local atime_diff=$(do_facet $SINGLEMDS \ + lctl get_param -n mdd.*MDT0000*.atime_diff) + + do_facet $SINGLEMDS \ + lctl set_param -n mdd.*MDT0000*.atime_diff=0 + + stack_trap "do_facet $SINGLEMDS \ + lctl set_param -n mdd.*MDT0000*.atime_diff=$atime_diff" EXIT + + dd if=/dev/zero of=$DIR/$tfile bs=1k count=1 conv=notrunc + check_mdt_xtimes $mdtdev + sleep 2 + + dd if=/dev/zero of=$DIR/$tfile bs=1k count=1 conv=notrunc + check_mdt_xtimes $mdtdev + sleep 2 + $MULTIOP $DIR2/$tfile Oz8192w8192_c & + pid=$! + sleep 2 + dd if=/dev/zero of=$DIR/$tfile bs=1k count=1 conv=notrunc + sleep 2 + kill -USR1 $pid && wait $pid || error "multiop failure" + check_mdt_xtimes $mdtdev + + local xtimes + local mdt_xtimes + + # Verify mtime/ctime is NOT upated on MDS when there is no modification + # on the client side + xtimes=($(get_stat_xtimes)) + $MULTIOP $DIR/$tfile O_c & + pid=$! + sleep 2 + kill -USR1 $pid && wait $pid || error "multiop failure" + mdt_xtimes=($(get_mdt_xtimes $mdtdev)) + [[ ${xtimes[1]} == ${mdt_xtimes[1]} ]] || + error "$DIR/$tfile mtime (${xtimes[1]}:${mdt_xtimes[1]}) diff" + [[ ${xtimes[2]} == ${mdt_xtimes[2]} ]] || + error "$DIR/$tfile ctime (${xtimes[2]}:${mdt_xtimes[2]}) diff" + check_mdt_xtimes $mdtdev + + sleep 2 + # Change ctime via chmod + $MULTIOP $DIR/$tfile o_tc & + pid=$! + sleep 2 + kill -USR1 $pid && wait $pid || error "multiop failure" + check_mdt_xtimes $mdtdev +} +run_test 104 "Verify that MDS stores atime/mtime/ctime during close" + log "cleanup: ======================================================" # kill and wait in each test only guarentee script finish, but command in script -- 1.8.3.1