int (*moo_readlink)(const struct lu_env *env, struct md_object *obj,
struct lu_buf *buf);
- int (*moo_changelog)(const struct lu_env *env,
- enum changelog_rec_type type, int flags,
- struct md_object *obj);
+ int (*moo_changelog)(const struct lu_env *env,
+ enum changelog_rec_type type, int flags,
+ struct md_device *m, const struct lu_fid *fid);
int (*moo_open)(const struct lu_env *env,
struct md_object *obj, int flag);
}
static inline int mo_changelog(const struct lu_env *env,
- enum changelog_rec_type type,
- int flags, struct md_object *m)
+ enum changelog_rec_type type,
+ int flags, struct md_device *m,
+ const struct lu_fid *fid)
{
- LASSERT(m->mo_ops->moo_changelog);
- return m->mo_ops->moo_changelog(env, type, flags, m);
+ struct lu_fid rootfid;
+ struct md_object *root;
+ int rc;
+
+ rc = m->md_ops->mdo_root_get(env, m, &rootfid);
+ if (rc)
+ return rc;
+
+ root = md_object_find_slice(env, m, &rootfid);
+ if (IS_ERR(root))
+ RETURN(PTR_ERR(root));
+
+ LASSERT(root->mo_ops->moo_changelog);
+ rc = root->mo_ops->moo_changelog(env, type, flags, m, fid);
+
+ lu_object_put(env, &root->mo_lu);
+
+ return rc;
}
static inline int mo_attr_set(const struct lu_env *env,
RETURN(0);
}
-/** Store a data change changelog record
- * If this fails, we must fail the whole transaction; we don't
- * want the change to commit without the log entry.
- * \param mdd_obj - mdd_object of change
- * \param handle - transaction handle
- */
-int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
- enum changelog_rec_type type, int flags,
- struct mdd_object *mdd_obj, struct thandle *handle)
+static int mdd_changelog_data_store_by_fid(const struct lu_env *env,
+ struct mdd_device *mdd,
+ enum changelog_rec_type type, int flags,
+ const struct lu_fid *fid,
+ struct thandle *handle)
{
- const struct lu_ucred *uc = lu_ucred(env);
- const struct lu_fid *tfid;
+ const struct lu_ucred *uc = lu_ucred(env);
struct llog_changelog_rec *rec;
struct lu_buf *buf;
int reclen;
int rc;
- /* Not recording */
- if (!(mdd->mdd_cl.mc_flags & CLM_ON))
- RETURN(0);
- if ((mdd->mdd_cl.mc_mask & (1 << type)) == 0)
- RETURN(0);
-
- LASSERT(mdd_obj != NULL);
- LASSERT(handle != NULL);
-
- tfid = mdo2fid(mdd_obj);
-
- if ((type >= CL_MTIME) && (type <= CL_ATIME) &&
- cfs_time_before_64(mdd->mdd_cl.mc_starttime, mdd_obj->mod_cltime)) {
- /* Don't need multiple updates in this log */
- /* Don't check under lock - no big deal if we get an extra
- entry */
- RETURN(0);
- }
-
flags = (flags & CLF_FLAGMASK) | CLF_VERSION;
if (uc != NULL && uc->uc_jobid[0] != '\0')
flags |= CLF_JOBID;
rec->cr.cr_flags = flags;
rec->cr.cr_type = (__u32)type;
- rec->cr.cr_tfid = *tfid;
+ rec->cr.cr_tfid = *fid;
rec->cr.cr_namelen = 0;
- mdd_obj->mod_cltime = cfs_time_current_64();
if (flags & CLF_JOBID)
mdd_changelog_rec_ext_jobid(&rec->cr, uc->uc_jobid);
RETURN(rc);
}
+
+/** Store a data change changelog record
+ * If this fails, we must fail the whole transaction; we don't
+ * want the change to commit without the log entry.
+ * \param mdd_obj - mdd_object of change
+ * \param handle - transaction handle
+ */
+int mdd_changelog_data_store(const struct lu_env *env, struct mdd_device *mdd,
+ enum changelog_rec_type type, int flags,
+ struct mdd_object *mdd_obj, struct thandle *handle)
+{
+ int rc;
+
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(0);
+ if ((mdd->mdd_cl.mc_mask & (1 << type)) == 0)
+ RETURN(0);
+
+ LASSERT(mdd_obj != NULL);
+ LASSERT(handle != NULL);
+
+ if ((type >= CL_MTIME) && (type <= CL_ATIME) &&
+ cfs_time_before_64(mdd->mdd_cl.mc_starttime, mdd_obj->mod_cltime)) {
+ /* Don't need multiple updates in this log */
+ /* Don't check under lock - no big deal if we get an extra
+ entry */
+ RETURN(0);
+ }
+
+ rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+ mdo2fid(mdd_obj), handle);
+ if (rc == 0)
+ mdd_obj->mod_cltime = cfs_time_current_64();
+
+ RETURN(rc);
+}
+
static int mdd_changelog(const struct lu_env *env, enum changelog_rec_type type,
- int flags, struct md_object *obj)
+ int flags, struct md_device *m, const struct lu_fid *fid)
{
struct thandle *handle;
- struct mdd_object *mdd_obj = md2mdd_obj(obj);
- struct mdd_device *mdd = mdo2mdd(obj);
+ struct mdd_device *mdd = lu2mdd_dev(&m->md_lu_dev);
int rc;
ENTRY;
+ /* Not recording */
+ if (!(mdd->mdd_cl.mc_flags & CLM_ON))
+ RETURN(0);
+ if (!(mdd->mdd_cl.mc_mask & (1 << type)))
+ RETURN(0);
+
+ LASSERT(fid != NULL);
+
handle = mdd_trans_create(env, mdd);
if (IS_ERR(handle))
RETURN(PTR_ERR(handle));
if (rc)
GOTO(stop, rc);
- rc = mdd_changelog_data_store(env, mdd, type, flags, mdd_obj,
- handle);
+ rc = mdd_changelog_data_store_by_fid(env, mdd, type, flags,
+ fid, handle);
stop:
rc = mdd_trans_stop(env, mdd, rc, handle);
/* default is to retry */
*status = ARS_WAITING;
- /* find object by FID */
+ /* find object by FID
+ * if error/removed continue anyway to get correct reporting done */
obj = mdt_hsm_get_md_hsm(mti, &car->car_hai->hai_fid, &mh);
/* we will update MD HSM only if needed */
is_mh_changed = false;
- if (IS_ERR(obj)) {
- /* object removed */
- *status = ARS_SUCCEED;
- goto unlock;
- }
/* no need to change mh->mh_arch_id
* mdt_hsm_get_md_hsm() got it from disk and it is still valid
*status = ARS_SUCCEED;
break;
default:
+ /* retry only if current policy or requested, and
+ * object is not on error/removed */
*status = (cdt->cdt_policy & CDT_NORETRY_ACTION ||
- !(pgs->hpk_flags & HP_FLAG_RETRY) ?
- ARS_FAILED : ARS_WAITING);
+ !(pgs->hpk_flags & HP_FLAG_RETRY) ||
+ IS_ERR(obj)) ? ARS_FAILED : ARS_WAITING;
break;
}
mh.mh_flags & HS_DIRTY ? CLF_HSM_DIRTY : 0);
/* unlock is done later, after layout lock management */
- if (is_mh_changed)
+ if (is_mh_changed && !IS_ERR(obj))
rc = mdt_hsm_attr_set(mti, obj, &mh);
-unlock:
/* we give back layout lock only if restore was successful or
- * if restore was canceled or if policy is to not retry
+ * if no retry will be attempted and if object is still alive,
* in other cases we just unlock the object */
- if (car->car_hai->hai_action == HSMA_RESTORE &&
- (pgs->hpk_errval == 0 || pgs->hpk_errval == ECANCELED ||
- cdt->cdt_policy & CDT_NORETRY_ACTION)) {
+ if (car->car_hai->hai_action == HSMA_RESTORE) {
struct cdt_restore_handle *crh;
/* restore in data FID done, we swap the layouts
GOTO(out, rc);
out:
- if (obj != NULL && !IS_ERR(obj)) {
- mo_changelog(env, CL_HSM, cl_flags,
- mdt_object_child(obj));
+ /* always add a ChangeLog record */
+ mo_changelog(env, CL_HSM, cl_flags, mdt->mdt_child,
+ &car->car_hai->hai_fid);
+
+ if (!IS_ERR(obj))
mdt_object_put(mti->mti_env, obj);
- }
RETURN(rc);
}
echo "Copytool is suspended on $agents"
}
+copytool_continue() {
+ local agents=${1:-$(facet_active_host $SINGLEAGT)}
+
+ do_nodesv $agents "pkill -CONT -x $HSMTOOL_BASE" || return 0
+ echo "Copytool is continued on $agents"
+}
+
copytool_remove_backend() {
local fid=$1
local be=$(do_facet $SINGLEAGT find $HSM_ARCHIVE -name $fid)
}
run_test 220 "Changelog for archive"
+test_220a() {
+ # test needs a running copytool
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+
+ local f=$DIR/$tdir/$tfile
+ local fid=$(copy_file /etc/passwd $f)
+
+ changelog_setup
+
+ # block copytool operations to allow for HSM request to be
+ # submitted and file be unlinked (CDT will find object removed)
+ copytool_suspend
+
+ $LFS hsm_archive --archive $HSM_ARCHIVE_NUMBER $f
+
+ rm -f $f
+
+ copytool_continue
+
+ wait_request_state $fid ARCHIVE FAILED
+
+ local flags=$(changelog_get_flags ${MDT[0]} HSM $fid | tail -1)
+ changelog_cleanup
+
+ # HE_ARCHIVE|ENOENT
+ local target=0x2
+ [[ $flags == $target ]] || error "Changelog flag is $flags not $target"
+
+ copytool_cleanup
+}
+run_test 220a "Changelog for failed archive"
+
test_221() {
# test needs a running copytool
copytool_setup
}
run_test 222b "Changelog for implicit restore"
+test_222c() {
+ # test needs a running copytool
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+ copy2archive /etc/passwd $tdir/$tfile
+
+ local f=$DIR/$tdir/$tfile
+ import_file $tdir/$tfile $f
+ local fid=$(path2fid $f)
+
+ changelog_setup
+
+ # block copytool operations to allow for HSM request to be
+ # submitted and file be unlinked (CDT will find object removed)
+ copytool_suspend
+
+ $LFS hsm_restore $f
+ rm -f $f
+
+ copytool_continue
+
+ wait_request_state $fid RESTORE FAILED
+
+ local flags=$(changelog_get_flags ${MDT[0]} HSM $fid | tail -1)
+
+ # HE_RESTORE|ENOENT
+ local target=0x82
+ [[ $flags == $target ]] || error "Changelog flag is $flags not $target"
+
+ cleanup
+}
+run_test 222c "Changelog for failed explicit restore"
+
+test_222d() {
+ # test needs a running copytool
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+ local f=$DIR/$tdir/$tfile
+ local fid=$(copy_file /etc/passwd $f)
+
+ changelog_setup
+ $LFS hsm_archive --archive $HSM_ARCHIVE_NUMBER $f
+ wait_request_state $fid ARCHIVE SUCCEED
+ $LFS hsm_release $f
+
+ copytool_remove_backend $fid
+ md5sum $f
+
+ wait_request_state $fid RESTORE FAILED
+
+ local flags=$(changelog_get_flags ${MDT[0]} HSM $fid | tail -1)
+
+ # HE_RESTORE|ENOENT
+ local target=0x82
+ [[ $flags == $target ]] || error "Changelog flag is $flags not $target"
+
+ cleanup
+}
+run_test 222d "Changelog for failed implicit restore"
+
test_223a() {
# test needs a running copytool
copytool_setup
}
run_test 224 "Changelog for remove"
+test_224a() {
+ # test needs a running copytool
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+
+ local f=$DIR/$tdir/$tfile
+ local fid=$(copy_file /etc/passwd $f)
+
+ changelog_setup
+ $LFS hsm_archive --archive $HSM_ARCHIVE_NUMBER $f
+ wait_request_state $fid ARCHIVE SUCCEED
+
+ copytool_remove_backend $fid
+
+ # block copytool operations to allow for HSM request to be
+ # submitted and file be unlinked (CDT will find object removed)
+ copytool_suspend
+
+ $LFS hsm_remove $f
+ rm -f $f
+
+ copytool_continue
+
+ wait_request_state $fid REMOVE FAILED
+
+ local flags=$(changelog_get_flags ${MDT[0]} HSM $fid | tail -n 1)
+
+ # HE_REMOVE|ENOENT
+ local target=0x202
+ [[ $flags == $target ]] ||
+ error "Changelog flag is $flags not $target"
+
+ cleanup
+}
+run_test 224a "Changelog for failed remove"
+
test_225() {
# test needs a running copytool
copytool_setup