+int llog_cat_process_or_fork(const struct lu_env *env,
+ struct llog_handle *cat_llh,
+ llog_cb_t cb, void *data, int startcat,
+ int startidx, bool fork)
+{
+ struct llog_process_data d;
+ struct llog_log_hdr *llh = cat_llh->lgh_hdr;
+ int rc;
+ ENTRY;
+
+ LASSERT(llh->llh_flags & LLOG_F_IS_CAT);
+ d.lpd_data = data;
+ d.lpd_cb = cb;
+ d.lpd_startcat = startcat;
+ d.lpd_startidx = startidx;
+
+ if (llh->llh_cat_idx > cat_llh->lgh_last_idx) {
+ struct llog_process_cat_data cd;
+
+ CWARN("catlog "LPX64" crosses index zero\n",
+ cat_llh->lgh_id.lgl_oid);
+
+ cd.lpcd_first_idx = llh->llh_cat_idx;
+ cd.lpcd_last_idx = 0;
+ rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb,
+ &d, &cd, fork);
+ if (rc != 0)
+ RETURN(rc);
+
+ cd.lpcd_first_idx = 0;
+ cd.lpcd_last_idx = cat_llh->lgh_last_idx;
+ rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb,
+ &d, &cd, fork);
+ } else {
+ rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb,
+ &d, NULL, fork);
+ }
+
+ RETURN(rc);
+}
+EXPORT_SYMBOL(llog_cat_process_or_fork);
+
+int llog_cat_process(const struct lu_env *env, struct llog_handle *cat_llh,
+ llog_cb_t cb, void *data, int startcat, int startidx)
+{
+ return llog_cat_process_or_fork(env, cat_llh, cb, data, startcat,
+ startidx, false);
+}
+EXPORT_SYMBOL(llog_cat_process);
+
+#ifdef __KERNEL__
+int llog_cat_process_thread(void *data)
+{
+ struct llog_process_cat_args *args = data;
+ struct llog_ctxt *ctxt = args->lpca_ctxt;
+ struct llog_handle *llh = NULL;
+ llog_cb_t cb = args->lpca_cb;
+ struct llog_thread_info *lgi;
+ struct lu_env env;
+ int rc;
+ ENTRY;
+
+ cfs_daemonize_ctxt("ll_log_process");
+
+ rc = lu_env_init(&env, LCT_LOCAL);
+ if (rc)
+ GOTO(out, rc);
+ lgi = llog_info(&env);
+ LASSERT(lgi);
+
+ lgi->lgi_logid = *(struct llog_logid *)(args->lpca_arg);
+ rc = llog_open(&env, ctxt, &llh, &lgi->lgi_logid, NULL,
+ LLOG_OPEN_EXISTS);
+ if (rc) {
+ CERROR("%s: cannot open llog "LPX64":%x: rc = %d\n",
+ ctxt->loc_obd->obd_name, lgi->lgi_logid.lgl_oid,
+ lgi->lgi_logid.lgl_ogen, rc);
+ GOTO(out_env, rc);
+ }
+ rc = llog_init_handle(&env, llh, LLOG_F_IS_CAT, NULL);
+ if (rc) {
+ CERROR("%s: llog_init_handle failed: rc = %d\n",
+ llh->lgh_ctxt->loc_obd->obd_name, rc);
+ GOTO(release_llh, rc);
+ }
+
+ if (cb) {
+ rc = llog_cat_process(&env, llh, cb, NULL, 0, 0);
+ if (rc != LLOG_PROC_BREAK && rc != 0)
+ CERROR("%s: llog_cat_process() failed: rc = %d\n",
+ llh->lgh_ctxt->loc_obd->obd_name, rc);
+ cb(&env, llh, NULL, NULL);
+ } else {
+ CWARN("No callback function for recovery\n");
+ }
+
+ /*
+ * Make sure that all cached data is sent.
+ */
+ llog_sync(ctxt, NULL, 0);
+ GOTO(release_llh, rc);
+release_llh:
+ rc = llog_cat_close(&env, llh);
+ if (rc)
+ CERROR("%s: llog_cat_close() failed: rc = %d\n",
+ llh->lgh_ctxt->loc_obd->obd_name, rc);
+out_env:
+ lu_env_fini(&env);
+out:
+ llog_ctxt_put(ctxt);
+ OBD_FREE_PTR(args);
+ return rc;
+}
+EXPORT_SYMBOL(llog_cat_process_thread);
+#endif
+
+static int llog_cat_reverse_process_cb(const struct lu_env *env,
+ struct llog_handle *cat_llh,
+ struct llog_rec_hdr *rec, void *data)