/* * Copyright (c) 2004, 2005 Christophe Varoqui * Copyright (c) 2004 Stefan Bader, IBM */ #include #include #include #include #include "checkers.h" #include "memory.h" #include "vector.h" #include "util.h" #include "structs.h" #include "config.h" #include "debug.h" #include "structs_vec.h" #include "blacklist.h" #include "prio.h" #include "prioritizers/alua_spc3.h" #include "dm-generic.h" struct adapter_group * alloc_adaptergroup(void) { struct adapter_group *agp; agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group)); if (!agp) return NULL; agp->host_groups = vector_alloc(); if (!agp->host_groups) { FREE(agp); agp = NULL; } return agp; } void free_adaptergroup(vector adapters) { int i; struct adapter_group *agp; vector_foreach_slot(adapters, agp, i) { free_hostgroup(agp->host_groups); FREE(agp); } vector_free(adapters); } void free_hostgroup(vector hostgroups) { int i; struct host_group *hgp; if (!hostgroups) return; vector_foreach_slot(hostgroups, hgp, i) { vector_free(hgp->paths); FREE(hgp); } vector_free(hostgroups); } struct host_group * alloc_hostgroup(void) { struct host_group *hgp; hgp = (struct host_group *)MALLOC(sizeof(struct host_group)); if (!hgp) return NULL; hgp->paths = vector_alloc(); if (!hgp->paths) { FREE(hgp); hgp = NULL; } return hgp; } struct path * alloc_path (void) { struct path * pp; pp = (struct path *)MALLOC(sizeof(struct path)); if (pp) { pp->sg_id.host_no = -1; pp->sg_id.channel = -1; pp->sg_id.scsi_id = -1; pp->sg_id.lun = -1; pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC; pp->fd = -1; pp->tpgs = TPGS_UNDEF; pp->priority = PRIO_UNDEF; pp->checkint = CHECKINT_UNDEF; checker_clear(&pp->checker); dm_path_to_gen(pp)->ops = &dm_gen_path_ops; pp->hwe = vector_alloc(); if (pp->hwe == NULL) { free(pp); return NULL; } } return pp; } void free_path (struct path * pp) { if (!pp) return; if (checker_selected(&pp->checker)) checker_put(&pp->checker); if (prio_selected(&pp->prio)) prio_put(&pp->prio); if (pp->fd >= 0) close(pp->fd); if (pp->udev) { udev_device_unref(pp->udev); pp->udev = NULL; } if (pp->vpd_data) free(pp->vpd_data); vector_free(pp->hwe); FREE(pp); } void free_pathvec (vector vec, enum free_path_mode free_paths) { int i; struct path * pp; if (!vec) return; if (free_paths == FREE_PATHS) vector_foreach_slot(vec, pp, i) free_path(pp); vector_free(vec); } struct pathgroup * alloc_pathgroup (void) { struct pathgroup * pgp; pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup)); if (!pgp) return NULL; pgp->paths = vector_alloc(); if (!pgp->paths) { FREE(pgp); return NULL; } dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops; return pgp; } void free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths) { if (!pgp) return; free_pathvec(pgp->paths, free_paths); FREE(pgp); } void free_pgvec (vector pgvec, enum free_path_mode free_paths) { int i; struct pathgroup * pgp; if (!pgvec) return; vector_foreach_slot(pgvec, pgp, i) free_pathgroup(pgp, free_paths); vector_free(pgvec); } struct multipath * alloc_multipath (void) { struct multipath * mpp; mpp = (struct multipath *)MALLOC(sizeof(struct multipath)); if (mpp) { mpp->bestpg = 1; mpp->mpcontext = NULL; mpp->no_path_retry = NO_PATH_RETRY_UNDEF; mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET; dm_multipath_to_gen(mpp)->ops = &dm_gen_multipath_ops; } return mpp; } void free_multipath_attributes(struct multipath *mpp) { if (!mpp) return; if (mpp->selector) { FREE(mpp->selector); mpp->selector = NULL; } if (mpp->features) { FREE(mpp->features); mpp->features = NULL; } if (mpp->hwhandler) { FREE(mpp->hwhandler); mpp->hwhandler = NULL; } } void free_multipath (struct multipath * mpp, enum free_path_mode free_paths) { if (!mpp) return; free_multipath_attributes(mpp); if (mpp->alias) { FREE(mpp->alias); mpp->alias = NULL; } if (mpp->dmi) { FREE(mpp->dmi); mpp->dmi = NULL; } free_pathvec(mpp->paths, free_paths); free_pgvec(mpp->pg, free_paths); FREE_PTR(mpp->mpcontext); FREE(mpp); } void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths) { int i; struct multipath * mpp; if (!mpvec) return; vector_foreach_slot (mpvec, mpp, i) { if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) { free_multipath(mpp, free_paths); vector_del_slot(mpvec, i); return; } } } void free_multipathvec (vector mpvec, enum free_path_mode free_paths) { int i; struct multipath * mpp; if (!mpvec) return; vector_foreach_slot (mpvec, mpp, i) free_multipath(mpp, free_paths); vector_free(mpvec); } int store_path (vector pathvec, struct path * pp) { int err = 0; if (!strlen(pp->dev_t)) { condlog(2, "%s: Empty device number", pp->dev); err++; } if (!strlen(pp->dev)) { condlog(2, "%s: Empty device name", pp->dev_t); err++; } if (err > 1) return 1; if (!vector_alloc_slot(pathvec)) return 1; vector_set_slot(pathvec, pp); return 0; } int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp) { if (!vector_alloc_slot(mpp->pg)) return 1; vector_set_slot(mpp->pg, pgp); pgp->mpp = mpp; return 0; } int store_hostgroup(vector hostgroupvec, struct host_group * hgp) { if (!vector_alloc_slot(hostgroupvec)) return 1; vector_set_slot(hostgroupvec, hgp); return 0; } int store_adaptergroup(vector adapters, struct adapter_group * agp) { if (!vector_alloc_slot(adapters)) return 1; vector_set_slot(adapters, agp); return 0; } struct multipath * find_mp_by_minor (const struct _vector *mpvec, unsigned int minor) { int i; struct multipath * mpp; if (!mpvec) return NULL; vector_foreach_slot (mpvec, mpp, i) { if (!mpp->dmi) continue; if (mpp->dmi->minor == minor) return mpp; } return NULL; } struct multipath * find_mp_by_wwid (const struct _vector *mpvec, const char * wwid) { int i; struct multipath * mpp; if (!mpvec) return NULL; vector_foreach_slot (mpvec, mpp, i) if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) return mpp; return NULL; } struct multipath * find_mp_by_alias (const struct _vector *mpvec, const char * alias) { int i; size_t len; struct multipath * mpp; if (!mpvec) return NULL; len = strlen(alias); if (!len) return NULL; vector_foreach_slot (mpvec, mpp, i) { if (strlen(mpp->alias) == len && !strncmp(mpp->alias, alias, len)) return mpp; } return NULL; } struct multipath * find_mp_by_str (const struct _vector *mpvec, const char * str) { int minor; if (sscanf(str, "dm-%d", &minor) == 1) return find_mp_by_minor(mpvec, minor); else return find_mp_by_alias(mpvec, str); } struct path * find_path_by_dev (const struct _vector *pathvec, const char * dev) { int i; struct path * pp; if (!pathvec) return NULL; vector_foreach_slot (pathvec, pp, i) if (!strcmp(pp->dev, dev)) return pp; condlog(4, "%s: dev not found in pathvec", dev); return NULL; } struct path * find_path_by_devt (const struct _vector *pathvec, const char * dev_t) { int i; struct path * pp; if (!pathvec) return NULL; vector_foreach_slot (pathvec, pp, i) if (!strcmp(pp->dev_t, dev_t)) return pp; condlog(4, "%s: dev_t not found in pathvec", dev_t); return NULL; } int pathcountgr(const struct pathgroup *pgp, int state) { struct path *pp; int count = 0; int i; vector_foreach_slot (pgp->paths, pp, i) if ((pp->state == state) || (state == PATH_WILD)) count++; return count; } int pathcount(const struct multipath *mpp, int state) { struct pathgroup *pgp; int count = 0; int i; if (mpp->pg) { vector_foreach_slot (mpp->pg, pgp, i) count += pathcountgr(pgp, state); } return count; } int count_active_paths(const struct multipath *mpp) { struct pathgroup *pgp; struct path *pp; int count = 0; int i, j; if (!mpp->pg) return 0; vector_foreach_slot (mpp->pg, pgp, i) { vector_foreach_slot (pgp->paths, pp, j) { if (pp->state == PATH_UP || pp->state == PATH_GHOST) count++; } } return count; } int pathcmp(const struct pathgroup *pgp, const struct pathgroup *cpgp) { int i, j; struct path *pp, *cpp; int pnum = 0, found = 0; vector_foreach_slot(pgp->paths, pp, i) { pnum++; vector_foreach_slot(cpgp->paths, cpp, j) { if ((long)pp == (long)cpp) { found++; break; } } } return pnum - found; } struct path * first_path (const struct multipath * mpp) { struct pathgroup * pgp; if (!mpp->pg) return NULL; pgp = VECTOR_SLOT(mpp->pg, 0); return pgp?VECTOR_SLOT(pgp->paths, 0):NULL; } int add_feature(char **f, const char *n) { int c = 0, d, l; char *e, *t; if (!f) return 1; /* Nothing to do */ if (!n || *n == '0') return 0; if (strchr(n, ' ') != NULL) { condlog(0, "internal error: feature \"%s\" contains spaces", n); return 1; } /* default feature is null */ if(!*f) { l = asprintf(&t, "1 %s", n); if(l == -1) return 1; *f = t; return 0; } /* Check if feature is already present */ if (strstr(*f, n)) return 0; /* Get feature count */ c = strtoul(*f, &e, 10); if (*f == e || (*e != ' ' && *e != '\0')) { condlog(0, "parse error in feature string \"%s\"", *f); return 1; } /* Add 1 digit and 1 space */ l = strlen(e) + strlen(n) + 2; c++; /* Check if we need more digits for feature count */ for (d = c; d >= 10; d /= 10) l++; t = MALLOC(l + 1); if (!t) return 1; /* e: old feature string with leading space, or "" */ if (*e == ' ') while (*(e + 1) == ' ') e++; snprintf(t, l + 1, "%0d%s %s", c, e, n); FREE(*f); *f = t; return 0; } int remove_feature(char **f, const char *o) { int c = 0, d, l; char *e, *p, *n; const char *q; if (!f || !*f) return 1; /* Nothing to do */ if (!o || *o == '\0') return 0; /* Check if not present */ if (!strstr(*f, o)) return 0; /* Get feature count */ c = strtoul(*f, &e, 10); if (*f == e) /* parse error */ return 1; /* Normalize features */ while (*o == ' ') { o++; } /* Just spaces, return */ if (*o == '\0') return 0; q = o + strlen(o); while (*q == ' ') q--; d = (int)(q - o); /* Update feature count */ c--; q = o; while (q[0] != '\0') { if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0') c--; q++; } /* Quick exit if all features have been removed */ if (c == 0) { n = MALLOC(2); if (!n) return 1; strcpy(n, "0"); goto out; } /* Search feature to be removed */ e = strstr(*f, o); if (!e) /* Not found, return */ return 0; /* Update feature count space */ l = strlen(*f) - d; n = MALLOC(l + 1); if (!n) return 1; /* Copy the feature count */ sprintf(n, "%0d", c); /* * Copy existing features up to the feature * about to be removed */ p = strchr(*f, ' '); if (!p) { /* Internal error, feature string inconsistent */ FREE(n); return 1; } while (*p == ' ') p++; p--; if (e != p) { do { e--; d++; } while (*e == ' '); e++; d--; strncat(n, p, (size_t)(e - p)); p += (size_t)(e - p); } /* Skip feature to be removed */ p += d; /* Copy remaining features */ if (strlen(p)) { while (*p == ' ') p++; if (strlen(p)) { p--; strcat(n, p); } } out: FREE(*f); *f = n; return 0; }