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