multipathd: decrease log level of waiter thread start/stop msgs
[multipath-tools/.git] / multipathd / waiter.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Kiyoshi Ueda, NEC
4  * Copyright (c) 2005 Benjamin Marzinski, Redhat
5  * Copyright (c) 2005 Edward Goggin, EMC
6  */
7 #include <unistd.h>
8 #include <libdevmapper.h>
9 #include <sys/mman.h>
10 #include <pthread.h>
11 #include <signal.h>
12 #include <urcu.h>
13
14 #include "vector.h"
15 #include "memory.h"
16 #include "checkers.h"
17 #include "config.h"
18 #include "structs.h"
19 #include "structs_vec.h"
20 #include "devmapper.h"
21 #include "debug.h"
22 #include "lock.h"
23 #include "waiter.h"
24 #include "main.h"
25
26 pthread_attr_t waiter_attr;
27 struct mutex_lock waiter_lock = { .mutex = PTHREAD_MUTEX_INITIALIZER };
28
29 static struct event_thread *alloc_waiter (void)
30 {
31
32         struct event_thread *wp;
33
34         wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
35         memset(wp, 0, sizeof(struct event_thread));
36
37         return wp;
38 }
39
40 static void free_waiter (void *data)
41 {
42         struct event_thread *wp = (struct event_thread *)data;
43
44         if (wp->dmt)
45                 dm_task_destroy(wp->dmt);
46
47         rcu_unregister_thread();
48         FREE(wp);
49 }
50
51 void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
52 {
53         pthread_t thread;
54
55         if (mpp->waiter == (pthread_t)0) {
56                 condlog(3, "%s: event checker thread already stopped",
57                         mpp->alias);
58                 return;
59         }
60         /* Don't cancel yourself. __setup_multipath is called by
61            by the waiter thread, and may remove a multipath device */
62         if (pthread_equal(mpp->waiter, pthread_self()))
63                 return;
64
65         condlog(3, "%s: stop event checker thread (%lu)", mpp->alias,
66                 mpp->waiter);
67         thread = mpp->waiter;
68         mpp->waiter = (pthread_t)0;
69         pthread_cleanup_push(cleanup_lock, &waiter_lock);
70         lock(&waiter_lock);
71         pthread_kill(thread, SIGUSR2);
72         pthread_cancel(thread);
73         lock_cleanup_pop(&waiter_lock);
74 }
75
76 /*
77  * returns the reschedule delay
78  * negative means *stop*
79  */
80 static int waiteventloop (struct event_thread *waiter)
81 {
82         sigset_t set, oldset;
83         int event_nr;
84         int r;
85
86         if (!waiter->event_nr)
87                 waiter->event_nr = dm_geteventnr(waiter->mapname);
88
89         if (!(waiter->dmt = libmp_dm_task_create(DM_DEVICE_WAITEVENT))) {
90                 condlog(0, "%s: devmap event #%i dm_task_create error",
91                                 waiter->mapname, waiter->event_nr);
92                 return 1;
93         }
94
95         if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
96                 condlog(0, "%s: devmap event #%i dm_task_set_name error",
97                                 waiter->mapname, waiter->event_nr);
98                 dm_task_destroy(waiter->dmt);
99                 waiter->dmt = NULL;
100                 return 1;
101         }
102
103         if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
104                                                       waiter->event_nr)) {
105                 condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
106                                 waiter->mapname, waiter->event_nr);
107                 dm_task_destroy(waiter->dmt);
108                 waiter->dmt = NULL;
109                 return 1;
110         }
111
112         dm_task_no_open_count(waiter->dmt);
113
114         /* wait */
115         sigemptyset(&set);
116         sigaddset(&set, SIGUSR2);
117         pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
118
119         pthread_testcancel();
120         r = dm_task_run(waiter->dmt);
121         pthread_testcancel();
122
123         pthread_sigmask(SIG_SETMASK, &oldset, NULL);
124         dm_task_destroy(waiter->dmt);
125         waiter->dmt = NULL;
126
127         if (!r) { /* wait interrupted by signal. check for cancellation */
128                 pthread_cleanup_push(cleanup_lock, &waiter_lock);
129                 lock(&waiter_lock);
130                 pthread_testcancel();
131                 lock_cleanup_pop(&waiter_lock);
132                 return 1; /* If we weren't cancelled, just reschedule */
133         }
134
135         waiter->event_nr++;
136
137         /*
138          * upon event ...
139          */
140         while (1) {
141                 condlog(3, "%s: devmap event #%i",
142                                 waiter->mapname, waiter->event_nr);
143
144                 /*
145                  * event might be :
146                  *
147                  * 1) a table reload, which means our mpp structure is
148                  *    obsolete : refresh it through update_multipath()
149                  * 2) a path failed by DM : mark as such through
150                  *    update_multipath()
151                  * 3) map has gone away : stop the thread.
152                  * 4) a path reinstate : nothing to do
153                  * 5) a switch group : nothing to do
154                  */
155                 pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
156                 lock(&waiter->vecs->lock);
157                 pthread_testcancel();
158                 r = update_multipath(waiter->vecs, waiter->mapname, 1);
159                 lock_cleanup_pop(waiter->vecs->lock);
160
161                 if (r) {
162                         condlog(2, "%s: event checker exit",
163                                 waiter->mapname);
164                         return -1; /* stop the thread */
165                 }
166
167                 event_nr = dm_geteventnr(waiter->mapname);
168
169                 if (waiter->event_nr == event_nr)
170                         return 1; /* upon problem reschedule 1s later */
171
172                 waiter->event_nr = event_nr;
173         }
174         return -1; /* never reach there */
175 }
176
177 static void *waitevent (void *et)
178 {
179         int r;
180         struct event_thread *waiter;
181
182         mlockall(MCL_CURRENT | MCL_FUTURE);
183
184         waiter = (struct event_thread *)et;
185         pthread_cleanup_push(free_waiter, et);
186
187         rcu_register_thread();
188         while (1) {
189                 r = waiteventloop(waiter);
190
191                 if (r < 0)
192                         break;
193
194                 sleep(r);
195         }
196
197         pthread_cleanup_pop(1);
198         return NULL;
199 }
200
201 int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
202 {
203         struct event_thread *wp;
204
205         if (!mpp)
206                 return 0;
207
208         wp = alloc_waiter();
209
210         if (!wp)
211                 goto out;
212
213         strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
214         wp->vecs = vecs;
215
216         if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
217                 condlog(0, "%s: cannot create event checker", wp->mapname);
218                 goto out1;
219         }
220         mpp->waiter = wp->thread;
221         condlog(3, "%s: event checker started", wp->mapname);
222
223         return 0;
224 out1:
225         free_waiter(wp);
226         mpp->waiter = (pthread_t)0;
227 out:
228         condlog(0, "failed to start waiter thread");
229         return 1;
230 }