Whamcloud - gitweb
LU-13383 ofd: lazy atime update 24/38024/21
authorAlex Zhuravlev <bzzz@whamcloud.com>
Tue, 31 Mar 2020 08:06:03 +0000 (11:06 +0300)
committerOleg Drokin <green@whamcloud.com>
Tue, 14 Apr 2020 08:10:42 +0000 (08:10 +0000)
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 <bzzz@whamcloud.com>
Change-Id: Ibe49882ec6f1984f9cf6a32f6ee9fef579ed2a03
Reviewed-on: https://review.whamcloud.com/38024
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Wang Shilong <wshilong@ddn.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/vvp_object.c
lustre/ofd/lproc_ofd.c
lustre/ofd/ofd_dev.c
lustre/ofd/ofd_internal.h
lustre/ofd/ofd_io.c
lustre/ofd/ofd_lvb.c
lustre/osc/osc_object.c
lustre/tests/sanity.sh

index 43e2a61..01003a7 100644 (file)
@@ -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);
index 9d78009..e7ed6a8 100644 (file)
@@ -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,
index d0d48c1..9e52108 100644 (file)
@@ -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)
index 8f6a70e..9765ca0 100644 (file)
 
 #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;
 };
index d86bb5c..1eb1668 100644 (file)
@@ -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 */
index 8c6dfbe..0397f0b 100644 (file)
@@ -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;
 
index f092577..a2f840f 100644 (file)
@@ -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;
        }
index 4d50dcf..a72963a 100755 (executable)
@@ -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