multipathd: minor dmevents polling code cleanups
[multipath-tools/.git] / multipathd / dmevents.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Kiyoshi Ueda, NEC
4  * Copyright (c) 2005 Edward Goggin, EMC
5  * Copyright (c) 2005, 2018 Benjamin Marzinski, Redhat
6  */
7 #include <unistd.h>
8 #include <libdevmapper.h>
9 #include <sys/mman.h>
10 #include <pthread.h>
11 #include <urcu.h>
12 #include <poll.h>
13 #include <sys/ioctl.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <linux/dm-ioctl.h>
18 #include <errno.h>
19
20 #include "vector.h"
21 #include "structs.h"
22 #include "structs_vec.h"
23 #include "devmapper.h"
24 #include "debug.h"
25 #include "main.h"
26 #include "dmevents.h"
27 #include "util.h"
28
29 #ifndef DM_DEV_ARM_POLL
30 #define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD + 1, struct dm_ioctl)
31 #endif
32
33 enum event_actions {
34         EVENT_NOTHING,
35         EVENT_REMOVE,
36         EVENT_UPDATE,
37 };
38
39 struct dev_event {
40         char name[WWID_SIZE];
41         uint32_t evt_nr;
42         enum event_actions action;
43 };
44
45 struct dmevent_waiter {
46         int fd;
47         struct vectors *vecs;
48         vector events;
49         pthread_mutex_t events_lock;
50 };
51
52 static struct dmevent_waiter *waiter;
53
54 int dmevent_poll_supported(void)
55 {
56         unsigned int minv[3] = {4, 37, 0};
57         unsigned int v[3];
58
59         if (dm_drv_version(v))
60                 return 0;
61
62         if (VERSION_GE(v, minv))
63                 return 1;
64         return 0;
65 }
66
67
68 int init_dmevent_waiter(struct vectors *vecs)
69 {
70         if (!vecs) {
71                 condlog(0, "can't create waiter structure. invalid vectors");
72                 goto fail;
73         }
74         waiter = (struct dmevent_waiter *)malloc(sizeof(struct dmevent_waiter));
75         if (!waiter) {
76                 condlog(0, "failed to allocate waiter structure");
77                 goto fail;
78         }
79         memset(waiter, 0, sizeof(struct dmevent_waiter));
80         waiter->events = vector_alloc();
81         if (!waiter->events) {
82                 condlog(0, "failed to allocate waiter events vector");
83                 goto fail_waiter;
84         }
85         waiter->fd = open("/dev/mapper/control", O_RDWR);
86         if (waiter->fd < 0) {
87                 condlog(0, "failed to open /dev/mapper/control for waiter");
88                 goto fail_events;
89         }
90         pthread_mutex_init(&waiter->events_lock, NULL);
91         waiter->vecs = vecs;
92
93         return 0;
94 fail_events:
95         vector_free(waiter->events);
96 fail_waiter:
97         free(waiter);
98 fail:
99         waiter = NULL;
100         return -1;
101 }
102
103 void cleanup_dmevent_waiter(void)
104 {
105         struct dev_event *dev_evt;
106         int i;
107
108         if (!waiter)
109                 return;
110         pthread_mutex_destroy(&waiter->events_lock);
111         close(waiter->fd);
112         vector_foreach_slot(waiter->events, dev_evt, i)
113                 free(dev_evt);
114         vector_free(waiter->events);
115         free(waiter);
116         waiter = NULL;
117 }
118
119 static int arm_dm_event_poll(int fd)
120 {
121         struct dm_ioctl dmi;
122         memset(&dmi, 0, sizeof(dmi));
123         dmi.version[0] = DM_VERSION_MAJOR;
124         dmi.version[1] = DM_VERSION_MINOR;
125         dmi.version[2] = DM_VERSION_PATCHLEVEL;
126         /* This flag currently does nothing. It simply exists to
127          * duplicate the behavior of libdevmapper */
128         dmi.flags = 0x4;
129         dmi.data_start = offsetof(struct dm_ioctl, data);
130         dmi.data_size = sizeof(dmi);
131         return ioctl(fd, DM_DEV_ARM_POLL, &dmi);
132 }
133
134 /*
135  * As of version 4.37.0 device-mapper stores the event number in the
136  * dm_names structure after the name, when DM_DEVICE_LIST is called
137  */
138 static uint32_t dm_event_nr(struct dm_names *n)
139 {
140         return *(uint32_t *)(((uintptr_t)(strchr(n->name, 0) + 1) + 7) & ~7);
141 }
142
143 static int dm_get_events(void)
144 {
145         struct dm_task *dmt;
146         struct dm_names *names;
147         struct dev_event *dev_evt;
148         int i;
149
150         if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
151                 return -1;
152
153         dm_task_no_open_count(dmt);
154
155         if (!dm_task_run(dmt))
156                 goto fail;
157
158         if (!(names = dm_task_get_names(dmt)))
159                 goto fail;
160
161         pthread_mutex_lock(&waiter->events_lock);
162         vector_foreach_slot(waiter->events, dev_evt, i)
163                 dev_evt->action = EVENT_REMOVE;
164         while (names->dev) {
165                 uint32_t event_nr;
166
167                 if (!dm_is_mpath(names->name))
168                         goto next;
169
170                 event_nr = dm_event_nr(names);
171                 vector_foreach_slot(waiter->events, dev_evt, i) {
172                         if (!strcmp(dev_evt->name, names->name)) {
173                                 if (event_nr != dev_evt->evt_nr) {
174                                         dev_evt->evt_nr = event_nr;
175                                         dev_evt->action = EVENT_UPDATE;
176                                 } else
177                                         dev_evt->action = EVENT_NOTHING;
178                                 break;
179                         }
180                 }
181 next:
182                 if (!names->next)
183                         break;
184                 names = (void *)names + names->next;
185         }
186         pthread_mutex_unlock(&waiter->events_lock);
187         dm_task_destroy(dmt);
188         return 0;
189
190 fail:
191         dm_task_destroy(dmt);
192         return -1;
193 }
194
195 /* You must call __setup_multipath() after calling this function, to
196  * deal with any events that came in before the device was added */
197 int watch_dmevents(char *name)
198 {
199         int event_nr;
200         struct dev_event *dev_evt, *old_dev_evt;
201         int i;
202
203         if (!dm_is_mpath(name)) {
204                 condlog(0, "%s: not a multipath device. can't watch events",
205                         name);
206                 return -1;
207         }
208
209         if ((event_nr = dm_geteventnr(name)) < 0)
210                 return -1;
211
212         dev_evt = (struct dev_event *)malloc(sizeof(struct dev_event));
213         if (!dev_evt) {
214                 condlog(0, "%s: can't allocate event waiter structure", name);
215                 return -1;
216         }
217
218         strlcpy(dev_evt->name, name, WWID_SIZE);
219         dev_evt->evt_nr = event_nr;
220         dev_evt->action = EVENT_NOTHING;
221
222         pthread_mutex_lock(&waiter->events_lock);
223         vector_foreach_slot(waiter->events, old_dev_evt, i){
224                 if (!strcmp(dev_evt->name, old_dev_evt->name)) {
225                         /* caller will be updating this device */
226                         old_dev_evt->evt_nr = event_nr;
227                         old_dev_evt->action = EVENT_NOTHING;
228                         pthread_mutex_unlock(&waiter->events_lock);
229                         condlog(2, "%s: already waiting for events on device",
230                                 name);
231                         free(dev_evt);
232                         return 0;
233                 }
234         }
235         if (!vector_alloc_slot(waiter->events)) {
236                 pthread_mutex_unlock(&waiter->events_lock);
237                 free(dev_evt);
238                 return -1;
239         }
240         vector_set_slot(waiter->events, dev_evt);
241         pthread_mutex_unlock(&waiter->events_lock);
242         return 0;
243 }
244
245 void unwatch_all_dmevents(void)
246 {
247         struct dev_event *dev_evt;
248         int i;
249
250         pthread_mutex_lock(&waiter->events_lock);
251         vector_foreach_slot(waiter->events, dev_evt, i)
252                 free(dev_evt);
253         vector_reset(waiter->events);
254         pthread_mutex_unlock(&waiter->events_lock);
255 }
256
257 static void unwatch_dmevents(char *name)
258 {
259         struct dev_event *dev_evt;
260         int i;
261
262         pthread_mutex_lock(&waiter->events_lock);
263         vector_foreach_slot(waiter->events, dev_evt, i) {
264                 if (!strcmp(dev_evt->name, name)) {
265                         vector_del_slot(waiter->events, i);
266                         free(dev_evt);
267                         break;
268                 }
269         }
270         pthread_mutex_unlock(&waiter->events_lock);
271 }
272
273 /*
274  * returns the reschedule delay
275  * negative means *stop*
276  */
277
278 /* poll, arm, update, return */
279 static int dmevent_loop (void)
280 {
281         int r, i = 0;
282         struct pollfd pfd;
283         struct dev_event *dev_evt;
284
285         pfd.fd = waiter->fd;
286         pfd.events = POLLIN;
287         r = poll(&pfd, 1, -1);
288         if (r <= 0) {
289                 condlog(0, "failed polling for dm events: %s", strerror(errno));
290                 /* sleep 1s and hope things get better */
291                 return 1;
292         }
293
294         if (arm_dm_event_poll(waiter->fd) != 0) {
295                 condlog(0, "Cannot re-arm event polling: %s", strerror(errno));
296                 /* sleep 1s and hope things get better */
297                 return 1;
298         }
299
300         if (dm_get_events() != 0) {
301                 condlog(0, "failed getting dm events: %s", strerror(errno));
302                 /* sleep 1s and hope things get better */
303                 return 1;
304         }
305
306         /*
307          * upon event ...
308          */
309
310         while (1) {
311                 int done = 1;
312                 struct dev_event curr_dev;
313
314                 pthread_mutex_lock(&waiter->events_lock);
315                 vector_foreach_slot(waiter->events, dev_evt, i) {
316                         if (dev_evt->action != EVENT_NOTHING) {
317                                 curr_dev = *dev_evt;
318                                 if (dev_evt->action == EVENT_REMOVE) {
319                                         vector_del_slot(waiter->events, i);
320                                         free(dev_evt);
321                                 } else
322                                         dev_evt->action = EVENT_NOTHING;
323                                 done = 0;
324                                 break;
325                         }
326                 }
327                 pthread_mutex_unlock(&waiter->events_lock);
328                 if (done)
329                         return 1;
330
331                 condlog(3, "%s: devmap event #%i", curr_dev.name,
332                         curr_dev.evt_nr);
333
334                 /*
335                  * event might be :
336                  *
337                  * 1) a table reload, which means our mpp structure is
338                  *    obsolete : refresh it through update_multipath()
339                  * 2) a path failed by DM : mark as such through
340                  *    update_multipath()
341                  * 3) map has gone away : stop the thread.
342                  * 4) a path reinstate : nothing to do
343                  * 5) a switch group : nothing to do
344                  */
345                 pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
346                 lock(&waiter->vecs->lock);
347                 pthread_testcancel();
348                 r = 0;
349                 if (curr_dev.action == EVENT_REMOVE)
350                         remove_map_by_alias(curr_dev.name, waiter->vecs, 1);
351                 else
352                         r = update_multipath(waiter->vecs, curr_dev.name, 1);
353                 pthread_cleanup_pop(1);
354
355                 if (r) {
356                         condlog(2, "%s: stopped watching dmevents",
357                                 curr_dev.name);
358                         unwatch_dmevents(curr_dev.name);
359                 }
360         }
361         condlog(0, "dmevent waiter thread unexpectedly quit");
362         return -1; /* never reach there */
363 }
364
365 static void rcu_unregister(void *param)
366 {
367         rcu_unregister_thread();
368 }
369
370 void *wait_dmevents (void *unused)
371 {
372         int r;
373
374
375         if (!waiter) {
376                 condlog(0, "dmevents waiter not intialized");
377                 return NULL;
378         }
379
380         pthread_cleanup_push(rcu_unregister, NULL);
381         rcu_register_thread();
382         mlockall(MCL_CURRENT | MCL_FUTURE);
383
384         while (1) {
385                 r = dmevent_loop();
386
387                 if (r < 0)
388                         break;
389
390                 sleep(r);
391         }
392
393         pthread_cleanup_pop(1);
394         return NULL;
395 }