2 * Copyright (c) 2004, 2005 Christophe Varoqui
3 * Copyright (c) 2004 Stefan Bader, IBM
7 #include <libdevmapper.h>
16 #include "structs_vec.h"
17 #include "blacklist.h"
19 #include "prioritizers/alua_spc3.h"
20 #include "dm-generic.h"
22 struct adapter_group *
23 alloc_adaptergroup(void)
25 struct adapter_group *agp;
27 agp = (struct adapter_group *)calloc(1, sizeof(struct adapter_group));
32 agp->host_groups = vector_alloc();
33 if (!agp->host_groups) {
40 void free_adaptergroup(vector adapters)
43 struct adapter_group *agp;
45 vector_foreach_slot(adapters, agp, i) {
46 free_hostgroup(agp->host_groups);
49 vector_free(adapters);
52 void free_hostgroup(vector hostgroups)
55 struct host_group *hgp;
60 vector_foreach_slot(hostgroups, hgp, i) {
61 vector_free(hgp->paths);
64 vector_free(hostgroups);
70 struct host_group *hgp;
72 hgp = (struct host_group *)calloc(1, sizeof(struct host_group));
77 hgp->paths = vector_alloc();
91 pp = (struct path *)calloc(1, sizeof(struct path));
94 pp->initialized = INIT_NEW;
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 = SCSI_INVALID_LUN;
99 pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
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) {
116 uninitialize_path(struct path *pp)
121 pp->dmstate = PSTATE_UNDEF;
122 pp->uid_attribute = NULL;
125 if (checker_selected(&pp->checker))
126 checker_put(&pp->checker);
128 if (prio_selected(&pp->prio))
138 free_path (struct path * pp)
143 uninitialize_path(pp);
146 udev_device_unref(pp->udev);
152 vector_free(pp->hwe);
158 free_pathvec (vector vec, enum free_path_mode free_paths)
166 if (free_paths == FREE_PATHS)
167 vector_foreach_slot(vec, pp, i)
174 alloc_pathgroup (void)
176 struct pathgroup * pgp;
178 pgp = (struct pathgroup *)calloc(1, sizeof(struct pathgroup));
183 pgp->paths = vector_alloc();
190 dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops;
195 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
200 free_pathvec(pgp->paths, free_paths);
205 free_pgvec (vector pgvec, enum free_path_mode free_paths)
208 struct pathgroup * pgp;
213 vector_foreach_slot(pgvec, pgp, i)
214 free_pathgroup(pgp, free_paths);
220 alloc_multipath (void)
222 struct multipath * mpp;
224 mpp = (struct multipath *)calloc(1, sizeof(struct multipath));
228 mpp->mpcontext = NULL;
229 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
230 mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
231 dm_multipath_to_gen(mpp)->ops = &dm_gen_multipath_ops;
236 void *set_mpp_hwe(struct multipath *mpp, const struct path *pp)
238 if (!mpp || !pp || !pp->hwe)
242 mpp->hwe = vector_convert(NULL, pp->hwe,
243 struct hwentry, identity);
247 void free_multipath_attributes(struct multipath *mpp)
254 mpp->selector = NULL;
259 mpp->features = NULL;
262 if (mpp->hwhandler) {
263 free(mpp->hwhandler);
264 mpp->hwhandler = NULL;
269 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
274 free_multipath_attributes(mpp);
286 if (!free_paths && mpp->pg) {
287 struct pathgroup *pgp;
292 * Make sure paths carry no reference to this mpp any more
294 vector_foreach_slot(mpp->pg, pgp, i) {
295 vector_foreach_slot(pgp->paths, pp, j)
301 free_pathvec(mpp->paths, free_paths);
302 free_pgvec(mpp->pg, free_paths);
304 vector_free(mpp->hwe);
307 free(mpp->mpcontext);
312 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
315 struct multipath * mpp;
320 vector_foreach_slot (mpvec, mpp, i) {
321 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
322 free_multipath(mpp, free_paths);
323 vector_del_slot(mpvec, i);
330 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
333 struct multipath * mpp;
338 vector_foreach_slot (mpvec, mpp, i)
339 free_multipath(mpp, free_paths);
345 store_path (vector pathvec, struct path * pp)
349 if (!strlen(pp->dev_t)) {
350 condlog(2, "%s: Empty device number", pp->dev);
353 if (!strlen(pp->dev)) {
354 condlog(3, "%s: Empty device name", pp->dev_t);
361 if (!vector_alloc_slot(pathvec))
364 vector_set_slot(pathvec, pp);
369 int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
371 if (!vector_alloc_slot(mpp->pg))
374 vector_set_slot(mpp->pg, pgp);
381 store_hostgroup(vector hostgroupvec, struct host_group * hgp)
383 if (!vector_alloc_slot(hostgroupvec))
386 vector_set_slot(hostgroupvec, hgp);
391 store_adaptergroup(vector adapters, struct adapter_group * agp)
393 if (!vector_alloc_slot(adapters))
396 vector_set_slot(adapters, agp);
401 find_mp_by_minor (const struct _vector *mpvec, unsigned int minor)
404 struct multipath * mpp;
409 vector_foreach_slot (mpvec, mpp, i) {
413 if (mpp->dmi->minor == minor)
420 find_mp_by_wwid (const struct _vector *mpvec, const char * wwid)
423 struct multipath * mpp;
428 vector_foreach_slot (mpvec, mpp, i)
429 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
436 find_mp_by_alias (const struct _vector *mpvec, const char * alias)
440 struct multipath * mpp;
450 vector_foreach_slot (mpvec, mpp, i) {
451 if (strlen(mpp->alias) == len &&
452 !strncmp(mpp->alias, alias, len))
459 find_mp_by_str (const struct _vector *mpvec, const char * str)
463 if (sscanf(str, "dm-%d", &minor) == 1)
464 return find_mp_by_minor(mpvec, minor);
466 return find_mp_by_alias(mpvec, str);
470 find_path_by_dev (const struct _vector *pathvec, const char *dev)
475 if (!pathvec || !dev)
478 vector_foreach_slot (pathvec, pp, i)
479 if (!strcmp(pp->dev, dev))
482 condlog(4, "%s: dev not found in pathvec", dev);
487 find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
495 vector_foreach_slot (pathvec, pp, i)
496 if (!strcmp(pp->dev_t, dev_t))
499 condlog(4, "%s: dev_t not found in pathvec", dev_t);
503 static int do_pathcount(const struct multipath *mpp, const int *states,
504 unsigned int nr_states)
506 struct pathgroup *pgp;
509 unsigned int i, j, k;
511 if (!mpp->pg || !nr_states)
514 vector_foreach_slot (mpp->pg, pgp, i) {
515 vector_foreach_slot (pgp->paths, pp, j) {
516 for (k = 0; k < nr_states; k++) {
517 if (pp->state == states[k]) {
527 int pathcount(const struct multipath *mpp, int state)
529 return do_pathcount(mpp, &state, 1);
532 int count_active_paths(const struct multipath *mpp)
534 struct pathgroup *pgp;
542 vector_foreach_slot (mpp->pg, pgp, i) {
543 vector_foreach_slot (pgp->paths, pp, j) {
544 if (pp->state == PATH_UP || pp->state == PATH_GHOST)
551 int count_active_pending_paths(const struct multipath *mpp)
553 int states[] = {PATH_UP, PATH_GHOST, PATH_PENDING};
555 return do_pathcount(mpp, states, 3);
558 int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp)
561 struct path *pp, *cpp;
562 int pnum = 0, found = 0;
564 vector_foreach_slot(pgp->paths, pp, i) {
566 vector_foreach_slot(cpgp->paths, cpp, j) {
567 if ((long)pp == (long)cpp) {
578 first_path (const struct multipath * mpp)
580 struct pathgroup * pgp;
583 pgp = VECTOR_SLOT(mpp->pg, 0);
585 return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
588 int add_feature(char **f, const char *n)
600 if (strchr(n, ' ') != NULL) {
601 condlog(0, "internal error: feature \"%s\" contains spaces", n);
605 /* default feature is null */
608 l = asprintf(&t, "1 %s", n);
616 /* Check if feature is already present */
620 /* Get feature count */
621 c = strtoul(*f, &e, 10);
622 if (*f == e || (*e != ' ' && *e != '\0')) {
623 condlog(0, "parse error in feature string \"%s\"", *f);
627 /* Add 1 digit and 1 space */
628 l = strlen(e) + strlen(n) + 2;
631 /* Check if we need more digits for feature count */
632 for (d = c; d >= 10; d /= 10)
635 t = calloc(1, l + 1);
639 /* e: old feature string with leading space, or "" */
641 while (*(e + 1) == ' ')
644 snprintf(t, l + 1, "%0d%s %s", c, e, n);
652 int remove_feature(char **f, const char *o)
662 if (!o || *o == '\0')
665 /* Check if not present */
669 /* Get feature count */
670 c = strtoul(*f, &e, 10);
675 /* Normalize features */
679 /* Just spaces, return */
687 /* Update feature count */
690 while (q[0] != '\0') {
691 if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
696 /* Quick exit if all features have been removed */
705 /* Search feature to be removed */
708 /* Not found, return */
711 /* Update feature count space */
717 /* Copy the feature count */
718 sprintf(n, "%0d", c);
720 * Copy existing features up to the feature
721 * about to be removed
725 /* Internal error, feature string inconsistent */
738 strncat(n, p, (size_t)(e - p));
739 p += (size_t)(e - p);
741 /* Skip feature to be removed */
744 /* Copy remaining features */