Make params variable local
[multipath-tools/.git] / libmultipath / configure.c
1 /*
2  * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Benjamin Marzinski, Redhat
4  * Copyright (c) 2005 Kiyoshi Ueda, NEC
5  * Copyright (c) 2005 Patrick Caulfield, Redhat
6  * Copyright (c) 2005 Edward Goggin, EMC
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <sys/file.h>
14 #include <errno.h>
15 #include <libdevmapper.h>
16
17 #include "checkers.h"
18 #include "vector.h"
19 #include "memory.h"
20 #include "devmapper.h"
21 #include "defaults.h"
22 #include "structs.h"
23 #include "structs_vec.h"
24 #include "dmparser.h"
25 #include "config.h"
26 #include "blacklist.h"
27 #include "propsel.h"
28 #include "discovery.h"
29 #include "debug.h"
30 #include "switchgroup.h"
31 #include "print.h"
32 #include "configure.h"
33 #include "pgpolicies.h"
34 #include "dict.h"
35 #include "alias.h"
36 #include "prio.h"
37 #include "util.h"
38
39 extern int
40 setup_map (struct multipath * mpp, char * params, int params_size)
41 {
42         struct pathgroup * pgp;
43         int i;
44
45         /*
46          * don't bother if devmap size is unknown
47          */
48         if (mpp->size <= 0) {
49                 condlog(3, "%s: devmap size is unknown", mpp->alias);
50                 return 1;
51         }
52
53         /*
54          * free features, selector, and hwhandler properties if they are being reused
55          */
56         free_multipath_attributes(mpp);
57
58         /*
59          * properties selectors
60          */
61         select_pgfailback(mpp);
62         select_pgpolicy(mpp);
63         select_selector(mpp);
64         select_features(mpp);
65         select_hwhandler(mpp);
66         select_rr_weight(mpp);
67         select_minio(mpp);
68         select_no_path_retry(mpp);
69         select_pg_timeout(mpp);
70         select_mode(mpp);
71         select_uid(mpp);
72         select_gid(mpp);
73         select_fast_io_fail(mpp);
74         select_dev_loss(mpp);
75
76         sysfs_set_scsi_tmo(mpp);
77         /*
78          * assign paths to path groups -- start with no groups and all paths
79          * in mpp->paths
80          */
81         if (mpp->pg) {
82                 vector_foreach_slot (mpp->pg, pgp, i)
83                         free_pathgroup(pgp, KEEP_PATHS);
84
85                 vector_free(mpp->pg);
86                 mpp->pg = NULL;
87         }
88         if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp))
89                 return 1;
90
91         mpp->nr_active = pathcount(mpp, PATH_UP);
92
93         /*
94          * ponders each path group and determine highest prio pg
95          * to switch over (default to first)
96          */
97         mpp->bestpg = select_path_group(mpp);
98
99         /*
100          * transform the mp->pg vector of vectors of paths
101          * into a mp->params strings to feed the device-mapper
102          */
103         if (assemble_map(mpp, params, params_size)) {
104                 condlog(0, "%s: problem assembing map", mpp->alias);
105                 return 1;
106         }
107         return 0;
108 }
109
110 static void
111 compute_pgid(struct pathgroup * pgp)
112 {
113         struct path * pp;
114         int i;
115
116         vector_foreach_slot (pgp->paths, pp, i)
117                 pgp->id ^= (long)pp;
118 }
119
120 static int
121 pgcmp (struct multipath * mpp, struct multipath * cmpp)
122 {
123         int i, j;
124         struct pathgroup * pgp;
125         struct pathgroup * cpgp;
126         int r = 0;
127
128         if (!mpp)
129                 return 0;
130
131         vector_foreach_slot (mpp->pg, pgp, i) {
132                 compute_pgid(pgp);
133
134                 vector_foreach_slot (cmpp->pg, cpgp, j) {
135                         if (pgp->id == cpgp->id) {
136                                 r = 0;
137                                 break;
138                         }
139                         r++;
140                 }
141                 if (r)
142                         return r;
143         }
144         return r;
145 }
146
147 static void
148 select_action (struct multipath * mpp, vector curmp, int force_reload)
149 {
150         struct multipath * cmpp;
151
152         cmpp = find_mp_by_alias(curmp, mpp->alias);
153
154         if (!cmpp) {
155                 cmpp = find_mp_by_wwid(curmp, mpp->wwid);
156
157                 if (cmpp) {
158                         condlog(2, "%s: rename %s to %s", mpp->wwid,
159                                 cmpp->alias, mpp->alias);
160                         strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
161                         mpp->action = ACT_RENAME;
162                         return;
163                 }
164                 mpp->action = ACT_CREATE;
165                 condlog(3, "%s: set ACT_CREATE (map does not exist)",
166                         mpp->alias);
167                 return;
168         }
169
170         if (!find_mp_by_wwid(curmp, mpp->wwid)) {
171                 condlog(2, "%s: remove (wwid changed)", cmpp->alias);
172                 dm_flush_map(mpp->alias);
173                 strncpy(cmpp->wwid, mpp->wwid, WWID_SIZE);
174                 drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
175                 mpp->action = ACT_CREATE;
176                 condlog(3, "%s: set ACT_CREATE (map wwid change)",
177                         mpp->alias);
178                 return;
179         }
180
181         if (pathcount(mpp, PATH_UP) == 0) {
182                 mpp->action = ACT_NOTHING;
183                 condlog(3, "%s: set ACT_NOTHING (no usable path)",
184                         mpp->alias);
185                 return;
186         }
187         if (force_reload) {
188                 mpp->action = ACT_RELOAD;
189                 condlog(3, "%s: set ACT_RELOAD (forced by user)",
190                         mpp->alias);
191                 return;
192         }
193         if (cmpp->size != mpp->size) {
194                 mpp->action = ACT_RELOAD;
195                 condlog(3, "%s: set ACT_RELOAD (size change)",
196                         mpp->alias);
197                 return;
198         }
199         if (!mpp->no_path_retry && !mpp->pg_timeout &&
200             (strlen(cmpp->features) != strlen(mpp->features) ||
201              strcmp(cmpp->features, mpp->features))) {
202                 mpp->action =  ACT_RELOAD;
203                 condlog(3, "%s: set ACT_RELOAD (features change)",
204                         mpp->alias);
205                 return;
206         }
207         if (!cmpp->selector || strncmp(cmpp->hwhandler, mpp->hwhandler,
208                     strlen(mpp->hwhandler))) {
209                 mpp->action = ACT_RELOAD;
210                 condlog(3, "%s: set ACT_RELOAD (hwhandler change)",
211                         mpp->alias);
212                 return;
213         }
214         if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector,
215                     strlen(mpp->selector))) {
216                 mpp->action = ACT_RELOAD;
217                 condlog(3, "%s: set ACT_RELOAD (selector change)",
218                         mpp->alias);
219                 return;
220         }
221         if (cmpp->minio != mpp->minio) {
222                 mpp->action = ACT_RELOAD;
223                 condlog(3, "%s: set ACT_RELOAD (minio change, %u->%u)",
224                         mpp->alias, cmpp->minio, mpp->minio);
225                 return;
226         }
227         if (!cmpp->pg || VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
228                 mpp->action = ACT_RELOAD;
229                 condlog(3, "%s: set ACT_RELOAD (path group number change)",
230                         mpp->alias);
231                 return;
232         }
233         if (pgcmp(mpp, cmpp)) {
234                 mpp->action = ACT_RELOAD;
235                 condlog(3, "%s: set ACT_RELOAD (path group topology change)",
236                         mpp->alias);
237                 return;
238         }
239         if (cmpp->nextpg != mpp->bestpg) {
240                 mpp->action = ACT_SWITCHPG;
241                 condlog(3, "%s: set ACT_SWITCHPG (next path group change)",
242                         mpp->alias);
243                 return;
244         }
245         mpp->action = ACT_NOTHING;
246         condlog(3, "%s: set ACT_NOTHING (map unchanged)",
247                 mpp->alias);
248         return;
249 }
250
251 extern int
252 reinstate_paths (struct multipath * mpp)
253 {
254         int i, j;
255         struct pathgroup * pgp;
256         struct path * pp;
257
258         if (!mpp->pg)
259                 return 0;
260
261         vector_foreach_slot (mpp->pg, pgp, i) {
262                 if (!pgp->paths)
263                         continue;
264
265                 vector_foreach_slot (pgp->paths, pp, j) {
266                         if (pp->state != PATH_UP &&
267                             (pgp->status == PGSTATE_DISABLED ||
268                              pgp->status == PGSTATE_ACTIVE))
269                                 continue;
270
271                         if (pp->dmstate == PSTATE_FAILED) {
272                                 if (dm_reinstate_path(mpp->alias, pp->dev_t))
273                                         condlog(0, "%s: error reinstating",
274                                                 pp->dev);
275                         }
276                 }
277         }
278         return 0;
279 }
280
281 static int
282 lock_multipath (struct multipath * mpp, int lock)
283 {
284         struct pathgroup * pgp;
285         struct path * pp;
286         int i, j;
287         int x, y;
288
289         if (!mpp || !mpp->pg)
290                 return 0;
291
292         vector_foreach_slot (mpp->pg, pgp, i) {
293                 if (!pgp->paths)
294                         continue;
295                 vector_foreach_slot(pgp->paths, pp, j) {
296                         if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
297                             errno == EWOULDBLOCK)
298                                 goto fail;
299                         else if (!lock)
300                                 flock(pp->fd, LOCK_UN);
301                 }
302         }
303         return 0;
304 fail:
305         vector_foreach_slot (mpp->pg, pgp, x) {
306                 if (x > i)
307                         return 1;
308                 if (!pgp->paths)
309                         continue;
310                 vector_foreach_slot(pgp->paths, pp, y) {
311                         if (x == i && y >= j)
312                                 return 1;
313                         flock(pp->fd, LOCK_UN);
314                 }
315         }
316         return 1;
317 }
318
319 /*
320  * Return value:
321  */
322 #define DOMAP_RETRY     -1
323 #define DOMAP_FAIL      0
324 #define DOMAP_OK        1
325 #define DOMAP_EXIST     2
326 #define DOMAP_DRY       3
327
328 extern int
329 domap (struct multipath * mpp, char * params)
330 {
331         int r = 0;
332
333         /*
334          * last chance to quit before touching the devmaps
335          */
336         if (conf->dry_run && mpp->action != ACT_NOTHING) {
337                 print_multipath_topology(mpp, conf->verbosity);
338                 return DOMAP_DRY;
339         }
340
341         switch (mpp->action) {
342         case ACT_REJECT:
343         case ACT_NOTHING:
344                 return DOMAP_EXIST;
345
346         case ACT_SWITCHPG:
347                 dm_switchgroup(mpp->alias, mpp->bestpg);
348                 /*
349                  * we may have avoided reinstating paths because there where in
350                  * active or disabled PG. Now that the topology has changed,
351                  * retry.
352                  */
353                 reinstate_paths(mpp);
354                 return DOMAP_EXIST;
355
356         case ACT_CREATE:
357                 if (lock_multipath(mpp, 1)) {
358                         condlog(3, "%s: failed to create map (in use)",
359                                 mpp->alias);
360                         return DOMAP_RETRY;
361                 }
362
363                 if (dm_map_present(mpp->alias)) {
364                         condlog(3, "%s: map already present", mpp->alias);
365                         lock_multipath(mpp, 0);
366                         break;
367                 }
368
369                 r = dm_addmap_create(mpp, params);
370
371                 if (!r)
372                         r = dm_addmap_create_ro(mpp, params);
373
374                 lock_multipath(mpp, 0);
375                 break;
376
377         case ACT_RELOAD:
378                 r = dm_addmap_reload(mpp, params);
379                 if (!r)
380                         r = dm_addmap_reload_ro(mpp, params);
381                 if (r)
382                         r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias);
383                 break;
384
385         case ACT_RESIZE:
386                 r = dm_addmap_reload(mpp, params);
387                 if (!r)
388                         r = dm_addmap_reload_ro(mpp, params);
389                 if (r)
390                         r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1);
391                 break;
392
393         case ACT_RENAME:
394                 r = dm_rename(mpp->alias_old, mpp->alias);
395                 break;
396
397         default:
398                 break;
399         }
400
401         if (r) {
402                 /*
403                  * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
404                  * succeeded
405                  */
406                 if (!conf->daemon) {
407                         /* multipath client mode */
408                         dm_switchgroup(mpp->alias, mpp->bestpg);
409                         if (mpp->action != ACT_NOTHING)
410                                 print_multipath_topology(mpp, conf->verbosity);
411                 } else  {
412                         /* multipath daemon mode */
413                         mpp->stat_map_loads++;
414                         condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
415                                 mpp->size, TGT_MPATH, params);
416                         /*
417                          * Required action is over, reset for the stateful daemon.
418                          * But don't do it for creation as we use in the caller the
419                          * mpp->action to figure out whether to start the watievent checker.
420                          */
421                         if (mpp->action != ACT_CREATE)
422                                 mpp->action = ACT_NOTHING;
423                 }
424                 dm_setgeometry(mpp);
425                 return DOMAP_OK;
426         }
427         return DOMAP_FAIL;
428 }
429
430 static int
431 deadmap (struct multipath * mpp)
432 {
433         int i, j;
434         struct pathgroup * pgp;
435         struct path * pp;
436
437         if (!mpp->pg)
438                 return 1;
439
440         vector_foreach_slot (mpp->pg, pgp, i) {
441                 if (!pgp->paths)
442                         continue;
443
444                 vector_foreach_slot (pgp->paths, pp, j)
445                         if (strlen(pp->dev))
446                                 return 0; /* alive */
447         }
448
449         return 1; /* dead */
450 }
451
452 extern int
453 coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_reload)
454 {
455         int r = 1;
456         int k, i;
457         char empty_buff[WWID_SIZE];
458         char params[PARAMS_SIZE];
459         struct multipath * mpp;
460         struct path * pp1;
461         struct path * pp2;
462         vector curmp = vecs->mpvec;
463         vector pathvec = vecs->pathvec;
464
465         memset(empty_buff, 0, WWID_SIZE);
466
467         if (force_reload) {
468                 vector_foreach_slot (pathvec, pp1, k) {
469                         pp1->mpp = NULL;
470                 }
471         }
472         vector_foreach_slot (pathvec, pp1, k) {
473                 /* skip this path for some reason */
474
475                 /* 1. if path has no unique id or wwid blacklisted */
476                 if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
477                     filter_path(conf, pp1) > 0) {
478                         orphan_path(pp1);
479                         continue;
480                 }
481
482                 /* 2. if path already coalesced */
483                 if (pp1->mpp)
484                         continue;
485
486                 /* 3. if path has disappeared */
487                 if (!pp1->size) {
488                         orphan_path(pp1);
489                         continue;
490                 }
491
492                 /* 4. path is out of scope */
493                 if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
494                         continue;
495
496                 /*
497                  * at this point, we know we really got a new mp
498                  */
499                 mpp = add_map_with_path(vecs, pp1, 0);
500                 if (!mpp)
501                         return 1;
502
503                 if (pp1->priority == PRIO_UNDEF)
504                         mpp->action = ACT_REJECT;
505
506                 if (!mpp->paths) {
507                         condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
508                         remove_map(mpp, vecs, 0);
509                         continue;
510                 }
511
512                 for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
513                         pp2 = VECTOR_SLOT(pathvec, i);
514
515                         if (strcmp(pp1->wwid, pp2->wwid))
516                                 continue;
517
518                         if (!pp2->size)
519                                 continue;
520
521                         if (pp2->size != mpp->size) {
522                                 /*
523                                  * ouch, avoid feeding that to the DM
524                                  */
525                                 condlog(0, "%s: size %llu, expected %llu. "
526                                         "Discard", pp2->dev_t, pp2->size,
527                                         mpp->size);
528                                 mpp->action = ACT_REJECT;
529                         }
530                         if (pp2->priority == PRIO_UNDEF)
531                                 mpp->action = ACT_REJECT;
532                 }
533                 verify_paths(mpp, vecs, NULL);
534
535                 params[0] = '\0';
536                 if (setup_map(mpp, params, PARAMS_SIZE)) {
537                         remove_map(mpp, vecs, 0);
538                         continue;
539                 }
540
541                 if (mpp->action == ACT_UNDEF)
542                         select_action(mpp, curmp, force_reload);
543
544                 r = domap(mpp, params);
545
546                 if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
547                         condlog(3, "%s: domap (%u) failure "
548                                    "for create/reload map",
549                                 mpp->alias, r);
550                         if (r == DOMAP_FAIL) {
551                                 remove_map(mpp, vecs, 0);
552                                 continue;
553                         } else /* if (r == DOMAP_RETRY) */
554                                 return r;
555                 }
556                 if (r == DOMAP_DRY)
557                         continue;
558
559                 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
560                         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
561                                 dm_queue_if_no_path(mpp->alias, 0);
562                         else
563                                 dm_queue_if_no_path(mpp->alias, 1);
564                 }
565                 if (mpp->pg_timeout != PGTIMEOUT_UNDEF) {
566                         if (mpp->pg_timeout == -PGTIMEOUT_NONE)
567                                 dm_set_pg_timeout(mpp->alias,  0);
568                         else
569                                 dm_set_pg_timeout(mpp->alias, mpp->pg_timeout);
570                 }
571
572                 if (newmp) {
573                         if (mpp->action != ACT_REJECT) {
574                                 if (!vector_alloc_slot(newmp))
575                                         return 1;
576                                 vector_set_slot(newmp, mpp);
577                         }
578                         else
579                                 remove_map(mpp, vecs, 0);
580                 }
581         }
582         /*
583          * Flush maps with only dead paths (ie not in sysfs)
584          * Keep maps with only failed paths
585          */
586         if (newmp) {
587                 vector_foreach_slot (newmp, mpp, i) {
588                         char alias[WWID_SIZE];
589                         int j;
590
591                         if (!deadmap(mpp))
592                                 continue;
593
594                         strncpy(alias, mpp->alias, WWID_SIZE);
595
596                         if ((j = find_slot(newmp, (void *)mpp)) != -1)
597                                 vector_del_slot(newmp, j);
598
599                         remove_map(mpp, vecs, 0);
600
601                         if (dm_flush_map(alias))
602                                 condlog(2, "%s: remove failed (dead)",
603                                         alias);
604                         else
605                                 condlog(2, "%s: remove (dead)", alias);
606                 }
607         }
608         return 0;
609 }
610
611 extern char *
612 get_refwwid (char * dev, enum devtypes dev_type, vector pathvec)
613 {
614         struct path * pp;
615         char buff[FILE_NAME_SIZE];
616         char * refwwid = NULL, tmpwwid[WWID_SIZE];
617
618         if (dev_type == DEV_NONE)
619                 return NULL;
620
621         if (dev_type == DEV_DEVNODE) {
622                 basenamecpy(dev, buff);
623                 pp = find_path_by_dev(pathvec, buff);
624                 
625                 if (!pp) {
626                         pp = alloc_path();
627
628                         if (!pp)
629                                 return NULL;
630
631                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
632
633                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
634                                 return NULL;
635
636                         if (store_path(pathvec, pp)) {
637                                 free_path(pp);
638                                 return NULL;
639                         }
640                 }
641                 refwwid = pp->wwid;
642                 goto out;
643         }
644
645         if (dev_type == DEV_DEVT) {
646                 pp = find_path_by_devt(pathvec, dev);
647                 
648                 if (!pp) {
649                         if (devt2devname(buff, dev))
650                                 return NULL;
651
652                         pp = alloc_path();
653
654                         if (!pp)
655                                 return NULL;
656
657                         strncpy(pp->dev, buff, FILE_NAME_SIZE);
658
659                         if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
660                                 return NULL;
661                         
662                         if (store_path(pathvec, pp)) {
663                                 free_path(pp);
664                                 return NULL;
665                         }
666                 }
667                 refwwid = pp->wwid;
668                 goto out;
669         }
670         if (dev_type == DEV_DEVMAP) {
671
672                 if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) {
673                         refwwid = tmpwwid;
674                         goto out;
675                 }
676
677                 /*
678                  * may be a binding
679                  */
680                 refwwid = get_user_friendly_wwid(dev,
681                                                  conf->bindings_file);
682
683                 if (refwwid)
684                         return refwwid;
685
686                 /*
687                  * or may be an alias
688                  */
689                 refwwid = get_mpe_wwid(dev);
690
691                 /*
692                  * or directly a wwid
693                  */
694                 if (!refwwid)
695                         refwwid = dev;
696         }
697 out:
698         if (refwwid && strlen(refwwid))
699                 return STRDUP(refwwid);
700
701         return NULL;
702 }
703