+}
+
+static int signal_completed_replay(struct obd_import *imp)
+{
+ struct ptlrpc_request *req;
+ int rc;
+ ENTRY;
+
+ req = ptlrpc_prep_req(imp, OBD_PING, 0, NULL, NULL);
+ if (!req)
+ RETURN(-ENOMEM);
+
+ req->rq_replen = lustre_msg_size(0, NULL);
+ req->rq_send_state = LUSTRE_IMP_REPLAY;
+ req->rq_reqmsg->flags |= MSG_LAST_REPLAY;
+ req->rq_timeout *= 3;
+
+ rc = ptlrpc_queue_wait(req);
+
+ ptlrpc_req_finished(req);
+ RETURN(rc);
+}
+
+int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid)
+{
+ int rc;
+ ENTRY;
+
+ rc = ptlrpc_recover_import_no_retry(imp, new_uuid);
+
+ if (rc && rc != -EALREADY) {
+ unsigned long flags;
+ CDEBUG(D_HA, "recovery of %s on %s failed (%d); restarting\n",
+ imp->imp_target_uuid.uuid,
+ new_uuid ? new_uuid :
+ (char *)imp->imp_connection->c_remote_uuid.uuid, rc);
+ spin_lock_irqsave(&imp->imp_lock, flags);
+ imp->imp_state = LUSTRE_IMP_FULL;
+ spin_unlock_irqrestore(&imp->imp_lock, flags);
+ ptlrpc_fail_import(imp, imp->imp_generation);
+ }
+ RETURN(rc);
+}
+
+static int ptlrpc_recover_import_no_retry(struct obd_import *imp,
+ char *new_uuid)
+{
+ int rc;
+ unsigned long flags;
+ int in_recovery = 0;
+ int was_invalid = 0;
+ ENTRY;
+
+ spin_lock_irqsave(&imp->imp_lock, flags);
+ if (imp->imp_state == LUSTRE_IMP_FULL) {
+ CDEBUG(D_HA, "%s: new state: DISCON\n",
+ imp->imp_client->cli_name);
+ imp->imp_state = LUSTRE_IMP_DISCON;
+ }
+
+ if (imp->imp_state != LUSTRE_IMP_DISCON) {
+ in_recovery = 1;
+ } else if (imp->imp_invalid) {
+ imp->imp_invalid = 0;
+ was_invalid = 1;
+ }
+
+ spin_unlock_irqrestore(&imp->imp_lock, flags);
+
+ if (in_recovery == 1)
+ RETURN(-EALREADY);
+
+ down(&imp->imp_recovery_sem);
+ /* If recovery happened while we waited, we're done. */
+ if (imp->imp_state == LUSTRE_IMP_FULL)
+ GOTO(out, rc = 0);
+
+ LASSERT (imp->imp_state == LUSTRE_IMP_DISCON);
+
+ if (new_uuid) {
+ struct ptlrpc_connection *conn;
+ struct obd_uuid uuid;
+ struct ptlrpc_peer peer;
+ struct obd_export *dlmexp;
+
+ obd_str2uuid(&uuid, new_uuid);
+ if (ptlrpc_uuid_to_peer(&uuid, &peer)) {
+ CERROR("no connection found for UUID %s\n", new_uuid);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ conn = ptlrpc_get_connection(&peer, &uuid);
+ if (!conn)
+ GOTO(out, rc = -ENOMEM);
+
+ CDEBUG(D_HA, "switching import %s/%s from %s to %s\n",
+ imp->imp_target_uuid.uuid, imp->imp_obd->obd_name,
+ imp->imp_connection->c_remote_uuid.uuid,
+ conn->c_remote_uuid.uuid);
+
+ /* Switch the import's connection and the DLM export's
+ * connection (which are almost certainly the same, but we
+ * keep distinct refs just to make things clearer. I think. */
+ if (imp->imp_connection)
+ ptlrpc_put_connection(imp->imp_connection);
+ /* We hand off the ref from ptlrpc_get_connection. */
+ imp->imp_connection = conn;
+
+ dlmexp = class_conn2export(&imp->imp_dlm_handle);
+ if (dlmexp->exp_connection)
+ ptlrpc_put_connection(dlmexp->exp_connection);
+ dlmexp->exp_connection = ptlrpc_connection_addref(conn);
+ class_export_put(dlmexp);
+
+ }
+
+ connect:
+ rc = ptlrpc_connect_import(imp);
+
+ if (rc < 0) {
+ CERROR("failed to reconnect to %s@%s: %d\n",
+ imp->imp_target_uuid.uuid,
+ imp->imp_connection->c_remote_uuid.uuid, rc);
+ GOTO(out, rc);
+ }
+
+ if (imp->imp_state == LUSTRE_IMP_EVICTED) {
+ CDEBUG(D_HA, "evicted from %s@%s; invalidating\n",
+ imp->imp_target_uuid.uuid,
+ imp->imp_connection->c_remote_uuid.uuid);
+ ptlrpc_set_import_active(imp, 0);
+ CDEBUG(D_HA, "%s: new state: RECOVER\n",
+ imp->imp_client->cli_name);
+ imp->imp_state = LUSTRE_IMP_RECOVER;
+ }
+
+ if (imp->imp_state == LUSTRE_IMP_REPLAY) {
+ CDEBUG(D_HA, "replay requested by %s\n",
+ imp->imp_target_uuid.uuid);
+ rc = ptlrpc_replay(imp);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = ldlm_replay_locks(imp);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = signal_completed_replay(imp);
+ if (rc)
+ GOTO(out, rc);
+ CDEBUG(D_HA, "%s: new state: RECOVER\n",
+ imp->imp_client->cli_name);
+ imp->imp_state = LUSTRE_IMP_RECOVER;
+ }
+
+ if (imp->imp_state == LUSTRE_IMP_RECOVER) {
+ CDEBUG(D_HA, "reconnected to %s@%s\n",
+ imp->imp_target_uuid.uuid,
+ imp->imp_connection->c_remote_uuid.uuid);
+
+ ptlrpc_set_import_active(imp, 1);
+ ptlrpc_resend(imp);
+ spin_lock_irqsave(&imp->imp_lock, flags);
+ CDEBUG(D_HA, "%s: new state: FULL\n",
+ imp->imp_client->cli_name);
+ imp->imp_state = LUSTRE_IMP_FULL;
+ spin_unlock_irqrestore(&imp->imp_lock, flags);
+ ptlrpc_wake_delayed(imp);
+ }
+
+
+ LASSERT(imp->imp_state == LUSTRE_IMP_FULL);
+