Imported Upstream version 0.8.4
[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->sg_id.host_no = -1;
96                 pp->sg_id.channel = -1;
97                 pp->sg_id.scsi_id = -1;
98                 pp->sg_id.lun = -1;
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 free_path (struct path * pp)
117 {
118         if (!pp)
119                 return;
120
121         if (checker_selected(&pp->checker))
122                 checker_put(&pp->checker);
123
124         if (prio_selected(&pp->prio))
125                 prio_put(&pp->prio);
126
127         if (pp->fd >= 0)
128                 close(pp->fd);
129
130         if (pp->udev) {
131                 udev_device_unref(pp->udev);
132                 pp->udev = NULL;
133         }
134         if (pp->vpd_data)
135                 free(pp->vpd_data);
136
137         vector_free(pp->hwe);
138
139         FREE(pp);
140 }
141
142 void
143 free_pathvec (vector vec, enum free_path_mode free_paths)
144 {
145         int i;
146         struct path * pp;
147
148         if (!vec)
149                 return;
150
151         if (free_paths == FREE_PATHS)
152                 vector_foreach_slot(vec, pp, i)
153                         free_path(pp);
154
155         vector_free(vec);
156 }
157
158 struct pathgroup *
159 alloc_pathgroup (void)
160 {
161         struct pathgroup * pgp;
162
163         pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
164
165         if (!pgp)
166                 return NULL;
167
168         pgp->paths = vector_alloc();
169
170         if (!pgp->paths) {
171                 FREE(pgp);
172                 return NULL;
173         }
174
175         dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops;
176         return pgp;
177 }
178
179 void
180 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
181 {
182         if (!pgp)
183                 return;
184
185         free_pathvec(pgp->paths, free_paths);
186         FREE(pgp);
187 }
188
189 void
190 free_pgvec (vector pgvec, enum free_path_mode free_paths)
191 {
192         int i;
193         struct pathgroup * pgp;
194
195         if (!pgvec)
196                 return;
197
198         vector_foreach_slot(pgvec, pgp, i)
199                 free_pathgroup(pgp, free_paths);
200
201         vector_free(pgvec);
202 }
203
204 struct multipath *
205 alloc_multipath (void)
206 {
207         struct multipath * mpp;
208
209         mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
210
211         if (mpp) {
212                 mpp->bestpg = 1;
213                 mpp->mpcontext = NULL;
214                 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
215                 mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
216                 dm_multipath_to_gen(mpp)->ops = &dm_gen_multipath_ops;
217         }
218         return mpp;
219 }
220
221 void free_multipath_attributes(struct multipath *mpp)
222 {
223         if (!mpp)
224                 return;
225
226         if (mpp->selector) {
227                 FREE(mpp->selector);
228                 mpp->selector = NULL;
229         }
230
231         if (mpp->features) {
232                 FREE(mpp->features);
233                 mpp->features = NULL;
234         }
235
236         if (mpp->hwhandler) {
237                 FREE(mpp->hwhandler);
238                 mpp->hwhandler = NULL;
239         }
240 }
241
242 void
243 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
244 {
245         if (!mpp)
246                 return;
247
248         free_multipath_attributes(mpp);
249
250         if (mpp->alias) {
251                 FREE(mpp->alias);
252                 mpp->alias = NULL;
253         }
254
255         if (mpp->dmi) {
256                 FREE(mpp->dmi);
257                 mpp->dmi = NULL;
258         }
259
260         free_pathvec(mpp->paths, free_paths);
261         free_pgvec(mpp->pg, free_paths);
262         FREE_PTR(mpp->mpcontext);
263         FREE(mpp);
264 }
265
266 void
267 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
268 {
269         int i;
270         struct multipath * mpp;
271
272         if (!mpvec)
273                 return;
274
275         vector_foreach_slot (mpvec, mpp, i) {
276                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
277                         free_multipath(mpp, free_paths);
278                         vector_del_slot(mpvec, i);
279                         return;
280                 }
281         }
282 }
283
284 void
285 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
286 {
287         int i;
288         struct multipath * mpp;
289
290         if (!mpvec)
291                 return;
292
293         vector_foreach_slot (mpvec, mpp, i)
294                 free_multipath(mpp, free_paths);
295
296         vector_free(mpvec);
297 }
298
299 int
300 store_path (vector pathvec, struct path * pp)
301 {
302         int err = 0;
303
304         if (!strlen(pp->dev_t)) {
305                 condlog(2, "%s: Empty device number", pp->dev);
306                 err++;
307         }
308         if (!strlen(pp->dev)) {
309                 condlog(2, "%s: Empty device name", pp->dev_t);
310                 err++;
311         }
312
313         if (err > 1)
314                 return 1;
315
316         if (!vector_alloc_slot(pathvec))
317                 return 1;
318
319         vector_set_slot(pathvec, pp);
320
321         return 0;
322 }
323
324 int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
325 {
326         if (!vector_alloc_slot(mpp->pg))
327                 return 1;
328
329         vector_set_slot(mpp->pg, pgp);
330
331         pgp->mpp = mpp;
332         return 0;
333 }
334
335 int
336 store_hostgroup(vector hostgroupvec, struct host_group * hgp)
337 {
338         if (!vector_alloc_slot(hostgroupvec))
339                 return 1;
340
341         vector_set_slot(hostgroupvec, hgp);
342         return 0;
343 }
344
345 int
346 store_adaptergroup(vector adapters, struct adapter_group * agp)
347 {
348         if (!vector_alloc_slot(adapters))
349                 return 1;
350
351         vector_set_slot(adapters, agp);
352         return 0;
353 }
354
355 struct multipath *
356 find_mp_by_minor (const struct _vector *mpvec, unsigned int minor)
357 {
358         int i;
359         struct multipath * mpp;
360
361         if (!mpvec)
362                 return NULL;
363
364         vector_foreach_slot (mpvec, mpp, i) {
365                 if (!mpp->dmi)
366                         continue;
367
368                 if (mpp->dmi->minor == minor)
369                         return mpp;
370         }
371         return NULL;
372 }
373
374 struct multipath *
375 find_mp_by_wwid (const struct _vector *mpvec, const char * wwid)
376 {
377         int i;
378         struct multipath * mpp;
379
380         if (!mpvec)
381                 return NULL;
382
383         vector_foreach_slot (mpvec, mpp, i)
384                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
385                         return mpp;
386
387         return NULL;
388 }
389
390 struct multipath *
391 find_mp_by_alias (const struct _vector *mpvec, const char * alias)
392 {
393         int i;
394         size_t len;
395         struct multipath * mpp;
396
397         if (!mpvec)
398                 return NULL;
399
400         len = strlen(alias);
401
402         if (!len)
403                 return NULL;
404
405         vector_foreach_slot (mpvec, mpp, i) {
406                 if (strlen(mpp->alias) == len &&
407                     !strncmp(mpp->alias, alias, len))
408                         return mpp;
409         }
410         return NULL;
411 }
412
413 struct multipath *
414 find_mp_by_str (const struct _vector *mpvec, const char * str)
415 {
416         int minor;
417
418         if (sscanf(str, "dm-%d", &minor) == 1)
419                 return find_mp_by_minor(mpvec, minor);
420         else
421                 return find_mp_by_alias(mpvec, str);
422 }
423
424 struct path *
425 find_path_by_dev (const struct _vector *pathvec, const char * dev)
426 {
427         int i;
428         struct path * pp;
429
430         if (!pathvec)
431                 return NULL;
432
433         vector_foreach_slot (pathvec, pp, i)
434                 if (!strcmp(pp->dev, dev))
435                         return pp;
436
437         condlog(4, "%s: dev not found in pathvec", dev);
438         return NULL;
439 }
440
441 struct path *
442 find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
443 {
444         int i;
445         struct path * pp;
446
447         if (!pathvec)
448                 return NULL;
449
450         vector_foreach_slot (pathvec, pp, i)
451                 if (!strcmp(pp->dev_t, dev_t))
452                         return pp;
453
454         condlog(4, "%s: dev_t not found in pathvec", dev_t);
455         return NULL;
456 }
457
458 int pathcountgr(const struct pathgroup *pgp, int state)
459 {
460         struct path *pp;
461         int count = 0;
462         int i;
463
464         vector_foreach_slot (pgp->paths, pp, i)
465                 if ((pp->state == state) || (state == PATH_WILD))
466                         count++;
467
468         return count;
469 }
470
471 int pathcount(const struct multipath *mpp, int state)
472 {
473         struct pathgroup *pgp;
474         int count = 0;
475         int i;
476
477         if (mpp->pg) {
478                 vector_foreach_slot (mpp->pg, pgp, i)
479                         count += pathcountgr(pgp, state);
480         }
481         return count;
482 }
483
484 int count_active_paths(const struct multipath *mpp)
485 {
486         struct pathgroup *pgp;
487         struct path *pp;
488         int count = 0;
489         int i, j;
490
491         if (!mpp->pg)
492                 return 0;
493
494         vector_foreach_slot (mpp->pg, pgp, i) {
495                 vector_foreach_slot (pgp->paths, pp, j) {
496                         if (pp->state == PATH_UP || pp->state == PATH_GHOST)
497                                 count++;
498                 }
499         }
500         return count;
501 }
502
503 int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
504 {
505         int i, j;
506         struct path *pp, *cpp;
507         int pnum = 0, found = 0;
508
509         vector_foreach_slot(pgp->paths, pp, i) {
510                 pnum++;
511                 vector_foreach_slot(cpgp->paths, cpp, j) {
512                         if ((long)pp == (long)cpp) {
513                                 found++;
514                                 break;
515                         }
516                 }
517         }
518
519         return pnum - found;
520 }
521
522 struct path *
523 first_path (const struct multipath * mpp)
524 {
525         struct pathgroup * pgp;
526         if (!mpp->pg)
527                 return NULL;
528         pgp = VECTOR_SLOT(mpp->pg, 0);
529
530         return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
531 }
532
533 int add_feature(char **f, const char *n)
534 {
535         int c = 0, d, l;
536         char *e, *t;
537
538         if (!f)
539                 return 1;
540
541         /* Nothing to do */
542         if (!n || *n == '0')
543                 return 0;
544
545         if (strchr(n, ' ') != NULL) {
546                 condlog(0, "internal error: feature \"%s\" contains spaces", n);
547                 return 1;
548         }
549
550         /* default feature is null */
551         if(!*f)
552         {
553                 l = asprintf(&t, "1 %s", n);
554                 if(l == -1)
555                         return 1;
556
557                 *f = t;
558                 return 0;
559         }
560
561         /* Check if feature is already present */
562         if (strstr(*f, n))
563                 return 0;
564
565         /* Get feature count */
566         c = strtoul(*f, &e, 10);
567         if (*f == e || (*e != ' ' && *e != '\0')) {
568                 condlog(0, "parse error in feature string \"%s\"", *f);
569                 return 1;
570         }
571
572         /* Add 1 digit and 1 space */
573         l = strlen(e) + strlen(n) + 2;
574
575         c++;
576         /* Check if we need more digits for feature count */
577         for (d = c; d >= 10; d /= 10)
578                 l++;
579
580         t = MALLOC(l + 1);
581         if (!t)
582                 return 1;
583
584         /* e: old feature string with leading space, or "" */
585         if (*e == ' ')
586                 while (*(e + 1) == ' ')
587                         e++;
588
589         snprintf(t, l + 1, "%0d%s %s", c, e, n);
590
591         FREE(*f);
592         *f = t;
593
594         return 0;
595 }
596
597 int remove_feature(char **f, const char *o)
598 {
599         int c = 0, d, l;
600         char *e, *p, *n;
601         const char *q;
602
603         if (!f || !*f)
604                 return 1;
605
606         /* Nothing to do */
607         if (!o || *o == '\0')
608                 return 0;
609
610         /* Check if not present */
611         if (!strstr(*f, o))
612                 return 0;
613
614         /* Get feature count */
615         c = strtoul(*f, &e, 10);
616         if (*f == e)
617                 /* parse error */
618                 return 1;
619
620         /* Normalize features */
621         while (*o == ' ') {
622                 o++;
623         }
624         /* Just spaces, return */
625         if (*o == '\0')
626                 return 0;
627         q = o + strlen(o);
628         while (*q == ' ')
629                 q--;
630         d = (int)(q - o);
631
632         /* Update feature count */
633         c--;
634         q = o;
635         while (q[0] != '\0') {
636                 if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
637                         c--;
638                 q++;
639         }
640
641         /* Quick exit if all features have been removed */
642         if (c == 0) {
643                 n = MALLOC(2);
644                 if (!n)
645                         return 1;
646                 strcpy(n, "0");
647                 goto out;
648         }
649
650         /* Search feature to be removed */
651         e = strstr(*f, o);
652         if (!e)
653                 /* Not found, return */
654                 return 0;
655
656         /* Update feature count space */
657         l = strlen(*f) - d;
658         n =  MALLOC(l + 1);
659         if (!n)
660                 return 1;
661
662         /* Copy the feature count */
663         sprintf(n, "%0d", c);
664         /*
665          * Copy existing features up to the feature
666          * about to be removed
667          */
668         p = strchr(*f, ' ');
669         if (!p) {
670                 /* Internal error, feature string inconsistent */
671                 FREE(n);
672                 return 1;
673         }
674         while (*p == ' ')
675                 p++;
676         p--;
677         if (e != p) {
678                 do {
679                         e--;
680                         d++;
681                 } while (*e == ' ');
682                 e++; d--;
683                 strncat(n, p, (size_t)(e - p));
684                 p += (size_t)(e - p);
685         }
686         /* Skip feature to be removed */
687         p += d;
688
689         /* Copy remaining features */
690         if (strlen(p)) {
691                 while (*p == ' ')
692                         p++;
693                 if (strlen(p)) {
694                         p--;
695                         strcat(n, p);
696                 }
697         }
698
699 out:
700         FREE(*f);
701         *f = n;
702
703         return 0;
704 }