libmultipath: "generic multipath" interface
authorMartin Wilck <mwilck@suse.com>
Mon, 5 Mar 2018 23:14:56 +0000 (00:14 +0100)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 7 Mar 2018 09:39:49 +0000 (10:39 +0100)
This patch adds a simplified abstract interface to the multipath data structures.
The idea is to allow "foreign" data structures to be treated by libmultipath
if they implement the same interface. Currently, the intention is to use this
only to provide formatted output about from this interface.

This interface assumes only that the data structure is organized in maps
containing path groups containing paths, and that formatted printing (using
the wildcards defined in libmultipath) is possible on each level of the data
structure.

The patch also implements the interface for the internal dm_multipath data
structure.

The style() method looks a bit exotic, but it's necessary because
print_multipath_topology() uses different formats depending on the mpp
properties. This needs to be in the generic interface, too, if we want to
produce identical output.

Signed-off-by: Martin Wilck <mwilck@suse.com>
libmultipath/Makefile
libmultipath/dm-generic.c [new file with mode: 0644]
libmultipath/dm-generic.h [new file with mode: 0644]
libmultipath/generic.c [new file with mode: 0644]
libmultipath/generic.h [new file with mode: 0644]
libmultipath/list.h
libmultipath/print.c
libmultipath/print.h
libmultipath/structs.c
libmultipath/structs.h

index 25b0527..0099d9d 100644 (file)
@@ -43,7 +43,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
        log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
        lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
-       io_err_stat.o
+       io_err_stat.o dm-generic.o generic.o
 
 all: $(LIBS)
 
diff --git a/libmultipath/dm-generic.c b/libmultipath/dm-generic.c
new file mode 100644 (file)
index 0000000..42a2608
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+  USA.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include "generic.h"
+#include "dm-generic.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "config.h"
+#include "print.h"
+
+static const struct _vector*
+dm_mp_get_pgs(const struct gen_multipath *gmp)
+{
+       return vector_convert(NULL, gen_multipath_to_dm(gmp)->pg,
+                             struct pathgroup, dm_pathgroup_to_gen);
+}
+
+static void dm_mp_rel_pgs(const struct gen_multipath *gmp,
+                         const struct _vector* v)
+{
+       vector_free_const(v);
+}
+
+static const struct _vector*
+dm_pg_get_paths(const struct gen_pathgroup *gpg)
+{
+       return vector_convert(NULL, gen_pathgroup_to_dm(gpg)->paths,
+                             struct path, dm_path_to_gen);
+}
+
+static void dm_mp_rel_paths(const struct gen_pathgroup *gpg,
+                           const struct _vector* v)
+{
+       vector_free_const(v);
+}
+
+const struct gen_multipath_ops dm_gen_multipath_ops = {
+       .get_pathgroups = dm_mp_get_pgs,
+       .rel_pathgroups = dm_mp_rel_pgs,
+       .snprint = snprint_multipath_attr,
+       /* .style = snprint_multipath_style, TBD */
+};
+
+const struct gen_pathgroup_ops dm_gen_pathgroup_ops = {
+       .get_paths = dm_pg_get_paths,
+       .rel_paths = dm_mp_rel_paths,
+       .snprint = snprint_pathgroup_attr,
+};
+
+const struct gen_path_ops dm_gen_path_ops = {
+       .snprint = snprint_path_attr,
+};
diff --git a/libmultipath/dm-generic.h b/libmultipath/dm-generic.h
new file mode 100644 (file)
index 0000000..5d59724
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+  USA.
+ */
+#ifndef _DM_GENERIC_H
+#define _DM_GENERIC_H
+#include "generic.h"
+#include "list.h" /* for container_of */
+#include "structs.h"
+
+#define dm_multipath_to_gen(mpp) (&((mpp)->generic_mp))
+#define gen_multipath_to_dm(gm) \
+       container_of_const((gm), struct multipath, generic_mp)
+
+#define dm_pathgroup_to_gen(pg) (&(pg->generic_pg))
+#define gen_pathgroup_to_dm(gpg) \
+       container_of_const((gpg), struct pathgroup, generic_pg)
+
+#define dm_path_to_gen(pp) (&((pp)->generic_path))
+#define gen_path_to_dm(gp) \
+       container_of_const((gp), struct path, generic_path)
+
+extern const struct gen_multipath_ops dm_gen_multipath_ops;
+extern const struct gen_pathgroup_ops dm_gen_pathgroup_ops;
+extern const struct gen_path_ops dm_gen_path_ops;
+
+#endif /* _DM_GENERIC_H */
diff --git a/libmultipath/generic.c b/libmultipath/generic.c
new file mode 100644 (file)
index 0000000..45012d0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+  USA.
+ */
+
+
+#include <string.h>
+#include "generic.h"
+#include "structs.h"
+
+int generic_style(const struct gen_multipath* gm,
+                 char *buf, int len, int verbosity)
+{
+       char alias_buf[WWID_SIZE];
+       char wwid_buf[WWID_SIZE];
+       int n = 0;
+
+       gm->ops->snprint(gm, alias_buf, sizeof(alias_buf), 'n');
+       gm->ops->snprint(gm, wwid_buf, sizeof(wwid_buf), 'w');
+
+       n += snprintf(buf, len, "%%n %s%%d %%s",
+                     strcmp(alias_buf, wwid_buf) ? "(%w) " : "");
+
+       return (n < len ? n : len - 1);
+}
diff --git a/libmultipath/generic.h b/libmultipath/generic.h
new file mode 100644 (file)
index 0000000..7f7fe66
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 2
+  of the License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+  USA.
+ */
+#ifndef _GENERIC_H
+#define _GENERIC_H
+#include "vector.h"
+
+struct gen_multipath;
+struct gen_pathgroup;
+struct gen_path;
+
+/**
+ * Methods implemented for gen_multipath "objects"
+ */
+struct gen_multipath_ops {
+       /**
+        * method: get_pathgroups(gmp)
+        * caller is responsible to returned data using rel_pathgroups()
+        * caller is also responsible to lock the gmp (directly or indirectly)
+        * while working with the return value.
+        * @param gmp: generic multipath object to act on
+        * @returns a vector of const struct gen_pathgroup*
+        */
+       const struct _vector* (*get_pathgroups)(const struct gen_multipath*);
+       /**
+        * method: rel_pathgroups(gmp, v)
+        * free data allocated by get_pathgroups(), if any
+        * @param gmp: generic multipath object to act on
+        * @param v the value returned by get_pathgroups()
+        */
+       void (*rel_pathgroups)(const struct gen_multipath*,
+                              const struct _vector*);
+       /**
+        * method: snprint(gmp, buf, len, wildcard)
+        * prints the property of the multipath map matching
+        * the passed-in wildcard character into "buf",
+        * 0-terminated, no more than "len" characters including trailing '\0'.
+        *
+        * @param gmp: generic multipath object to act on
+        * @param buf: output buffer
+        * @param buflen: buffer size
+        * @param wildcard: the multipath wildcard (see print.c)
+        * @returns the number of characters printed (without trailing '\0').
+        */
+       int (*snprint)(const struct gen_multipath*,
+                      char *buf, int len, char wildcard);
+       /**
+        * method: style(gmp, buf, len, verbosity)
+        * returns the format string to be used for the multipath object,
+        * defined with the wildcards as defined in print.c
+        * generic_style() should work well in most cases.
+        * @param gmp: generic multipath object to act on
+        * @param buf: output buffer
+        * @param buflen: buffer size
+        * @param verbosity: verbosity level
+        * @returns number of format chars printed
+        */
+       int (*style)(const struct gen_multipath*,
+                    char *buf, int len, int verbosity);
+};
+
+/**
+ * Methods implemented for gen_pathgroup "objects"
+ */
+struct gen_pathgroup_ops {
+       /**
+        * method: get_paths(gpg)
+        * caller is responsible to returned data using rel_paths()
+        * @param gpg: generic pathgroup object to act on
+        * @returns a vector of const struct gen_path*
+        */
+       const struct _vector* (*get_paths)(const struct gen_pathgroup*);
+       /**
+        * method: rel_paths(gpg, v)
+        * free data allocated by get_paths(), if any
+        * @param gmp: generic pathgroup object to act on
+        * @param v the value returned by get_paths()
+        */
+       void (*rel_paths)(const struct gen_pathgroup*, const struct _vector*);
+       /**
+        * Method snprint()
+        * see gen_multipath_ops->snprint() above
+        */
+       int (*snprint)(const struct gen_pathgroup*,
+                      char *buf, int len, char wildcard);
+};
+
+struct gen_path_ops {
+       /**
+        * Method snprint()
+        * see gen_multipath_ops->snprint() above
+        */
+       int (*snprint)(const struct gen_path*,
+                      char *buf, int len, char wildcard);
+};
+
+struct gen_multipath {
+       const struct gen_multipath_ops *ops;
+};
+
+struct gen_pathgroup {
+       const struct gen_pathgroup_ops *ops;
+};
+
+struct gen_path {
+       const struct gen_path_ops *ops;
+};
+
+/**
+ * Helper functions for setting up the various generic_X_ops
+ */
+
+/**
+ * generic_style()
+ * A simple style() method (see above) that should fit most
+ * foreign libraries.
+ */
+int generic_style(const struct gen_multipath*,
+                 char *buf, int len, int verbosity);
+
+#endif /* _GENERIC_H */
index c9110ac..ced021f 100644 (file)
  * @member:    the name of the member within the struct.
  *
  */
+#define container_of_const(ptr, type, member) ({               \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (const type *)( (const char *)__mptr - offsetof(type,member) );})
+
 #define container_of(ptr, type, member) ({             \
        typeof( ((type *)0)->member ) *__mptr = (ptr);  \
        (type *)( (char *)__mptr - offsetof(type,member) );})
index 594ca56..e9b8fdd 100644 (file)
@@ -756,6 +756,17 @@ mpd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_multipath_attr(const struct gen_multipath* gm,
+                          char *buf, int len, char wildcard)
+{
+       const struct multipath *mpp = gen_multipath_to_dm(gm);
+       struct multipath_data *mpd = mpd_lookup(wildcard);
+
+       if (mpd == NULL)
+               return 0;
+       return mpd->snprint(buf, len, mpp);
+}
+
 static struct path_data *
 pd_lookup(char wildcard)
 {
@@ -768,6 +779,17 @@ pd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_path_attr(const struct gen_path* gp,
+                     char *buf, int len, char wildcard)
+{
+       const struct path *pp = gen_path_to_dm(gp);
+       struct path_data *pd = pd_lookup(wildcard);
+
+       if (pd == NULL)
+               return 0;
+       return pd->snprint(buf, len, pp);
+}
+
 static struct pathgroup_data *
 pgd_lookup(char wildcard)
 {
@@ -780,6 +802,17 @@ pgd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
+                          char *buf, int len, char wildcard)
+{
+       const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
+       struct pathgroup_data *pdg = pgd_lookup(wildcard);
+
+       if (pdg == NULL)
+               return 0;
+       return pdg->snprint(buf, len, pg);
+}
+
 int
 snprint_multipath_header (char * line, int len, const char * format)
 {
index 02c5b07..214777c 100644 (file)
@@ -1,3 +1,7 @@
+#ifndef _PRINT_H
+#define _PRINT_H
+#include "dm-generic.h"
+
 #define PRINT_PATH_LONG      "%w %i %d %D %p %t %T %s %o"
 #define PRINT_PATH_INDENT    "%i %d %D %t %T %o"
 #define PRINT_PATH_CHECKER   "%i %d %D %p %t %T %o %C"
@@ -122,3 +126,11 @@ int snprint_tgt_wwpn (char *, size_t, const struct path *);
 void print_multipath_topology (struct multipath * mpp, int verbosity);
 void print_all_paths (vector pathvec, int banner);
 void print_all_paths_custo (vector pathvec, int banner, char *fmt);
+
+int snprint_path_attr(const struct gen_path* gp,
+                     char *buf, int len, char wildcard);
+int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
+                          char *buf, int len, char wildcard);
+int snprint_multipath_attr(const struct gen_multipath* gm,
+                          char *buf, int len, char wildcard);
+#endif /* _PRINT_H */
index 4db0845..991095c 100644 (file)
@@ -18,6 +18,7 @@
 #include "blacklist.h"
 #include "prio.h"
 #include "prioritizers/alua_spc3.h"
+#include "dm-generic.h"
 
 struct adapter_group *
 alloc_adaptergroup(void)
@@ -100,6 +101,7 @@ alloc_path (void)
                pp->tpgs = TPGS_UNDEF;
                pp->priority = PRIO_UNDEF;
                checker_clear(&pp->checker);
+               dm_path_to_gen(pp)->ops = &dm_gen_path_ops;
        }
        return pp;
 }
@@ -160,6 +162,7 @@ alloc_pathgroup (void)
                pgp = NULL;
        }
 
+       dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops;
        return pgp;
 }
 
@@ -200,6 +203,7 @@ alloc_multipath (void)
                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;
 }
index bccc845..88a4b78 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "prio.h"
 #include "byteorder.h"
+#include "generic.h"
 
 #define WWID_SIZE              128
 #define SERIAL_SIZE            65
@@ -256,6 +257,7 @@ struct path {
        int io_err_pathfail_starttime;
        /* configlet pointers */
        struct hwentry * hwe;
+       struct gen_path generic_path;
 };
 
 typedef int (pgpolicyfn) (struct multipath *);
@@ -332,6 +334,7 @@ struct multipath {
        int prkey_source;
        struct be64 reservation_key;
        unsigned char prflag;
+       struct gen_multipath generic_mp;
 };
 
 struct pathgroup {
@@ -341,6 +344,7 @@ struct pathgroup {
        int enabled_paths;
        vector paths;
        struct multipath *mpp;
+       struct gen_pathgroup generic_pg;
 };
 
 struct adapter_group {