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