unsigned int th_sync:1,
/* local transation, no need to inform other layers */
th_local:1,
- /* Whether we need wait the transaction to be submitted */
+ /* Whether we need wait the transaction to be submitted
+ * (send to remote target) */
th_wait_submit:1,
- /* complex transaction which will track updates on all targets */
+ /* complex transaction which will track updates on all targets,
+ * including OSTs */
th_complex:1;
};
}
if (rec->lrh_len == 0 || rec->lrh_len > chunk_size) {
- CWARN("invalid length %d in llog record for "
- "index %d/%d\n", rec->lrh_len,
- rec->lrh_index, index);
+ CWARN("%s: invalid length %d in llog "DOSTID
+ "record for index %d/%d\n",
+ loghandle->lgh_ctxt->loc_obd->obd_name,
+ rec->lrh_len,
+ POSTID(&loghandle->lgh_id.lgl_oi),
+ rec->lrh_index, index);
+
GOTO(out, rc = -EINVAL);
}
}
if (rec->lrh_index != index) {
- CERROR("%s: Invalid record: index %u but "
- "expected %u\n",
+ CERROR("%s: "DOSTID" Invalid record: index %u"
+ " but expected %u\n",
loghandle->lgh_ctxt->loc_obd->obd_name,
+ POSTID(&loghandle->lgh_id.lgl_oi),
rec->lrh_index, index);
GOTO(out, rc = -ERANGE);
}
INIT_LIST_HEAD(&osp->opd_update->ou_list);
osp->opd_update->ou_rpc_version = 1;
osp->opd_update->ou_version = 1;
+ osp->opd_update->ou_generation = 0;
/* start thread handling sending updates to the remote MDT */
task = kthread_run(osp_send_update_thread, osp,
struct osp_thandle *our_th;
__u64 our_version;
+ __u64 our_generation;
/* protect our_list and flag */
spinlock_t our_list_lock;
/* linked to the list(ou_list) in osp_updates */
struct list_head ou_list;
spinlock_t ou_lock;
wait_queue_head_t ou_waitq;
- /* wait for next updates */
+
+ /* The next rpc version which supposed to be sent in
+ * osp_send_update_thread().*/
__u64 ou_rpc_version;
+
+ /* The rpc version assigned to the osp thandle during (osp_md_write()),
+ * which will be sent by this order. Note: the osp_thandle has be sent
+ * by this order to make sure the remote update log will follow the
+ * llog format rule. XXX: these probably should be removed once we
+ * invent new llog format */
__u64 ou_version;
+
+ /* The generation of current osp update RPC, which is used to make sure
+ * those stale RPC(with older generation) will not be sent, otherwise it
+ * will cause update lllog corruption */
+ __u64 ou_generation;
};
struct osp_device {
*
* Set the version for the transaction and add the request to
* the sending list, then after transaction stop, the request
- * will be picked in the order of version, by sending thread.
+ * will be sent in the order of version by the sending thread.
*
* \param [in] oth osp thandle to be set version.
*
/* Assign the version and add it to the sending list */
osp_thandle_get(oth);
oth->ot_our->our_version = ou->ou_version++;
+ oth->ot_our->our_generation = ou->ou_generation;
list_add_tail(&oth->ot_our->our_list,
&osp->opd_update->ou_list);
oth->ot_our->our_req_ready = 0;
spin_unlock(&ou->ou_lock);
LASSERT(oth->ot_super.th_wait_submit == 1);
- CDEBUG(D_INFO, "%s: version %llu oth:version %p:%llu\n",
- osp->opd_obd->obd_name, ou->ou_version, oth,
+ CDEBUG(D_INFO, "%s: version %llu gen %llu oth:version %p:%llu\n",
+ osp->opd_obd->obd_name, ou->ou_version, ou->ou_generation, oth,
oth->ot_our->our_version);
return 0;
if (rc < 0) {
CERROR("%s: init env error: rc = %d\n", osp->opd_obd->obd_name,
rc);
+
+ spin_lock(&ou->ou_lock);
+ ou->ou_generation++;
+ spin_unlock(&ou->ou_lock);
+
return;
}
our);
}
+ /* Increase the generation, then the update request with old generation
+ * will fail with -EIO. */
+ ou->ou_generation++;
spin_unlock(&ou->ou_lock);
/* invalidate all of request in the sending list */
osp_trans_callback(&env, our->our_th,
our->our_th->ot_super.th_result);
rc = our->our_th->ot_super.th_result;
- } else if (OBD_FAIL_CHECK(OBD_FAIL_INVALIDATE_UPDATE)) {
+ } else if (ou->ou_generation != our->our_generation ||
+ OBD_FAIL_CHECK(OBD_FAIL_INVALIDATE_UPDATE)) {
rc = -EIO;
osp_trans_callback(&env, our->our_th, rc);
} else {