From e33d196b937957f257590d823088e0cda388a11e Mon Sep 17 00:00:00 2001 From: Keguang Xu Date: Tue, 15 Oct 2024 14:28:58 +0800 Subject: [PATCH] LU-17309 llog: set timestamp on llog objects at creation time To facilitate debugging, this commit introduces the storage of the creation time (ctime) for llog objects upon creation. Additionally, the modification time (mtime) will be updated when the catalog is modified. - For llog creation, la_ctime/mtime/atime are set within llog_osd_create(). - For update, there are 2 entries leading to the modification of llog: 1) direct usage over plain-log?, dt_attr_set() is added with la_mtime set in llog.c; 2) update through catalog, dt_attr_set() is added in llog_cat.c Performance Considerations: - Catalog modifications are infrequent, minimizing the performance impact. - Updating the mtime incurs no additional overhead when new records are added to an llog file, as the new inode size/ blocks must be written regardless. Signed-off-by: Keguang Xu Change-Id: I13c260cc576e35a811a9d33cacfdd0bdf8492962 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56691 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Alexander Boyko Reviewed-by: Oleg Drokin --- lustre/obdclass/llog.c | 31 ++++++++++++++++++++++++-- lustre/obdclass/llog_cat.c | 17 +++++++++++++- lustre/obdclass/llog_osd.c | 9 ++++++-- lustre/tests/sanity.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 5 deletions(-) diff --git a/lustre/obdclass/llog.c b/lustre/obdclass/llog.c index f1a8a79..e59e723 100644 --- a/lustre/obdclass/llog.c +++ b/lustre/obdclass/llog.c @@ -253,6 +253,8 @@ int llog_cancel_arr_rec(const struct lu_env *env, struct llog_handle *loghandle, if (rc < 0) GOTO(out_trans, rc); } + if (llh->llh_flags & LLOG_F_IS_CAT) + dt_declare_attr_set(env, loghandle->lgh_obj, NULL, th); th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); @@ -313,6 +315,13 @@ int llog_cancel_arr_rec(const struct lu_env *env, struct llog_handle *loghandle, rc = LLOG_DEL_PLAIN; } + /* update for catalog which doesn't happen very often */ + if (llh->llh_flags & LLOG_F_IS_CAT) { + lgi->lgi_attr.la_valid = LA_MTIME; + lgi->lgi_attr.la_mtime = ktime_get_real_seconds(); + dt_attr_set(env, loghandle->lgh_obj, &lgi->lgi_attr, th); + } + out_unlock: if (rc < 0) { /* restore bitmap while holding a mutex */ @@ -1319,8 +1328,10 @@ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, { struct dt_device *dt; struct thandle *th; - bool need_cookie; - int rc; + struct llog_thread_info *lgi = llog_info(env); + bool need_cookie; + bool update_attr; + int rc; ENTRY; @@ -1341,6 +1352,17 @@ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, if (rc) GOTO(out_trans, rc); + /* + * update mtime given 1) append mode, no overhead since inode + * size/block needs to be written anyway; 2) update for catalog + * since this doesn't happen very often + */ + update_attr = (idx == LLOG_NEXT_IDX || + (loghandle->lgh_hdr && + loghandle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)); + if (update_attr) + dt_declare_attr_set(env, loghandle->lgh_obj, NULL, th); + th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); if (rc) @@ -1360,6 +1382,11 @@ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, } else { rc = llog_write_rec(env, loghandle, rec, NULL, idx, th); } + if (rc == 0 && update_attr) { + lgi->lgi_attr.la_valid = LA_MTIME; + lgi->lgi_attr.la_mtime = ktime_get_real_seconds(); + dt_attr_set(env, loghandle->lgh_obj, &lgi->lgi_attr, th); + } up_write(&loghandle->lgh_lock); out_trans: diff --git a/lustre/obdclass/llog_cat.c b/lustre/obdclass/llog_cat.c index 334de1b..a0da211 100644 --- a/lustre/obdclass/llog_cat.c +++ b/lustre/obdclass/llog_cat.c @@ -141,6 +141,7 @@ static int llog_cat_new_log(const struct lu_env *env, handle); if (rc != 0) GOTO(out, rc); + dt_declare_attr_set(env, cathandle->lgh_obj, NULL, handle); rc = dt_trans_start_local(env, dt, handle); if (rc != 0) @@ -176,6 +177,10 @@ static int llog_cat_new_log(const struct lu_env *env, &loghandle->u.phd.phd_cookie, LLOG_NEXT_IDX, th); if (rc < 0) GOTO(out_destroy, rc); + /* update for catalog which doesn't happen very often */ + lgi->lgi_attr.la_valid = LA_MTIME; + lgi->lgi_attr.la_mtime = ktime_get_real_seconds(); + dt_attr_set(env, cathandle->lgh_obj, &lgi->lgi_attr, th); CDEBUG(D_OTHER, "new plain log "DFID".%u of catalog "DFID"\n", PLOGID(&loghandle->lgh_id), rec->lid_hdr.lrh_index, @@ -343,6 +348,7 @@ start: lirec->lid_hdr.lrh_len = sizeof(*lirec); rc = llog_declare_write_rec(env, cathandle, &lirec->lid_hdr, -1, th); + dt_declare_attr_set(env, cathandle->lgh_obj, NULL, th); } out: @@ -560,7 +566,8 @@ int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle, struct llog_rec_hdr *rec, struct llog_cookie *reccookie, struct thandle *th) { - struct llog_handle *loghandle; + struct llog_handle *loghandle; + struct llog_thread_info *lgi = llog_info(env); int rc, retried = 0; ENTRY; @@ -597,7 +604,13 @@ retry: * actual cause here */ if (rc == -ENOSPC && llog_is_full(loghandle)) rc = -ENOBUFS; + } else { + /* no overhead since inode size needs to be written anyway */ + lgi->lgi_attr.la_valid = LA_MTIME; + lgi->lgi_attr.la_mtime = ktime_get_real_seconds(); + dt_attr_set(env, loghandle->lgh_obj, &lgi->lgi_attr, th); } + up_write(&loghandle->lgh_lock); if (rc == -ENOBUFS) { @@ -640,6 +653,8 @@ start: RETURN(rc); goto start; } + dt_declare_attr_set(env, cathandle->u.chd.chd_current_log->lgh_obj, + NULL, th); #if 0 /* diff --git a/lustre/obdclass/llog_osd.c b/lustre/obdclass/llog_osd.c index 76bd90d..9151cb4 100644 --- a/lustre/obdclass/llog_osd.c +++ b/lustre/obdclass/llog_osd.c @@ -104,8 +104,10 @@ static int llog_osd_create_new_object(const struct lu_env *env, { struct llog_thread_info *lgi = llog_info(env); - lgi->lgi_attr.la_valid = LA_MODE; + lgi->lgi_attr.la_valid = LA_MODE | LA_CTIME | LA_MTIME | LA_ATIME; lgi->lgi_attr.la_mode = S_IFREG | S_IRUGO | S_IWUSR; + lgi->lgi_attr.la_ctime = lgi->lgi_attr.la_mtime = + lgi->lgi_attr.la_atime = ktime_get_real_seconds(); lgi->lgi_dof.dof_type = dt_mode_to_dft(S_IFREG); return local_object_create(env, los, o, &lgi->lgi_attr, @@ -1822,9 +1824,12 @@ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res, if (res->lgh_ctxt->loc_flags & LLOG_CTXT_FLAG_NORMAL_FID) { struct llog_thread_info *lgi = llog_info(env); - lgi->lgi_attr.la_valid = LA_MODE | LA_SIZE | LA_TYPE; + lgi->lgi_attr.la_valid = LA_MODE | LA_SIZE | LA_TYPE | + LA_CTIME | LA_MTIME | LA_ATIME; lgi->lgi_attr.la_size = 0; lgi->lgi_attr.la_mode = S_IFREG | S_IRUGO | S_IWUSR; + lgi->lgi_attr.la_ctime = lgi->lgi_attr.la_mtime = + lgi->lgi_attr.la_atime = ktime_get_real_seconds(); lgi->lgi_dof.dof_type = dt_mode_to_dft(S_IFREG); dt_write_lock(env, o, 0); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index c6a054d..7291756 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -34163,6 +34163,61 @@ test_907() { } run_test 907 "write rpc error during unlink" +test_908a() { + (( MDS1_VERSION >= $(version_code 2.16.0) )) || + skip "need MDS >= 2.16.0 for llog timestamps" + [[ "$mds1_FSTYPE" == ldiskfs ]] || skip "ldiskfs only test" + + local dev=$(mdsdevname 1) + local cmd="debugfs -c -R \\\"stat CONFIGS/params\\\" $dev" + + # ctime_mds value is in hex + local base_time=`date -d "24 hours ago" +%s` + local ctime_mds=$(do_facet mds1 "$cmd" |& + awk -F'[: ]' '/ctime:/ { print $4 }') + ctime_mds=$((ctime_mds)) + echo "ctime_mds=$ctime_mds, base_time=$base_time" + (( "$ctime_mds" > "$base_time" )) || + error "invalid ctime $ctime_mds <= $base_time" +} +run_test 908a "llog created with valid ctime" + +test_908b() { + (( MDS1_VERSION >= $(version_code 2.16.0) )) || + skip "need MDS >= 2.16.0 for llog timestamps" + [[ "$mds1_FSTYPE" == ldiskfs ]] || skip "ldiskfs only test" + + local dev=$(mdsdevname 1) + + changelog_register || error "cannot register changelog user" + # set changelog_mask to ALL + changelog_chmask "ALL" + changelog_clear + + for ((i=0; i<100; i++)); do + echo "$i" > $DIR/$tfile${i} + rm $DIR/$tfile${i} + done + sleep 5 + + changelog_deregister || error "changelog_deregister failed" + + local cmd="debugfs -c -R \\\"stat changelog_catalog\\\" $dev" + + # ctime_mdt value is in hex + local ctime_mds=$(do_facet mds1 "$cmd" |& + awk -F'[: ]' '/ctime:/ { print $4 }') + ctime_mds=$((ctime_mds)) + local mtime_mds=$(do_facet mds1 "$cmd" |& + awk -F'[: ]' '/mtime:/ { print $4 }') + mtime_mds=$((mtime_mds)) + + echo "ctime_mds=$ctime_mds, mtime_mds=$mtime_mds" + (( "$mtime_mds" > "$ctime_mds" )) || + error "invalid mtime $mtime_mds <= $ctime_mds" +} +run_test 908b "changelog stores valid mtime" + complete_test $SECONDS [ -f $EXT2_DEV ] && rm $EXT2_DEV || true check_and_cleanup_lustre -- 1.8.3.1