Whamcloud - gitweb
A patch only a mother could love to notify LOVs when OSCs are disabled due to
[fs/lustre-release.git] / lustre / llite / recover.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Lustre Lite recovery infrastructure.
5  *
6  * Copyright (C) 2002 Cluster File Systems Inc.
7  */
8
9 #define DEBUG_SUBSYSTEM S_LLITE
10
11 #include <linux/lustre_lite.h>
12 #include <linux/lustre_ha.h>
13 #include <linux/lustre_dlm.h>
14 #include <linux/lustre_idl.h>
15 #include <linux/obd_lov.h> /* for IOC_LOV_SET_OSC_ACTIVE */
16
17 static int ll_retry_recovery(struct ptlrpc_connection *conn)
18 {
19     ENTRY;
20     RETURN(0);
21 }
22
23 /* XXX looks a lot like super.c:invalidate_request_list, don't it? */
24 static void abort_inflight_for_import(struct obd_import *imp)
25 {
26         struct list_head *tmp, *n;
27
28         /* Make sure that no new requests get processed for this import.
29          * ptlrpc_queue_wait must (and does) hold c_lock while testing this
30          * flags and then putting requests on sending_head or delayed_head.
31          */
32         spin_lock(&imp->imp_connection->c_lock);
33         imp->imp_flags |= IMP_INVALID;
34         spin_unlock(&imp->imp_connection->c_lock);
35
36         list_for_each_safe(tmp, n, &imp->imp_connection->c_sending_head) {
37                 struct ptlrpc_request *req =
38                         list_entry(tmp, struct ptlrpc_request, rq_list);
39
40                 if (req->rq_import != imp)
41                         continue;
42
43                 if (req->rq_flags & PTL_RPC_FL_REPLIED) {
44                         /* no need to replay, just discard */
45                         CERROR("uncommitted req xid "LPD64" op %d to OST %s\n",
46                                (unsigned long long)req->rq_xid,
47                                req->rq_reqmsg->opc,
48                                imp->imp_obd->u.cli.cl_target_uuid);
49                         ptlrpc_req_finished(req);
50                 } else {
51                         CERROR("inflight req xid "LPD64" op %d to OST %s\n",
52                                (unsigned long long)req->rq_xid,
53                                req->rq_reqmsg->opc,
54                                imp->imp_obd->u.cli.cl_target_uuid);
55
56                         req->rq_flags |= PTL_RPC_FL_ERR;
57                         wake_up(&req->rq_wait_for_rep);
58                 }
59         }
60
61         list_for_each_safe(tmp, n, &imp->imp_connection->c_delayed_head) {
62                 struct ptlrpc_request *req =
63                         list_entry(tmp, struct ptlrpc_request, rq_list);
64                 CERROR("aborting waiting req xid "LPD64" op %d to OST %s\n",
65                        (unsigned long long)req->rq_xid, req->rq_reqmsg->opc,
66                        imp->imp_obd->u.cli.cl_target_uuid);
67                 req->rq_flags |= PTL_RPC_FL_ERR;
68                 wake_up(&req->rq_wait_for_rep);
69         }
70 }
71
72 static void prepare_ost(struct obd_import *imp)
73 {
74         int rc;
75         struct ldlm_namespace *ns = imp->imp_obd->obd_namespace;
76         struct obd_device *notify_obd = imp->imp_obd->u.cli.cl_containing_lov;
77
78         CDEBUG(D_HA, "invalidating all locks for OST imp %p (to %s):\n",
79                imp, imp->imp_connection->c_remote_uuid);
80         ldlm_namespace_dump(ns);
81         ldlm_namespace_cleanup(ns, 1 /* no network ops */);
82
83         abort_inflight_for_import(imp);
84
85         /* How gross is _this_? */
86         if (!list_empty(&notify_obd->obd_exports)) {
87                 struct lustre_handle fakeconn;
88                 struct obd_ioctl_data ioc_data;
89                 struct obd_export *exp = 
90                         list_entry(&notify_obd->obd_exports.next, 
91                                    struct obd_export, exp_obd_chain);
92                 fakeconn.addr = (__u64)(unsigned long)exp;
93                 fakeconn.cookie = exp->exp_cookie;
94                 ioc_data.ioc_inlbuf1 = imp->imp_obd->obd_uuid;
95                 ioc_data.ioc_offset = 0; /* inactive */
96                 rc = obd_iocontrol(IOC_LOV_SET_OSC_ACTIVE, &fakeconn,
97                                    sizeof ioc_data, &ioc_data, NULL);
98                 if (rc) 
99                         CERROR("disabling %s on LOV %p/%s: %d\n", 
100                                imp->imp_obd->obd_uuid, notify_obd,
101                                notify_obd->obd_uuid, rc);
102         } else {
103                 CDEBUG(D_HA, "No exports for obd %p/%s, can't notify about %p\n",
104                        notify_obd, notify_obd->obd_uuid, imp->imp_obd->obd_uuid);
105         }
106 }
107
108 static int ll_prepare_recovery(struct ptlrpc_connection *conn)
109 {
110         struct list_head *tmp;
111
112         list_for_each(tmp, &conn->c_imports) {
113                 struct obd_import *imp = list_entry(tmp, struct obd_import,
114                                                     imp_chain);
115
116                 if (imp->imp_obd->obd_type->typ_ops->o_brw)
117                         prepare_ost(imp);
118         }
119
120         return ptlrpc_run_recovery_upcall(conn);
121 }
122
123 static void reconnect_ost(struct obd_import *imp)
124 {
125         (void)ptlrpc_reconnect_import(imp, OST_CONNECT);
126 }
127
128 static int ll_reconnect(struct ptlrpc_connection *conn)
129 {
130         struct list_head *tmp;
131         int need_replay = 0;
132
133         ENTRY;
134
135         /* XXX c_lock semantics! */
136         conn->c_level = LUSTRE_CONN_CON;
137
138         /* XXX this code MUST be shared with class_obd_connect! */
139         list_for_each(tmp, &conn->c_imports) {
140                 struct obd_import *imp = list_entry(tmp, struct obd_import,
141                                                     imp_chain);
142                 if (imp->imp_obd->obd_type->typ_ops->o_brw) {
143                         /* XXX what to do if we fail? */
144                         reconnect_ost(imp);
145                 } else {
146                         int rc = ptlrpc_reconnect_import(imp, MDS_CONNECT);
147                         if (!rc) {
148                                 need_replay = 1;
149                                 /* XXX obd_cancel_unused */
150                         }
151                         /* make sure we don't try to replay for dead imps?
152                          *
153                          * else imp->imp_connection = NULL;
154                          *
155                          */
156                         
157                 }
158         }
159
160         if (!need_replay) {
161                 /* all done! */
162                 conn->c_level = LUSTRE_CONN_FULL;
163                 RETURN(0);
164         }
165         
166         conn->c_level = LUSTRE_CONN_RECOVD;
167         /* this will replay, up the c_level, recovd_conn_fixed and continue reqs.
168          * also, makes a mean cup of coffee.
169          */
170         RETURN(ptlrpc_replay(conn));
171 }
172
173 int ll_recover(struct recovd_data *rd, int phase)
174 {
175         struct ptlrpc_connection *conn = class_rd2conn(rd);
176
177         LASSERT(conn);
178         ENTRY;
179
180         switch (phase) {
181             case PTLRPC_RECOVD_PHASE_PREPARE:
182                 RETURN(ll_prepare_recovery(conn));
183             case PTLRPC_RECOVD_PHASE_RECOVER:
184                 RETURN(ll_reconnect(conn));
185             case PTLRPC_RECOVD_PHASE_FAILURE:
186                 RETURN(ll_retry_recovery(conn));
187         }
188
189         LBUG();
190         RETURN(-ENOSYS);
191 }