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