multipathd: fix device creation issues
[multipath-tools/.git] / libmultipath / structs_vec.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4
5 #include "checkers.h"
6 #include "vector.h"
7 #include "defaults.h"
8 #include "debug.h"
9 #include "config.h"
10 #include "structs.h"
11 #include "structs_vec.h"
12 #include "sysfs.h"
13 #include "waiter.h"
14 #include "devmapper.h"
15 #include "dmparser.h"
16 #include "propsel.h"
17 #include "discovery.h"
18 #include "prio.h"
19 #include "configure.h"
20 #include "libdevmapper.h"
21
22 /*
23  * creates or updates mpp->paths reading mpp->pg
24  */
25 int update_mpp_paths(struct multipath *mpp, vector pathvec)
26 {
27         struct pathgroup * pgp;
28         struct path * pp;
29         int i,j;
30
31         if (!mpp || !mpp->pg)
32                 return 0;
33
34         if (!mpp->paths &&
35             !(mpp->paths = vector_alloc()))
36                 return 1;
37
38         vector_foreach_slot (mpp->pg, pgp, i) {
39                 vector_foreach_slot (pgp->paths, pp, j) {
40                         if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
41                             (find_path_by_devt(pathvec, pp->dev_t)) &&
42                             store_path(mpp->paths, pp))
43                                 return 1;
44                 }
45         }
46         return 0;
47 }
48
49 int adopt_paths(vector pathvec, struct multipath *mpp)
50 {
51         int i, ret;
52         struct path * pp;
53         struct config *conf;
54
55         if (!mpp)
56                 return 0;
57
58         if (update_mpp_paths(mpp, pathvec))
59                 return 1;
60
61         vector_foreach_slot (pathvec, pp, i) {
62                 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
63                         condlog(3, "%s: ownership set to %s",
64                                 pp->dev, mpp->alias);
65                         pp->mpp = mpp;
66
67                         if (!mpp->paths && !(mpp->paths = vector_alloc()))
68                                 return 1;
69
70                         if (!find_path_by_dev(mpp->paths, pp->dev) &&
71                             store_path(mpp->paths, pp))
72                                         return 1;
73                         conf = get_multipath_config();
74                         ret = pathinfo(pp, conf,
75                                        DI_PRIO | DI_CHECKER);
76                         put_multipath_config(conf);
77                         if (ret)
78                                 return 1;
79                 }
80         }
81         return 0;
82 }
83
84 void orphan_path(struct path *pp, const char *reason)
85 {
86         condlog(3, "%s: orphan path, %s", pp->dev, reason);
87         pp->mpp = NULL;
88         pp->dmstate = PSTATE_UNDEF;
89         pp->uid_attribute = NULL;
90         pp->getuid = NULL;
91         prio_put(&pp->prio);
92         checker_put(&pp->checker);
93         if (pp->fd >= 0)
94                 close(pp->fd);
95         pp->fd = -1;
96 }
97
98 void orphan_paths(vector pathvec, struct multipath *mpp)
99 {
100         int i;
101         struct path * pp;
102
103         vector_foreach_slot (pathvec, pp, i) {
104                 if (pp->mpp == mpp) {
105                         orphan_path(pp, "map flushed");
106                 }
107         }
108 }
109
110 static void
111 set_multipath_wwid (struct multipath * mpp)
112 {
113         if (strlen(mpp->wwid))
114                 return;
115
116         dm_get_uuid(mpp->alias, mpp->wwid);
117 }
118
119 #define KEEP_WAITER 0
120 #define STOP_WAITER 1
121 #define PURGE_VEC 1
122
123 static void
124 _remove_map (struct multipath * mpp, struct vectors * vecs,
125             int stop_waiter, int purge_vec)
126 {
127         int i;
128
129         condlog(4, "%s: remove multipath map", mpp->alias);
130
131         /*
132          * stop the DM event waiter thread
133          */
134         if (stop_waiter)
135                 stop_waiter_thread(mpp, vecs);
136
137         /*
138          * clear references to this map
139          */
140         orphan_paths(vecs->pathvec, mpp);
141
142         if (purge_vec &&
143             (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
144                 vector_del_slot(vecs->mpvec, i);
145
146         /*
147          * final free
148          */
149         free_multipath(mpp, KEEP_PATHS);
150 }
151
152 void remove_map(struct multipath *mpp, struct vectors *vecs, int purge_vec)
153 {
154         _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
155 }
156
157 void remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
158                                 int purge_vec)
159 {
160         _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
161 }
162
163 static void
164 _remove_maps (struct vectors * vecs, int stop_waiter)
165 {
166         int i;
167         struct multipath * mpp;
168
169         if (!vecs)
170                 return;
171
172         vector_foreach_slot (vecs->mpvec, mpp, i) {
173                 _remove_map(mpp, vecs, stop_waiter, 1);
174                 i--;
175         }
176
177         vector_free(vecs->mpvec);
178         vecs->mpvec = NULL;
179 }
180
181 void remove_maps(struct vectors *vecs)
182 {
183         _remove_maps(vecs, KEEP_WAITER);
184 }
185
186 void remove_maps_and_stop_waiters(struct vectors *vecs)
187 {
188         _remove_maps(vecs, STOP_WAITER);
189 }
190
191 void
192 extract_hwe_from_path(struct multipath * mpp)
193 {
194         struct path * pp = NULL;
195         int i;
196
197         if (mpp->hwe || !mpp->paths)
198                 return;
199
200         condlog(3, "%s: searching paths for valid hwe", mpp->alias);
201         /* doing this in two passes seems like paranoia to me */
202         vector_foreach_slot(mpp->paths, pp, i) {
203                 if (pp->state != PATH_UP)
204                         continue;
205                 if (pp->hwe) {
206                         mpp->hwe = pp->hwe;
207                         return;
208                 }
209         }
210         vector_foreach_slot(mpp->paths, pp, i) {
211                 if (pp->state == PATH_UP)
212                         continue;
213                 if (pp->hwe) {
214                         mpp->hwe = pp->hwe;
215                         return;
216                 }
217         }
218 }
219
220 int
221 update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
222 {
223         char params[PARAMS_SIZE] = {0};
224
225         if (!mpp)
226                 return 1;
227
228         if (dm_get_map(mpp->alias, &mpp->size, params)) {
229                 condlog(3, "%s: cannot get map", mpp->alias);
230                 return 1;
231         }
232
233         if (disassemble_map(pathvec, params, mpp, is_daemon)) {
234                 condlog(3, "%s: cannot disassemble map", mpp->alias);
235                 return 1;
236         }
237
238         return 0;
239 }
240
241 int
242 update_multipath_status (struct multipath *mpp)
243 {
244         char status[PARAMS_SIZE] = {0};
245
246         if (!mpp)
247                 return 1;
248
249         if (dm_get_status(mpp->alias, status)) {
250                 condlog(3, "%s: cannot get status", mpp->alias);
251                 return 1;
252         }
253
254         if (disassemble_status(status, mpp)) {
255                 condlog(3, "%s: cannot disassemble status", mpp->alias);
256                 return 1;
257         }
258
259         return 0;
260 }
261
262 void sync_paths(struct multipath *mpp, vector pathvec)
263 {
264         struct path *pp;
265         struct pathgroup  *pgp;
266         int found, i, j;
267
268         vector_foreach_slot (mpp->paths, pp, i) {
269                 found = 0;
270                 vector_foreach_slot(mpp->pg, pgp, j) {
271                         if (find_slot(pgp->paths, (void *)pp) != -1) {
272                                 found = 1;
273                                 break;
274                         }
275                 }
276                 if (!found) {
277                         condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
278                         vector_del_slot(mpp->paths, i--);
279                         orphan_path(pp, "path removed externally");
280                 }
281         }
282         update_mpp_paths(mpp, pathvec);
283         vector_foreach_slot (mpp->paths, pp, i)
284                 pp->mpp = mpp;
285 }
286
287 int
288 update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
289 {
290         if (!mpp)
291                 return 1;
292
293         update_mpp_paths(mpp, pathvec);
294         condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
295
296         free_multipath_attributes(mpp);
297         free_pgvec(mpp->pg, KEEP_PATHS);
298         mpp->pg = NULL;
299
300         if (update_multipath_table(mpp, pathvec, is_daemon))
301                 return 1;
302         sync_paths(mpp, pathvec);
303
304         if (update_multipath_status(mpp))
305                 return 1;
306
307         return 0;
308 }
309
310 void set_no_path_retry(struct config *conf, struct multipath *mpp)
311 {
312         mpp->retry_tick = 0;
313         mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
314         select_no_path_retry(conf, mpp);
315
316         switch (mpp->no_path_retry) {
317         case NO_PATH_RETRY_UNDEF:
318                 break;
319         case NO_PATH_RETRY_FAIL:
320                 dm_queue_if_no_path(mpp->alias, 0);
321                 break;
322         case NO_PATH_RETRY_QUEUE:
323                 dm_queue_if_no_path(mpp->alias, 1);
324                 break;
325         default:
326                 dm_queue_if_no_path(mpp->alias, 1);
327                 if (mpp->nr_active == 0) {
328                         struct config *conf = get_multipath_config();
329                         /* Enter retry mode */
330                         mpp->retry_tick = mpp->no_path_retry * conf->checkint;
331                         condlog(1, "%s: Entering recovery mode: max_retries=%d",
332                                 mpp->alias, mpp->no_path_retry);
333                         put_multipath_config(conf);
334                 }
335                 break;
336         }
337 }
338
339 int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
340                       int reset, int is_daemon)
341 {
342         struct config *conf;
343
344         if (dm_get_info(mpp->alias, &mpp->dmi)) {
345                 /* Error accessing table */
346                 condlog(3, "%s: cannot access table", mpp->alias);
347                 goto out;
348         }
349
350         if (!dm_map_present(mpp->alias)) {
351                 /* Table has been removed */
352                 condlog(3, "%s: table does not exist", mpp->alias);
353                 goto out;
354         }
355
356         if (update_multipath_strings(mpp, vecs->pathvec, is_daemon)) {
357                 condlog(0, "%s: failed to setup multipath", mpp->alias);
358                 goto out;
359         }
360
361         if (reset) {
362                 conf = get_multipath_config();
363                 select_rr_weight(conf, mpp);
364                 select_pgfailback(conf, mpp);
365                 set_no_path_retry(conf, mpp);
366                 select_flush_on_last_del(conf, mpp);
367                 put_multipath_config(conf);
368                 if (VECTOR_SIZE(mpp->paths) != 0)
369                         dm_cancel_deferred_remove(mpp);
370         }
371
372         return 0;
373 out:
374         remove_map(mpp, vecs, PURGE_VEC);
375         return 1;
376 }
377
378 void
379 sync_map_state(struct multipath *mpp)
380 {
381         struct pathgroup *pgp;
382         struct path *pp;
383         unsigned int i, j;
384
385         if (!mpp->pg)
386                 return;
387
388         vector_foreach_slot (mpp->pg, pgp, i){
389                 vector_foreach_slot (pgp->paths, pp, j){
390                         if (pp->state == PATH_UNCHECKED ||
391                             pp->state == PATH_WILD ||
392                             pp->state == PATH_DELAYED)
393                                 continue;
394                         if (mpp->ghost_delay_tick > 0)
395                                 continue;
396                         if ((pp->dmstate == PSTATE_FAILED ||
397                              pp->dmstate == PSTATE_UNDEF) &&
398                             (pp->state == PATH_UP || pp->state == PATH_GHOST))
399                                 dm_reinstate_path(mpp->alias, pp->dev_t);
400                         else if ((pp->dmstate == PSTATE_ACTIVE ||
401                                   pp->dmstate == PSTATE_UNDEF) &&
402                                  (pp->state == PATH_DOWN ||
403                                   pp->state == PATH_SHAKY))
404                                 dm_fail_path(mpp->alias, pp->dev_t);
405                 }
406         }
407 }
408
409 int
410 update_map (struct multipath *mpp, struct vectors *vecs)
411 {
412         int retries = 3;
413         char params[PARAMS_SIZE] = {0};
414
415 retry:
416         condlog(4, "%s: updating new map", mpp->alias);
417         if (adopt_paths(vecs->pathvec, mpp)) {
418                 condlog(0, "%s: failed to adopt paths for new map update",
419                         mpp->alias);
420                 retries = -1;
421                 goto fail;
422         }
423         verify_paths(mpp, vecs);
424         mpp->flush_on_last_del = FLUSH_UNDEF;
425         mpp->action = ACT_RELOAD;
426
427         extract_hwe_from_path(mpp);
428         if (setup_map(mpp, params, PARAMS_SIZE)) {
429                 condlog(0, "%s: failed to setup new map in update", mpp->alias);
430                 retries = -1;
431                 goto fail;
432         }
433         if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
434                 condlog(0, "%s: map_udate sleep", mpp->alias);
435                 sleep(1);
436                 goto retry;
437         }
438         dm_lib_release();
439
440 fail:
441         if (setup_multipath(vecs, mpp))
442                 return 1;
443
444         sync_map_state(mpp);
445
446         if (retries < 0)
447                 condlog(0, "%s: failed reload in new map update", mpp->alias);
448         return 0;
449 }
450
451 struct multipath *add_map_without_path (struct vectors *vecs, char *alias)
452 {
453         struct multipath * mpp = alloc_multipath();
454         struct config *conf;
455
456         if (!mpp)
457                 return NULL;
458         if (!alias) {
459                 FREE(mpp);
460                 return NULL;
461         }
462
463         mpp->alias = STRDUP(alias);
464
465         if (dm_get_info(mpp->alias, &mpp->dmi)) {
466                 condlog(3, "%s: cannot access table", mpp->alias);
467                 goto out;
468         }
469         set_multipath_wwid(mpp);
470         conf = get_multipath_config();
471         mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
472         put_multipath_config(conf);
473
474         if (update_multipath_table(mpp, vecs->pathvec, 1))
475                 goto out;
476         if (update_multipath_status(mpp))
477                 goto out;
478
479         if (!vector_alloc_slot(vecs->mpvec))
480                 goto out;
481
482         vector_set_slot(vecs->mpvec, mpp);
483
484         if (update_map(mpp, vecs) != 0) /* map removed */
485                 return NULL;
486
487         if (start_waiter_thread(mpp, vecs))
488                 goto out;
489
490         return mpp;
491 out:
492         remove_map(mpp, vecs, PURGE_VEC);
493         return NULL;
494 }
495
496 static void
497 find_existing_alias (struct multipath * mpp,
498                      struct vectors *vecs)
499 {
500         struct multipath * mp;
501         int i;
502
503         vector_foreach_slot (vecs->mpvec, mp, i)
504                 if (strncmp(mp->wwid, mpp->wwid, WWID_SIZE - 1) == 0) {
505                         strncpy(mpp->alias_old, mp->alias, WWID_SIZE - 1);
506                         return;
507                 }
508 }
509
510 struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp,
511                                     int add_vec)
512 {
513         struct multipath * mpp;
514         struct config *conf = NULL;
515
516         if (!strlen(pp->wwid))
517                 return NULL;
518
519         if (!(mpp = alloc_multipath()))
520                 return NULL;
521
522         conf = get_multipath_config();
523         mpp->mpe = find_mpe(conf->mptable, pp->wwid);
524         mpp->hwe = pp->hwe;
525         put_multipath_config(conf);
526
527         strcpy(mpp->wwid, pp->wwid);
528         find_existing_alias(mpp, vecs);
529         if (select_alias(conf, mpp))
530                 goto out;
531         mpp->size = pp->size;
532
533         if (adopt_paths(vecs->pathvec, mpp))
534                 goto out;
535
536         if (add_vec) {
537                 if (!vector_alloc_slot(vecs->mpvec))
538                         goto out;
539
540                 vector_set_slot(vecs->mpvec, mpp);
541         }
542
543         return mpp;
544
545 out:
546         remove_map(mpp, vecs, PURGE_VEC);
547         return NULL;
548 }
549
550 int verify_paths(struct multipath *mpp, struct vectors *vecs)
551 {
552         struct path * pp;
553         int count = 0;
554         int i, j;
555
556         if (!mpp)
557                 return 0;
558
559         vector_foreach_slot (mpp->paths, pp, i) {
560                 /*
561                  * see if path is in sysfs
562                  */
563                 if (sysfs_attr_get_value(pp->udev, "dev",
564                                          pp->dev_t, BLK_DEV_SIZE) < 0) {
565                         if (pp->state != PATH_DOWN) {
566                                 condlog(1, "%s: removing valid path %s in state %d",
567                                         mpp->alias, pp->dev, pp->state);
568                         } else {
569                                 condlog(3, "%s: failed to access path %s",
570                                         mpp->alias, pp->dev);
571                         }
572                         count++;
573                         vector_del_slot(mpp->paths, i);
574                         i--;
575
576                         if ((j = find_slot(vecs->pathvec,
577                                            (void *)pp)) != -1)
578                                 vector_del_slot(vecs->pathvec, j);
579                         free_path(pp);
580                 } else {
581                         condlog(4, "%s: verified path %s dev_t %s",
582                                 mpp->alias, pp->dev, pp->dev_t);
583                 }
584         }
585         return count;
586 }
587
588 int update_multipath (struct vectors *vecs, char *mapname, int reset)
589 {
590         struct multipath *mpp;
591         struct pathgroup  *pgp;
592         struct path *pp;
593         int i, j;
594
595         mpp = find_mp_by_alias(vecs->mpvec, mapname);
596
597         if (!mpp) {
598                 condlog(3, "%s: multipath map not found", mapname);
599                 return 2;
600         }
601
602         if (__setup_multipath(vecs, mpp, reset, 1))
603                 return 1; /* mpp freed in setup_multipath */
604
605         /*
606          * compare checkers states with DM states
607          */
608         vector_foreach_slot (mpp->pg, pgp, i) {
609                 vector_foreach_slot (pgp->paths, pp, j) {
610                         if (pp->dmstate != PSTATE_FAILED)
611                                 continue;
612
613                         if (pp->state != PATH_DOWN) {
614                                 struct config *conf = get_multipath_config();
615                                 int oldstate = pp->state;
616                                 condlog(2, "%s: mark as failed", pp->dev);
617                                 mpp->stat_path_failures++;
618                                 pp->state = PATH_DOWN;
619                                 if (oldstate == PATH_UP ||
620                                     oldstate == PATH_GHOST)
621                                         update_queue_mode_del_path(mpp);
622
623                                 /*
624                                  * if opportune,
625                                  * schedule the next check earlier
626                                  */
627                                 if (pp->tick > conf->checkint)
628                                         pp->tick = conf->checkint;
629                                 put_multipath_config(conf);
630                         }
631                 }
632         }
633         return 0;
634 }
635
636 /*
637  * mpp->no_path_retry:
638  *   -2 (QUEUE) : queue_if_no_path enabled, never turned off
639  *   -1 (FAIL)  : fail_if_no_path
640  *    0 (UNDEF) : nothing
641  *   >0         : queue_if_no_path enabled, turned off after polling n times
642  */
643 void update_queue_mode_del_path(struct multipath *mpp)
644 {
645         if (--mpp->nr_active == 0) {
646                 if (mpp->no_path_retry > 0) {
647                         struct config *conf = get_multipath_config();
648
649                         /*
650                          * Enter retry mode.
651                          * meaning of +1: retry_tick may be decremented in
652                          *                checkerloop before starting retry.
653                          */
654                         mpp->stat_queueing_timeouts++;
655                         mpp->retry_tick = mpp->no_path_retry *
656                                           conf->checkint + 1;
657                         condlog(1, "%s: Entering recovery mode: max_retries=%d",
658                                 mpp->alias, mpp->no_path_retry);
659                         put_multipath_config(conf);
660                 } else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE)
661                         mpp->stat_map_failures++;
662         }
663         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
664 }
665
666 void update_queue_mode_add_path(struct multipath *mpp)
667 {
668         if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
669                 /* come back to normal mode from retry mode */
670                 mpp->retry_tick = 0;
671                 dm_queue_if_no_path(mpp->alias, 1);
672                 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
673                 condlog(1, "%s: Recovered to normal mode", mpp->alias);
674         }
675         condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
676 }