return;
}
+ CERROR("connection %p to %s failed\n", conn, conn->c_remote_uuid);
spin_lock(&recovd->recovd_lock);
list_del(&rd->rd_managed_chain);
list_add_tail(&rd->rd_managed_chain, &recovd->recovd_troubled_items);
static int recovd_check_event(struct recovd_obd *recovd)
{
int rc = 0;
+ struct list_head *tmp;
+
ENTRY;
spin_lock(&recovd->recovd_lock);
- if (recovd->recovd_phase == RECOVD_IDLE &&
- !list_empty(&recovd->recovd_troubled_items)) {
+ if (recovd->recovd_state == RECOVD_STOPPING)
GOTO(out, rc = 1);
- }
- if (recovd->recovd_flags & RECOVD_STOPPING)
- GOTO(out, rc = 1);
+ list_for_each(tmp, &recovd->recovd_troubled_items) {
- if (recovd->recovd_flags & RECOVD_FAILED) {
- LASSERT(recovd->recovd_phase != RECOVD_IDLE &&
- recovd->recovd_current_rd);
- GOTO(out, rc = 1);
- }
+ struct recovd_data *rd = list_entry(tmp, struct recovd_data,
+ rd_managed_chain);
- if (recovd->recovd_phase == recovd->recovd_next_phase)
- GOTO(out, rc = 1);
+ if (rd->rd_phase == rd->rd_next_phase ||
+ rd->rd_phase == RECOVD_FAILED)
+ GOTO(out, rc = 1);
+ }
out:
spin_unlock(&recovd->recovd_lock);
RETURN(rc);
}
-static int recovd_handle_event(struct recovd_obd *recovd)
+static void dump_connection_list(struct list_head *head)
{
- struct recovd_data *rd;
- int rc;
- ENTRY;
-
- if (recovd->recovd_flags & RECOVD_FAILED) {
-
- LASSERT(recovd->recovd_phase != RECOVD_IDLE &&
- recovd->recovd_current_rd);
+ struct list_head *tmp;
- rd = recovd->recovd_current_rd;
- cb_failed:
- CERROR("recovery FAILED for rd %p (conn %p), recovering\n",
- rd, class_rd2conn(rd));
+ list_for_each(tmp, head) {
+ struct ptlrpc_connection *conn =
+ list_entry(tmp, struct ptlrpc_connection,
+ c_recovd_data.rd_managed_chain);
+ CDEBUG(D_NET, " %p = %s\n", conn, conn->c_remote_uuid);
+ }
+}
- list_add(&rd->rd_managed_chain, &recovd->recovd_managed_items);
- spin_unlock(&recovd->recovd_lock);
- rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_FAILURE);
- spin_lock(&recovd->recovd_lock);
- recovd->recovd_phase = RECOVD_IDLE;
- recovd->recovd_next_phase = RECOVD_PREPARING;
-
- recovd->recovd_flags &= ~RECOVD_FAILED;
+static int recovd_handle_event(struct recovd_obd *recovd)
+{
+ struct list_head *tmp, *n;
+ int rc = 0;
+ ENTRY;
- RETURN(1);
- }
+ spin_lock(&recovd->recovd_lock);
- switch (recovd->recovd_phase) {
- case RECOVD_IDLE:
- if (recovd->recovd_current_rd ||
- list_empty(&recovd->recovd_troubled_items))
+ CDEBUG(D_NET, "managed: \n");
+ dump_connection_list(&recovd->recovd_managed_items);
+ CDEBUG(D_NET, "troubled: \n");
+ dump_connection_list(&recovd->recovd_troubled_items);
+
+ /*
+ * We use _safe here because one of the callbacks, expecially
+ * FAILURE or PREPARED, could move list items around.
+ */
+ list_for_each_safe(tmp, n, &recovd->recovd_troubled_items) {
+ struct recovd_data *rd = list_entry(tmp, struct recovd_data,
+ rd_managed_chain);
+
+ if (rd->rd_phase != RECOVD_FAILED &&
+ rd->rd_phase != rd->rd_next_phase)
+ continue;
+
+ switch (rd->rd_phase) {
+ case RECOVD_FAILED:
+ cb_failed: /* must always reach here with recovd_lock held! */
+ CERROR("recovery FAILED for rd %p (conn %p): %d\n",
+ rd, class_rd2conn(rd), rc);
+
+ spin_unlock(&recovd->recovd_lock);
+ (void)rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_FAILURE);
+ spin_lock(&recovd->recovd_lock);
+ break;
+
+ case RECOVD_IDLE:
+ if (!rd->rd_recover) {
+ CERROR("no rd_recover for rd %p (conn %p)\n",
+ rd, class_rd2conn(rd));
+ rc = -EINVAL;
+ break;
+ }
+ CERROR("starting recovery for rd %p (conn %p)\n",
+ rd, class_rd2conn(rd));
+ rd->rd_phase = RECOVD_PREPARING;
+
+ spin_unlock(&recovd->recovd_lock);
+ rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_PREPARE);
+ spin_lock(&recovd->recovd_lock);
+ if (rc)
+ goto cb_failed;
+
+ rd->rd_next_phase = RECOVD_PREPARED;
+ break;
+
+ case RECOVD_PREPARED:
+ rd->rd_phase = RECOVD_RECOVERING;
+
+ CERROR("recovery prepared for rd %p (conn %p)\n",
+ rd, class_rd2conn(rd));
+
+ spin_unlock(&recovd->recovd_lock);
+ rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_RECOVER);
+ spin_lock(&recovd->recovd_lock);
+ if (rc)
+ goto cb_failed;
+
+ rd->rd_next_phase = RECOVD_RECOVERED;
+ break;
+
+ case RECOVD_RECOVERED:
+ rd->rd_phase = RECOVD_IDLE;
+ rd->rd_next_phase = RECOVD_PREPARING;
+
+ CERROR("recovery complete for rd %p (conn %p)\n",
+ rd, class_rd2conn(rd));
+ break;
+
+ default:
break;
- rd = list_entry(recovd->recovd_troubled_items.next,
- struct recovd_data, rd_managed_chain);
-
- list_del(&rd->rd_managed_chain);
- if (!rd->rd_recover)
- LBUG();
-
- CERROR("starting recovery for rd %p (conn %p)\n",
- rd, class_rd2conn(rd));
- recovd->recovd_current_rd = rd;
- recovd->recovd_flags &= ~RECOVD_FAILED;
- recovd->recovd_phase = RECOVD_PREPARING;
-
- spin_unlock(&recovd->recovd_lock);
- rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_PREPARE);
- spin_lock(&recovd->recovd_lock);
- if (rc)
- goto cb_failed;
-
- recovd->recovd_next_phase = RECOVD_PREPARED;
- break;
-
- case RECOVD_PREPARED:
- rd = recovd->recovd_current_rd;
- recovd->recovd_phase = RECOVD_RECOVERING;
-
- CERROR("recovery prepared for rd %p (conn %p), recovering\n",
- rd, class_rd2conn(rd));
-
- spin_unlock(&recovd->recovd_lock);
- rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_RECOVER);
- spin_lock(&recovd->recovd_lock);
- if (rc)
- goto cb_failed;
-
- recovd->recovd_next_phase = RECOVD_RECOVERED;
- break;
-
- case RECOVD_RECOVERED:
- rd = recovd->recovd_current_rd;
- recovd->recovd_phase = RECOVD_IDLE;
- recovd->recovd_next_phase = RECOVD_PREPARING;
-
- CERROR("recovery complete for rd %p (conn %p), recovering\n",
- rd, class_rd2conn(rd));
- break;
-
- default:
- break;
+ }
}
-
+ spin_unlock(&recovd->recovd_lock);
RETURN(0);
}
sprintf(current->comm, "lustre_recovd");
unlock_kernel();
- /* Record that the thread is running */
+ /* Signal that the thread is running. */
recovd->recovd_thread = current;
- recovd->recovd_flags = RECOVD_IDLE;
+ recovd->recovd_state = RECOVD_READY;
wake_up(&recovd->recovd_ctl_waitq);
- /* And now, loop forever on requests */
+ /* And now, loop forever on requests. */
while (1) {
wait_event(recovd->recovd_waitq, recovd_check_event(recovd));
-
- spin_lock(&recovd->recovd_lock);
-
- if (recovd->recovd_flags & RECOVD_STOPPING) {
- spin_unlock(&recovd->recovd_lock);
- CERROR("lustre_recovd stopping\n");
- EXIT;
+ if (recovd->recovd_state == RECOVD_STOPPING)
break;
- }
-
recovd_handle_event(recovd);
- spin_unlock(&recovd->recovd_lock);
}
recovd->recovd_thread = NULL;
- recovd->recovd_flags = RECOVD_STOPPED;
+ recovd->recovd_state = RECOVD_STOPPED;
wake_up(&recovd->recovd_ctl_waitq);
CDEBUG(D_NET, "mgr exiting process %d\n", current->pid);
RETURN(0);
init_waitqueue_head(&recovd->recovd_recovery_waitq);
init_waitqueue_head(&recovd->recovd_ctl_waitq);
- recovd->recovd_next_phase = RECOVD_PREPARING;
-
rc = kernel_thread(recovd_main, (void *)recovd,
CLONE_VM | CLONE_FS | CLONE_FILES);
if (rc < 0) {
RETURN(-EINVAL);
}
wait_event(recovd->recovd_ctl_waitq,
- recovd->recovd_phase == RECOVD_IDLE);
+ recovd->recovd_state == RECOVD_READY);
/* exported and called by obdclass timeout handlers */
class_signal_connection_failure = recovd_conn_fail;
int recovd_cleanup(struct recovd_obd *recovd)
{
spin_lock(&recovd->recovd_lock);
- recovd->recovd_flags = RECOVD_STOPPING;
+ recovd->recovd_state = RECOVD_STOPPING;
wake_up(&recovd->recovd_waitq);
spin_unlock(&recovd->recovd_lock);
wait_event(recovd->recovd_ctl_waitq,
- (recovd->recovd_flags & RECOVD_STOPPED));
+ (recovd->recovd_state == RECOVD_STOPPED));
RETURN(0);
}
/* replay what needs to be replayed */
if (req->rq_flags & PTL_RPC_FL_REPLAY) {
- CDEBUG(D_INODE, "req %Ld needs replay [last rcvd %Ld]\n",
+ CDEBUG(D_NET, "req %Ld needs replay [last rcvd %Ld]\n",
req->rq_xid, conn->c_last_xid);
rc = ptlrpc_replay_req(req);
#if 0
/* server has seen req, we have reply: skip */
if ((req->rq_flags & PTL_RPC_FL_REPLIED) &&
req->rq_xid <= conn->c_last_xid) {
- CDEBUG(D_INODE,
+ CDEBUG(D_NET,
"req %Ld was complete: skip [last rcvd %Ld]\n",
req->rq_xid, conn->c_last_xid);
continue;
/* server has lost req, we have reply: resend, ign reply */
if ((req->rq_flags & PTL_RPC_FL_REPLIED) &&
req->rq_xid > conn->c_last_xid) {
- CDEBUG(D_INODE, "lost req %Ld have rep: replay [last "
+ CDEBUG(D_NET, "lost req %Ld have rep: replay [last "
"rcvd %Ld]\n", req->rq_xid, conn->c_last_xid);
rc = ptlrpc_replay_req(req);
if (rc) {
/* server has seen req, we have lost reply: -ERESTARTSYS */
if ( !(req->rq_flags & PTL_RPC_FL_REPLIED) &&
req->rq_xid <= conn->c_last_xid) {
- CDEBUG(D_INODE, "lost rep %Ld srv did req: restart "
+ CDEBUG(D_NET, "lost rep %Ld srv did req: restart "
"[last rcvd %Ld]\n",
req->rq_xid, conn->c_last_xid);
ptlrpc_restart_req(req);
/* service has not seen req, no reply: resend */
if ( !(req->rq_flags & PTL_RPC_FL_REPLIED) &&
req->rq_xid > conn->c_last_xid) {
- CDEBUG(D_INODE,
+ CDEBUG(D_NET,
"lost rep/req %Ld: resend [last rcvd %Ld]\n",
req->rq_xid, conn->c_last_xid);
ptlrpc_resend_req(req);
conn->c_level = LUSTRE_CONN_FULL;
recovd_conn_fixed(conn);
+ CDEBUG(D_NET, "recovery complete on conn %p(%s), waking delayed reqs\n",
+ conn, conn->c_remote_uuid);
/* Finally, continue what we delayed since recovery started */
list_for_each_safe(tmp, pos, &conn->c_delayed_head) {
req = list_entry(tmp, struct ptlrpc_request, rq_list);
return rc;
}
+static int ll_retry_recovery(struct ptlrpc_connection *conn)
+{
+ /* XXX use a timer, sideshow bob */
+ recovd_conn_fail(conn);
+ return 0;
+}
+
int ll_recover(struct recovd_data *rd, int phase)
{
struct ptlrpc_connection *conn = class_rd2conn(rd);
case PTLRPC_RECOVD_PHASE_RECOVER:
RETURN(ll_recover_reconnect(conn));
case PTLRPC_RECOVD_PHASE_FAILURE:
- fixme();
- RETURN(0);
+ RETURN(ll_retry_recovery(conn));
}
LBUG();
RETURN(0);
}
-/* should this be in llite? */
-
int connmgr_iocontrol(long cmd, struct lustre_handle *hdl, int len, void *karg,
void *uarg)
{
struct obd_device *obd = class_conn2obd(hdl);
struct recovd_obd *recovd = &obd->u.recovd;
struct obd_ioctl_data *data = karg;
-#if 0 && PARALLEL_RECOVERY
struct list_head *tmp;
-#endif
+ int rc = 0;
ENTRY;
/* Find the connection that's been rebuilt. */
spin_lock(&recovd->recovd_lock);
-#if 0 && PARALLEL_RECOVERY
list_for_each(tmp, &recovd->recovd_troubled_items) {
conn = list_entry(tmp, struct ptlrpc_connection,
c_recovd_data.rd_managed_chain);
break;
conn = NULL;
}
-#endif
- if (!recovd->recovd_current_rd) {
- spin_unlock(&recovd->recovd_lock);
- LBUG();
- }
-
- conn = class_rd2conn(recovd->recovd_current_rd);
- spin_unlock(&recovd->recovd_lock);
- spin_lock(&conn->c_lock);
+ if (!conn)
+ GOTO(out, rc = -EINVAL);
- if (strcmp(conn->c_remote_uuid, data->ioc_inlbuf1)) {
- CERROR("NEWCONN for %s: currently recovering %s\n",
- data->ioc_inlbuf1, conn->c_remote_uuid);
- spin_unlock(&conn->c_lock);
- RETURN(-EINVAL);
- }
+ if (conn->c_recovd_data.rd_phase != RECOVD_PREPARING)
+ GOTO(out, rc = -EALREADY);
+ spin_lock(&conn->c_lock);
if (data->ioc_inllen2) {
CERROR("conn %p UUID change %s -> %s\n",
conn, conn->c_remote_uuid, data->ioc_inlbuf2);
conn->c_remote_uuid);
}
ptlrpc_readdress_connection(conn, conn->c_remote_uuid);
+ spin_unlock(&conn->c_lock);
- spin_lock(&recovd->recovd_lock);
-#if 0 && PARALLEL_RECOVERY
- if (conn->c_recovd_data->rd_state != RECOVD_PREPARING)
- LBUG();
- conn->c_recovd_data->rd_state = RECOVD_PREPARED;
-#endif
- if (recovd->recovd_phase != RECOVD_PREPARING ||
- recovd->recovd_next_phase != RECOVD_PREPARED ||
- recovd->recovd_current_rd != &conn->c_recovd_data) {
- LBUG();
- }
- recovd->recovd_phase = RECOVD_PREPARED;
+ conn->c_recovd_data.rd_phase = RECOVD_PREPARED;
wake_up(&recovd->recovd_waitq);
+ out:
spin_unlock(&recovd->recovd_lock);
- spin_unlock(&conn->c_lock);
- RETURN(0);
+ RETURN(rc);
}