Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[fs/lustre-release.git] / lustre / ptlrpc / pinger.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Portal-RPC reconnection and replay operations, for use in recovery.
5  *
6  *  Copyright (c) 2003 Cluster File Systems, Inc.
7  *   Authors: Phil Schwan <phil@clusterfs.com>
8  *            Mike Shaver <shaver@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #ifndef __KERNEL__
27 #include <liblustre.h>
28 #else
29 #include <linux/version.h>
30 #include <asm/semaphore.h>
31 #define DEBUG_SUBSYSTEM S_RPC
32 #endif
33
34 #include <linux/obd_support.h>
35 #include <linux/obd_class.h>
36 #include "ptlrpc_internal.h"
37
38 #ifdef __KERNEL__
39
40 static struct ptlrpc_thread *pinger_thread = NULL;
41 static DECLARE_MUTEX(pinger_sem);
42 static struct list_head pinger_imports = LIST_HEAD_INIT(pinger_imports);
43
44 static int ptlrpc_pinger_main(void *arg)
45 {
46         struct ptlrpc_svc_data *data = (struct ptlrpc_svc_data *)arg;
47         struct ptlrpc_thread *thread = data->thread;
48         unsigned long flags;
49         ENTRY;
50
51         lock_kernel();
52         ptlrpc_daemonize();
53
54         SIGNAL_MASK_LOCK(current, flags);
55         sigfillset(&current->blocked);
56         RECALC_SIGPENDING;
57         SIGNAL_MASK_UNLOCK(current, flags);
58
59         THREAD_NAME(current->comm, "%s", data->name);
60         unlock_kernel();
61
62         /* Record that the thread is running */
63         thread->t_flags = SVC_RUNNING;
64         wake_up(&thread->t_ctl_waitq);
65
66         /* And now, loop forever, pinging as needed. */
67         while (1) {
68                 unsigned long this_ping = jiffies;
69                 long time_to_next_ping;
70                 struct l_wait_info lwi = LWI_TIMEOUT(obd_timeout * HZ,
71                                                      NULL, NULL);
72                 struct ptlrpc_request_set *set;
73                 struct ptlrpc_request *req;
74                 struct list_head *iter;
75                 wait_queue_t set_wait;
76                 int rc;
77
78                 set = ptlrpc_prep_set();
79                 down(&pinger_sem);
80                 list_for_each(iter, &pinger_imports) {
81                         struct obd_import *imp =
82                                 list_entry(iter, struct obd_import,
83                                            imp_pinger_chain);
84                         int generation, level;
85                         unsigned long flags;
86
87                         if (imp->imp_next_ping <= this_ping) {
88                                 /* Add a ping. */
89                                 spin_lock_irqsave(&imp->imp_lock, flags);
90                                 generation = imp->imp_generation;
91                                 level = imp->imp_state;
92                                 spin_unlock_irqrestore(&imp->imp_lock, flags);
93
94                                 if (level != LUSTRE_IMP_FULL) {
95                                         CDEBUG(D_HA,
96                                                "not pinging %s (in recovery)\n",
97                                                imp->imp_target_uuid.uuid);
98                                         continue;
99                                 }
100
101                                 req = ptlrpc_prep_req(imp, OBD_PING, 0, NULL,
102                                                       NULL);
103                                 if (!req) {
104                                         CERROR("OOM trying to ping\n");
105                                         break;
106                                 }
107                                 req->rq_no_resend = 1;
108                                 req->rq_replen = lustre_msg_size(0, NULL);
109                                 req->rq_send_state = LUSTRE_IMP_FULL;
110                                 req->rq_phase = RQ_PHASE_RPC;
111                                 req->rq_import_generation = generation;
112                                 ptlrpc_set_add_req(set, req);
113                         } else {
114                                 CDEBUG(D_HA, "don't need to ping %s (%lu > "
115                                        "%lu)\n", imp->imp_target_uuid.uuid,
116                                        imp->imp_next_ping, this_ping);
117                         }
118                 }
119                 up(&pinger_sem);
120
121                 /* Might be empty, that's OK. */
122                 if (set->set_remaining == 0)
123                         CDEBUG(D_HA, "nothing to ping\n");
124                 list_for_each(iter, &set->set_requests) {
125                         struct ptlrpc_request *req =
126                                 list_entry(iter, struct ptlrpc_request,
127                                            rq_set_chain);
128                         DEBUG_REQ(D_HA, req, "pinging %s->%s",
129                                   req->rq_import->imp_obd->obd_uuid.uuid,
130                                   req->rq_import->imp_target_uuid.uuid);
131                         (void)ptl_send_rpc(req);
132                 }
133
134                 /* Have to wait on both the thread's queue and the set's. */
135                 init_waitqueue_entry(&set_wait, current);
136                 add_wait_queue(&set->set_waitq, &set_wait);
137                 rc = l_wait_event(thread->t_ctl_waitq,
138                                   thread->t_flags & SVC_STOPPING ||
139                                   ptlrpc_check_set(set),
140                                   &lwi);
141                 remove_wait_queue(&set->set_waitq, &set_wait);
142                 CDEBUG(D_HA, "ping complete (%lu)\n", jiffies);
143
144                 if (thread->t_flags & SVC_STOPPING) {
145                         thread->t_flags &= ~SVC_STOPPING;
146                         list_for_each(iter, &set->set_requests) {
147                                 req = list_entry(iter, struct ptlrpc_request,
148                                                  rq_set_chain);
149                                 if (!req->rq_replied)
150                                         ptlrpc_unregister_reply(req);
151                         }
152                         ptlrpc_set_destroy(set);
153                         EXIT;
154                         break;
155                 }
156
157                 /* Expire all the requests that didn't come back. */
158                 down(&pinger_sem);
159                 list_for_each(iter, &set->set_requests) {
160                         req = list_entry(iter, struct ptlrpc_request,
161                                          rq_set_chain);
162
163                         if (req->rq_replied)
164                                 continue;
165
166                         req->rq_phase = RQ_PHASE_COMPLETE;
167                         set->set_remaining--;
168                         /* If it was disconnected, don't sweat it. */
169                         if (list_empty(&req->rq_import->imp_pinger_chain)) {
170                                 ptlrpc_unregister_reply(req);
171                                 continue;
172                         }
173
174                         ptlrpc_expire_one_request(req);
175                 }
176                 up(&pinger_sem);
177                 ptlrpc_set_destroy(set);
178
179                 /* Wait until the next ping time, or until we're stopped. */
180                 time_to_next_ping = this_ping + (obd_timeout * HZ) - jiffies;
181                 CDEBUG(D_HA, "next ping in %lu (%lu)\n", time_to_next_ping,
182                        this_ping + (obd_timeout * HZ));
183                 if (time_to_next_ping > 0) {
184                         lwi = LWI_TIMEOUT(time_to_next_ping, NULL, NULL);
185                         l_wait_event(thread->t_ctl_waitq,
186                                      thread->t_flags & (SVC_STOPPING|SVC_EVENT),
187                                      &lwi);
188                         if (thread->t_flags & SVC_STOPPING) {
189                                 thread->t_flags &= ~SVC_STOPPING;
190                                 EXIT;
191                                 break;
192                         } else if (thread->t_flags & SVC_EVENT) {
193                                 /* woken after adding import to reset timer */
194                                 thread->t_flags &= ~SVC_EVENT;
195                         }
196                 }
197         }
198
199         thread->t_flags = SVC_STOPPED;
200         wake_up(&thread->t_ctl_waitq);
201
202         CDEBUG(D_NET, "pinger thread exiting, process %d\n", current->pid);
203         return 0;
204 }
205
206 int ptlrpc_start_pinger(void)
207 {
208         struct l_wait_info lwi = { 0 };
209         struct ptlrpc_svc_data d;
210         int rc;
211 #ifndef ENABLE_PINGER
212         return 0;
213 #endif
214         ENTRY;
215
216         if (pinger_thread != NULL)
217                 RETURN(-EALREADY);
218
219         OBD_ALLOC(pinger_thread, sizeof(*pinger_thread));
220         if (pinger_thread == NULL)
221                 RETURN(-ENOMEM);
222         init_waitqueue_head(&pinger_thread->t_ctl_waitq);
223
224         d.name = "ll_ping";
225         d.thread = pinger_thread;
226
227         /* CLONE_VM and CLONE_FILES just avoid a needless copy, because we
228          * just drop the VM and FILES in ptlrpc_daemonize() right away. */
229         rc = kernel_thread(ptlrpc_pinger_main, &d, CLONE_VM | CLONE_FILES);
230         if (rc < 0) {
231                 CERROR("cannot start thread: %d\n", rc);
232                 OBD_FREE(pinger_thread, sizeof(*pinger_thread));
233                 RETURN(rc);
234         }
235         l_wait_event(pinger_thread->t_ctl_waitq,
236                      pinger_thread->t_flags & SVC_RUNNING, &lwi);
237
238         RETURN(rc);
239 }
240
241 int ptlrpc_stop_pinger(void)
242 {
243         struct l_wait_info lwi = { 0 };
244         int rc = 0;
245 #ifndef ENABLE_PINGER
246         return 0;
247 #endif
248         ENTRY;
249
250         if (pinger_thread == NULL)
251                 RETURN(-EALREADY);
252         down(&pinger_sem);
253         pinger_thread->t_flags = SVC_STOPPING;
254         wake_up(&pinger_thread->t_ctl_waitq);
255         up(&pinger_sem);
256
257         l_wait_event(pinger_thread->t_ctl_waitq,
258                      (pinger_thread->t_flags & SVC_STOPPED), &lwi);
259
260         OBD_FREE(pinger_thread, sizeof(*pinger_thread));
261         pinger_thread = NULL;
262         RETURN(rc);
263 }
264
265 void ptlrpc_pinger_sending_on_import(struct obd_import *imp)
266 {
267         down(&pinger_sem);
268         imp->imp_next_ping = jiffies + (obd_timeout * HZ);
269         up(&pinger_sem);
270 }
271
272 int ptlrpc_pinger_add_import(struct obd_import *imp)
273 {
274         ENTRY;
275         if (!list_empty(&imp->imp_pinger_chain))
276                 RETURN(-EALREADY);
277
278         down(&pinger_sem);
279         CDEBUG(D_HA, "adding pingable import %s->%s\n",
280                imp->imp_obd->obd_uuid.uuid, imp->imp_target_uuid.uuid);
281         imp->imp_next_ping = jiffies + (obd_timeout * HZ);
282         /* XXX sort, blah blah */
283         list_add_tail(&imp->imp_pinger_chain, &pinger_imports);
284         class_import_get(imp);
285
286 #ifdef ENABLE_PINGER
287         pinger_thread->t_flags |= SVC_EVENT;
288         wake_up(&pinger_thread->t_ctl_waitq);
289 #endif
290         up(&pinger_sem);
291
292         RETURN(0);
293 }
294
295 int ptlrpc_pinger_del_import(struct obd_import *imp)
296 {
297         ENTRY;
298         if (list_empty(&imp->imp_pinger_chain))
299                 RETURN(-ENOENT);
300
301         down(&pinger_sem);
302         list_del_init(&imp->imp_pinger_chain);
303         CDEBUG(D_HA, "removing pingable import %s->%s\n",
304                imp->imp_obd->obd_uuid.uuid, imp->imp_target_uuid.uuid);
305         class_import_put(imp);
306         up(&pinger_sem);
307         RETURN(0);
308 }
309
310 #else /* !__KERNEL__ */
311
312 int ptlrpc_start_pinger(void)
313 {
314         return 0;
315 }
316
317 int ptlrpc_stop_pinger(void)
318 {
319         return 0;
320 }
321
322 int ptlrpc_pinger_add_import(struct obd_import *imp)
323 {
324         return 0;
325 }
326
327 int ptlrpc_pinger_del_import(struct obd_import *imp)
328 {
329         return 0;
330 }
331
332 void ptlrpc_pinger_sending_on_import(struct obd_import *imp)
333 {
334 }
335
336 #endif