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