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;
32 spin_lock(&recovd->recovd_lock);
33 list_add(&rd->rd_managed_chain, &recovd->recovd_managed_items);
34 spin_unlock(&recovd->recovd_lock);
39 void recovd_conn_fail(struct ptlrpc_connection *conn)
41 struct recovd_data *rd = &conn->c_recovd_data;
42 struct recovd_obd *recovd = rd->rd_recovd;
46 CERROR("no recovd for connection %p\n", conn);
52 spin_lock(&recovd->recovd_lock);
53 if (rd->rd_phase != RECOVD_IDLE || rd->rd_next_phase != RECOVD_IDLE) {
54 CDEBUG(D_INFO, "connection %p to %s already in recovery\n",
55 conn, conn->c_remote_uuid);
56 spin_unlock(&recovd->recovd_lock);
61 CERROR("connection %p to %s failed\n", conn, conn->c_remote_uuid);
62 list_del(&rd->rd_managed_chain);
63 list_add_tail(&rd->rd_managed_chain, &recovd->recovd_troubled_items);
64 rd->rd_next_phase = RECOVD_PREPARING;
65 spin_unlock(&recovd->recovd_lock);
67 wake_up(&recovd->recovd_waitq);
72 /* this function must be called with conn->c_lock held */
73 void recovd_conn_fixed(struct ptlrpc_connection *conn)
75 struct recovd_data *rd = &conn->c_recovd_data;
78 list_del(&rd->rd_managed_chain);
79 list_add(&rd->rd_managed_chain, &rd->rd_recovd->recovd_managed_items);
85 static int recovd_check_event(struct recovd_obd *recovd)
88 struct list_head *tmp;
92 spin_lock(&recovd->recovd_lock);
94 if (recovd->recovd_state == RECOVD_STOPPING)
97 list_for_each(tmp, &recovd->recovd_troubled_items) {
99 struct recovd_data *rd = list_entry(tmp, struct recovd_data,
102 if (rd->rd_phase == rd->rd_next_phase ||
103 (rd->rd_phase == RECOVD_IDLE &&
104 rd->rd_next_phase == RECOVD_PREPARING) ||
105 rd->rd_phase == RECOVD_FAILED)
110 spin_unlock(&recovd->recovd_lock);
114 static void dump_connection_list(struct list_head *head)
116 struct list_head *tmp;
118 list_for_each(tmp, head) {
119 struct ptlrpc_connection *conn =
120 list_entry(tmp, struct ptlrpc_connection,
121 c_recovd_data.rd_managed_chain);
122 CDEBUG(D_NET, " %p = %s\n", conn, conn->c_remote_uuid);
126 static int recovd_handle_event(struct recovd_obd *recovd)
128 struct list_head *tmp, *n;
132 spin_lock(&recovd->recovd_lock);
134 CDEBUG(D_NET, "managed: \n");
135 dump_connection_list(&recovd->recovd_managed_items);
136 CDEBUG(D_NET, "troubled: \n");
137 dump_connection_list(&recovd->recovd_troubled_items);
140 * We use _safe here because one of the callbacks, expecially
141 * FAILURE or PREPARED, could move list items around.
143 list_for_each_safe(tmp, n, &recovd->recovd_troubled_items) {
144 struct recovd_data *rd = list_entry(tmp, struct recovd_data,
147 /* XXXshaver This is very ugly -- add a RECOVD_TROUBLED state! */
148 if (rd->rd_phase != RECOVD_FAILED &&
149 !(rd->rd_phase == RECOVD_IDLE &&
150 rd->rd_next_phase == RECOVD_PREPARING) &&
151 rd->rd_phase != rd->rd_next_phase)
154 switch (rd->rd_phase) {
156 cb_failed: /* must always reach here with recovd_lock held! */
157 CERROR("recovery FAILED for rd %p (conn %p): %d\n",
158 rd, class_rd2conn(rd), rc);
160 spin_unlock(&recovd->recovd_lock);
161 (void)rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_FAILURE);
162 spin_lock(&recovd->recovd_lock);
166 if (!rd->rd_recover) {
167 CERROR("no rd_recover for rd %p (conn %p)\n",
168 rd, class_rd2conn(rd));
172 CERROR("starting recovery for rd %p (conn %p)\n",
173 rd, class_rd2conn(rd));
174 rd->rd_phase = RECOVD_PREPARING;
176 spin_unlock(&recovd->recovd_lock);
177 rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_PREPARE);
178 spin_lock(&recovd->recovd_lock);
182 rd->rd_next_phase = RECOVD_PREPARED;
185 case RECOVD_PREPARED:
186 rd->rd_phase = RECOVD_RECOVERING;
188 CERROR("recovery prepared for rd %p (conn %p)\n",
189 rd, class_rd2conn(rd));
191 spin_unlock(&recovd->recovd_lock);
192 rc = rd->rd_recover(rd, PTLRPC_RECOVD_PHASE_RECOVER);
193 spin_lock(&recovd->recovd_lock);
197 rd->rd_next_phase = RECOVD_RECOVERED;
200 case RECOVD_RECOVERED:
201 rd->rd_phase = RECOVD_IDLE;
202 rd->rd_next_phase = RECOVD_PREPARING;
204 CERROR("recovery complete for rd %p (conn %p)\n",
205 rd, class_rd2conn(rd));
212 spin_unlock(&recovd->recovd_lock);
216 static int recovd_main(void *arg)
218 struct recovd_obd *recovd = (struct recovd_obd *)arg;
224 spin_lock_irq(¤t->sigmask_lock);
225 sigfillset(¤t->blocked);
226 recalc_sigpending(current);
227 spin_unlock_irq(¤t->sigmask_lock);
229 sprintf(current->comm, "lustre_recovd");
232 /* Signal that the thread is running. */
233 recovd->recovd_thread = current;
234 recovd->recovd_state = RECOVD_READY;
235 wake_up(&recovd->recovd_ctl_waitq);
237 /* And now, loop forever on requests. */
239 wait_event(recovd->recovd_waitq, recovd_check_event(recovd));
240 if (recovd->recovd_state == RECOVD_STOPPING)
242 recovd_handle_event(recovd);
245 recovd->recovd_thread = NULL;
246 recovd->recovd_state = RECOVD_STOPPED;
247 wake_up(&recovd->recovd_ctl_waitq);
248 CDEBUG(D_NET, "mgr exiting process %d\n", current->pid);
252 int recovd_setup(struct recovd_obd *recovd)
258 INIT_LIST_HEAD(&recovd->recovd_managed_items);
259 INIT_LIST_HEAD(&recovd->recovd_troubled_items);
260 spin_lock_init(&recovd->recovd_lock);
262 init_waitqueue_head(&recovd->recovd_waitq);
263 init_waitqueue_head(&recovd->recovd_recovery_waitq);
264 init_waitqueue_head(&recovd->recovd_ctl_waitq);
266 rc = kernel_thread(recovd_main, (void *)recovd,
267 CLONE_VM | CLONE_FS | CLONE_FILES);
269 CERROR("cannot start thread\n");
272 wait_event(recovd->recovd_ctl_waitq,
273 recovd->recovd_state == RECOVD_READY);
275 ptlrpc_recovd = recovd;
280 int recovd_cleanup(struct recovd_obd *recovd)
282 spin_lock(&recovd->recovd_lock);
283 recovd->recovd_state = RECOVD_STOPPING;
284 wake_up(&recovd->recovd_waitq);
285 spin_unlock(&recovd->recovd_lock);
287 wait_event(recovd->recovd_ctl_waitq,
288 (recovd->recovd_state == RECOVD_STOPPED));
292 struct recovd_obd *ptlrpc_recovd;