libmultipath: update waiter handling
[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
9 #include "checkers.h"
10 #include "memory.h"
11 #include "vector.h"
12 #include "util.h"
13 #include "structs.h"
14 #include "config.h"
15 #include "debug.h"
16 #include "structs_vec.h"
17 #include "blacklist.h"
18 #include "prio.h"
19
20 struct path *
21 alloc_path (void)
22 {
23         struct path * pp;
24
25         pp = (struct path *)MALLOC(sizeof(struct path));
26
27         if (pp) {
28                 pp->sg_id.host_no = -1;
29                 pp->sg_id.channel = -1;
30                 pp->sg_id.scsi_id = -1;
31                 pp->sg_id.lun = -1;
32                 pp->fd = -1;
33                 pp->priority = PRIO_UNDEF;
34         }
35         return pp;
36 }
37
38 void
39 free_path (struct path * pp)
40 {
41         if (!pp)
42                 return;
43
44         if (checker_selected(&pp->checker))
45                 checker_put(&pp->checker);
46
47         if (pp->fd >= 0)
48                 close(pp->fd);
49
50         FREE(pp);
51 }
52
53 void
54 free_pathvec (vector vec, enum free_path_mode free_paths)
55 {
56         int i;
57         struct path * pp;
58
59         if (!vec)
60                 return;
61
62         if (free_paths == FREE_PATHS)
63                 vector_foreach_slot(vec, pp, i)
64                         free_path(pp);
65
66         vector_free(vec);
67 }
68
69 struct pathgroup *
70 alloc_pathgroup (void)
71 {
72         struct pathgroup * pgp;
73
74         pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
75
76         if (!pgp)
77                 return NULL;
78
79         pgp->paths = vector_alloc();
80
81         if (!pgp->paths) {
82                 FREE(pgp);
83                 pgp = NULL;
84         }
85
86         return pgp;
87 }
88
89 void
90 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
91 {
92         if (!pgp)
93                 return;
94
95         free_pathvec(pgp->paths, free_paths);
96         FREE(pgp);
97 }
98
99 void
100 free_pgvec (vector pgvec, enum free_path_mode free_paths)
101 {
102         int i;
103         struct pathgroup * pgp;
104
105         if (!pgvec)
106                 return;
107
108         vector_foreach_slot(pgvec, pgp, i)
109                 free_pathgroup(pgp, free_paths);
110
111         vector_free(pgvec);
112 }
113
114 struct multipath *
115 alloc_multipath (void)
116 {
117         struct multipath * mpp;
118
119         mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
120
121         if (mpp) {
122                 mpp->bestpg = 1;
123                 mpp->mpcontext = NULL;
124                 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
125         }
126         return mpp;
127 }
128
129 extern void
130 free_multipath_attributes (struct multipath * mpp)
131 {
132         if (!mpp)
133                 return;
134
135         if (mpp->selector &&
136             mpp->selector != conf->selector &&
137             (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
138             (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
139                 FREE(mpp->selector);
140                 mpp->selector = NULL;
141         }
142
143         if (mpp->features) {
144                 FREE(mpp->features);
145                 mpp->features = NULL;
146         }
147
148         if (mpp->hwhandler &&
149             mpp->hwhandler != conf->hwhandler &&
150             (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
151                 FREE(mpp->hwhandler);
152                 mpp->hwhandler = NULL;
153         }
154 }
155
156 void
157 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
158 {
159         if (!mpp)
160                 return;
161
162         free_multipath_attributes(mpp);
163
164         if (mpp->alias) {
165                 FREE(mpp->alias);
166                 mpp->alias = NULL;
167         }
168
169         if (mpp->dmi) {
170                 FREE(mpp->dmi);
171                 mpp->dmi = NULL;
172         }
173
174         free_pathvec(mpp->paths, free_paths);
175         free_pgvec(mpp->pg, free_paths);
176         FREE_PTR(mpp->mpcontext);
177         FREE(mpp);
178 }
179
180 void
181 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
182 {
183         int i;
184         struct multipath * mpp;
185
186         if (!mpvec)
187                 return;
188
189         vector_foreach_slot (mpvec, mpp, i) {
190                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
191                         free_multipath(mpp, free_paths);
192                         vector_del_slot(mpvec, i);
193                         return;
194                 }
195         }
196 }
197
198 void
199 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
200 {
201         int i;
202         struct multipath * mpp;
203
204         if (!mpvec)
205                 return;
206
207         vector_foreach_slot (mpvec, mpp, i)
208                 free_multipath(mpp, free_paths);
209
210         vector_free(mpvec);
211 }
212
213 int
214 store_path (vector pathvec, struct path * pp)
215 {
216         if (!vector_alloc_slot(pathvec))
217                 return 1;
218
219         vector_set_slot(pathvec, pp);
220
221         return 0;
222 }
223
224 int
225 store_pathgroup (vector pgvec, struct pathgroup * pgp)
226 {
227         if (!vector_alloc_slot(pgvec))
228                 return 1;
229
230         vector_set_slot(pgvec, pgp);
231
232         return 0;
233 }
234
235 struct multipath *
236 find_mp_by_minor (vector mpvec, int minor)
237 {
238         int i;
239         struct multipath * mpp;
240
241         if (!mpvec)
242                 return NULL;
243
244         vector_foreach_slot (mpvec, mpp, i) {
245                 if (!mpp->dmi)
246                         continue;
247
248                 if (mpp->dmi->minor == minor)
249                         return mpp;
250         }
251         return NULL;
252 }
253
254 struct multipath *
255 find_mp_by_wwid (vector mpvec, char * wwid)
256 {
257         int i;
258         struct multipath * mpp;
259
260         if (!mpvec)
261                 return NULL;
262
263         vector_foreach_slot (mpvec, mpp, i)
264                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
265                         return mpp;
266
267         return NULL;
268 }
269
270 struct multipath *
271 find_mp_by_alias (vector mpvec, char * alias)
272 {
273         int i;
274         int len;
275         struct multipath * mpp;
276
277         if (!mpvec)
278                 return NULL;
279
280         len = strlen(alias);
281
282         if (!len)
283                 return NULL;
284
285         vector_foreach_slot (mpvec, mpp, i) {
286                 if (strlen(mpp->alias) == len &&
287                     !strncmp(mpp->alias, alias, len))
288                         return mpp;
289         }
290         return NULL;
291 }
292
293 struct multipath *
294 find_mp_by_str (vector mpvec, char * str)
295 {
296         int minor;
297
298         if (sscanf(str, "dm-%d", &minor) == 1)
299                 return find_mp_by_minor(mpvec, minor);
300         else
301                 return find_mp_by_alias(mpvec, str);
302 }
303
304 struct path *
305 find_path_by_dev (vector pathvec, char * dev)
306 {
307         int i;
308         struct path * pp;
309
310         if (!pathvec)
311                 return NULL;
312
313         vector_foreach_slot (pathvec, pp, i)
314                 if (!strcmp(pp->dev, dev))
315                         return pp;
316
317         condlog(3, "%s: not found in pathvec", dev);
318         return NULL;
319 }
320
321 struct path *
322 find_path_by_devt (vector pathvec, char * dev_t)
323 {
324         int i;
325         struct path * pp;
326
327         if (!pathvec)
328                 return NULL;
329
330         vector_foreach_slot (pathvec, pp, i)
331                 if (!strcmp(pp->dev_t, dev_t))
332                         return pp;
333
334         condlog(3, "%s: not found in pathvec", dev_t);
335         return NULL;
336 }
337
338 extern int
339 pathcountgr (struct pathgroup * pgp, int state)
340 {
341         struct path *pp;
342         int count = 0;
343         int i;
344
345         vector_foreach_slot (pgp->paths, pp, i)
346                 if ((pp->state == state) || (state == PATH_WILD))
347                         count++;
348
349         return count;
350 }
351
352 extern int
353 pathcount (struct multipath * mpp, int state)
354 {
355         struct pathgroup *pgp;
356         int count = 0;
357         int i;
358
359         if (mpp->pg) {
360                 vector_foreach_slot (mpp->pg, pgp, i)
361                         count += pathcountgr(pgp, state);
362         }
363         return count;
364 }
365
366 extern int
367 pathcmp (struct pathgroup *pgp, struct pathgroup *cpgp)
368 {
369         int i, j;
370         struct path *pp, *cpp;
371         int pnum = 0, found = 0;
372
373         vector_foreach_slot(pgp->paths, pp, i) {
374                 pnum++;
375                 vector_foreach_slot(cpgp->paths, cpp, j) {
376                         if ((long)pp == (long)cpp) {
377                                 found++;
378                                 break;
379                         }
380                 }
381         }
382
383         return pnum - found;
384 }
385
386 struct path *
387 first_path (struct multipath * mpp)
388 {
389         struct pathgroup * pgp;
390         if (!mpp->pg)
391                 return NULL;
392         pgp = VECTOR_SLOT(mpp->pg, 0);
393
394         return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
395 }
396
397 extern void
398 setup_feature(struct multipath * mpp, char *feature)
399 {
400         if (!strncmp(feature, "queue_if_no_path", 16)) {
401                 if (mpp->no_path_retry <= NO_PATH_RETRY_UNDEF)
402                         mpp->no_path_retry = NO_PATH_RETRY_QUEUE;
403         }
404 }
405
406 extern int
407 add_feature (char **f, char *n)
408 {
409         int c = 0, d, l;
410         char *e, *p, *t;
411
412         if (!f)
413                 return 1;
414
415         /* Nothing to do */
416         if (!n || *n == '0')
417                 return 0;
418
419         /* Check if feature is already present */
420         if (strstr(*f, n))
421                 return 0;
422
423         /* Get feature count */
424         c = strtoul(*f, &e, 10);
425         if (*f == e)
426                 /* parse error */
427                 return 1;
428
429         /* Check if we need to increase feature count space */
430         l = strlen(*f) + strlen(n) + 1;
431
432         /* Count new features */
433         if ((c % 10) == 9)
434                 l++;
435         c++;
436         p = n;
437         while (*p != '\0') {
438                 if (*p == ' ' && p[1] != '\0' && p[1] != ' ') {
439                         if ((c % 10) == 9)
440                                 l++;
441                         c++;
442                 }
443                 p++;
444         }
445
446         t = MALLOC(l + 1);
447         if (!t)
448                 return 1;
449
450         memset(t, 0, l + 1);
451
452         /* Update feature count */
453         d = c;
454         l = 1;
455         while (d > 9) {
456                 d /= 10;
457                 l++;
458         }
459         p = t;
460         snprintf(p, l + 2, "%0d ", c);
461
462         /* Copy the feature string */
463         p = strchr(*f, ' ');
464         if (p) {
465                 while (*p == ' ')
466                         p++;
467                 strcat(t, p);
468                 strcat(t, " ");
469         } else {
470                 p = t + strlen(t);
471         }
472         strcat(t, n);
473
474         FREE(*f);
475         *f = t;
476
477         return 0;
478 }
479
480 extern int
481 remove_feature(char **f, char *o)
482 {
483         int c = 0, d, l;
484         char *e, *p, *n;
485
486         if (!f || !*f)
487                 return 1;
488
489         /* Nothing to do */
490         if (!o || *o == '\0')
491                 return 0;
492
493         /* Check if not present */
494         if (!strstr(*f, o))
495                 return 0;
496
497         /* Get feature count */
498         c = strtoul(*f, &e, 10);
499         if (*f == e)
500                 /* parse error */
501                 return 1;
502
503         /* Normalize features */
504         while (*o == ' ') {
505                 o++;
506         }
507         /* Just spaces, return */
508         if (*o == '\0')
509                 return 0;
510         e = o + strlen(o);
511         while (*e == ' ')
512                 e--;
513         d = (int)(e - o);
514
515         /* Update feature count */
516         c--;
517         p = o;
518         while (p[0] != '\0') {
519                 if (p[0] == ' ' && p[1] != ' ' && p[1] != '\0')
520                         c--;
521                 p++;
522         }
523
524         /* Quick exit if all features have been removed */
525         if (c == 0) {
526                 n = MALLOC(2);
527                 if (!n)
528                         return 1;
529                 strcpy(n, "0");
530                 goto out;
531         }
532
533         /* Search feature to be removed */
534         e = strstr(*f, o);
535         if (!e)
536                 /* Not found, return */
537                 return 0;
538
539         /* Update feature count space */
540         l = strlen(*f) - d;
541         n =  MALLOC(l + 1);
542         if (!n)
543                 return 1;
544
545         /* Copy the feature count */
546         sprintf(n, "%0d", c);
547         /*
548          * Copy existing features up to the feature
549          * about to be removed
550          */
551         p = strchr(*f, ' ');
552         while (*p == ' ')
553                 p++;
554         p--;
555         if (e != p) {
556                 do {
557                         e--;
558                         d++;
559                 } while (*e == ' ');
560                 e++; d--;
561                 strncat(n, p, (size_t)(e - p));
562                 p += (size_t)(e - p);
563         }
564         /* Skip feature to be removed */
565         p += d;
566
567         /* Copy remaining features */
568         if (strlen(p)) {
569                 while (*p == ' ')
570                         p++;
571                 if (strlen(p)) {
572                         p--;
573                         strcat(n, p);
574                 }
575         }
576
577 out:
578         FREE(*f);
579         *f = n;
580
581         return 0;
582 }
583