Imported Upstream version 0.8.5
[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 free_multipath_attributes(struct multipath *mpp)
238 {
239         if (!mpp)
240                 return;
241
242         if (mpp->selector) {
243                 FREE(mpp->selector);
244                 mpp->selector = NULL;
245         }
246
247         if (mpp->features) {
248                 FREE(mpp->features);
249                 mpp->features = NULL;
250         }
251
252         if (mpp->hwhandler) {
253                 FREE(mpp->hwhandler);
254                 mpp->hwhandler = NULL;
255         }
256 }
257
258 void
259 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
260 {
261         if (!mpp)
262                 return;
263
264         free_multipath_attributes(mpp);
265
266         if (mpp->alias) {
267                 FREE(mpp->alias);
268                 mpp->alias = NULL;
269         }
270
271         if (mpp->dmi) {
272                 FREE(mpp->dmi);
273                 mpp->dmi = NULL;
274         }
275
276         if (!free_paths && mpp->pg) {
277                 struct pathgroup *pgp;
278                 struct path *pp;
279                 int i, j;
280
281                 /*
282                  * Make sure paths carry no reference to this mpp any more
283                  */
284                 vector_foreach_slot(mpp->pg, pgp, i) {
285                         vector_foreach_slot(pgp->paths, pp, j)
286                                 if (pp->mpp == mpp)
287                                         pp->mpp = NULL;
288                 }
289         }
290
291         free_pathvec(mpp->paths, free_paths);
292         free_pgvec(mpp->pg, free_paths);
293         FREE_PTR(mpp->mpcontext);
294         FREE(mpp);
295 }
296
297 void
298 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
299 {
300         int i;
301         struct multipath * mpp;
302
303         if (!mpvec)
304                 return;
305
306         vector_foreach_slot (mpvec, mpp, i) {
307                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
308                         free_multipath(mpp, free_paths);
309                         vector_del_slot(mpvec, i);
310                         return;
311                 }
312         }
313 }
314
315 void
316 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
317 {
318         int i;
319         struct multipath * mpp;
320
321         if (!mpvec)
322                 return;
323
324         vector_foreach_slot (mpvec, mpp, i)
325                 free_multipath(mpp, free_paths);
326
327         vector_free(mpvec);
328 }
329
330 int
331 store_path (vector pathvec, struct path * pp)
332 {
333         int err = 0;
334
335         if (!strlen(pp->dev_t)) {
336                 condlog(2, "%s: Empty device number", pp->dev);
337                 err++;
338         }
339         if (!strlen(pp->dev)) {
340                 condlog(3, "%s: Empty device name", pp->dev_t);
341                 err++;
342         }
343
344         if (err > 1)
345                 return 1;
346
347         if (!vector_alloc_slot(pathvec))
348                 return 1;
349
350         vector_set_slot(pathvec, pp);
351
352         return 0;
353 }
354
355 int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
356 {
357         if (!vector_alloc_slot(mpp->pg))
358                 return 1;
359
360         vector_set_slot(mpp->pg, pgp);
361
362         pgp->mpp = mpp;
363         return 0;
364 }
365
366 int
367 store_hostgroup(vector hostgroupvec, struct host_group * hgp)
368 {
369         if (!vector_alloc_slot(hostgroupvec))
370                 return 1;
371
372         vector_set_slot(hostgroupvec, hgp);
373         return 0;
374 }
375
376 int
377 store_adaptergroup(vector adapters, struct adapter_group * agp)
378 {
379         if (!vector_alloc_slot(adapters))
380                 return 1;
381
382         vector_set_slot(adapters, agp);
383         return 0;
384 }
385
386 struct multipath *
387 find_mp_by_minor (const struct _vector *mpvec, unsigned int minor)
388 {
389         int i;
390         struct multipath * mpp;
391
392         if (!mpvec)
393                 return NULL;
394
395         vector_foreach_slot (mpvec, mpp, i) {
396                 if (!mpp->dmi)
397                         continue;
398
399                 if (mpp->dmi->minor == minor)
400                         return mpp;
401         }
402         return NULL;
403 }
404
405 struct multipath *
406 find_mp_by_wwid (const struct _vector *mpvec, const char * wwid)
407 {
408         int i;
409         struct multipath * mpp;
410
411         if (!mpvec)
412                 return NULL;
413
414         vector_foreach_slot (mpvec, mpp, i)
415                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
416                         return mpp;
417
418         return NULL;
419 }
420
421 struct multipath *
422 find_mp_by_alias (const struct _vector *mpvec, const char * alias)
423 {
424         int i;
425         size_t len;
426         struct multipath * mpp;
427
428         if (!mpvec)
429                 return NULL;
430
431         len = strlen(alias);
432
433         if (!len)
434                 return NULL;
435
436         vector_foreach_slot (mpvec, mpp, i) {
437                 if (strlen(mpp->alias) == len &&
438                     !strncmp(mpp->alias, alias, len))
439                         return mpp;
440         }
441         return NULL;
442 }
443
444 struct multipath *
445 find_mp_by_str (const struct _vector *mpvec, const char * str)
446 {
447         int minor;
448
449         if (sscanf(str, "dm-%d", &minor) == 1)
450                 return find_mp_by_minor(mpvec, minor);
451         else
452                 return find_mp_by_alias(mpvec, str);
453 }
454
455 struct path *
456 find_path_by_dev (const struct _vector *pathvec, const char * dev)
457 {
458         int i;
459         struct path * pp;
460
461         if (!pathvec)
462                 return NULL;
463
464         vector_foreach_slot (pathvec, pp, i)
465                 if (!strcmp(pp->dev, dev))
466                         return pp;
467
468         condlog(4, "%s: dev not found in pathvec", dev);
469         return NULL;
470 }
471
472 struct path *
473 find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
474 {
475         int i;
476         struct path * pp;
477
478         if (!pathvec)
479                 return NULL;
480
481         vector_foreach_slot (pathvec, pp, i)
482                 if (!strcmp(pp->dev_t, dev_t))
483                         return pp;
484
485         condlog(4, "%s: dev_t not found in pathvec", dev_t);
486         return NULL;
487 }
488
489 static int do_pathcount(const struct multipath *mpp, const int *states,
490                         unsigned int nr_states)
491 {
492         struct pathgroup *pgp;
493         struct path *pp;
494         int count = 0;
495         unsigned int i, j, k;
496
497         if (!mpp->pg || !nr_states)
498                 return count;
499
500         vector_foreach_slot (mpp->pg, pgp, i) {
501                 vector_foreach_slot (pgp->paths, pp, j) {
502                         for (k = 0; k < nr_states; k++) {
503                                 if (pp->state == states[k]) {
504                                         count++;
505                                         break;
506                                 }
507                         }
508                 }
509         }
510         return count;
511 }
512
513 int pathcount(const struct multipath *mpp, int state)
514 {
515         return do_pathcount(mpp, &state, 1);
516 }
517
518 int count_active_paths(const struct multipath *mpp)
519 {
520         struct pathgroup *pgp;
521         struct path *pp;
522         int count = 0;
523         int i, j;
524
525         if (!mpp->pg)
526                 return 0;
527
528         vector_foreach_slot (mpp->pg, pgp, i) {
529                 vector_foreach_slot (pgp->paths, pp, j) {
530                         if (pp->state == PATH_UP || pp->state == PATH_GHOST)
531                                 count++;
532                 }
533         }
534         return count;
535 }
536
537 int count_active_pending_paths(const struct multipath *mpp)
538 {
539         int states[] = {PATH_UP, PATH_GHOST, PATH_PENDING};
540
541         return do_pathcount(mpp, states, 3);
542 }
543
544 int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
545 {
546         int i, j;
547         struct path *pp, *cpp;
548         int pnum = 0, found = 0;
549
550         vector_foreach_slot(pgp->paths, pp, i) {
551                 pnum++;
552                 vector_foreach_slot(cpgp->paths, cpp, j) {
553                         if ((long)pp == (long)cpp) {
554                                 found++;
555                                 break;
556                         }
557                 }
558         }
559
560         return pnum - found;
561 }
562
563 struct path *
564 first_path (const struct multipath * mpp)
565 {
566         struct pathgroup * pgp;
567         if (!mpp->pg)
568                 return NULL;
569         pgp = VECTOR_SLOT(mpp->pg, 0);
570
571         return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
572 }
573
574 int add_feature(char **f, const char *n)
575 {
576         int c = 0, d, l;
577         char *e, *t;
578
579         if (!f)
580                 return 1;
581
582         /* Nothing to do */
583         if (!n || *n == '0')
584                 return 0;
585
586         if (strchr(n, ' ') != NULL) {
587                 condlog(0, "internal error: feature \"%s\" contains spaces", n);
588                 return 1;
589         }
590
591         /* default feature is null */
592         if(!*f)
593         {
594                 l = asprintf(&t, "1 %s", n);
595                 if(l == -1)
596                         return 1;
597
598                 *f = t;
599                 return 0;
600         }
601
602         /* Check if feature is already present */
603         if (strstr(*f, n))
604                 return 0;
605
606         /* Get feature count */
607         c = strtoul(*f, &e, 10);
608         if (*f == e || (*e != ' ' && *e != '\0')) {
609                 condlog(0, "parse error in feature string \"%s\"", *f);
610                 return 1;
611         }
612
613         /* Add 1 digit and 1 space */
614         l = strlen(e) + strlen(n) + 2;
615
616         c++;
617         /* Check if we need more digits for feature count */
618         for (d = c; d >= 10; d /= 10)
619                 l++;
620
621         t = MALLOC(l + 1);
622         if (!t)
623                 return 1;
624
625         /* e: old feature string with leading space, or "" */
626         if (*e == ' ')
627                 while (*(e + 1) == ' ')
628                         e++;
629
630         snprintf(t, l + 1, "%0d%s %s", c, e, n);
631
632         FREE(*f);
633         *f = t;
634
635         return 0;
636 }
637
638 int remove_feature(char **f, const char *o)
639 {
640         int c = 0, d, l;
641         char *e, *p, *n;
642         const char *q;
643
644         if (!f || !*f)
645                 return 1;
646
647         /* Nothing to do */
648         if (!o || *o == '\0')
649                 return 0;
650
651         /* Check if not present */
652         if (!strstr(*f, o))
653                 return 0;
654
655         /* Get feature count */
656         c = strtoul(*f, &e, 10);
657         if (*f == e)
658                 /* parse error */
659                 return 1;
660
661         /* Normalize features */
662         while (*o == ' ') {
663                 o++;
664         }
665         /* Just spaces, return */
666         if (*o == '\0')
667                 return 0;
668         q = o + strlen(o);
669         while (*q == ' ')
670                 q--;
671         d = (int)(q - o);
672
673         /* Update feature count */
674         c--;
675         q = o;
676         while (q[0] != '\0') {
677                 if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
678                         c--;
679                 q++;
680         }
681
682         /* Quick exit if all features have been removed */
683         if (c == 0) {
684                 n = MALLOC(2);
685                 if (!n)
686                         return 1;
687                 strcpy(n, "0");
688                 goto out;
689         }
690
691         /* Search feature to be removed */
692         e = strstr(*f, o);
693         if (!e)
694                 /* Not found, return */
695                 return 0;
696
697         /* Update feature count space */
698         l = strlen(*f) - d;
699         n =  MALLOC(l + 1);
700         if (!n)
701                 return 1;
702
703         /* Copy the feature count */
704         sprintf(n, "%0d", c);
705         /*
706          * Copy existing features up to the feature
707          * about to be removed
708          */
709         p = strchr(*f, ' ');
710         if (!p) {
711                 /* Internal error, feature string inconsistent */
712                 FREE(n);
713                 return 1;
714         }
715         while (*p == ' ')
716                 p++;
717         p--;
718         if (e != p) {
719                 do {
720                         e--;
721                         d++;
722                 } while (*e == ' ');
723                 e++; d--;
724                 strncat(n, p, (size_t)(e - p));
725                 p += (size_t)(e - p);
726         }
727         /* Skip feature to be removed */
728         p += d;
729
730         /* Copy remaining features */
731         if (strlen(p)) {
732                 while (*p == ' ')
733                         p++;
734                 if (strlen(p)) {
735                         p--;
736                         strcat(n, p);
737                 }
738         }
739
740 out:
741         FREE(*f);
742         *f = n;
743
744         return 0;
745 }