1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * Lustre High Availability Daemon
8 * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
10 * This code is issued under the GNU General Public License.
11 * See the file COPYING in this distribution
13 * by Peter Braam <braam@clusterfs.com>
17 #define DEBUG_SUBSYSTEM S_RPC
19 #include <linux/lustre_lite.h>
20 #include <linux/lustre_ha.h>
21 #include <linux/obd_support.h>
23 void recovd_conn_manage(struct ptlrpc_connection *conn,
24 struct recovd_obd *recovd, ptlrpc_recovery_cb_t recover)
26 struct recovd_data *rd = &conn->c_recovd_data;
29 rd->rd_recovd = recovd;
30 rd->rd_recover = recover;
31 rd->rd_phase = RD_IDLE;
32 rd->rd_next_phase = RD_TROUBLED;
34 spin_lock(&recovd->recovd_lock);
35 INIT_LIST_HEAD(&rd->rd_managed_chain);
36 list_add(&recovd->recovd_managed_items, &rd->rd_managed_chain);
37 spin_unlock(&recovd->recovd_lock);
42 void recovd_conn_fail(struct ptlrpc_connection *conn)
44 struct recovd_data *rd = &conn->c_recovd_data;
45 struct recovd_obd *recovd = rd->rd_recovd;
49 CERROR("no recovd for connection %p\n", conn);
55 spin_lock(&recovd->recovd_lock);
56 if (rd->rd_phase != RD_IDLE) {
57 CERROR("connection %p to %s already in recovery\n",
58 conn, conn->c_remote_uuid);
59 /* XXX need to distinguish from failure-in-recovery */
60 spin_unlock(&recovd->recovd_lock);
65 CERROR("connection %p to %s failed\n", conn, conn->c_remote_uuid);
66 list_del(&rd->rd_managed_chain);
67 list_add_tail(&rd->rd_managed_chain, &recovd->recovd_troubled_items);
68 rd->rd_phase = RD_TROUBLED;
69 spin_unlock(&recovd->recovd_lock);
71 wake_up(&recovd->recovd_waitq);
76 void recovd_conn_fixed(struct ptlrpc_connection *conn)
78 struct recovd_data *rd = &conn->c_recovd_data;
81 CDEBUG(D_HA, "connection %p (now to %s) fixed\n",
82 conn, conn->c_remote_uuid);
83 spin_lock(&rd->rd_recovd->recovd_lock);
84 list_del(&rd->rd_managed_chain);
85 rd->rd_phase = RD_IDLE;
86 rd->rd_next_phase = RD_TROUBLED;
87 list_add(&rd->rd_managed_chain, &rd->rd_recovd->recovd_managed_items);
88 spin_unlock(&rd->rd_recovd->recovd_lock);
94 static int recovd_check_event(struct recovd_obd *recovd)
97 struct list_head *tmp;
101 spin_lock(&recovd->recovd_lock);
103 if (recovd->recovd_state == RECOVD_STOPPING)
106 list_for_each(tmp, &recovd->recovd_troubled_items) {
108 struct recovd_data *rd = list_entry(tmp, struct recovd_data,
111 if (rd->rd_phase == rd->rd_next_phase ||
112 rd->rd_phase == RD_FAILED)
117 spin_unlock(&recovd->recovd_lock);
121 static void dump_connection_list(struct list_head *head)
123 struct list_head *tmp;
125 list_for_each(tmp, head) {
126 struct ptlrpc_connection *conn =
127 list_entry(tmp, struct ptlrpc_connection,
128 c_recovd_data.rd_managed_chain);
129 CDEBUG(D_HA, " %p = %s (%d/%d)\n", conn, conn->c_remote_uuid,
130 conn->c_recovd_data.rd_phase,
131 conn->c_recovd_data.rd_next_phase);
135 static int recovd_handle_event(struct recovd_obd *recovd)
137 struct list_head *tmp, *n;
141 spin_lock(&recovd->recovd_lock);
143 CERROR("managed: \n");
144 dump_connection_list(&recovd->recovd_managed_items);
145 CERROR("troubled: \n");
146 dump_connection_list(&recovd->recovd_troubled_items);
149 * We use _safe here because one of the callbacks, expecially
150 * FAILURE or PREPARED, could move list items around.
152 list_for_each_safe(tmp, n, &recovd->recovd_troubled_items) {
153 struct recovd_data *rd = list_entry(tmp, struct recovd_data,
156 if (rd->rd_phase != RD_FAILED &&
157 rd->rd_phase != rd->rd_next_phase)
160 switch (rd->rd_phase) {
162 cb_failed: /* must always reach here with recovd_lock held! */
163 CERROR("recovery FAILED for rd %p (conn %p): %d\n",
164 rd, class_rd2conn(rd), rc);
166 spin_unlock(&recovd->recovd_lock);
167 (void)rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_FAILURE);
168 spin_lock(&recovd->recovd_lock);
172 if (!rd->rd_recover) {
173 CERROR("no rd_recover for rd %p (conn %p)\n",
174 rd, class_rd2conn(rd));
178 CERROR("starting recovery for rd %p (conn %p)\n",
179 rd, class_rd2conn(rd));
180 rd->rd_phase = RD_PREPARING;
182 spin_unlock(&recovd->recovd_lock);
183 rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_PREPARE);
184 spin_lock(&recovd->recovd_lock);
188 rd->rd_next_phase = RD_PREPARED;
192 rd->rd_phase = RD_RECOVERING;
194 CERROR("recovery prepared for rd %p (conn %p)\n",
195 rd, class_rd2conn(rd));
197 spin_unlock(&recovd->recovd_lock);
198 rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_RECOVER);
199 spin_lock(&recovd->recovd_lock);
203 rd->rd_next_phase = RD_RECOVERED;
207 rd->rd_phase = RD_IDLE;
208 rd->rd_next_phase = RD_TROUBLED;
210 CERROR("recovery complete for rd %p (conn %p)\n",
211 rd, class_rd2conn(rd));
218 spin_unlock(&recovd->recovd_lock);
222 static int recovd_main(void *arg)
224 struct recovd_obd *recovd = (struct recovd_obd *)arg;
230 spin_lock_irq(¤t->sigmask_lock);
231 sigfillset(¤t->blocked);
232 recalc_sigpending(current);
233 spin_unlock_irq(¤t->sigmask_lock);
235 sprintf(current->comm, "lustre_recovd");
238 /* Signal that the thread is running. */
239 recovd->recovd_thread = current;
240 recovd->recovd_state = RECOVD_READY;
241 wake_up(&recovd->recovd_ctl_waitq);
243 /* And now, loop forever on requests. */
245 wait_event(recovd->recovd_waitq, recovd_check_event(recovd));
246 if (recovd->recovd_state == RECOVD_STOPPING)
248 recovd_handle_event(recovd);
251 recovd->recovd_thread = NULL;
252 recovd->recovd_state = RECOVD_STOPPED;
253 wake_up(&recovd->recovd_ctl_waitq);
254 CDEBUG(D_HA, "mgr exiting process %d\n", current->pid);
258 int recovd_setup(struct recovd_obd *recovd)
264 INIT_LIST_HEAD(&recovd->recovd_managed_items);
265 INIT_LIST_HEAD(&recovd->recovd_troubled_items);
266 spin_lock_init(&recovd->recovd_lock);
268 init_waitqueue_head(&recovd->recovd_waitq);
269 init_waitqueue_head(&recovd->recovd_recovery_waitq);
270 init_waitqueue_head(&recovd->recovd_ctl_waitq);
272 rc = kernel_thread(recovd_main, (void *)recovd,
273 CLONE_VM | CLONE_FS | CLONE_FILES);
275 CERROR("cannot start thread\n");
278 wait_event(recovd->recovd_ctl_waitq,
279 recovd->recovd_state == RECOVD_READY);
281 ptlrpc_recovd = recovd;
282 class_signal_connection_failure = recovd_conn_fail;
287 int recovd_cleanup(struct recovd_obd *recovd)
290 spin_lock(&recovd->recovd_lock);
291 recovd->recovd_state = RECOVD_STOPPING;
292 wake_up(&recovd->recovd_waitq);
293 spin_unlock(&recovd->recovd_lock);
295 wait_event(recovd->recovd_ctl_waitq,
296 (recovd->recovd_state == RECOVD_STOPPED));
300 struct recovd_obd *ptlrpc_recovd;