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