Imported Upstream version 0.8.9
[platform/upstream/multipath-tools.git] / libmultipath / structs.c
index 082d53f..4b62da5 100644 (file)
@@ -5,9 +5,9 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <libdevmapper.h>
+#include <libudev.h>
 
 #include "checkers.h"
-#include "memory.h"
 #include "vector.h"
 #include "util.h"
 #include "structs.h"
 #include "debug.h"
 #include "structs_vec.h"
 #include "blacklist.h"
-#include "waiter.h"
 #include "prio.h"
+#include "prioritizers/alua_spc3.h"
+#include "dm-generic.h"
+#include "devmapper.h"
+
+struct adapter_group *
+alloc_adaptergroup(void)
+{
+       struct adapter_group *agp;
+
+       agp = (struct adapter_group *)calloc(1, 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 *)calloc(1, 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));
+
+       pp = (struct path *)calloc(1, sizeof(struct path));
 
        if (pp) {
+               pp->initialized = INIT_NEW;
                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.lun = SCSI_INVALID_LUN;
+               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)
+uninitialize_path(struct path *pp)
 {
        if (!pp)
                return;
 
+       pp->dmstate = PSTATE_UNDEF;
+       pp->uid_attribute = NULL;
+       pp->getuid = NULL;
+
        if (checker_selected(&pp->checker))
                checker_put(&pp->checker);
 
-       if (pp->fd >= 0)
+       if (prio_selected(&pp->prio))
+               prio_put(&pp->prio);
+
+       if (pp->fd >= 0) {
                close(pp->fd);
+               pp->fd = -1;
+       }
+}
+
+void
+free_path (struct path * pp)
+{
+       if (!pp)
+               return;
+
+       uninitialize_path(pp);
+
+       if (pp->udev) {
+               udev_device_unref(pp->udev);
+               pp->udev = NULL;
+       }
+       if (pp->vpd_data)
+               free(pp->vpd_data);
 
-       FREE(pp);
+       vector_free(pp->hwe);
+
+       free(pp);
 }
 
 void
-free_pathvec (vector vec, int free_paths)
+free_pathvec (vector vec, enum free_path_mode free_paths)
 {
        int i;
        struct path * pp;
@@ -60,7 +164,7 @@ free_pathvec (vector vec, int free_paths)
        if (!vec)
                return;
 
-       if (free_paths)
+       if (free_paths == FREE_PATHS)
                vector_foreach_slot(vec, pp, i)
                        free_path(pp);
 
@@ -72,31 +176,34 @@ alloc_pathgroup (void)
 {
        struct pathgroup * pgp;
 
-       pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
+       pgp = (struct pathgroup *)calloc(1, sizeof(struct pathgroup));
 
        if (!pgp)
                return NULL;
 
        pgp->paths = vector_alloc();
 
-       if (!pgp->paths)
-               FREE(pgp);
+       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, int free_paths)
+free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
 {
        if (!pgp)
                return;
 
        free_pathvec(pgp->paths, free_paths);
-       FREE(pgp);
+       free(pgp);
 }
 
 void
-free_pgvec (vector pgvec, int free_paths)
+free_pgvec (vector pgvec, enum free_path_mode free_paths)
 {
        int i;
        struct pathgroup * pgp;
@@ -115,76 +222,90 @@ alloc_multipath (void)
 {
        struct multipath * mpp;
 
-       mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
+       mpp = (struct multipath *)calloc(1, 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;
 }
 
-extern void
-free_multipath_attributes (struct multipath * mpp)
+void *set_mpp_hwe(struct multipath *mpp, const struct path *pp)
+{
+       if (!mpp || !pp || !pp->hwe)
+               return NULL;
+       if (mpp->hwe)
+               return mpp->hwe;
+       mpp->hwe = vector_convert(NULL, pp->hwe,
+                                 struct hwentry, identity);
+       return mpp->hwe;
+}
+
+void free_multipath_attributes(struct multipath *mpp)
 {
        if (!mpp)
                return;
 
-       if (mpp->selector &&
-           mpp->selector != conf->selector &&
-           (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
-           (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
-               FREE(mpp->selector);
+       if (mpp->selector) {
+               free(mpp->selector);
                mpp->selector = NULL;
        }
 
-       if (mpp->features &&
-           mpp->features != conf->features &&
-           (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features))) {
-               FREE(mpp->features);
+       if (mpp->features) {
+               free(mpp->features);
                mpp->features = NULL;
        }
 
-       if (mpp->hwhandler &&
-           mpp->hwhandler != conf->hwhandler &&
-           (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
-               FREE(mpp->hwhandler);
+       if (mpp->hwhandler) {
+               free(mpp->hwhandler);
                mpp->hwhandler = NULL;
        }
 }
 
 void
-free_multipath (struct multipath * mpp, int free_paths)
+free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
 {
        if (!mpp)
                return;
 
        free_multipath_attributes(mpp);
 
-       if (mpp->alias &&
-           (!mpp->mpe || (mpp->mpe && mpp->alias != mpp->mpe->alias)) &&
-           (mpp->wwid && mpp->alias != mpp->wwid)) {
-               FREE(mpp->alias);
+       if (mpp->alias) {
+               free(mpp->alias);
                mpp->alias = NULL;
        }
 
-       if (mpp->dmi)
-               FREE(mpp->dmi);
-
-       /*
-        * better own vecs->lock here
-        */
-       if (mpp->waiter)
-               ((struct event_thread *)mpp->waiter)->mpp = NULL;
+       if (!free_paths && mpp->pg) {
+               struct pathgroup *pgp;
+               struct path *pp;
+               int i, j;
+
+               /*
+                * Make sure paths carry no reference to this mpp any more
+                */
+               vector_foreach_slot(mpp->pg, pgp, i) {
+                       vector_foreach_slot(pgp->paths, pp, j)
+                               if (pp->mpp == mpp)
+                                       pp->mpp = NULL;
+               }
+       }
 
        free_pathvec(mpp->paths, free_paths);
        free_pgvec(mpp->pg, free_paths);
-       FREE_PTR(mpp->mpcontext);
-       FREE(mpp);
+       if (mpp->hwe) {
+               vector_free(mpp->hwe);
+               mpp->hwe = NULL;
+       }
+       free(mpp->mpcontext);
+       free(mpp);
 }
 
 void
-drop_multipath (vector mpvec, char * wwid, int free_paths)
+drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
 {
        int i;
        struct multipath * mpp;
@@ -202,7 +323,7 @@ drop_multipath (vector mpvec, char * wwid, int free_paths)
 }
 
 void
-free_multipathvec (vector mpvec, int free_paths)
+free_multipathvec (vector mpvec, enum free_path_mode free_paths)
 {
        int i;
        struct multipath * mpp;
@@ -219,6 +340,20 @@ free_multipathvec (vector mpvec, int free_paths)
 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(3, "%s: Empty device name", pp->dev_t);
+               err++;
+       }
+
+       if (err > 1)
+               return 1;
+
        if (!vector_alloc_slot(pathvec))
                return 1;
 
@@ -227,42 +362,62 @@ store_path (vector pathvec, struct path * 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_pathgroup (vector pgvec, struct pathgroup * pgp)
+store_hostgroup(vector hostgroupvec, struct host_group * hgp)
 {
-       if (!vector_alloc_slot(pgvec))
+       if (!vector_alloc_slot(hostgroupvec))
                return 1;
 
-       vector_set_slot(pgvec, pgp);
+       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 (vector mpvec, int minor)
+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)
+               if (!has_dm_info(mpp))
                        continue;
 
-               if (mpp->dmi->minor == minor)
+               if (mpp->dmi.minor == minor)
                        return mpp;
        }
        return NULL;
 }
 
 struct multipath *
-find_mp_by_wwid (vector mpvec, char * wwid)
+find_mp_by_wwid (const struct _vector *mpvec, const char * wwid)
 {
        int i;
        struct multipath * mpp;
-       
+
        if (!mpvec)
                return NULL;
 
@@ -274,12 +429,12 @@ find_mp_by_wwid (vector mpvec, char * wwid)
 }
 
 struct multipath *
-find_mp_by_alias (vector mpvec, char * alias)
+find_mp_by_alias (const struct _vector *mpvec, const char * alias)
 {
        int i;
-       int len;
+       size_t len;
        struct multipath * mpp;
-       
+
        if (!mpvec)
                return NULL;
 
@@ -287,7 +442,7 @@ find_mp_by_alias (vector mpvec, char * alias)
 
        if (!len)
                return NULL;
-       
+
        vector_foreach_slot (mpvec, mpp, i) {
                if (strlen(mpp->alias) == len &&
                    !strncmp(mpp->alias, alias, len))
@@ -297,7 +452,7 @@ find_mp_by_alias (vector mpvec, char * alias)
 }
 
 struct multipath *
-find_mp_by_str (vector mpvec, char * str)
+find_mp_by_str (const struct _vector *mpvec, const char * str)
 {
        int minor;
 
@@ -308,24 +463,24 @@ find_mp_by_str (vector mpvec, char * str)
 }
 
 struct path *
-find_path_by_dev (vector pathvec, char * dev)
+find_path_by_dev (const struct _vector *pathvec, const char *dev)
 {
        int i;
        struct path * pp;
 
-       if (!pathvec)
+       if (!pathvec || !dev)
                return NULL;
-       
+
        vector_foreach_slot (pathvec, pp, i)
-               if (!strcmp_chomp(pp->dev, dev))
+               if (!strcmp(pp->dev, dev))
                        return pp;
 
-       condlog(3, "%s: not found in pathvec", dev);
+       condlog(4, "%s: dev not found in pathvec", dev);
        return NULL;
 }
 
 struct path *
-find_path_by_devt (vector pathvec, char * dev_t)
+find_path_by_devt (const struct _vector *pathvec, const char * dev_t)
 {
        int i;
        struct path * pp;
@@ -334,43 +489,277 @@ find_path_by_devt (vector pathvec, char * dev_t)
                return NULL;
 
        vector_foreach_slot (pathvec, pp, i)
-               if (!strcmp_chomp(pp->dev_t, dev_t))
+               if (!strcmp(pp->dev_t, dev_t))
                        return pp;
 
-       condlog(3, "%s: not found in pathvec", dev_t);
+       condlog(4, "%s: dev_t not found in pathvec", dev_t);
        return NULL;
 }
 
-extern int
-pathcountgr (struct pathgroup * pgp, int state)
+static int do_pathcount(const struct multipath *mpp, const int *states,
+                       unsigned int nr_states)
 {
+       struct pathgroup *pgp;
        struct path *pp;
        int count = 0;
-       int i;
-
-       vector_foreach_slot (pgp->paths, pp, i)
-               if ((pp->state == state) || (state < 0))
-                       count++;
-
+       unsigned int i, j, k;
+
+       if (!mpp->pg || !nr_states)
+               return count;
+
+       vector_foreach_slot (mpp->pg, pgp, i) {
+               vector_foreach_slot (pgp->paths, pp, j) {
+                       for (k = 0; k < nr_states; k++) {
+                               if (pp->state == states[k]) {
+                                       count++;
+                                       break;
+                               }
+                       }
+               }
+       }
        return count;
 }
 
-extern int
-pathcount (struct multipath * mpp, int state)
+int pathcount(const struct multipath *mpp, int state)
+{
+       return do_pathcount(mpp, &state, 1);
+}
+
+int count_active_paths(const struct multipath *mpp)
 {
        struct pathgroup *pgp;
+       struct path *pp;
        int count = 0;
-       int i;
+       int i, j;
 
-       vector_foreach_slot (mpp->pg, pgp, i)
-               count += pathcountgr(pgp, state);
+       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 count_active_pending_paths(const struct multipath *mpp)
+{
+       int states[] = {PATH_UP, PATH_GHOST, PATH_PENDING};
+
+       return do_pathcount(mpp, states, 3);
+}
+
+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 (struct multipath * mpp)
+first_path (const struct multipath * mpp)
 {
-       struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0);
-       return VECTOR_SLOT(pgp->paths, 0);
+       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 = calloc(1, 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;
+}
+
+unsigned int bus_protocol_id(const struct path *pp) {
+       if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_SCSI)
+               return SYSFS_BUS_UNDEF;
+       if (pp->bus != SYSFS_BUS_SCSI)
+               return pp->bus;
+       if ((int)pp->sg_id.proto_id < 0 || pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
+               return SYSFS_BUS_UNDEF;
+       return SYSFS_BUS_SCSI + pp->sg_id.proto_id;
 }