Replay requests have FIDs already assigned and the
sequence could be different to the osp:
seq rollover happened after the original request,
then something triggers replay, or osp lost the
seq rollover record on storage.
Detect this and avoid the assert in osp_fid_diff(),
we don't update the last id on osp in this case,
otherwise orhpan cleanup could cleanup the objects
in the current osp's sequence.
Also when rollover seq happens in osp, do not
LASSERT() if we didn't get a new seq, most likely
on ofd/ost the previous seq update was lost on storage.
We could return the error code and let precreate
thread try again.
Cleanup lu_fid_diff() which is not used.
In osp_create(), do not call osp_update_last_fid()
again for the regular non-replay case, it's already
done via osp_object_assign_fid()->osp_precreate_get_fid().
Change-Id: I509c00b998933d45865c9540e12a2db7d1b2b8ed
Signed-off-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54020
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
u32 lu_fid_hash(const void *data, u32 len, u32 seed);
u32 lu_fid_hash(const void *data, u32 len, u32 seed);
-static inline int
-lu_fid_diff(const struct lu_fid *fid1, const struct lu_fid *fid2)
-{
- LASSERTF(fid_seq(fid1) == fid_seq(fid2), "fid1:"DFID", fid2:"DFID"\n",
- PFID(fid1), PFID(fid2));
-
- if (fid_is_idif(fid1) && fid_is_idif(fid2))
- return fid_idif_id(fid1->f_seq, fid1->f_oid, fid1->f_ver) -
- fid_idif_id(fid2->f_seq, fid2->f_oid, fid2->f_ver);
-
- return fid_oid(fid1) - fid_oid(fid2);
-}
-
static inline int fid_set_id(struct lu_fid *fid, u64 oid)
{
if (unlikely(fid_seq_is_igif(fid->f_seq))) {
static inline int fid_set_id(struct lu_fid *fid, u64 oid)
{
if (unlikely(fid_seq_is_igif(fid->f_seq))) {
fid_idif_id(fid2->f_seq, fid2->f_oid, 0);
}
fid_idif_id(fid2->f_seq, fid2->f_oid, 0);
}
- /* Changed to new seq before replay, we always start with oid 2 in
- * a new seq. In this case just return 1.
- */
- if (fid_seq(fid1) != fid_seq(fid2) && fid_oid(fid1) == 2)
- return 1;
-
LASSERTF(fid_seq(fid1) == fid_seq(fid2), "fid1:"DFID", fid2:"DFID"\n",
PFID(fid1), PFID(fid2));
LASSERTF(fid_seq(fid1) == fid_seq(fid2), "fid1:"DFID", fid2:"DFID"\n",
PFID(fid1), PFID(fid2));
*osi_id = fid_oid(last_fid);
}
*osi_id = fid_oid(last_fid);
}
-static inline void osp_update_last_fid(struct osp_device *d, struct lu_fid *fid)
+static inline void osp_update_last_fid(struct osp_device *d, struct lu_fid *fid,
+ bool replay)
- int diff = osp_fid_diff(fid, &d->opd_last_used_fid);
struct lu_fid *gap_start = &d->opd_gap_start_fid;
struct lu_fid *gap_start = &d->opd_gap_start_fid;
+ int diff;
+
+ /*
+ * replay could cross seq rollover, in this case we don't update
+ * the last used fid
+ */
+ if (replay && fid_seq(fid) != fid_seq(&d->opd_last_used_fid))
+ diff = 0;
+ else
+ diff = osp_fid_diff(fid, &d->opd_last_used_fid);
/*
* we might have lost precreated objects due to VBR and precreate
/*
* we might have lost precreated objects due to VBR and precreate
struct lu_attr *attr, struct dt_allocation_hint *hint,
struct dt_object_format *dof, struct thandle *th)
{
struct lu_attr *attr, struct dt_allocation_hint *hint,
struct dt_object_format *dof, struct thandle *th)
{
- struct osp_thread_info *osi = osp_env_info(env);
- struct osp_device *d = lu2osp_dev(dt->do_lu.lo_dev);
- struct osp_object *o = dt2osp_obj(dt);
- int rc = 0;
- struct lu_fid *fid = &osi->osi_fid;
- struct thandle *local_th;
+ struct osp_thread_info *osi = osp_env_info(env);
+ struct osp_device *d = lu2osp_dev(dt->do_lu.lo_dev);
+ struct osp_object *o = dt2osp_obj(dt);
+ struct lu_fid *fid = &osi->osi_fid;
+ struct thandle *local_th;
+ bool replay = false;
+ int rc = 0;
+
ENTRY;
if (is_only_remote_trans(th) &&
ENTRY;
if (is_only_remote_trans(th) &&
if (o->opo_reserved) {
/* regular case, fid is assigned holding transaction open */
osp_object_assign_fid(env, d, o);
if (o->opo_reserved) {
/* regular case, fid is assigned holding transaction open */
osp_object_assign_fid(env, d, o);
+ } else {
+ replay = true;
}
memcpy(fid, lu_object_fid(&dt->do_lu), sizeof(*fid));
}
memcpy(fid, lu_object_fid(&dt->do_lu), sizeof(*fid));
LASSERTF(fid_is_sane(fid), "fid for osp_object %px is insane"DFID"!\n",
o, PFID(fid));
LASSERTF(fid_is_sane(fid), "fid for osp_object %px is insane"DFID"!\n",
o, PFID(fid));
- if (!o->opo_reserved) {
/* special case, id was assigned outside of transaction
* see comments in osp_declare_attr_set */
LASSERT(d->opd_pre != NULL);
spin_lock(&d->opd_pre_lock);
/* special case, id was assigned outside of transaction
* see comments in osp_declare_attr_set */
LASSERT(d->opd_pre != NULL);
spin_lock(&d->opd_pre_lock);
- osp_update_last_fid(d, fid);
+ osp_update_last_fid(d, fid, true);
spin_unlock(&d->opd_pre_lock);
}
spin_unlock(&d->opd_pre_lock);
}
+ if (fid_seq(fid) <= fid_seq(last_fid)) {
+ rc = -ESTALE;
+ CERROR("%s: not a new sequence: fid "DFID", last_used_fid "DFID": rc = %d\n",
+ osp->opd_obd->obd_name, PFID(fid), PFID(last_fid), rc);
+ RETURN(rc);
+ }
+
fid->f_oid = 1;
fid->f_ver = 0;
fid->f_oid = 1;
fid->f_ver = 0;
- LASSERTF(fid_seq(fid) != fid_seq(last_fid),
- "fid "DFID", last_fid "DFID"\n", PFID(fid),
- PFID(last_fid));
rc = osp_write_last_oid_seq_files(env, osp, fid, 1);
if (rc != 0) {
rc = osp_write_last_oid_seq_files(env, osp, fid, 1);
if (rc != 0) {
* last_used_id must be changed along with getting new id otherwise
* we might miscalculate gap causing object loss or leak
*/
* last_used_id must be changed along with getting new id otherwise
* we might miscalculate gap causing object loss or leak
*/
- osp_update_last_fid(d, fid);
+ osp_update_last_fid(d, fid, false);
spin_unlock(&d->opd_pre_lock);
/*
spin_unlock(&d->opd_pre_lock);
/*
assert_DIR
rm -rf $DIR/d[0-9]* $DIR/f.${TESTSUITE}*
assert_DIR
rm -rf $DIR/d[0-9]* $DIR/f.${TESTSUITE}*
test_1() {
local f1="$DIR/$tfile"
local f2="$DIR/$tfile.2"
test_1() {
local f1="$DIR/$tfile"
local f2="$DIR/$tfile.2"
assert_DIR
rm -rf $DIR/[Rdfs][0-9]*
assert_DIR
rm -rf $DIR/[Rdfs][0-9]*
test_0a() {
[ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"
test_0a() {
[ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"