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