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