}
int dt_declare_version_set(const struct lu_env *env, struct dt_object *o,
- struct thandle *th);
+ struct thandle *th);
void dt_version_set(const struct lu_env *env, struct dt_object *o,
- dt_obj_version_t version, struct thandle *th);
+ dt_obj_version_t version, struct thandle *th);
+int dt_declare_data_version_set(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th);
+void dt_data_version_set(const struct lu_env *env, struct dt_object *o,
+ dt_obj_version_t version, struct thandle *th);
+int dt_declare_data_version_del(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th);
+void dt_data_version_del(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th);
dt_obj_version_t dt_version_get(const struct lu_env *env, struct dt_object *o);
-
+dt_obj_version_t dt_data_version_get(const struct lu_env *env,
+ struct dt_object *o);
+dt_obj_version_t dt_data_version_init(const struct lu_env *env,
+ struct dt_object *o);
int dt_read(const struct lu_env *env, struct dt_object *dt,
struct lu_buf *buf, loff_t *pos);
* this value onto disk for recovery when tgt_txn_stop_cb() is called.
*/
__u64 tsi_opdata;
+ bool tsi_dv_update;
/*
* Additional fail id that can be set by handler.
return tsi;
}
-static inline void tgt_vbr_obj_set(const struct lu_env *env,
- struct dt_object *obj)
+static inline void tgt_vbr_obj_data_set(const struct lu_env *env,
+ struct dt_object *obj, bool dv_update)
{
struct tgt_session_info *tsi;
if (env->le_ses != NULL) {
tsi = tgt_ses_info(env);
tsi->tsi_vbr_obj = obj;
+ tsi->tsi_dv_update = dv_update;
}
}
+static inline void tgt_vbr_obj_set(const struct lu_env *env,
+ struct dt_object *obj)
+{
+ return tgt_vbr_obj_data_set(env, obj, false);
+}
+
static inline void tgt_opdata_set(const struct lu_env *env, __u64 flags)
{
struct tgt_session_info *tsi;
#define XATTR_NAME_DUMMY "trusted.dummy"
#define XATTR_NAME_PROJID "trusted.projid"
#define XATTR_NAME_PIN "trusted.pin"
+#define XATTR_NAME_DATAVER "trusted.dataver"
#define LL_XATTR_NAME_ENCRYPTION_CONTEXT_OLD XATTR_SECURITY_PREFIX"c"
#define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_ENCRYPTION_PREFIX"c"
ioc->idv_version = io->u.ci_data_version.dv_data_version;
ioc->idv_layout_version = io->u.ci_data_version.dv_layout_version;
-
cl_io_fini(env, io);
if (unlikely(io->ci_need_restart))
struct mdd_object *mdd_obj,
const char *xattr_name,
struct thandle *handle);
+int mdd_dom_fixup(const struct lu_env *env, struct mdd_device *mdd,
+ struct mdd_object *mo, struct mdd_object *vo);
/* mdd_trans.c */
void mdd_object_make_hint(const struct lu_env *env, struct mdd_object *parent,
return 0;
}
-static int mdd_dom_data_truncate(const struct lu_env *env,
- struct mdd_device *mdd, struct mdd_object *mo);
-
static int mdd_xattr_split(const struct lu_env *env, struct md_object *md_obj,
struct md_rejig_data *mrd)
{
/* Truncate local DOM data if all went well */
if (!rc && dom_stripe)
- mdd_dom_data_truncate(env, mdd, obj);
+ mdd_dom_fixup(env, mdd, obj, NULL);
lu_buf_free(buf_save);
lu_buf_free(buf);
return mdd_lmm_gen(lmm, gen, false);
}
-static int mdd_dom_data_truncate(const struct lu_env *env,
- struct mdd_device *mdd, struct mdd_object *mo)
+int mdd_dom_fixup(const struct lu_env *env, struct mdd_device *mdd,
+ struct mdd_object *mo, struct mdd_object *vo)
{
+ struct dt_object *dom, *vlt;
+ dt_obj_version_t dv = 0;
struct thandle *th;
- struct dt_object *dom;
int rc;
+ ENTRY;
+
+ if (vo) {
+ vlt = dt_object_locate(mdd_object_child(vo), mdd->mdd_bottom);
+ if (!vlt)
+ GOTO(out, rc = -ENOENT);
+ dv = dt_data_version_get(env, vlt);
+ if (!dv)
+ GOTO(out, rc = -ENODATA);
+ }
+
dom = dt_object_locate(mdd_object_child(mo), mdd->mdd_bottom);
- if (!dom)
- GOTO(out, rc = -ENODATA);
th = dt_trans_create(env, mdd->mdd_bottom);
if (IS_ERR(th))
GOTO(out, rc = PTR_ERR(th));
- rc = dt_declare_punch(env, dom, 0, OBD_OBJECT_EOF, th);
- if (rc)
- GOTO(stop, rc);
+ if (vo) {
+ rc = dt_declare_data_version_set(env, dom, th);
+ if (rc)
+ GOTO(stop, rc);
+ } else {
+ rc = dt_declare_data_version_del(env, dom, th);
+ if (rc)
+ GOTO(stop, rc);
+ rc = dt_declare_punch(env, dom, 0, OBD_OBJECT_EOF, th);
+ if (rc)
+ GOTO(stop, rc);
+ }
rc = dt_trans_start_local(env, mdd->mdd_bottom, th);
if (rc != 0)
GOTO(stop, rc);
- rc = dt_punch(env, dom, 0, OBD_OBJECT_EOF, th);
+ if (vo) {
+ dt_data_version_set(env, dom, dv, th);
+ } else {
+ dt_data_version_del(env, dom, th);
+ rc = dt_punch(env, dom, 0, OBD_OBJECT_EOF, th);
+ }
+
stop:
dt_trans_stop(env, mdd->mdd_bottom, th);
out:
/* Ignore failure but report the error */
if (rc)
- CERROR("%s: can't truncate DOM inode "DFID" data: rc = %d\n",
+ CERROR("%s: can't manage DOM file "DFID" data: rc = %d\n",
mdd_obj_dev_name(mo), PFID(mdd_object_fid(mo)), rc);
return rc;
}
struct lu_buf *snd_hsm_buf = &info->mdi_buf[3];
struct ost_id *saved_oi = NULL;
struct thandle *handle;
- struct mdd_object *dom_o = NULL;
+ struct mdd_object *dom_o = NULL, *vlt_o = NULL;
__u64 domsize_dom, domsize_vlt;
__u32 fst_gen, snd_gen, saved_gen;
int fst_fl;
* target file must be volatile and orphan.
*/
if (fst_o->mod_flags & (ORPHAN_OBJ | VOLATILE_OBJ)) {
+ vlt_o = domsize_vlt ? fst_o : NULL;
dom_o = domsize_dom ? snd_o : NULL;
} else if (snd_o->mod_flags & (ORPHAN_OBJ | VOLATILE_OBJ)) {
swap(domsize_dom, domsize_vlt);
+ vlt_o = domsize_vlt ? snd_o : NULL;
dom_o = domsize_dom ? fst_o : NULL;
} else if (domsize_dom > 0 || domsize_vlt > 0) {
/* 'lfs swap_layouts' case, neither file should have DoM */
mdd_obj_dev_name(fst_o),
PFID(mdd_object_fid(fst_o)), rc);
GOTO(stop, rc);
- } else if (domsize_vlt > 0) {
- /* Migration with the same DOM component size, no need to
- * truncate local data, it is still being used */
- dom_o = NULL;
}
/* swapping 2 non existant layouts is a success */
stop:
rc = mdd_trans_stop(env, mdd, rc, handle);
- /* Truncate local DOM data if all went well */
+ /* Truncate local DOM data if all went well, except migration case
+ * with the same DOM component size. In that case a local data is
+ * still in use and shouldn't be deleted.
+ */
if (!rc && dom_o)
- mdd_dom_data_truncate(env, mdd, dom_o);
+ mdd_dom_fixup(env, mdd, dom_o, vlt_o);
mdd_write_unlock(env, snd_o);
mdd_write_unlock(env, fst_o);
GOTO(out_stop, rc);
}
- tgt_vbr_obj_set(env, dob);
+ tgt_vbr_obj_data_set(env, dob, true);
rc = dt_trans_start(env, dt, th);
if (rc)
GOTO(out_stop, rc);
if (rc)
GOTO(stop, rc);
- tgt_vbr_obj_set(env, dob);
+ tgt_vbr_obj_data_set(env, dob, true);
rc = dt_trans_start(env, dt, th);
if (rc)
GOTO(stop, rc);
GOTO(out, rc = -EBADF);
/* Get version first */
- version = dt_version_get(tsi->tsi_env, mdt_obj2dt(mo));
+ version = dt_data_version_get(tsi->tsi_env, mdt_obj2dt(mo));
if (version && version != -EOPNOTSUPP) {
repbody->mbo_valid |= OBD_MD_FLDATAVERSION;
/* re-use mbo_ioepoch to transfer version */
vbuf.lb_buf = NULL;
vbuf.lb_len = sizeof(dt_obj_version_t);
return dt_declare_xattr_set(env, o, &vbuf, xname, 0, th);
-
}
EXPORT_SYMBOL(dt_declare_version_set);
LASSERT(o);
vbuf.lb_buf = &version;
vbuf.lb_len = sizeof(version);
-
rc = dt_xattr_set(env, o, &vbuf, xname, 0, th);
if (rc < 0)
CDEBUG(D_INODE, "Can't set version, rc %d\n", rc);
CDEBUG(D_INODE, "Can't get version, rc %d\n", rc);
version = 0;
}
+
return version;
}
EXPORT_SYMBOL(dt_version_get);
+int dt_declare_data_version_set(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th)
+{
+ struct lu_buf vbuf;
+
+ vbuf.lb_buf = NULL;
+ vbuf.lb_len = sizeof(dt_obj_version_t);
+
+ return dt_declare_xattr_set(env, o, &vbuf, XATTR_NAME_DATAVER, 0, th);
+}
+EXPORT_SYMBOL(dt_declare_data_version_set);
+
+void dt_data_version_set(const struct lu_env *env, struct dt_object *o,
+ dt_obj_version_t version, struct thandle *th)
+{
+ struct lu_buf vbuf;
+
+ CDEBUG(D_INODE, DFID": set new data version -> %llu\n",
+ PFID(lu_object_fid(&o->do_lu)), version);
+
+ /* version should never be set to zero */
+ LASSERT(version);
+ vbuf.lb_buf = &version;
+ vbuf.lb_len = sizeof(version);
+ dt_xattr_set(env, o, &vbuf, XATTR_NAME_DATAVER, 0, th);
+}
+EXPORT_SYMBOL(dt_data_version_set);
+
+int dt_declare_data_version_del(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th)
+{
+ return dt_declare_xattr_del(env, o, XATTR_NAME_DATAVER, th);
+}
+EXPORT_SYMBOL(dt_declare_data_version_del);
+
+void dt_data_version_del(const struct lu_env *env, struct dt_object *o,
+ struct thandle *th)
+{
+ /* file doesn't need explicit data version anymore */
+ CDEBUG(D_INODE, DFID": remove explicit data version\n",
+ PFID(lu_object_fid(&o->do_lu)));
+ dt_xattr_del(env, o, XATTR_NAME_DATAVER, th);
+}
+EXPORT_SYMBOL(dt_data_version_del);
+
+/* Initialize explicit data version, e.g. for DoM files.
+ * It uses inode version as initial value.
+ */
+dt_obj_version_t dt_data_version_init(const struct lu_env *env,
+ struct dt_object *o)
+{
+ struct dt_device *dt = lu2dt_dev(o->do_lu.lo_dev);
+ dt_obj_version_t dv;
+ struct thandle *th;
+ int rc;
+
+ ENTRY;
+
+ dv = dt_version_get(env, o);
+ if (!dv)
+ RETURN(1);
+
+ th = dt_trans_create(env, dt);
+ if (IS_ERR(th))
+ GOTO(out, rc = PTR_ERR(th));
+
+ rc = dt_declare_data_version_set(env, o, th);
+ if (rc)
+ GOTO(stop, rc);
+
+ rc = dt_trans_start_local(env, dt, th);
+ if (rc)
+ GOTO(stop, rc);
+
+ dt_data_version_set(env, o, dv, th);
+stop:
+ dt_trans_stop(env, dt, th);
+out:
+ /* Ignore failure but report the error */
+ if (rc)
+ CDEBUG(D_INODE, "can't init data version for "DFID": rc = %d\n",
+ PFID(lu_object_fid(&o->do_lu)), rc);
+
+ RETURN(dv);
+}
+
+dt_obj_version_t dt_data_version_get(const struct lu_env *env,
+ struct dt_object *o)
+{
+ struct lu_buf vbuf;
+ dt_obj_version_t version;
+ int rc;
+
+ vbuf.lb_buf = &version;
+ vbuf.lb_len = sizeof(version);
+ rc = dt_xattr_get(env, o, &vbuf, XATTR_NAME_DATAVER);
+
+ CDEBUG(D_INODE, DFID": get data version %llu: rc = %d\n",
+ PFID(lu_object_fid(&o->do_lu)), version, rc);
+
+ if (rc == sizeof(version))
+ return version;
+
+ /* data version EA wasn't set yet on the object, initialize it now */
+ if (rc == -ENODATA)
+ return dt_data_version_init(env, o);
+
+ CDEBUG(D_INODE, "Can't get data version: rc = %d\n", rc);
+
+ return 0;
+}
+EXPORT_SYMBOL(dt_data_version_get);
+
/* list of all supported index types */
/* directories */
/** VBR: set new versions */
if (th->th_result == 0 && obj != NULL) {
struct dt_object *dto = dt_object_locate(obj, th->th_dev);
+
dt_version_set(env, dto, tti->tti_transno, th);
+ if (unlikely(tsi->tsi_dv_update))
+ dt_data_version_set(env, dto, tti->tti_transno, th);
}
/* filling reply data */
!lu_object_remote(&tsi->tsi_vbr_obj->do_lu)) {
dto = dt_object_locate(tsi->tsi_vbr_obj, th->th_dev);
rc = dt_declare_version_set(env, dto, th);
+ if (!rc && tsi->tsi_dv_update)
+ rc = dt_declare_data_version_set(env, dto, th);
}
return rc;
}
run_test 1e "Archive, Release and Restore SEL file"
+test_1f() {
+ (( $MDS1_VERSION >= $(version_code 2.14.0.116) )) ||
+ skip "need MDS version at least 2.14.0.116"
+ local dom=$DIR/$tdir/$tfile
+
+ mkdir_on_mdt0 $DIR/$tdir
+ $LFS setstripe -E 512K -L mdt -E -1 -c 2 $DIR/$tdir ||
+ error "failed to set default stripe"
+
+ test_1bde_base $dom
+
+ [[ $($LFS getstripe --component-start=0 -L $dom) == 'mdt' ]] ||
+ error "MDT stripe isn't set"
+
+ # check that metadata change doesn't prevent second release
+ chmod 600 $dom || error "chmod failed"
+
+ echo "release again $dom"
+ $LFS hsm_release $dom || error "second release failed"
+ $LFS hsm_state $dom
+ echo "verify released state: "
+ check_hsm_flags $dom "0x0000000d" && echo "pass"
+}
+run_test 1f "DoM file release after restore"
+
test_2() {
local f=$DIR/$tdir/$tfile
}
run_test 270i "DoM: setting invalid DoM striping should fail"
+test_270j() {
+ (( $MDS1_VERSION >= $(version_code 2.14.0.116) )) ||
+ skip "Need MDS version at least 2.14.0.116"
+
+ local dom=$DIR/$tdir/$tfile
+ local odv
+ local ndv
+
+ mkdir -p $DIR/$tdir
+
+ $LFS setstripe -E 1M -L mdt -E -1 -c1 $dom
+
+ odv=$($LFS data_version $dom)
+ chmod 666 $dom
+ mv $dom ${dom}_moved
+ link ${dom}_moved $dom
+ setfattr -n user.attrx -v "some_attr" $dom
+ ndv=$($LFS data_version $dom)
+ (( $ndv == $odv )) ||
+ error "data version was changed by metadata operations"
+
+ dd if=/dev/urandom of=$dom bs=1M count=1 ||
+ error "failed to write data into $dom"
+ cancel_lru_locks mdc
+ ndv=$($LFS data_version $dom)
+ (( $ndv != $odv )) ||
+ error "data version wasn't changed on write"
+
+ odv=$ndv
+ $TRUNCATE $dom 1000 || error "failed to truncate $dom"
+ ndv=$($LFS data_version $dom)
+ (( $ndv != $odv )) ||
+ error "data version wasn't changed on truncate down"
+
+ odv=$ndv
+ $TRUNCATE $dom 25000
+ ndv=$($LFS data_version $dom)
+ (( $ndv != $odv )) ||
+ error "data version wasn't changed on truncate up"
+
+ # check also fallocate for ldiskfs, skip because patch(#41418) is not backported
+ if false && [[ "$mds1_FSTYPE" == ldiskfs ]]; then
+ odv=$ndv
+ export LANG=C
+ local err=$(fallocate -l 1048576 $dom 2>&1)
+ rc=$?
+
+ if (( $rc != 0 )); then
+ if [[ "$err" =~ "Operation not supported" ]]; then
+ skip "fallocate not supported for DoM"
+ else
+ error "$err"
+ fi
+ fi
+
+ ndv=$($LFS data_version $dom)
+ (( $ndv != $odv )) ||
+ error "data version wasn't changed on fallocate"
+
+ odv=$ndv
+ fallocate -p --offset 4096 -l 4096 $dom
+ ndv=$($LFS data_version $dom)
+ (( $ndv != $odv )) ||
+ error "data version wasn't changed on fallocate punch"
+ fi
+}
+run_test 270j "DoM migration: DOM file to the OST-striped file (plain)"
+
test_271a() {
[ $MDS1_VERSION -lt $(version_code 2.10.55) ] &&
skip "Need MDS version at least 2.10.55"
$LFS migrate -c2 $dom ||
error "failed to migrate to the new composite layout"
- [ $($LFS getstripe -L $dom) != 'mdt' ] ||
+ [[ $($LFS getstripe --component-start=0 -L $dom) != 'mdt' ]] ||
error "MDT stripe was not removed"
+ ! getfattr -n trusted.dataver $dom &> /dev/null ||
+ error "$dir1 shouldn't have DATAVER EA"
cancel_lru_locks mdc
local new_md5=$(md5sum $dom)
$LFS migrate -E 2M -c1 -E -1 -c2 $dom ||
error "failed to migrate to the new composite layout"
- [ $($LFS getstripe -L $dom) == 'mdt' ] &&
+ [[ $($LFS getstripe --component-start=0 -L $dom) != 'mdt' ]] ||
error "MDT stripe was not removed"
cancel_lru_locks mdc