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