d1b8aa33d9fe1c92e6831a8de9b87b1de985751e
[platform/upstream/multipath-tools.git] / libmultipath / structs.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2004 Stefan Bader, IBM
4  */
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <libdevmapper.h>
8 #include <libudev.h>
9
10 #include "checkers.h"
11 #include "vector.h"
12 #include "util.h"
13 #include "structs.h"
14 #include "config.h"
15 #include "debug.h"
16 #include "structs_vec.h"
17 #include "blacklist.h"
18 #include "prio.h"
19 #include "prioritizers/alua_spc3.h"
20 #include "dm-generic.h"
21
22 struct adapter_group *
23 alloc_adaptergroup(void)
24 {
25         struct adapter_group *agp;
26
27         agp = (struct adapter_group *)calloc(1, sizeof(struct adapter_group));
28
29         if (!agp)
30                 return NULL;
31
32         agp->host_groups = vector_alloc();
33         if (!agp->host_groups) {
34                 free(agp);
35                 agp = NULL;
36         }
37         return agp;
38 }
39
40 void free_adaptergroup(vector adapters)
41 {
42         int i;
43         struct adapter_group *agp;
44
45         vector_foreach_slot(adapters, agp, i) {
46                 free_hostgroup(agp->host_groups);
47                 free(agp);
48         }
49         vector_free(adapters);
50 }
51
52 void free_hostgroup(vector hostgroups)
53 {
54         int i;
55         struct host_group *hgp;
56
57         if (!hostgroups)
58                 return;
59
60         vector_foreach_slot(hostgroups, hgp, i) {
61                 vector_free(hgp->paths);
62                 free(hgp);
63         }
64         vector_free(hostgroups);
65 }
66
67 struct host_group *
68 alloc_hostgroup(void)
69 {
70         struct host_group *hgp;
71
72         hgp = (struct host_group *)calloc(1, sizeof(struct host_group));
73
74         if (!hgp)
75                 return NULL;
76
77         hgp->paths = vector_alloc();
78
79         if (!hgp->paths) {
80                 free(hgp);
81                 hgp = NULL;
82         }
83         return hgp;
84 }
85
86 struct path *
87 alloc_path (void)
88 {
89         struct path * pp;
90
91         pp = (struct path *)calloc(1, sizeof(struct path));
92
93         if (pp) {
94                 pp->initialized = INIT_NEW;
95                 pp->sg_id.host_no = -1;
96                 pp->sg_id.channel = -1;
97                 pp->sg_id.scsi_id = -1;
98                 pp->sg_id.lun = SCSI_INVALID_LUN;
99                 pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
100                 pp->fd = -1;
101                 pp->tpgs = TPGS_UNDEF;
102                 pp->priority = PRIO_UNDEF;
103                 pp->checkint = CHECKINT_UNDEF;
104                 checker_clear(&pp->checker);
105                 dm_path_to_gen(pp)->ops = &dm_gen_path_ops;
106                 pp->hwe = vector_alloc();
107                 if (pp->hwe == NULL) {
108                         free(pp);
109                         return NULL;
110                 }
111         }
112         return pp;
113 }
114
115 void
116 uninitialize_path(struct path *pp)
117 {
118         if (!pp)
119                 return;
120
121         pp->dmstate = PSTATE_UNDEF;
122         pp->uid_attribute = NULL;
123         pp->getuid = NULL;
124
125         if (checker_selected(&pp->checker))
126                 checker_put(&pp->checker);
127
128         if (prio_selected(&pp->prio))
129                 prio_put(&pp->prio);
130
131         if (pp->fd >= 0) {
132                 close(pp->fd);
133                 pp->fd = -1;
134         }
135 }
136
137 void
138 free_path (struct path * pp)
139 {
140         if (!pp)
141                 return;
142
143         uninitialize_path(pp);
144
145         if (pp->udev) {
146                 udev_device_unref(pp->udev);
147                 pp->udev = NULL;
148         }
149         if (pp->vpd_data)
150                 free(pp->vpd_data);
151
152         vector_free(pp->hwe);
153
154         free(pp);
155 }
156
157 void
158 free_pathvec (vector vec, enum free_path_mode free_paths)
159 {
160         int i;
161         struct path * pp;
162
163         if (!vec)
164                 return;
165
166         if (free_paths == FREE_PATHS)
167                 vector_foreach_slot(vec, pp, i)
168                         free_path(pp);
169
170         vector_free(vec);
171 }
172
173 struct pathgroup *
174 alloc_pathgroup (void)
175 {
176         struct pathgroup * pgp;
177
178         pgp = (struct pathgroup *)calloc(1, sizeof(struct pathgroup));
179
180         if (!pgp)
181                 return NULL;
182
183         pgp->paths = vector_alloc();
184
185         if (!pgp->paths) {
186                 free(pgp);
187                 return NULL;
188         }
189
190         dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops;
191         return pgp;
192 }
193
194 void
195 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
196 {
197         if (!pgp)
198                 return;
199
200         free_pathvec(pgp->paths, free_paths);
201         free(pgp);
202 }
203
204 void
205 free_pgvec (vector pgvec, enum free_path_mode free_paths)
206 {
207         int i;
208         struct pathgroup * pgp;
209
210         if (!pgvec)
211                 return;
212
213         vector_foreach_slot(pgvec, pgp, i)
214                 free_pathgroup(pgp, free_paths);
215
216         vector_free(pgvec);
217 }
218
219 struct multipath *
220 alloc_multipath (void)
221 {
222         struct multipath * mpp;
223
224         mpp = (struct multipath *)calloc(1, sizeof(struct multipath));
225
226         if (mpp) {
227                 mpp->bestpg = 1;
228                 mpp->mpcontext = NULL;
229                 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
230                 mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
231                 dm_multipath_to_gen(mpp)->ops = &dm_gen_multipath_ops;
232         }
233         return mpp;
234 }
235
236 void *set_mpp_hwe(struct multipath *mpp, const struct path *pp)
237 {
238         if (!mpp || !pp || !pp->hwe)
239                 return NULL;
240         if (mpp->hwe)
241                 return mpp->hwe;
242         mpp->hwe = vector_convert(NULL, pp->hwe,
243                                   struct hwentry, identity);
244         return mpp->hwe;
245 }
246
247 void free_multipath_attributes(struct multipath *mpp)
248 {
249         if (!mpp)
250                 return;
251
252         if (mpp->selector) {
253                 free(mpp->selector);
254                 mpp->selector = NULL;
255         }
256
257         if (mpp->features) {
258                 free(mpp->features);
259                 mpp->features = NULL;
260         }
261
262         if (mpp->hwhandler) {
263                 free(mpp->hwhandler);
264                 mpp->hwhandler = NULL;
265         }
266 }
267
268 void
269 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
270 {
271         if (!mpp)
272                 return;
273
274         free_multipath_attributes(mpp);
275
276         if (mpp->alias) {
277                 free(mpp->alias);
278                 mpp->alias = NULL;
279         }
280
281         if (mpp->dmi) {
282                 free(mpp->dmi);
283                 mpp->dmi = NULL;
284         }
285
286         if (!free_paths && mpp->pg) {
287                 struct pathgroup *pgp;
288                 struct path *pp;
289                 int i, j;
290
291                 /*
292                  * Make sure paths carry no reference to this mpp any more
293                  */
294                 vector_foreach_slot(mpp->pg, pgp, i) {
295                         vector_foreach_slot(pgp->paths, pp, j)
296                                 if (pp->mpp == mpp)
297                                         pp->mpp = NULL;
298                 }
299         }
300
301         free_pathvec(mpp->paths, free_paths);
302         free_pgvec(mpp->pg, free_paths);
303         if (mpp->hwe) {
304                 vector_free(mpp->hwe);
305                 mpp->hwe = NULL;
306         }
307         free(mpp->mpcontext);
308         free(mpp);
309 }
310
311 void
312 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
313 {
314         int i;
315         struct multipath * mpp;
316
317         if (!mpvec)
318                 return;
319
320         vector_foreach_slot (mpvec, mpp, i) {
321                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
322                         free_multipath(mpp, free_paths);
323                         vector_del_slot(mpvec, i);
324                         return;
325                 }
326         }
327 }
328
329 void
330 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
331 {
332         int i;
333         struct multipath * mpp;
334
335         if (!mpvec)
336                 return;
337
338         vector_foreach_slot (mpvec, mpp, i)
339                 free_multipath(mpp, free_paths);
340
341         vector_free(mpvec);
342 }
343
344 int
345 store_path (vector pathvec, struct path * pp)
346 {
347         int err = 0;
348
349         if (!strlen(pp->dev_t)) {
350                 condlog(2, "%s: Empty device number", pp->dev);
351                 err++;
352         }
353         if (!strlen(pp->dev)) {
354                 condlog(3, "%s: Empty device name", pp->dev_t);
355                 err++;
356         }
357
358         if (err > 1)
359                 return 1;
360
361         if (!vector_alloc_slot(pathvec))
362                 return 1;
363
364         vector_set_slot(pathvec, pp);
365
366         return 0;
367 }
368
369 int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
370 {
371         if (!vector_alloc_slot(mpp->pg))
372                 return 1;
373
374         vector_set_slot(mpp->pg, pgp);
375
376         pgp->mpp = mpp;
377         return 0;
378 }
379
380 int
381 store_hostgroup(vector hostgroupvec, struct host_group * hgp)
382 {
383         if (!vector_alloc_slot(hostgroupvec))
384                 return 1;
385
386         vector_set_slot(hostgroupvec, hgp);
387         return 0;
388 }
389
390 int
391 store_adaptergroup(vector adapters, struct adapter_group * agp)
392 {
393         if (!vector_alloc_slot(adapters))
394                 return 1;
395
396         vector_set_slot(adapters, agp);
397         return 0;
398 }
399
400 struct multipath *
401 find_mp_by_minor (const struct _vector *mpvec, unsigned int minor)
402 {
403         int i;
404         struct multipath * mpp;
405
406         if (!mpvec)
407                 return NULL;
408
409         vector_foreach_slot (mpvec, mpp, i) {
410                 if (!mpp->dmi)
411                         continue;
412
413                 if (mpp->dmi->minor == minor)
414                         return mpp;
415         }
416         return NULL;
417 }
418
419 struct multipath *
420 find_mp_by_wwid (const struct _vector *mpvec, const char * wwid)
421 {
422         int i;
423         struct multipath * mpp;
424
425         if (!mpvec)
426                 return NULL;
427
428         vector_foreach_slot (mpvec, mpp, i)
429                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
430                         return mpp;
431
432         return NULL;
433 }
434
435 struct multipath *
436 find_mp_by_alias (const struct _vector *mpvec, const char * alias)
437 {
438         int i;
439         size_t len;
440         struct multipath * mpp;
441
442         if (!mpvec)
443                 return NULL;
444
445         len = strlen(alias);
446
447         if (!len)
448                 return NULL;
449
450         vector_foreach_slot (mpvec, mpp, i) {
451                 if (strlen(mpp->alias) == len &&
452                     !strncmp(mpp->alias, alias, len))
453                         return mpp;
454         }
455         return NULL;
456 }
457
458 struct multipath *
459 find_mp_by_str (const struct _vector *mpvec, const char * str)
460 {
461         int minor;
462
463         if (sscanf(str, "dm-%d", &minor) == 1)
464                 return find_mp_by_minor(mpvec, minor);
465         else
466                 return find_mp_by_alias(mpvec, str);
467 }
468
469 struct path *
470 find_path_by_dev (const struct _vector *pathvec, const char *dev)
471 {
472         int i;
473         struct path * pp;
474
475         if (!pathvec || !dev)
476                 return NULL;
477
478         vector_foreach_slot (pathvec, pp, i)
479                 if (!strcmp(pp->dev, dev))
480                         return pp;
481
482         condlog(4, "%s: dev not found in pathvec", dev);
483         return NULL;
484 }
485
486 struct path *
487 find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
488 {
489         int i;
490         struct path * pp;
491
492         if (!pathvec)
493                 return NULL;
494
495         vector_foreach_slot (pathvec, pp, i)
496                 if (!strcmp(pp->dev_t, dev_t))
497                         return pp;
498
499         condlog(4, "%s: dev_t not found in pathvec", dev_t);
500         return NULL;
501 }
502
503 static int do_pathcount(const struct multipath *mpp, const int *states,
504                         unsigned int nr_states)
505 {
506         struct pathgroup *pgp;
507         struct path *pp;
508         int count = 0;
509         unsigned int i, j, k;
510
511         if (!mpp->pg || !nr_states)
512                 return count;
513
514         vector_foreach_slot (mpp->pg, pgp, i) {
515                 vector_foreach_slot (pgp->paths, pp, j) {
516                         for (k = 0; k < nr_states; k++) {
517                                 if (pp->state == states[k]) {
518                                         count++;
519                                         break;
520                                 }
521                         }
522                 }
523         }
524         return count;
525 }
526
527 int pathcount(const struct multipath *mpp, int state)
528 {
529         return do_pathcount(mpp, &state, 1);
530 }
531
532 int count_active_paths(const struct multipath *mpp)
533 {
534         struct pathgroup *pgp;
535         struct path *pp;
536         int count = 0;
537         int i, j;
538
539         if (!mpp->pg)
540                 return 0;
541
542         vector_foreach_slot (mpp->pg, pgp, i) {
543                 vector_foreach_slot (pgp->paths, pp, j) {
544                         if (pp->state == PATH_UP || pp->state == PATH_GHOST)
545                                 count++;
546                 }
547         }
548         return count;
549 }
550
551 int count_active_pending_paths(const struct multipath *mpp)
552 {
553         int states[] = {PATH_UP, PATH_GHOST, PATH_PENDING};
554
555         return do_pathcount(mpp, states, 3);
556 }
557
558 int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
559 {
560         int i, j;
561         struct path *pp, *cpp;
562         int pnum = 0, found = 0;
563
564         vector_foreach_slot(pgp->paths, pp, i) {
565                 pnum++;
566                 vector_foreach_slot(cpgp->paths, cpp, j) {
567                         if ((long)pp == (long)cpp) {
568                                 found++;
569                                 break;
570                         }
571                 }
572         }
573
574         return pnum - found;
575 }
576
577 struct path *
578 first_path (const struct multipath * mpp)
579 {
580         struct pathgroup * pgp;
581         if (!mpp->pg)
582                 return NULL;
583         pgp = VECTOR_SLOT(mpp->pg, 0);
584
585         return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
586 }
587
588 int add_feature(char **f, const char *n)
589 {
590         int c = 0, d, l;
591         char *e, *t;
592
593         if (!f)
594                 return 1;
595
596         /* Nothing to do */
597         if (!n || *n == '0')
598                 return 0;
599
600         if (strchr(n, ' ') != NULL) {
601                 condlog(0, "internal error: feature \"%s\" contains spaces", n);
602                 return 1;
603         }
604
605         /* default feature is null */
606         if(!*f)
607         {
608                 l = asprintf(&t, "1 %s", n);
609                 if(l == -1)
610                         return 1;
611
612                 *f = t;
613                 return 0;
614         }
615
616         /* Check if feature is already present */
617         if (strstr(*f, n))
618                 return 0;
619
620         /* Get feature count */
621         c = strtoul(*f, &e, 10);
622         if (*f == e || (*e != ' ' && *e != '\0')) {
623                 condlog(0, "parse error in feature string \"%s\"", *f);
624                 return 1;
625         }
626
627         /* Add 1 digit and 1 space */
628         l = strlen(e) + strlen(n) + 2;
629
630         c++;
631         /* Check if we need more digits for feature count */
632         for (d = c; d >= 10; d /= 10)
633                 l++;
634
635         t = calloc(1, l + 1);
636         if (!t)
637                 return 1;
638
639         /* e: old feature string with leading space, or "" */
640         if (*e == ' ')
641                 while (*(e + 1) == ' ')
642                         e++;
643
644         snprintf(t, l + 1, "%0d%s %s", c, e, n);
645
646         free(*f);
647         *f = t;
648
649         return 0;
650 }
651
652 int remove_feature(char **f, const char *o)
653 {
654         int c = 0, d, l;
655         char *e, *p, *n;
656         const char *q;
657
658         if (!f || !*f)
659                 return 1;
660
661         /* Nothing to do */
662         if (!o || *o == '\0')
663                 return 0;
664
665         /* Check if not present */
666         if (!strstr(*f, o))
667                 return 0;
668
669         /* Get feature count */
670         c = strtoul(*f, &e, 10);
671         if (*f == e)
672                 /* parse error */
673                 return 1;
674
675         /* Normalize features */
676         while (*o == ' ') {
677                 o++;
678         }
679         /* Just spaces, return */
680         if (*o == '\0')
681                 return 0;
682         q = o + strlen(o);
683         while (*q == ' ')
684                 q--;
685         d = (int)(q - o);
686
687         /* Update feature count */
688         c--;
689         q = o;
690         while (q[0] != '\0') {
691                 if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
692                         c--;
693                 q++;
694         }
695
696         /* Quick exit if all features have been removed */
697         if (c == 0) {
698                 n = malloc(2);
699                 if (!n)
700                         return 1;
701                 strcpy(n, "0");
702                 goto out;
703         }
704
705         /* Search feature to be removed */
706         e = strstr(*f, o);
707         if (!e)
708                 /* Not found, return */
709                 return 0;
710
711         /* Update feature count space */
712         l = strlen(*f) - d;
713         n =  malloc(l + 1);
714         if (!n)
715                 return 1;
716
717         /* Copy the feature count */
718         sprintf(n, "%0d", c);
719         /*
720          * Copy existing features up to the feature
721          * about to be removed
722          */
723         p = strchr(*f, ' ');
724         if (!p) {
725                 /* Internal error, feature string inconsistent */
726                 free(n);
727                 return 1;
728         }
729         while (*p == ' ')
730                 p++;
731         p--;
732         if (e != p) {
733                 do {
734                         e--;
735                         d++;
736                 } while (*e == ' ');
737                 e++; d--;
738                 strncat(n, p, (size_t)(e - p));
739                 p += (size_t)(e - p);
740         }
741         /* Skip feature to be removed */
742         p += d;
743
744         /* Copy remaining features */
745         if (strlen(p)) {
746                 while (*p == ' ')
747                         p++;
748                 if (strlen(p)) {
749                         p--;
750                         strcat(n, p);
751                 }
752         }
753
754 out:
755         free(*f);
756         *f = n;
757
758         return 0;
759 }