+/**
+ * wait for recovery events,
+ * check its status with help of check_routine
+ * evict dead clients via health_check
+ */
+static int target_recovery_overseer(struct obd_device *obd,
+ int (*check_routine)(struct obd_device *),
+ int (*health_check)(struct obd_export *))
+{
+ int abort = 0, expired = 1;
+
+ do {
+ cfs_wait_event(obd->obd_next_transno_waitq, check_routine(obd));
+ spin_lock_bh(&obd->obd_processing_task_lock);
+ abort = obd->obd_abort_recovery;
+ expired = obd->obd_recovery_expired;
+ obd->obd_recovery_expired = 0;
+ spin_unlock_bh(&obd->obd_processing_task_lock);
+ if (abort) {
+ CWARN("recovery is aborted, evict exports in recovery\n");
+ /** evict exports which didn't finish recovery yet */
+ class_disconnect_stale_exports(obd, exp_finished);
+ } else if (expired) {
+ /** If some clients died being recovered, evict them */
+ CDEBUG(D_WARNING, "recovery is timed out, evict stale exports\n");
+ /** evict cexports with no replay in queue, they are stalled */
+ class_disconnect_stale_exports(obd, health_check);
+ /** continue with VBR */
+ spin_lock_bh(&obd->obd_processing_task_lock);
+ obd->obd_version_recov = 1;
+ spin_unlock_bh(&obd->obd_processing_task_lock);
+ /**
+ * reset timer, recovery will proceed with versions now,
+ * timeout is set just to handle reconnection delays
+ */
+ reset_recovery_timer(obd, RECONNECT_DELAY_MAX * 2, 1);
+ /** Wait for recovery events again, after evicting bad clients */
+ }
+ } while (!abort && expired);
+
+ return abort;
+}
+
+static struct ptlrpc_request *target_next_replay_req(struct obd_device *obd)
+{
+ struct ptlrpc_request *req = NULL;
+ ENTRY;
+
+ CDEBUG(D_HA, "Waiting for transno "LPD64"\n",
+ obd->obd_next_recovery_transno);
+
+ if (target_recovery_overseer(obd, check_for_next_transno,
+ exp_req_replay_healthy)) {
+ abort_req_replay_queue(obd);
+ abort_lock_replay_queue(obd);
+ }
+
+ spin_lock_bh(&obd->obd_processing_task_lock);
+ if (!list_empty(&obd->obd_req_replay_queue)) {
+ req = list_entry(obd->obd_req_replay_queue.next,
+ struct ptlrpc_request, rq_list);
+ list_del_init(&req->rq_list);
+ obd->obd_requests_queued_for_recovery--;
+ spin_unlock_bh(&obd->obd_processing_task_lock);
+ } else {
+ spin_unlock_bh(&obd->obd_processing_task_lock);
+ LASSERT(list_empty(&obd->obd_req_replay_queue));
+ LASSERT(atomic_read(&obd->obd_req_replay_clients) == 0);
+ /** evict exports failed VBR */
+ class_disconnect_stale_exports(obd, exp_vbr_healthy);
+ }
+ RETURN(req);
+}
+