+struct lod_recovery_data {
+ struct lod_device *lrd_lod;
+ struct lod_tgt_desc *lrd_ltd;
+ struct ptlrpc_thread *lrd_thread;
+ __u32 lrd_idx;
+};
+
+
+/**
+ * process update recovery record
+ *
+ * Add the update recovery recode to the update recovery list in
+ * lod_recovery_data. Then the recovery thread (target_recovery_thread)
+ * will redo these updates.
+ *
+ * \param[in]env execution environment
+ * \param[in]llh log handle of update record
+ * \param[in]rec update record to be replayed
+ * \param[in]data update recovery data which holds the necessary
+ * arguments for recovery (see struct lod_recovery_data)
+ *
+ * \retval 0 if the record is processed successfully.
+ * \retval negative errno if the record processing fails.
+ */
+static int lod_process_recovery_updates(const struct lu_env *env,
+ struct llog_handle *llh,
+ struct llog_rec_hdr *rec,
+ void *data)
+{
+ struct lod_recovery_data *lrd = data;
+ struct llog_cookie *cookie = &lod_env_info(env)->lti_cookie;
+ struct lu_target *lut;
+ __u32 index = 0;
+ ENTRY;
+
+ if (lrd->lrd_ltd == NULL) {
+ int rc;
+
+ rc = lodname2mdt_index(lod2obd(lrd->lrd_lod)->obd_name, &index);
+ if (rc != 0)
+ return rc;
+ } else {
+ index = lrd->lrd_ltd->ltd_index;
+ }
+
+ if (rec->lrh_len !=
+ llog_update_record_size((struct llog_update_record *)rec)) {
+ CERROR("%s broken update record! index %u "DOSTID":%u : rc = %d\n",
+ lod2obd(lrd->lrd_lod)->obd_name, index,
+ POSTID(&llh->lgh_id.lgl_oi), rec->lrh_index, -EIO);
+ return -EIO;
+ }
+
+ cookie->lgc_lgl = llh->lgh_id;
+ cookie->lgc_index = rec->lrh_index;
+ cookie->lgc_subsys = LLOG_UPDATELOG_ORIG_CTXT;
+
+ CDEBUG(D_HA, "%s: process recovery updates "DOSTID":%u\n",
+ lod2obd(lrd->lrd_lod)->obd_name,
+ POSTID(&llh->lgh_id.lgl_oi), rec->lrh_index);
+ lut = lod2lu_dev(lrd->lrd_lod)->ld_site->ls_tgt;
+
+ return insert_update_records_to_replay_list(lut->lut_tdtd,
+ (struct llog_update_record *)rec,
+ cookie, index);
+}
+
+/**
+ * recovery thread for update log
+ *
+ * Start recovery thread and prepare the sub llog, then it will retrieve
+ * the update records from the correpondent MDT and do recovery.
+ *
+ * \param[in] arg pointer to the recovery data
+ *
+ * \retval 0 if recovery succeeds
+ * \retval negative errno if recovery failed.
+ */
+static int lod_sub_recovery_thread(void *arg)
+{
+ struct lod_recovery_data *lrd = arg;
+ struct lod_device *lod = lrd->lrd_lod;
+ struct dt_device *dt;
+ struct ptlrpc_thread *thread = lrd->lrd_thread;
+ struct llog_ctxt *ctxt;
+ struct lu_env env;
+ int rc;
+ ENTRY;
+
+ thread->t_flags = SVC_RUNNING;
+ wake_up(&thread->t_ctl_waitq);
+
+ rc = lu_env_init(&env, LCT_LOCAL | LCT_MD_THREAD);
+ if (rc != 0) {
+ OBD_FREE_PTR(lrd);
+ CERROR("%s: can't initialize env: rc = %d\n",
+ lod2obd(lod)->obd_name, rc);
+ RETURN(rc);
+ }
+
+ if (lrd->lrd_ltd == NULL)
+ dt = lod->lod_child;
+ else
+ dt = lrd->lrd_ltd->ltd_tgt;
+
+ rc = lod_sub_prep_llog(&env, lod, dt, lrd->lrd_idx);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ /* Process the recovery record */
+ ctxt = llog_get_context(dt->dd_lu_dev.ld_obd, LLOG_UPDATELOG_ORIG_CTXT);
+ LASSERT(ctxt != NULL);
+ LASSERT(ctxt->loc_handle != NULL);
+
+ rc = llog_cat_process(&env, ctxt->loc_handle,
+ lod_process_recovery_updates, lrd, 0, 0);
+ llog_ctxt_put(ctxt);
+
+ if (rc < 0) {
+ CERROR("%s getting update log failed: rc = %d\n",
+ dt->dd_lu_dev.ld_obd->obd_name, rc);
+ GOTO(out, rc);
+ }
+
+ CDEBUG(D_HA, "%s retrieve update log: rc = %d\n",
+ dt->dd_lu_dev.ld_obd->obd_name, rc);
+
+ if (lrd->lrd_ltd == NULL)
+ lod->lod_child_got_update_log = 1;
+ else
+ lrd->lrd_ltd->ltd_got_update_log = 1;
+
+ if (lod->lod_child_got_update_log) {
+ struct lod_tgt_descs *ltd = &lod->lod_mdt_descs;
+ struct lod_tgt_desc *tgt = NULL;
+ bool all_got_log = true;
+ int i;
+
+ cfs_foreach_bit(ltd->ltd_tgt_bitmap, i) {
+ tgt = LTD_TGT(ltd, i);
+ if (!tgt->ltd_got_update_log) {
+ all_got_log = false;
+ break;
+ }
+ }
+
+ if (all_got_log) {
+ struct lu_target *lut;
+
+ lut = lod2lu_dev(lod)->ld_site->ls_tgt;
+ CDEBUG(D_HA, "%s got update logs from all MDTs.\n",
+ lut->lut_obd->obd_name);
+ lut->lut_tdtd->tdtd_replay_ready = 1;
+ wake_up(&lut->lut_obd->obd_next_transno_waitq);
+ }
+ }
+
+out:
+ OBD_FREE_PTR(lrd);
+ thread->t_flags = SVC_STOPPED;
+ wake_up(&thread->t_ctl_waitq);
+ lu_env_fini(&env);
+ RETURN(rc);
+}
+
+/**
+ * finish sub llog context
+ *
+ * Stop update recovery thread for the sub device, then cleanup the
+ * correspondent llog ctxt.
+ *
+ * \param[in] env execution environment
+ * \param[in] lod lod device to do update recovery
+ * \param[in] thread recovery thread on this sub device
+ */
+void lod_sub_fini_llog(const struct lu_env *env,
+ struct dt_device *dt, struct ptlrpc_thread *thread)
+{
+ struct obd_device *obd;
+ struct llog_ctxt *ctxt;
+ ENTRY;
+
+ obd = dt->dd_lu_dev.ld_obd;
+ CDEBUG(D_INFO, "%s: finish sub llog\n", obd->obd_name);
+ /* Stop recovery thread first */
+ if (thread != NULL && thread->t_flags & SVC_RUNNING) {
+ thread->t_flags = SVC_STOPPING;
+ wake_up(&thread->t_ctl_waitq);
+ wait_event(thread->t_ctl_waitq, thread->t_flags & SVC_STOPPED);
+ }
+
+ ctxt = llog_get_context(obd, LLOG_UPDATELOG_ORIG_CTXT);
+ if (ctxt == NULL)
+ RETURN_EXIT;
+
+ if (ctxt->loc_handle != NULL)
+ llog_cat_close(env, ctxt->loc_handle);
+
+ llog_cleanup(env, ctxt);
+
+ RETURN_EXIT;
+}
+
+/**
+ * Extract MDT target index from a device name.
+ *
+ * a helper function to extract index from the given device name
+ * like "fsname-MDTxxxx-mdtlov"
+ *
+ * \param[in] lodname device name
+ * \param[out] mdt_index extracted index
+ *
+ * \retval 0 on success
+ * \retval -EINVAL if the name is invalid
+ */
+int lodname2mdt_index(char *lodname, __u32 *mdt_index)