From 7c9ce8aac9e80a3819c4a3a075180efcf8c29353 Mon Sep 17 00:00:00 2001 From: Alex Zhuravlev Date: Tue, 31 Mar 2020 11:06:03 +0300 Subject: [PATCH] LU-13383 ofd: lazy atime update OST_BRW_WRITE updates atime both in memory and on-disk OST_BRW_READ updates atime in memory and once difference exceeds delay (obdfilter.*.atime_delay seconds) - it's updated on-disk. Test-Parameters: testlist=sanity env=ONLY=39r,ONLY_REPEAT=100 Signed-off-by: Alex Zhuravlev Change-Id: Ibe49882ec6f1984f9cf6a32f6ee9fef579ed2a03 Reviewed-on: https://review.whamcloud.com/38024 Reviewed-by: Andreas Dilger Reviewed-by: Wang Shilong Tested-by: jenkins Tested-by: Maloo --- lustre/llite/vvp_object.c | 2 ++ lustre/ofd/lproc_ofd.c | 52 +++++++++++++++++++++++++++++++++ lustre/ofd/ofd_dev.c | 1 + lustre/ofd/ofd_internal.h | 8 +++++ lustre/ofd/ofd_io.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ lustre/ofd/ofd_lvb.c | 11 ++++--- lustre/osc/osc_object.c | 7 ++++- lustre/tests/sanity.sh | 43 +++++++++++++++++++++++++++ 8 files changed, 193 insertions(+), 5 deletions(-) diff --git a/lustre/llite/vvp_object.c b/lustre/llite/vvp_object.c index 43e2a61..01003a7 100644 --- a/lustre/llite/vvp_object.c +++ b/lustre/llite/vvp_object.c @@ -213,6 +213,8 @@ static void vvp_req_attr_set(const struct lu_env *env, struct cl_object *obj, if (attr->cra_type == CRT_WRITE) { valid_flags |= OBD_MD_FLMTIME | OBD_MD_FLCTIME; obdo_set_o_projid(oa, ll_i2info(inode)->lli_projid); + } else if (attr->cra_type == CRT_READ) { + valid_flags |= OBD_MD_FLATIME; } obdo_from_inode(oa, inode, valid_flags & attr->cra_flags); obdo_set_parent_fid(oa, &ll_i2info(inode)->lli_fid); diff --git a/lustre/ofd/lproc_ofd.c b/lustre/ofd/lproc_ofd.c index 9d78009..e7ed6a8 100644 --- a/lustre/ofd/lproc_ofd.c +++ b/lustre/ofd/lproc_ofd.c @@ -147,6 +147,57 @@ static ssize_t precreate_batch_store(struct kobject *kobj, LUSTRE_RW_ATTR(precreate_batch); /** + * Show number of seconds to delay atime + * + * \param[in] m seq_file handle + * \param[in] data unused for single entry + * + * \retval 0 on success + * \retval negative value on error + */ +static ssize_t atime_diff_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct obd_device *obd = container_of(kobj, struct obd_device, + obd_kset.kobj); + struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev); + + return snprintf(buf, PAGE_SIZE, "%lld\n", ofd->ofd_atime_diff); +} + +/** + * Change number of seconds to delay atime + * + * \param[in] file proc file + * \param[in] buffer string which represents maximum number + * \param[in] count \a buffer length + * \param[in] off unused for single entry + * + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t atime_diff_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct obd_device *obd = container_of(kobj, struct obd_device, + obd_kset.kobj); + struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev); + unsigned int val; + int rc; + + rc = kstrtouint(buffer, 0, &val); + if (rc) + return rc; + + if (val > 86400) + return -EINVAL; + + ofd->ofd_atime_diff = val; + return count; +} +LUSTRE_RW_ATTR(atime_diff); + +/** * Show the last used ID for each FID sequence used by OFD. * * \param[in] m seq_file handle @@ -920,6 +971,7 @@ static struct attribute *ofd_attrs[] = { &lustre_attr_seqs_allocated.attr, &lustre_attr_grant_precreate.attr, &lustre_attr_precreate_batch.attr, + &lustre_attr_atime_diff.attr, &lustre_attr_degraded.attr, &lustre_attr_fstype.attr, &lustre_attr_no_precreate.attr, diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index d0d48c1..9e52108 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -2946,6 +2946,7 @@ static int ofd_init0(const struct lu_env *env, struct ofd_device *m, if (tgd->tgd_osfs.os_bsize * tgd->tgd_osfs.os_blocks < OFD_PRECREATE_SMALL_FS) m->ofd_precreate_batch = OFD_PRECREATE_BATCH_SMALL; + m->ofd_atime_diff = OFD_DEF_ATIME_DIFF; rc = ofd_fs_setup(env, m, obd); if (rc) diff --git a/lustre/ofd/ofd_internal.h b/lustre/ofd/ofd_internal.h index 8f6a70e..9765ca0 100644 --- a/lustre/ofd/ofd_internal.h +++ b/lustre/ofd/ofd_internal.h @@ -53,6 +53,12 @@ #define OFD_SOFT_SYNC_LIMIT_DEFAULT 16 +/* + * update atime if on-disk value older than client's one + * by OFD_ATIME_DIFF or more + */ +#define OFD_DEF_ATIME_DIFF 0 /* disabled */ + /* request stats */ enum { LPROC_OFD_STATS_READ = 0, @@ -150,6 +156,7 @@ struct ofd_device { struct attribute *ofd_read_cache_enable; struct attribute *ofd_read_cache_max_filesize; struct attribute *ofd_write_cache_enable; + time64_t ofd_atime_diff; }; static inline struct ofd_device *ofd_dev(struct lu_device *d) @@ -176,6 +183,7 @@ struct ofd_object { struct lu_object_header ofo_header; struct dt_object ofo_obj; struct filter_fid ofo_ff; + time64_t ofo_atime_ondisk; unsigned int ofo_pfid_checking:1, ofo_pfid_verified:1; }; diff --git a/lustre/ofd/ofd_io.c b/lustre/ofd/ofd_io.c index d86bb5c..1eb1668 100644 --- a/lustre/ofd/ofd_io.c +++ b/lustre/ofd/ofd_io.c @@ -475,6 +475,71 @@ out: } +/* + * Lazy ATIME update to refresh atime every ofd_atime_diff + * seconds so that external scanning tool can see it actual + * within that period and be able to identify accessed files + */ +static void ofd_handle_atime(const struct lu_env *env, struct ofd_device *ofd, + struct ofd_object *fo, time64_t atime) +{ + struct lu_attr *la; + struct dt_object *o; + struct thandle *th; + int rc; + + if (ofd->ofd_atime_diff == 0) + return; + + la = &ofd_info(env)->fti_attr2; + o = ofd_object_child(fo); + + if (unlikely(fo->ofo_atime_ondisk == 0)) { + rc = dt_attr_get(env, o, la); + if (unlikely(rc)) + return; + LASSERT(la->la_valid & LA_ATIME); + if (la->la_atime == 0) + la->la_atime = la->la_mtime; + fo->ofo_atime_ondisk = la->la_atime; + } + if (atime - fo->ofo_atime_ondisk < ofd->ofd_atime_diff) + return; + + /* atime hasn't been updated too long, update it */ + fo->ofo_atime_ondisk = atime; + + th = ofd_trans_create(env, ofd); + if (IS_ERR(th)) { + CERROR("%s: cannot create transaction: rc = %d\n", + ofd_name(ofd), (int)PTR_ERR(th)); + return; + } + + la->la_valid = LA_ATIME; + rc = dt_declare_attr_set(env, o, la, th); + if (rc) + GOTO(out_tx, rc); + + rc = dt_trans_start_local(env, ofd->ofd_osd , th); + if (rc) { + CERROR("%s: cannot start transaction: rc = %d\n", + ofd_name(ofd), rc); + GOTO(out_tx, rc); + } + + ofd_read_lock(env, fo); + if (ofd_object_exists(fo)) { + la->la_atime = fo->ofo_atime_ondisk; + rc = dt_attr_set(env, o, la, th); + } + + ofd_read_unlock(env, fo); + +out_tx: + ofd_trans_stop(env, ofd, th, rc); +} + /** * Prepare buffers for read request processing. * @@ -517,6 +582,9 @@ static int ofd_preprw_read(const struct lu_env *env, struct obd_export *exp, ofd_info(env)->fti_obj = fo; + if (oa->o_valid & OBD_MD_FLATIME) + ofd_handle_atime(env, ofd, fo, oa->o_atime); + ofd_read_lock(env, fo); if (!ofd_object_exists(fo)) GOTO(unlock, rc = -ENOENT); @@ -1186,6 +1254,10 @@ retry: GOTO(out_stop, rc); } + /* don't update atime on disk if it is older */ + if (la->la_valid & LA_ATIME && la->la_atime <= fo->ofo_atime_ondisk) + la->la_valid &= ~LA_ATIME; + if (la->la_valid) { /* update [mac]time if needed */ rc = dt_declare_attr_set(env, o, la, th); @@ -1213,6 +1285,8 @@ retry: rc = dt_attr_set(env, o, la, th); if (rc) GOTO(out_unlock, rc); + if (la->la_valid & LA_ATIME) + fo->ofo_atime_ondisk = la->la_atime; } /* get attr to return */ diff --git a/lustre/ofd/ofd_lvb.c b/lustre/ofd/ofd_lvb.c index 8c6dfbe..0397f0b 100644 --- a/lustre/ofd/ofd_lvb.c +++ b/lustre/ofd/ofd_lvb.c @@ -147,10 +147,13 @@ static int ofd_lvbo_init(struct ldlm_resource *res) lvb->lvb_atime = info->fti_attr.la_atime; lvb->lvb_ctime = info->fti_attr.la_ctime; - CDEBUG(D_DLMTRACE, "res: "DFID" initial lvb size: %llu, " - "mtime: %#llx, blocks: %#llx\n", - PFID(&info->fti_fid), lvb->lvb_size, - lvb->lvb_mtime, lvb->lvb_blocks); + if (fo->ofo_atime_ondisk == 0) + fo->ofo_atime_ondisk = info->fti_attr.la_atime; + + CDEBUG(D_DLMTRACE, + "res: "DFID" initial LVB size: %llu, mtime: %#llx, atime: %#llx, ctime: %#llx, blocks: %#llx\n", + PFID(&info->fti_fid), lvb->lvb_size, lvb->lvb_mtime, + lvb->lvb_atime, lvb->lvb_ctime, lvb->lvb_blocks); info->fti_attr.la_valid = 0; diff --git a/lustre/osc/osc_object.c b/lustre/osc/osc_object.c index f092577..a2f840f 100644 --- a/lustre/osc/osc_object.c +++ b/lustre/osc/osc_object.c @@ -379,7 +379,12 @@ static void osc_req_attr_set(const struct lu_env *env, struct cl_object *obj, oa->o_mtime = lvb->lvb_mtime; oa->o_valid |= OBD_MD_FLMTIME; } - if ((flags & OBD_MD_FLATIME) != 0) { + /* XXX: + * I don't understand this part, what for OSC resets atime just + * set by VVP layer to 0 so that OST gets 0 instead of actual + * atime, bzzz. please inspect this place with extra care. + */ + if ((flags & OBD_MD_FLATIME) && lvb->lvb_atime > oa->o_atime) { oa->o_atime = lvb->lvb_atime; oa->o_valid |= OBD_MD_FLATIME; } diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 4d50dcf..a72963a 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -4508,6 +4508,49 @@ test_39p() { } run_test 39p "remote directory cached attributes updated after create ========" +test_39r() { + [ $OST1_VERSION -ge $(version_code 2.13.52) ] || + skip "no atime update on old OST" + if [ "$ost1_FSTYPE" != ldiskfs ]; then + skip_env "ldiskfs only test" + fi + + local saved_adiff + saved_adiff=$(do_facet ost1 \ + lctl get_param -n obdfilter.*OST0000.atime_diff) + stack_trap "do_facet ost1 \ + lctl set_param obdfilter.*.atime_diff=$saved_adiff" + + do_facet ost1 "lctl set_param obdfilter.*.atime_diff=5" + + $LFS setstripe -i 0 $DIR/$tfile + dd if=/dev/zero of=$DIR/$tfile bs=4k count=1 || + error "can't write initial file" + cancel_lru_locks osc + + # exceed atime_diff and access file + sleep 6 + dd if=$DIR/$tfile of=/dev/null || error "can't udpate atime" + + local atime_cli=$(stat -c %X $DIR/$tfile) + echo "client atime: $atime_cli" + # allow atime update to be written to device + do_facet ost1 "$LCTL set_param -n osd*.*OST*.force_sync 1" + sleep 5 + + local ostdev=$(ostdevname 1) + local fid=($(lfs getstripe -y $DIR/$tfile | + awk '/l_fid:/ { print $2 }' | tr ':' ' ')) + local objpath="O/0/d$((${fid[1]} % 32))/$((${fid[1]}))" + local cmd="debugfs -c -R \\\"stat $objpath\\\" $ostdev" + + echo "OST atime: $(do_facet ost1 "$cmd" |& grep atime)" + local atime_ost=$(do_facet ost1 "$cmd" |& + awk -F'[: ]' '/atime:/ { print $4 }') + (( atime_cli == atime_ost )) || + error "atime on client $atime_cli != ost $atime_ost" +} +run_test 39r "lazy atime update on OST" test_39q() { # LU-8041 local testdir=$DIR/$tdir -- 1.8.3.1