All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools
@ 2018-03-05 23:14 Martin Wilck
  2018-03-05 23:14 ` [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
                   ` (22 more replies)
  0 siblings, 23 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Hello Christophe,

This patch series adds limited support for "foreign" multipath devices
to multipath and multipathd, and implements the respective API for
"native" NVMe multipath devices. The implementation is done using
a shared library approach similar to checkers, so other non-dm multipath
implementations could hook into this API easily.

"Limited support" means here that multipath and multipathd are able
to print information about "foreign" multipath maps with the commands
"multipath -l[l]", "multipathd show topology", "multipathd show maps", and
"multipathd show paths", and that multipathd checks the devices in the
checker loop and prints log messages if something interesting is detected.
No support for other functionality such real health monitoring or
administration is currently planned, although it might be be doable
by extending the code from this patch set.

Sample output from multipathd with this patch set:

multipathd show topology
sys0:NQN:subsysname (uuid.96926ba3-b207-437c-902c-4a4df6538c3f) [nvme] nvme0n1 NVMe,Linux,4.15.0-r
size=2097152 features='n/a' hwhandler='n/a' wp=rw
`-+- policy='n/a' prio=n/a status=n/a
  |- 0:1:1 nvme0c1n1 0:0 n/a n/a live
  |- 0:2:1 nvme0c2n1 0:0 n/a n/a live
  |- 0:3:1 nvme0c3n1 0:0 n/a n/a live
  `- 0:4:1 nvme0c4n1 0:0 n/a n/a live

The first part of the set (01-09) consists only of cleanup patches, improving the
usage of "const" qualifiers in the part of the code I've been working with.
(I'm routinely trying to do at least some cleanup work when I look more deeply
into parts of the code). These patches don't change functionality. 10 and
11 are two minor helpers for the patches that follow.

Patch 12 and 15 represent the actual new APIs. Patch 13, 14 change the
libmultipath printing code to work with the strongly simplified "generic"
multipath API from patch 12. This allows to provide foreign library code
without replicating the complex data structures libmultipath is using
internally, and yet use libmultipath's native printing code for displaying
map and path properties.

Patch 15 defines the actual API for "foreign" libraries. It is built on
top of the "generic" API which defines the data structures with which objects
like multipath maps and paths are described.

Patch 17 and 21 provide the implementation of NVMe native multipath
support using these APIs. Patch 18 - 20 contain the necessary changes
to multipath and multipathd to call into the new APIs.
(Note the numbering has changed from v1, as patch 18 has been split off
patch 20).

Patch 22 makes multipathd update path group priorities also when not strictly
necessary. This was added because patch 05 removed code that updated the
pg prios in the printing code path.

Patch 23 fixes multipathd's signal blocking logic, a response to the discussion
that came up on the first submission of this patch set.

The patch set is based on the previous multipath-tools patches I
sent to dm-devel:
 - "[PATCH v2 00/20] Various multipath-tools fixes" ff.
 - "[PATCH 0/7] multipath-tools: uevent processing fixes and unit tests" ff.
   (7/7 replaced by "[PATCH v2] multipathd: ignore uevents for non-mpath
   devices")
 - "[PATCH 1/3] multipath.rules: handle NVME devices" ff.
 - "[PATCH] libmultipath: increase path product_id/rev field size for NVMe"

To try and reduce confusion, the full series is available here:
https://github.com/openSUSE/multipath-tools/tree/upstream-queue

Reviews and comments are of course welcome.

Changes v1 -> v2:
 - 12/23: added '#include "dm-generic.h"' to print.h (Ben Marzinski)
 - 12/23: added "%d %s" formats in generic_style() to print device and product info
   in topology printout by default
 - 13/23: removed double "%d %s" format (Ben Marzinski)
 - 15/23: added locking to the foreign implementation to avoid use of deallocated
   data structures in foreign libraries (because of Ben's comment on 17/20)
 - 15/23: avoid "name" pointer (Ben Marzinski)
 - 15/23: simplify prototype of free_foreign()
 - 15/23: use scandir() rather than glob() for scanning foreign libraries
 - 17/23: avoid superfluous udev references (Ben Marzinski)
 - 17/23: add commend about locking in cleanup() (Ben Marzinski)
 - 17/23: substitute __attribute__ ((fallthrough)) by comment (Ben Marzinski)
 - 18/23 is new (it has been split off former 20/23 because of Ben's comment on
   19/23); numbering has changed from here (18 becomes 19, 19->20, 20->21).
 - 20/23: don't call foreign libraries in ev_add_path(), as foreign paths are never
   added to pathvec anyway
 - 21/23: nvme: use scandir() rather than glob() for looking for path devices
   (Ben Marzinski)
 - 22/23: new, because of Ben's comment on patch 5
 - 23/23: new, result of discussion about signal blocking
(Patches not mentioned are identical to the first series, except 19/23 they have
Reviewed-by: tags by Ben).

Martin Wilck (23):
  multipath(d)/Makefile: add explicit dependency on libraries
  libmultipath: remove unused "stdout helpers"
  libmultipath: get rid of selector "hack" in print.c
  libmultipath: parser: use call-by-value for "snprint" methods
  libmultipath: don't update path groups when printing
  libmultipath/print: use "const" where appropriate
  libmultipath: use "const" in devmapper code
  libmultipath: fix compiler warnings for -Wcast-qual
  multipath-tools: Makefile.inc: use -Werror=cast-qual
  libmultipath: add vector_free_const()
  libmultipath: add vector_convert()
  libmultipath: "generic multipath" interface
  libmultipath: print: convert API to generic data type
  libmultipath: print: use generic API for get_x_layout()
  libmultipath: API for foreign multipath handling
  libmultipath/print: add "%G - foreign" wildcard
  libmultipath/foreign: nvme foreign library
  libmultipath: pathinfo: call into foreign library
  multipath: use foreign API
  multipathd: use foreign API
  libmultipath: foreign/nvme: implement path display
  multipathd: update path group prio in check_path
  multipathd: fix signal blocking logic

 Makefile                      |   1 +
 Makefile.inc                  |   1 +
 kpartx/devmapper.c            |   3 +-
 libmpathcmd/mpath_cmd.c       |   2 +-
 libmultipath/Makefile         |   2 +-
 libmultipath/checkers/rbd.c   |   4 +-
 libmultipath/configure.c      |   1 +
 libmultipath/configure.h      |   1 -
 libmultipath/devmapper.c      |  35 +-
 libmultipath/devmapper.h      |  16 +-
 libmultipath/dict.c           | 206 ++++++------
 libmultipath/discovery.c      |  22 +-
 libmultipath/discovery.h      |   6 +-
 libmultipath/dm-generic.c     |  70 ++++
 libmultipath/dm-generic.h     |  41 +++
 libmultipath/dmparser.c       |   2 +-
 libmultipath/foreign.c        | 602 +++++++++++++++++++++++++++++++++
 libmultipath/foreign.h        | 322 ++++++++++++++++++
 libmultipath/foreign/Makefile |  30 ++
 libmultipath/foreign/nvme.c   | 761 ++++++++++++++++++++++++++++++++++++++++++
 libmultipath/generic.c        |  39 +++
 libmultipath/generic.h        | 136 ++++++++
 libmultipath/io_err_stat.c    |  17 +-
 libmultipath/list.h           |   6 +-
 libmultipath/memory.h         |   8 +-
 libmultipath/parser.c         |   9 +-
 libmultipath/parser.h         |  12 +-
 libmultipath/pgpolicies.c     |  11 +-
 libmultipath/print.c          | 395 +++++++++++++---------
 libmultipath/print.h          |  82 +++--
 libmultipath/structs.c        |  16 +-
 libmultipath/structs.h        |   9 +-
 libmultipath/uevent.c         |   6 +-
 libmultipath/util.c           |   6 +-
 libmultipath/vector.h         |  30 ++
 multipath/Makefile            |   2 +-
 multipath/main.c              |  14 +
 multipathd/Makefile           |   2 +-
 multipathd/cli_handlers.c     |  40 ++-
 multipathd/main.c             |  59 +++-
 multipathd/uxlsnr.c           |  10 +-
 41 files changed, 2656 insertions(+), 381 deletions(-)
 create mode 100644 libmultipath/dm-generic.c
 create mode 100644 libmultipath/dm-generic.h
 create mode 100644 libmultipath/foreign.c
 create mode 100644 libmultipath/foreign.h
 create mode 100644 libmultipath/foreign/Makefile
 create mode 100644 libmultipath/foreign/nvme.c
 create mode 100644 libmultipath/generic.c
 create mode 100644 libmultipath/generic.h

-- 
2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:04   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 02/23] libmultipath: remove unused "stdout helpers" Martin Wilck
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Otherwise the binaries won't be re-linked if the libraries change.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 multipath/Makefile  | 2 +-
 multipathd/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/multipath/Makefile b/multipath/Makefile
index 654568af3576..0828a8f72db7 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -14,7 +14,7 @@ OBJS = main.o
 
 all: $(EXEC)
 
-$(EXEC): $(OBJS)
+$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
 	$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
diff --git a/multipathd/Makefile b/multipathd/Makefile
index 251690ec5e2a..4c9d29634160 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -28,7 +28,7 @@ EXEC = multipathd
 
 all : $(EXEC)
 
-$(EXEC): $(OBJS)
+$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
 	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(EXEC) $(LIBDEPS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 02/23] libmultipath: remove unused "stdout helpers"
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
  2018-03-05 23:14 ` [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:04   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c Martin Wilck
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/print.c | 26 --------------------------
 libmultipath/print.h |  5 -----
 2 files changed, 31 deletions(-)

diff --git a/libmultipath/print.c b/libmultipath/print.c
index 65a98247a753..27636c35e5ff 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -1765,32 +1765,6 @@ void print_path(struct path *pp, char *style)
 	printf("%s", line);
 }
 
-void print_multipath(struct multipath *mpp, char *style)
-{
-	char line[MAX_LINE_LEN];
-
-	memset(&line[0], 0, MAX_LINE_LEN);
-	snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp, 1);
-	printf("%s", line);
-}
-
-void print_pathgroup(struct pathgroup *pgp, char *style)
-{
-	char line[MAX_LINE_LEN];
-
-	memset(&line[0], 0, MAX_LINE_LEN);
-	snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
-	printf("%s", line);
-}
-
-void print_map(struct multipath *mpp, char *params)
-{
-	if (mpp->size && params)
-		printf("0 %llu %s %s\n",
-			 mpp->size, TGT_MPATH, params);
-	return;
-}
-
 void print_all_paths(vector pathvec, int banner)
 {
 	print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
diff --git a/libmultipath/print.h b/libmultipath/print.h
index b8c343679e15..734f43fd4cb6 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -119,10 +119,5 @@ int snprint_tgt_wwnn (char *, size_t, struct path *);
 int snprint_tgt_wwpn (char *, size_t, struct path *);
 
 void print_multipath_topology (struct multipath * mpp, int verbosity);
-void print_path (struct path * pp, char * style);
-void print_multipath (struct multipath * mpp, char * style);
-void print_pathgroup (struct pathgroup * pgp, char * style);
-void print_map (struct multipath * mpp, char * params);
 void print_all_paths (vector pathvec, int banner);
 void print_all_paths_custo (vector pathvec, int banner, char *fmt);
-void print_hwtable (vector hwtable);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
  2018-03-05 23:14 ` [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
  2018-03-05 23:14 ` [PATCH v2 02/23] libmultipath: remove unused "stdout helpers" Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:05   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

By properly linking the path groups with their parent multipath,
we don't need this "hack" any more.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/dmparser.c   |  2 +-
 libmultipath/pgpolicies.c | 11 ++++++-----
 libmultipath/print.c      |  6 +++---
 libmultipath/structs.c    | 10 ++++++++++
 libmultipath/structs.h    |  3 ++-
 5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 027ae989781e..783c934f1154 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -267,7 +267,7 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
 		if (!pgp)
 			goto out;
 
-		if (store_pathgroup(mpp->pg, pgp))
+		if (add_pathgroup(mpp, pgp))
 			goto out;
 
 		p += get_word(p, &word);
diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
index 4ae4afbccdb7..ac2596ada442 100644
--- a/libmultipath/pgpolicies.c
+++ b/libmultipath/pgpolicies.c
@@ -120,7 +120,7 @@ int group_by_node_name(struct multipath * mp)
 		if (!pgp)
 			goto out1;
 
-		if (store_pathgroup(mp->pg, pgp))
+		if (add_pathgroup(mp, pgp))
 			goto out2;
 
 		/* feed the first path */
@@ -196,7 +196,7 @@ int group_by_serial(struct multipath * mp)
 		if (!pgp)
 			goto out1;
 
-		if (store_pathgroup(mp->pg, pgp))
+		if (add_pathgroup(mp, pgp))
 			goto out2;
 
 		/* feed the first path */
@@ -254,7 +254,7 @@ int one_path_per_group(struct multipath *mp)
 		if (!pgp)
 			goto out;
 
-		if (store_pathgroup(mp->pg, pgp))
+		if (add_pathgroup(mp, pgp))
 			goto out1;
 
 		if (store_path(pgp->paths, pp))
@@ -293,7 +293,7 @@ int one_group(struct multipath *mp)	/* aka multibus */
 
 		vector_free(pgp->paths);
 
-		if (store_pathgroup(mp->pg, pgp))
+		if (add_pathgroup(mp, pgp))
 			goto out1;
 
 		pgp->paths = mp->paths;
@@ -367,8 +367,9 @@ int group_by_prio(struct multipath *mp)
 		if (i < VECTOR_SIZE(mp->pg)) {
 			if (!vector_insert_slot(mp->pg, i, pgp))
 				goto out2;
+			pgp->mpp = mp;
 		} else {
-			if (store_pathgroup(mp->pg, pgp))
+			if (add_pathgroup(mp, pgp))
 				goto out2;
 		}
 
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 27636c35e5ff..8fb5c5058965 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -476,7 +476,9 @@ snprint_pri (char * buff, size_t len, struct path * pp)
 static int
 snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
 {
-	return snprint_str(buff, len, pgp->selector);
+	const char *s = pgp->mpp->selector;
+
+	return snprint_str(buff, len, s ? s : "");
 }
 
 static int
@@ -1030,7 +1032,6 @@ int snprint_multipath_topology(char *buff, int len, struct multipath *mpp,
 
 	vector_foreach_slot (mpp->pg, pgp, j) {
 		f=fmt;
-		pgp->selector = mpp->selector; /* hack */
 		if (j + 1 < VECTOR_SIZE(mpp->pg)) {
 			strcpy(f, "|-+- " PRINT_PG_INDENT);
 		} else
@@ -1122,7 +1123,6 @@ snprint_multipath_fields_json (char * buff, int len,
 
 	vector_foreach_slot (mpp->pg, pgp, i) {
 
-		pgp->selector = mpp->selector;
 		fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
 		if (fwd >= len)
 			return fwd;
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 4caad2a40302..1ade1a6705ad 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -318,6 +318,16 @@ store_pathgroup (vector pgvec, struct pathgroup * pgp)
 	return 0;
 }
 
+int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
+{
+	int ret = store_pathgroup(mpp->pg, pgp);
+
+	if (ret)
+		return ret;
+	pgp->mpp = mpp;
+	return 0;
+}
+
 int
 store_hostgroup(vector hostgroupvec, struct host_group * hgp)
 {
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index b951c7b0e157..71b37cc20674 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -340,7 +340,7 @@ struct pathgroup {
 	int priority;
 	int enabled_paths;
 	vector paths;
-	char * selector;
+	struct multipath *mpp;
 };
 
 struct adapter_group {
@@ -379,6 +379,7 @@ int store_hostgroup(vector hostgroupvec, struct host_group *hgp);
 
 int store_path (vector pathvec, struct path * pp);
 int store_pathgroup (vector pgvec, struct pathgroup * pgp);
+int add_pathgroup(struct multipath*, struct pathgroup *);
 
 struct multipath * find_mp_by_alias (vector mp, const char * alias);
 struct multipath * find_mp_by_wwid (vector mp, char * wwid);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (2 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:05   ` Hannes Reinecke
  2018-03-15 14:25   ` Bart Van Assche
  2018-03-05 23:14 ` [PATCH v2 05/23] libmultipath: don't update path groups when printing Martin Wilck
                   ` (18 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Convert the snprint methods for all keywords to call-by-value,
and use "const" qualifier for the "data" argument. This makes sure
that "snprint" type functions don't modify the data they're print,
helps compile-time correctness checking, and allows more proper
"const" cleanups in the future.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/dict.c   | 206 ++++++++++++++++++++++++--------------------------
 libmultipath/parser.c |   9 ++-
 libmultipath/parser.h |  12 ++-
 3 files changed, 112 insertions(+), 115 deletions(-)

diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index e52f1f798f7a..47dc2a38f1ac 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -92,46 +92,35 @@ set_yes_no_undef(vector strvec, void *ptr)
 }
 
 static int
-print_int (char *buff, int len, void *ptr)
+print_int (char *buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-	return snprintf(buff, len, "%i", *int_ptr);
+	return snprintf(buff, len, "%li", v);
 }
 
 static int
-print_nonzero (char *buff, int len, void *ptr)
+print_nonzero (char *buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-	if (!*int_ptr)
-		return 0;
-	return snprintf(buff, len, "%i", *int_ptr);
+	return snprintf(buff, len, "%li", v);
 }
 
 static int
-print_str (char *buff, int len, void *ptr)
+print_str (char *buff, int len, const char *ptr)
 {
-	char **str_ptr = (char **)ptr;
-	if (!*str_ptr)
-		return 0;
-	return snprintf(buff, len, "\"%s\"", *str_ptr);
+	return snprintf(buff, len, "\"%s\"", ptr);
 }
 
 static int
-print_yes_no (char *buff, int len, void *ptr)
+print_yes_no (char *buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
 	return snprintf(buff, len, "\"%s\"",
-			(*int_ptr == YN_NO)? "no" : "yes");
+			(v == YN_NO)? "no" : "yes");
 }
 
 static int
-print_yes_no_undef (char *buff, int len, void *ptr)
+print_yes_no_undef (char *buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-	if (!*int_ptr)
-		return 0;
 	return snprintf(buff, len, "\"%s\"",
-			(*int_ptr == YNU_NO)? "no" : "yes");
+			(v == YNU_NO)? "no" : "yes");
 }
 
 #define declare_def_handler(option, function)				\
@@ -143,29 +132,32 @@ def_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_def_snprint(option, function)				\
 static int								\
-snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len,	\
+			const void * data)				\
 {									\
-	return function (buff, len, &conf->option);			\
+	return function (buff, len, conf->option);			\
 }
 
 #define declare_def_snprint_defint(option, function, value)		\
 static int								\
-snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len,	\
+			const void * data)				\
 {									\
 	int i = value;							\
 	if (!conf->option)						\
-		return function (buff, len, &i);			\
-	return function (buff, len, &conf->option);			\
+		return function (buff, len, i);				\
+	return function (buff, len, conf->option);			\
 }
 
 #define declare_def_snprint_defstr(option, function, value)		\
 static int								\
-snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len,	\
+			const void * data)				\
 {									\
-	char *s = value;						\
+	static const char *s = value;					\
 	if (!conf->option)						\
-		return function (buff, len, &s);			\
-	return function (buff, len, &conf->option);			\
+		return function (buff, len, s);				\
+	return function (buff, len, conf->option);			\
 }
 
 #define declare_hw_handler(option, function)				\
@@ -180,10 +172,11 @@ hw_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_hw_snprint(option, function)				\
 static int								\
-snprint_hw_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_hw_ ## option (struct config *conf, char * buff, int len,	\
+		       const void * data)				\
 {									\
-	struct hwentry * hwe = (struct hwentry *)data;			\
-	return function (buff, len, &hwe->option);			\
+	const struct hwentry * hwe = (const struct hwentry *)data;	\
+	return function (buff, len, hwe->option);			\
 }
 
 #define declare_ovr_handler(option, function)				\
@@ -197,9 +190,10 @@ ovr_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_ovr_snprint(option, function)				\
 static int								\
-snprint_ovr_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_ovr_ ## option (struct config *conf, char * buff, int len,	\
+			const void * data)				\
 {									\
-	return function (buff, len, &conf->overrides->option);		\
+	return function (buff, len, conf->overrides->option);		\
 }
 
 #define declare_mp_handler(option, function)				\
@@ -214,10 +208,11 @@ mp_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_mp_snprint(option, function)				\
 static int								\
-snprint_mp_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_mp_ ## option (struct config *conf, char * buff, int len,	\
+		       const void * data)				\
 {									\
-	struct mpentry * mpe = (struct mpentry *)data;			\
-	return function (buff, len, &mpe->option);			\
+	const struct mpentry * mpe = (const struct mpentry *)data;	\
+	return function (buff, len, mpe->option);			\
 }
 
 declare_def_handler(checkint, set_int)
@@ -328,7 +323,7 @@ declare_mp_snprint(minio_rq, print_nonzero)
 declare_def_handler(queue_without_daemon, set_yes_no)
 static int
 snprint_def_queue_without_daemon (struct config *conf,
-				  char * buff, int len, void * data)
+				  char * buff, int len, const void * data)
 {
 	switch (conf->queue_without_daemon) {
 	case QUE_NO_DAEMON_OFF:
@@ -459,10 +454,11 @@ def_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_def_attr_snprint(option, function)			\
 static int								\
-snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len,	\
+			const void * data)				\
 {									\
-	return function (buff, len, &conf->option,			\
-			 &conf->attribute_flags);			\
+	return function (buff, len, conf->option,			\
+			 conf->attribute_flags);			\
 }
 
 #define declare_mp_attr_handler(option, function)			\
@@ -477,11 +473,12 @@ mp_ ## option ## _handler (struct config *conf, vector strvec)		\
 
 #define declare_mp_attr_snprint(option, function)			\
 static int								\
-snprint_mp_ ## option (struct config *conf, char * buff, int len, void * data) \
+snprint_mp_ ## option (struct config *conf, char * buff, int len,	\
+		       const void * data)				\
 {									\
-	struct mpentry * mpe = (struct mpentry *)data;			\
-	return function (buff, len, &mpe->option,			\
-			 &mpe->attribute_flags);			\
+	const struct mpentry * mpe = (const struct mpentry *)data;	\
+	return function (buff, len, mpe->option,			\
+			 mpe->attribute_flags);				\
 }
 
 static int
@@ -556,30 +553,30 @@ set_gid(vector strvec, void *ptr, int *flags)
 }
 
 static int
-print_mode(char * buff, int len, void *ptr, int *flags)
+print_mode(char * buff, int len, long v, int flags)
 {
-	mode_t *mode_ptr = (mode_t *)ptr;
-	if ((*flags & (1 << ATTR_MODE)) == 0)
+	mode_t mode = (mode_t)v;
+	if ((flags & (1 << ATTR_MODE)) == 0)
 		return 0;
-	return snprintf(buff, len, "0%o", *mode_ptr);
+	return snprintf(buff, len, "0%o", mode);
 }
 
 static int
-print_uid(char * buff, int len, void *ptr, int *flags)
+print_uid(char * buff, int len, long v, int flags)
 {
-	uid_t *uid_ptr = (uid_t *)ptr;
-	if ((*flags & (1 << ATTR_UID)) == 0)
+	uid_t uid = (uid_t)v;
+	if ((flags & (1 << ATTR_UID)) == 0)
 		return 0;
-	return snprintf(buff, len, "0%o", *uid_ptr);
+	return snprintf(buff, len, "0%o", uid);
 }
 
 static int
-print_gid(char * buff, int len, void *ptr, int *flags)
+print_gid(char * buff, int len, long v, int flags)
 {
-	gid_t *gid_ptr = (gid_t *)ptr;
-	if ((*flags & (1 << ATTR_GID)) == 0)
+	gid_t gid = (gid_t)v;
+	if ((flags & (1 << ATTR_GID)) == 0)
 		return 0;
-	return snprintf(buff, len, "0%o", *gid_ptr);
+	return snprintf(buff, len, "0%o", gid);
 }
 
 declare_def_attr_handler(mode, set_mode)
@@ -620,17 +617,15 @@ set_fast_io_fail(vector strvec, void *ptr)
 }
 
 int
-print_fast_io_fail(char * buff, int len, void *ptr)
+print_fast_io_fail(char * buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-
-	if (*int_ptr == MP_FAST_IO_FAIL_UNSET)
+	if (v == MP_FAST_IO_FAIL_UNSET)
 		return 0;
-	if (*int_ptr == MP_FAST_IO_FAIL_OFF)
+	if (v == MP_FAST_IO_FAIL_OFF)
 		return snprintf(buff, len, "\"off\"");
-	if (*int_ptr == MP_FAST_IO_FAIL_ZERO)
+	if (v == MP_FAST_IO_FAIL_ZERO)
 		return snprintf(buff, len, "0");
-	return snprintf(buff, len, "%d", *int_ptr);
+	return snprintf(buff, len, "%ld", v);
 }
 
 declare_def_handler(fast_io_fail, set_fast_io_fail)
@@ -660,15 +655,11 @@ set_dev_loss(vector strvec, void *ptr)
 }
 
 int
-print_dev_loss(char * buff, int len, void *ptr)
+print_dev_loss(char * buff, int len, unsigned long v)
 {
-	unsigned int *uint_ptr = (unsigned int *)ptr;
-
-	if (!*uint_ptr)
-		return 0;
-	if (*uint_ptr >= MAX_DEV_LOSS_TMO)
+	if (v >= MAX_DEV_LOSS_TMO)
 		return snprintf(buff, len, "\"infinity\"");
-	return snprintf(buff, len, "%u", *uint_ptr);
+	return snprintf(buff, len, "%lu", v);
 }
 
 declare_def_handler(dev_loss, set_dev_loss)
@@ -695,10 +686,9 @@ set_pgpolicy(vector strvec, void *ptr)
 }
 
 int
-print_pgpolicy(char * buff, int len, void *ptr)
+print_pgpolicy(char * buff, int len, long pgpolicy)
 {
 	char str[POLICY_NAME_SIZE];
-	int pgpolicy = *(int *)ptr;
 
 	if (!pgpolicy)
 		return 0;
@@ -776,7 +766,7 @@ max_fds_handler(struct config *conf, vector strvec)
 }
 
 static int
-snprint_max_fds (struct config *conf, char * buff, int len, void * data)
+snprint_max_fds (struct config *conf, char * buff, int len, const void * data)
 {
 	int r = 0, max_fds;
 
@@ -813,15 +803,13 @@ set_rr_weight(vector strvec, void *ptr)
 }
 
 int
-print_rr_weight (char * buff, int len, void *ptr)
+print_rr_weight (char * buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-
-	if (!*int_ptr)
+	if (!v)
 		return 0;
-	if (*int_ptr == RR_WEIGHT_PRIO)
+	if (v == RR_WEIGHT_PRIO)
 		return snprintf(buff, len, "\"priorities\"");
-	if (*int_ptr == RR_WEIGHT_NONE)
+	if (v == RR_WEIGHT_NONE)
 		return snprintf(buff, len, "\"uniform\"");
 
 	return 0;
@@ -861,11 +849,9 @@ set_pgfailback(vector strvec, void *ptr)
 }
 
 int
-print_pgfailback (char * buff, int len, void *ptr)
+print_pgfailback (char * buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-
-	switch(*int_ptr) {
+	switch(v) {
 	case  FAILBACK_UNDEF:
 		return 0;
 	case -FAILBACK_MANUAL:
@@ -875,7 +861,7 @@ print_pgfailback (char * buff, int len, void *ptr)
 	case -FAILBACK_FOLLOWOVER:
 		return snprintf(buff, len, "\"followover\"");
 	default:
-		return snprintf(buff, len, "%i", *int_ptr);
+		return snprintf(buff, len, "%li", v);
 	}
 }
 
@@ -910,11 +896,9 @@ set_no_path_retry(vector strvec, void *ptr)
 }
 
 int
-print_no_path_retry(char * buff, int len, void *ptr)
+print_no_path_retry(char * buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-
-	switch(*int_ptr) {
+	switch(v) {
 	case NO_PATH_RETRY_UNDEF:
 		return 0;
 	case NO_PATH_RETRY_FAIL:
@@ -922,7 +906,7 @@ print_no_path_retry(char * buff, int len, void *ptr)
 	case NO_PATH_RETRY_QUEUE:
 		return snprintf(buff, len, "\"queue\"");
 	default:
-		return snprintf(buff, len, "%i", *int_ptr);
+		return snprintf(buff, len, "%li", v);
 	}
 }
 
@@ -955,7 +939,8 @@ def_log_checker_err_handler(struct config *conf, vector strvec)
 }
 
 static int
-snprint_def_log_checker_err (struct config *conf, char * buff, int len, void * data)
+snprint_def_log_checker_err (struct config *conf, char * buff, int len,
+			     const void * data)
 {
 	if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
 		return snprintf(buff, len, "once");
@@ -1008,7 +993,7 @@ def_reservation_key_handler(struct config *conf, vector strvec)
 
 static int
 snprint_def_reservation_key (struct config *conf, char * buff, int len,
-			     void * data)
+			     const void * data)
 {
 	return print_reservation_key(buff, len, conf->reservation_key,
 				     conf->prkey_source);
@@ -1026,9 +1011,9 @@ mp_reservation_key_handler(struct config *conf, vector strvec)
 
 static int
 snprint_mp_reservation_key (struct config *conf, char * buff, int len,
-			     void * data)
+			    const void * data)
 {
-	struct mpentry * mpe = (struct mpentry *)data;
+	const struct mpentry * mpe = (const struct mpentry *)data;
 	return print_reservation_key(buff, len, mpe->reservation_key,
 				     mpe->prkey_source);
 }
@@ -1053,17 +1038,15 @@ set_off_int_undef(vector strvec, void *ptr)
 }
 
 int
-print_off_int_undef(char * buff, int len, void *ptr)
+print_off_int_undef(char * buff, int len, long v)
 {
-	int *int_ptr = (int *)ptr;
-
-	switch(*int_ptr) {
+	switch(v) {
 	case NU_UNDEF:
 		return 0;
 	case NU_NO:
 		return snprintf(buff, len, "\"no\"");
 	default:
-		return snprintf(buff, len, "%i", *int_ptr);
+		return snprintf(buff, len, "%li", v);
 	}
 }
 
@@ -1231,15 +1214,17 @@ declare_ble_handler(blist_property)
 declare_ble_handler(elist_property)
 
 static int
-snprint_def_uxsock_timeout(struct config *conf, char * buff, int len, void * data)
+snprint_def_uxsock_timeout(struct config *conf, char * buff, int len,
+			   const void * data)
 {
 	return snprintf(buff, len, "%u", conf->uxsock_timeout);
 }
 
 static int
-snprint_ble_simple (struct config *conf, char * buff, int len, void * data)
+snprint_ble_simple (struct config *conf, char * buff, int len,
+		    const void * data)
 {
-	struct blentry * ble = (struct blentry *)data;
+	const struct blentry * ble = (const struct blentry *)data;
 
 	return snprintf(buff, len, "\"%s\"", ble->str);
 }
@@ -1262,17 +1247,21 @@ declare_ble_device_handler(product, blist_device, NULL, buff)
 declare_ble_device_handler(product, elist_device, NULL, buff)
 
 static int
-snprint_bled_vendor (struct config *conf, char * buff, int len, void * data)
+snprint_bled_vendor (struct config *conf, char * buff, int len,
+		     const void * data)
 {
-	struct blentry_device * bled = (struct blentry_device *)data;
+	const struct blentry_device * bled =
+		(const struct blentry_device *)data;
 
 	return snprintf(buff, len, "\"%s\"", bled->vendor);
 }
 
 static int
-snprint_bled_product (struct config *conf, char * buff, int len, void * data)
+snprint_bled_product (struct config *conf, char * buff, int len,
+		      const void * data)
 {
-	struct blentry_device * bled = (struct blentry_device *)data;
+	const struct blentry_device * bled =
+		(const struct blentry_device *)data;
 
 	return snprintf(buff, len, "\"%s\"", bled->product);
 }
@@ -1402,7 +1391,8 @@ deprecated_handler(struct config *conf, vector strvec)
 }
 
 static int
-snprint_deprecated (struct config *conf, char * buff, int len, void * data)
+snprint_deprecated (struct config *conf, char * buff, int len,
+		    const void * data)
 {
 	return 0;
 }
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index c47d891ec369..5caa2019a1a4 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -33,7 +33,8 @@ static int line_nr;
 int
 keyword_alloc(vector keywords, char *string,
 	      int (*handler) (struct config *, vector),
-	      int (*print) (struct config *, char *, int, void *), int unique)
+	      int (*print) (struct config *, char *, int, const void*),
+	      int unique)
 {
 	struct keyword *keyword;
 
@@ -71,7 +72,8 @@ install_sublevel_end(void)
 int
 _install_keyword(vector keywords, char *string,
 		 int (*handler) (struct config *, vector),
-		 int (*print) (struct config *, char *, int, void *), int unique)
+		 int (*print) (struct config *, char *, int, const void*),
+		 int unique)
 {
 	int i = 0;
 	struct keyword *keyword;
@@ -143,7 +145,8 @@ find_keyword(vector keywords, vector v, char * name)
 }
 
 int
-snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
+snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+		const void *data)
 {
 	int r;
 	int fwd = 0;
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
index 519b805d4149..0a747507d7be 100644
--- a/libmultipath/parser.h
+++ b/libmultipath/parser.h
@@ -43,7 +43,7 @@
 struct keyword {
 	char *string;
 	int (*handler) (struct config *, vector);
-	int (*print) (struct config *, char *, int, void *);
+	int (*print) (struct config *, char *, int, const void *);
 	vector sub;
 	int unique;
 };
@@ -60,13 +60,17 @@ struct keyword {
 /* Prototypes */
 extern int keyword_alloc(vector keywords, char *string,
 			 int (*handler) (struct config *, vector),
-			 int (*print) (struct config *, char *, int, void *), int unique);
+			 int (*print) (struct config *, char *, int,
+				       const void *),
+			 int unique);
 #define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1)
 extern void install_sublevel(void);
 extern void install_sublevel_end(void);
 extern int _install_keyword(vector keywords, char *string,
 			    int (*handler) (struct config *, vector),
-			    int (*print) (struct config *, char *, int, void *), int unique);
+			    int (*print) (struct config *, char *, int,
+					  const void *),
+			    int unique);
 #define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1)
 #define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0)
 extern void dump_keywords(vector keydump, int level);
@@ -76,6 +80,6 @@ extern void *set_value(vector strvec);
 extern int process_file(struct config *conf, char *conf_file);
 extern struct keyword * find_keyword(vector keywords, vector v, char * name);
 int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
-		    void *data);
+		    const void *data);
 
 #endif
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 05/23] libmultipath: don't update path groups when printing
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (3 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:06   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 06/23] libmultipath/print: use "const" where appropriate Martin Wilck
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Updating the prio values for printing makes no sense. The user wants to see
the prio values multipath is actually using for path group selection, and
updating the values here means actually lying to the user if the prio values
have changed, but multipathd hasn't updated them internally.

If we really don't update the pathgroup prios when we need to, this should be
fixed elsewhere. The current wrong output would just hide that if it occured.

Moreover, correctness forbids changing properties so deeply in a code path
that's supposed to print them only. Finally, this piece of code prevents the
print.c code to be converted to proper "const" usage.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/print.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/libmultipath/print.c b/libmultipath/print.c
index 8fb5c5058965..b5c00bfe69a5 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -484,13 +484,6 @@ snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
 static int
 snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
 {
-	/*
-	 * path group priority is not updated for every path prio change,
-	 * but only on switch group code path.
-	 *
-	 * Printing is another reason to update.
-	 */
-	path_group_prio_update(pgp);
 	return snprint_int(buff, len, pgp->priority);
 }
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 06/23] libmultipath/print: use "const" where appropriate
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (4 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 05/23] libmultipath: don't update path groups when printing Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:07   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 07/23] libmultipath: use "const" in devmapper code Martin Wilck
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Convert the print.h/print.c code to use "const" qualifiers
properly. This is generally considered good programming practice,
and the printing code shouldn't change any objects anyway.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/configure.h |   1 -
 libmultipath/discovery.c |   6 +--
 libmultipath/discovery.h |   6 ++-
 libmultipath/print.c     | 133 ++++++++++++++++++++++++-----------------------
 libmultipath/print.h     |  41 ++++++++-------
 5 files changed, 95 insertions(+), 92 deletions(-)

diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 0ffc28efdaf7..0f5d30a540ca 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -35,5 +35,4 @@ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int forc
 int get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
 		 vector pathvec, char **wwid);
 int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon);
-int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
 struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 88e9f3b61510..98bddee52c8f 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -401,7 +401,7 @@ sysfs_get_tgt_nodename (struct path *pp, char * node)
 	return 0;
 }
 
-int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
+int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name)
 {
 	int proto_id;
 
@@ -427,7 +427,7 @@ int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
 	return sysfs_get_host_pci_name(pp, adapter_name);
 }
 
-int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
+int sysfs_get_host_pci_name(const struct path *pp, char *pci_name)
 {
 	struct udev_device *hostdev, *parent;
 	char host_name[HOST_NAME_LEN];
@@ -466,7 +466,7 @@ int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
 	return 1;
 }
 
-int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
+int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address)
 {
 	struct udev_device *hostdev;
 	char host_name[HOST_NAME_LEN];
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index bd5e6678a26d..9aacf75bfeb0 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -44,8 +44,10 @@ int store_pathinfo (vector pathvec, struct config *conf,
 		    struct path **pp_ptr);
 int sysfs_set_scsi_tmo (struct multipath *mpp, int checkint);
 int sysfs_get_timeout(struct path *pp, unsigned int *timeout);
-int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
-int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
+int sysfs_get_host_pci_name(const struct path *pp, char *pci_name);
+int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address);
+int sysfs_get_host_adapter_name(const struct path *pp,
+				char *adapter_name);
 ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff,
 		       size_t len);
 int sysfs_get_asymmetric_access_state(struct path *pp,
diff --git a/libmultipath/print.c b/libmultipath/print.c
index b5c00bfe69a5..594ca567e22a 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -28,6 +28,7 @@
 #include "devmapper.h"
 #include "uevent.h"
 #include "debug.h"
+#include "discovery.h"
 
 #define MAX(x,y) (x > y) ? x : y
 #define TAIL     (line + len - 1 - c)
@@ -97,7 +98,7 @@ snprint_size (char * buff, size_t len, unsigned long long size)
  * multipath info printing functions
  */
 static int
-snprint_name (char * buff, size_t len, struct multipath * mpp)
+snprint_name (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (mpp->alias)
 		return snprintf(buff, len, "%s", mpp->alias);
@@ -106,7 +107,7 @@ snprint_name (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
+snprint_sysfs (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (mpp->dmi)
 		return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
@@ -115,7 +116,7 @@ snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_ro (char * buff, size_t len, struct multipath * mpp)
+snprint_ro (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (!mpp->dmi)
 		return snprintf(buff, len, "undef");
@@ -154,7 +155,7 @@ out:
 }
 
 static int
-snprint_failback (char * buff, size_t len, struct multipath * mpp)
+snprint_failback (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
 		return snprintf(buff, len, "immediate");
@@ -169,7 +170,7 @@ snprint_failback (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_queueing (char * buff, size_t len, struct multipath * mpp)
+snprint_queueing (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
 		return snprintf(buff, len, "off");
@@ -191,13 +192,13 @@ snprint_queueing (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
+snprint_nb_paths (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_int(buff, len, mpp->nr_active);
 }
 
 static int
-snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
+snprint_dm_map_state (char * buff, size_t len, const struct multipath * mpp)
 {
 	if (mpp->dmi && mpp->dmi->suspended)
 		return snprintf(buff, len, "suspend");
@@ -206,67 +207,67 @@ snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_size (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_size(buff, len, mpp->size);
 }
 
 static int
-snprint_features (char * buff, size_t len, struct multipath * mpp)
+snprint_features (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_str(buff, len, mpp->features);
 }
 
 static int
-snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
+snprint_hwhandler (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_str(buff, len, mpp->hwhandler);
 }
 
 static int
-snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
+snprint_path_faults (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_path_failures);
 }
 
 static int
-snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
+snprint_switch_grp (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_switchgroup);
 }
 
 static int
-snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
+snprint_map_loads (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_map_loads);
 }
 
 static int
-snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
+snprint_total_q_time (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_total_queueing_time);
 }
 
 static int
-snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
+snprint_q_timeouts (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
 }
 
 static int
-snprint_map_failures (char * buff, size_t len, struct multipath * mpp)
+snprint_map_failures (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_uint(buff, len, mpp->stat_map_failures);
 }
 
 static int
-snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_uuid (char * buff, size_t len, const struct multipath * mpp)
 {
 	return snprint_str(buff, len, mpp->wwid);
 }
 
 static int
-snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp)
 {
 	struct pathgroup * pgp;
 	struct path * pp;
@@ -286,7 +287,7 @@ snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
 
 
 static int
-snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
 {
 	struct pathgroup * pgp;
 	struct path * pp;
@@ -304,7 +305,7 @@ snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
 {
 	struct pathgroup * pgp;
 	struct path * pp;
@@ -322,7 +323,7 @@ snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
 {
 	struct pathgroup * pgp;
 	struct path * pp;
@@ -340,7 +341,7 @@ snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_action (char * buff, size_t len, struct multipath * mpp)
+snprint_action (char * buff, size_t len, const struct multipath * mpp)
 {
 	switch (mpp->action) {
 	case ACT_REJECT:
@@ -362,13 +363,13 @@ snprint_action (char * buff, size_t len, struct multipath * mpp)
  * path info printing functions
  */
 static int
-snprint_path_uuid (char * buff, size_t len, struct path * pp)
+snprint_path_uuid (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_str(buff, len, pp->wwid);
 }
 
 static int
-snprint_hcil (char * buff, size_t len, struct path * pp)
+snprint_hcil (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || pp->sg_id.host_no < 0)
 		return snprintf(buff, len, "#:#:#:#");
@@ -381,7 +382,7 @@ snprint_hcil (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dev (char * buff, size_t len, struct path * pp)
+snprint_dev (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || !strlen(pp->dev))
 		return snprintf(buff, len, "-");
@@ -390,7 +391,7 @@ snprint_dev (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dev_t (char * buff, size_t len, struct path * pp)
+snprint_dev_t (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || !strlen(pp->dev))
 		return snprintf(buff, len, "#:#");
@@ -399,7 +400,7 @@ snprint_dev_t (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_offline (char * buff, size_t len, struct path * pp)
+snprint_offline (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || !pp->mpp)
 		return snprintf(buff, len, "unknown");
@@ -410,7 +411,7 @@ snprint_offline (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_chk_state (char * buff, size_t len, struct path * pp)
+snprint_chk_state (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || !pp->mpp)
 		return snprintf(buff, len, "undef");
@@ -436,7 +437,7 @@ snprint_chk_state (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dm_path_state (char * buff, size_t len, struct path * pp)
+snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp)
 		return snprintf(buff, len, "undef");
@@ -452,14 +453,14 @@ snprint_dm_path_state (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_vpr (char * buff, size_t len, struct path * pp)
+snprint_vpr (char * buff, size_t len, const struct path * pp)
 {
 	return snprintf(buff, len, "%s,%s",
 			pp->vendor_id, pp->product_id);
 }
 
 static int
-snprint_next_check (char * buff, size_t len, struct path * pp)
+snprint_next_check (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp || !pp->mpp)
 		return snprintf(buff, len, "orphan");
@@ -468,13 +469,13 @@ snprint_next_check (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_pri (char * buff, size_t len, struct path * pp)
+snprint_pri (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_int(buff, len, pp ? pp->priority : -1);
 }
 
 static int
-snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
 {
 	const char *s = pgp->mpp->selector;
 
@@ -482,13 +483,13 @@ snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
 }
 
 static int
-snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
 {
 	return snprint_int(buff, len, pgp->priority);
 }
 
 static int
-snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
 {
 	switch (pgp->status) {
 	case PGSTATE_ENABLED:
@@ -503,19 +504,19 @@ snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
 }
 
 static int
-snprint_path_size (char * buff, size_t len, struct path * pp)
+snprint_path_size (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_size(buff, len, pp->size);
 }
 
 int
-snprint_path_serial (char * buff, size_t len, struct path * pp)
+snprint_path_serial (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_str(buff, len, pp->serial);
 }
 
 static int
-snprint_path_mpp (char * buff, size_t len, struct path * pp)
+snprint_path_mpp (char * buff, size_t len, const struct path * pp)
 {
 	if (!pp->mpp)
 		return snprintf(buff, len, "[orphan]");
@@ -525,7 +526,7 @@ snprint_path_mpp (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
+snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
 {
 	struct udev_device *host_dev = NULL;
 	char host_id[32];
@@ -552,19 +553,19 @@ out:
 }
 
 int
-snprint_host_wwnn (char * buff, size_t len, struct path * pp)
+snprint_host_wwnn (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_host_attr(buff, len, pp, "node_name");
 }
 
 int
-snprint_host_wwpn (char * buff, size_t len, struct path * pp)
+snprint_host_wwpn (char * buff, size_t len, const struct path * pp)
 {
 	return snprint_host_attr(buff, len, pp, "port_name");
 }
 
 int
-snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
+snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
 {
 	struct udev_device *rport_dev = NULL;
 	char rport_id[32];
@@ -594,7 +595,7 @@ out:
 
 
 int
-snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
+snprint_tgt_wwnn (char * buff, size_t len, const struct path * pp)
 {
 	if (pp->tgt_node_name[0] == '\0')
 		return snprintf(buff, len, "[undef]");
@@ -602,7 +603,7 @@ snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_host_adapter (char * buff, size_t len, struct path * pp)
+snprint_host_adapter (char * buff, size_t len, const struct path * pp)
 {
 	char adapter[SLOT_NAME_SIZE];
 
@@ -612,9 +613,9 @@ snprint_host_adapter (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_path_checker (char * buff, size_t len, struct path * pp)
+snprint_path_checker (char * buff, size_t len, const struct path * pp)
 {
-	struct checker * c = &pp->checker;
+	const struct checker * c = &pp->checker;
 	return snprint_str(buff, len, c->name);
 }
 
@@ -780,11 +781,11 @@ pgd_lookup(char wildcard)
 }
 
 int
-snprint_multipath_header (char * line, int len, char * format)
+snprint_multipath_header (char * line, int len, const char * format)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
-	char * f = format; /* format string cursor */
+	const char * f = format; /* format string cursor */
 	int fwd;
 	struct multipath_data * data;
 
@@ -811,12 +812,12 @@ snprint_multipath_header (char * line, int len, char * format)
 }
 
 int
-snprint_multipath (char * line, int len, char * format,
-	     struct multipath * mpp, int pad)
+snprint_multipath (char * line, int len, const char * format,
+	     const struct multipath * mpp, int pad)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
-	char * f = format; /* format string cursor */
+	const char * f = format; /* format string cursor */
 	int fwd;
 	struct multipath_data * data;
 	char buff[MAX_FIELD_LEN] = {};
@@ -847,11 +848,11 @@ snprint_multipath (char * line, int len, char * format,
 }
 
 int
-snprint_path_header (char * line, int len, char * format)
+snprint_path_header (char * line, int len, const char * format)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
-	char * f = format; /* format string cursor */
+	const char * f = format; /* format string cursor */
 	int fwd;
 	struct path_data * data;
 
@@ -878,12 +879,12 @@ snprint_path_header (char * line, int len, char * format)
 }
 
 int
-snprint_path (char * line, int len, char * format,
-	     struct path * pp, int pad)
+snprint_path (char * line, int len, const char * format,
+	     const struct path * pp, int pad)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
-	char * f = format; /* format string cursor */
+	const char * f = format; /* format string cursor */
 	int fwd;
 	struct path_data * data;
 	char buff[MAX_FIELD_LEN];
@@ -914,7 +915,7 @@ snprint_path (char * line, int len, char * format,
 
 int
 snprint_pathgroup (char * line, int len, char * format,
-		   struct pathgroup * pgp)
+		   const struct pathgroup * pgp)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
@@ -976,7 +977,7 @@ void print_multipath_topology(struct multipath *mpp, int verbosity)
 	FREE(buff);
 }
 
-int snprint_multipath_topology(char *buff, int len, struct multipath *mpp,
+int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp,
 			       int verbosity)
 {
 	int j, i, fwd = 0;
@@ -1100,7 +1101,7 @@ snprint_json_elem_footer (char * buff, int len, int indent, int last)
 
 static int
 snprint_multipath_fields_json (char * buff, int len,
-		struct multipath * mpp, int last)
+		const struct multipath * mpp, int last)
 {
 	int i, j, fwd = 0;
 	struct path *pp;
@@ -1158,7 +1159,7 @@ snprint_multipath_fields_json (char * buff, int len,
 
 int
 snprint_multipath_map_json (char * buff, int len,
-		struct multipath * mpp, int last){
+		const struct multipath * mpp, int last){
 	int fwd = 0;
 
 	fwd +=  snprint_json_header(buff, len);
@@ -1184,7 +1185,7 @@ snprint_multipath_map_json (char * buff, int len,
 }
 
 int
-snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)
+snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
 {
 	int i, fwd = 0;
 	struct multipath * mpp;
@@ -1215,7 +1216,7 @@ snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)
 }
 
 static int
-snprint_hwentry (struct config *conf, char * buff, int len, struct hwentry * hwe)
+snprint_hwentry (struct config *conf, char * buff, int len, const struct hwentry * hwe)
 {
 	int i;
 	int fwd = 0;
@@ -1273,7 +1274,7 @@ int snprint_hwtable(struct config *conf, char *buff, int len, vector hwtable)
 }
 
 static int
-snprint_mpentry (struct config *conf, char * buff, int len, struct mpentry * mpe)
+snprint_mpentry (struct config *conf, char * buff, int len, const struct mpentry * mpe)
 {
 	int i;
 	int fwd = 0;
@@ -1325,7 +1326,7 @@ int snprint_mptable(struct config *conf, char *buff, int len, vector mptable)
 }
 
 int snprint_overrides(struct config *conf, char * buff, int len,
-		      struct hwentry *overrides)
+		      const struct hwentry *overrides)
 {
 	int fwd = 0;
 	int i;
@@ -1649,7 +1650,7 @@ int snprint_blacklist_except(struct config *conf, char *buff, int len)
 	return fwd;
 }
 
-int snprint_status(char *buff, int len, struct vectors *vecs)
+int snprint_status(char *buff, int len, const struct vectors *vecs)
 {
 	int fwd = 0;
 	int i;
@@ -1681,7 +1682,7 @@ int snprint_status(char *buff, int len, struct vectors *vecs)
 }
 
 int snprint_devices(struct config *conf, char * buff, int len,
-		    struct vectors *vecs)
+		    const struct vectors *vecs)
 {
 	DIR *blkdir;
 	struct dirent *blkdev;
diff --git a/libmultipath/print.h b/libmultipath/print.h
index 734f43fd4cb6..02c5b072cc2b 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -73,50 +73,51 @@ struct path_data {
 	char wildcard;
 	char * header;
 	int width;
-	int (*snprint)(char * buff, size_t len, struct path * pp);
+	int (*snprint)(char * buff, size_t len, const struct path * pp);
 };
 
 struct multipath_data {
 	char wildcard;
 	char * header;
 	int width;
-	int (*snprint)(char * buff, size_t len, struct multipath * mpp);
+	int (*snprint)(char * buff, size_t len, const struct multipath * mpp);
 };
 
 struct pathgroup_data {
 	char wildcard;
 	char * header;
 	int width;
-	int (*snprint)(char * buff, size_t len, struct pathgroup * pgp);
+	int (*snprint)(char * buff, size_t len, const struct pathgroup * pgp);
 };
 
 void get_path_layout (vector pathvec, int header);
 void get_multipath_layout (vector mpvec, int header);
-int snprint_path_header (char *, int, char *);
-int snprint_multipath_header (char *, int, char *);
-int snprint_path (char *, int, char *, struct path *, int);
-int snprint_multipath (char *, int, char *, struct multipath *, int);
-int snprint_multipath_topology (char *, int, struct multipath * mpp,
+int snprint_path_header (char *, int, const char *);
+int snprint_multipath_header (char *, int, const char *);
+int snprint_path (char *, int, const char *, const struct path *, int);
+int snprint_multipath (char *, int, const char *,
+		       const struct multipath *, int);
+int snprint_multipath_topology (char *, int, const struct multipath * mpp,
 				int verbosity);
 int snprint_multipath_topology_json (char * buff, int len,
-				struct vectors * vecs);
+				const struct vectors * vecs);
 int snprint_multipath_map_json (char * buff, int len,
-				struct multipath * mpp, int last);
+				const struct multipath * mpp, int last);
 int snprint_defaults (struct config *, char *, int);
 int snprint_blacklist (struct config *, char *, int);
 int snprint_blacklist_except (struct config *, char *, int);
 int snprint_blacklist_report (struct config *, char *, int);
 int snprint_wildcards (char *, int);
-int snprint_status (char *, int, struct vectors *);
-int snprint_devices (struct config *, char *, int, struct vectors *);
-int snprint_hwtable (struct config *, char *, int, vector);
-int snprint_mptable (struct config *, char *, int, vector);
-int snprint_overrides (struct config *, char *, int, struct hwentry *);
-int snprint_path_serial (char *, size_t, struct path *);
-int snprint_host_wwnn (char *, size_t, struct path *);
-int snprint_host_wwpn (char *, size_t, struct path *);
-int snprint_tgt_wwnn (char *, size_t, struct path *);
-int snprint_tgt_wwpn (char *, size_t, struct path *);
+int snprint_status (char *, int, const struct vectors *);
+int snprint_devices (struct config *, char *, int, const struct vectors *);
+int snprint_hwtable (struct config *, char *, int, const vector);
+int snprint_mptable (struct config *, char *, int, const vector);
+int snprint_overrides (struct config *, char *, int, const struct hwentry *);
+int snprint_path_serial (char *, size_t, const struct path *);
+int snprint_host_wwnn (char *, size_t, const struct path *);
+int snprint_host_wwpn (char *, size_t, const struct path *);
+int snprint_tgt_wwnn (char *, size_t, const struct path *);
+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);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 07/23] libmultipath: use "const" in devmapper code
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (5 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 06/23] libmultipath/print: use "const" where appropriate Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:07   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Improve use of "const" qualifiers in libmultipath's devmapper code.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/devmapper.c | 32 ++++++++++++++++----------------
 libmultipath/devmapper.h | 16 ++++++++--------
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index f112e1cb0e66..f61838cbe369 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -583,7 +583,7 @@ is_mpath_part(const char *part_name, const char *map_name)
 	return 0;
 }
 
-int dm_get_status(char *name, char *outstatus)
+int dm_get_status(const char *name, char *outstatus)
 {
 	int r = 1;
 	struct dm_task *dmt;
@@ -807,7 +807,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
 	if (need_suspend &&
 	    !dm_get_map(mapname, &mapsize, params) &&
 	    strstr(params, "queue_if_no_path")) {
-		if (!dm_queue_if_no_path((char *)mapname, 0))
+		if (!dm_queue_if_no_path(mapname, 0))
 			queue_if_no_path = 1;
 		else
 			/* Leave queue_if_no_path alone if unset failed */
@@ -850,7 +850,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove,
 	} while (retries-- > 0);
 
 	if (queue_if_no_path == 1)
-		dm_queue_if_no_path((char *)mapname, 1);
+		dm_queue_if_no_path(mapname, 1);
 
 	return 1;
 }
@@ -938,7 +938,7 @@ out:
 }
 
 int
-dm_fail_path(char * mapname, char * path)
+dm_fail_path(const char * mapname, char * path)
 {
 	char message[32];
 
@@ -949,7 +949,7 @@ dm_fail_path(char * mapname, char * path)
 }
 
 int
-dm_reinstate_path(char * mapname, char * path)
+dm_reinstate_path(const char * mapname, char * path)
 {
 	char message[32];
 
@@ -960,7 +960,7 @@ dm_reinstate_path(char * mapname, char * path)
 }
 
 int
-dm_queue_if_no_path(char *mapname, int enable)
+dm_queue_if_no_path(const char *mapname, int enable)
 {
 	char *message;
 
@@ -973,7 +973,7 @@ dm_queue_if_no_path(char *mapname, int enable)
 }
 
 static int
-dm_groupmsg (char * msg, char * mapname, int index)
+dm_groupmsg (const char * msg, const char * mapname, int index)
 {
 	char message[32];
 
@@ -984,19 +984,19 @@ dm_groupmsg (char * msg, char * mapname, int index)
 }
 
 int
-dm_switchgroup(char * mapname, int index)
+dm_switchgroup(const char * mapname, int index)
 {
 	return dm_groupmsg("switch", mapname, index);
 }
 
 int
-dm_enablegroup(char * mapname, int index)
+dm_enablegroup(const char * mapname, int index)
 {
 	return dm_groupmsg("enable", mapname, index);
 }
 
 int
-dm_disablegroup(char * mapname, int index)
+dm_disablegroup(const char * mapname, int index)
 {
 	return dm_groupmsg("disable", mapname, index);
 }
@@ -1080,7 +1080,7 @@ out:
 }
 
 int
-dm_geteventnr (char *name)
+dm_geteventnr (const char *name)
 {
 	struct dm_info info;
 
@@ -1139,7 +1139,7 @@ dm_mapname(int major, int minor)
 
 	map = dm_task_get_name(dmt);
 	if (map && strlen(map))
-		response = STRDUP((char *)dm_task_get_name(dmt));
+		response = STRDUP((const char *)dm_task_get_name(dmt));
 
 	dm_task_destroy(dmt);
 	return response;
@@ -1264,7 +1264,7 @@ cancel_remove_partmap (const char *name, void *unused)
 }
 
 static int
-dm_get_deferred_remove (char * mapname)
+dm_get_deferred_remove (const char * mapname)
 {
 	struct dm_info info;
 
@@ -1412,10 +1412,10 @@ out:
 	return r;
 }
 
-void dm_reassign_deps(char *table, char *dep, char *newdep)
+void dm_reassign_deps(char *table, const char *dep, const char *newdep)
 {
-	char *p, *n;
-	char *newtable;
+	char *n;
+	const char *p, *newtable;
 
 	newtable = strdup(table);
 	if (!newtable)
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 558e6914074f..8c8ea6c29b27 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -38,7 +38,7 @@ int dm_addmap_create (struct multipath *mpp, char *params);
 int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
 int dm_map_present (const char *);
 int dm_get_map(const char *, unsigned long long *, char *);
-int dm_get_status(char *, char *);
+int dm_get_status(const char *, char *);
 int dm_type(const char *, char *);
 int dm_is_mpath(const char *);
 int _dm_flush_map (const char *, int, int, int, int);
@@ -49,14 +49,14 @@ int dm_flush_map_nopaths(const char * mapname, int deferred_remove);
 	_dm_flush_map(mapname, 1, 0, 1, retries)
 int dm_cancel_deferred_remove(struct multipath *mpp);
 int dm_flush_maps (int retries);
-int dm_fail_path(char * mapname, char * path);
-int dm_reinstate_path(char * mapname, char * path);
-int dm_queue_if_no_path(char *mapname, int enable);
-int dm_switchgroup(char * mapname, int index);
-int dm_enablegroup(char * mapname, int index);
-int dm_disablegroup(char * mapname, int index);
+int dm_fail_path(const char * mapname, char * path);
+int dm_reinstate_path(const char * mapname, char * path);
+int dm_queue_if_no_path(const char *mapname, int enable);
+int dm_switchgroup(const char * mapname, int index);
+int dm_enablegroup(const char * mapname, int index);
+int dm_disablegroup(const char * mapname, int index);
 int dm_get_maps (vector mp);
-int dm_geteventnr (char *name);
+int dm_geteventnr (const char *name);
 int dm_is_suspended(const char *name);
 int dm_get_major_minor (const char *name, int *major, int *minor);
 char * dm_mapname(int major, int minor);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (6 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 07/23] libmultipath: use "const" in devmapper code Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:08   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 10/23] libmultipath: add vector_free_const() Martin Wilck
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Casting "const" away is often an indicator for wrong code.
Add a compiler flag to warn about such possible breakage.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 Makefile.inc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile.inc b/Makefile.inc
index eb99c36010c1..a5b9d4e3fa74 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -87,6 +87,7 @@ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
 OPTFLAGS	= -O2 -g -pipe -Wall -Wextra -Wformat=2 -Werror=implicit-int \
 		  -Werror=implicit-function-declaration -Werror=format-security \
 		  -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered \
+		  -Werror=cast-qual -Werror=discarded-qualifiers \
 		  -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \
 		  --param=ssp-buffer-size=4
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 10/23] libmultipath: add vector_free_const()
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (7 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  1:01   ` Bart Van Assche
  2018-03-06  7:08   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 11/23] libmultipath: add vector_convert() Martin Wilck
                   ` (13 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

... to dispose of constant vectors (const struct _vector*).

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/vector.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libmultipath/vector.h b/libmultipath/vector.h
index 5cfd4d060412..3f6e579ae19a 100644
--- a/libmultipath/vector.h
+++ b/libmultipath/vector.h
@@ -46,6 +46,7 @@ typedef struct _vector *vector;
 extern vector vector_alloc(void);
 extern void *vector_alloc_slot(vector v);
 extern void vector_free(vector v);
+#define vector_free_const(x) vector_free((vector)(long)(x))
 extern void free_strvec(vector strvec);
 extern void vector_set_slot(vector v, void *value);
 extern void vector_del_slot(vector v, int slot);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 11/23] libmultipath: add vector_convert()
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (8 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 10/23] libmultipath: add vector_free_const() Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:10   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 12/23] libmultipath: "generic multipath" interface Martin Wilck
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

This is a handy helper for creating one vector from another,
mapping each element of the origin vector to an element of
the target vector with a given conversion function. It can
also be used to "concatenate" vectors by passing in a non-NULL first
argument.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/vector.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/libmultipath/vector.h b/libmultipath/vector.h
index 3f6e579ae19a..6018b57525bf 100644
--- a/libmultipath/vector.h
+++ b/libmultipath/vector.h
@@ -42,6 +42,35 @@ typedef struct _vector *vector;
 #define vector_foreach_slot_backwards(v,p,i) \
 	for (i = VECTOR_SIZE(v); i > 0 && ((p) = (v)->slot[i-1]); i--)
 
+#define identity(x) (x)
+/*
+ * Given a vector vec with elements of given type,
+ * return a newly allocated vector with elements conv(e) for each element
+ * e in vec. "conv" may be a macro or a function.
+ * Use "identity" for a simple copy.
+ */
+#define vector_convert(new, vec, type, conv)				\
+	({								\
+		const struct _vector *__v = (vec);			\
+		vector __t = (new);					\
+		type *__j;						\
+		int __i;						\
+									\
+		if (__t == NULL)					\
+			__t = vector_alloc();				\
+		if (__t != NULL) {					\
+			vector_foreach_slot(__v, __j, __i) {		\
+				if (vector_alloc_slot(__t) == NULL) {	\
+					vector_free(__t);		\
+					__t = NULL;			\
+					break;				\
+				}					\
+				vector_set_slot(__t, conv(__j));	\
+			}						\
+		}							\
+		__t;							\
+	})
+
 /* Prototypes */
 extern vector vector_alloc(void);
 extern void *vector_alloc_slot(vector v);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 12/23] libmultipath: "generic multipath" interface
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (9 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 11/23] libmultipath: add vector_convert() Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:10   ` Hannes Reinecke
  2018-03-07 19:01   ` Benjamin Marzinski
  2018-03-05 23:14 ` [PATCH v2 13/23] libmultipath: print: convert API to generic data type Martin Wilck
                   ` (11 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

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     |   2 +-
 libmultipath/dm-generic.c |  70 ++++++++++++++++++++++++
 libmultipath/dm-generic.h |  41 ++++++++++++++
 libmultipath/generic.c    |  39 +++++++++++++
 libmultipath/generic.h    | 136 ++++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/list.h       |   4 ++
 libmultipath/print.c      |  33 +++++++++++
 libmultipath/print.h      |  12 ++++
 libmultipath/structs.c    |   4 ++
 libmultipath/structs.h    |   4 ++
 10 files changed, 344 insertions(+), 1 deletion(-)
 create mode 100644 libmultipath/dm-generic.c
 create mode 100644 libmultipath/dm-generic.h
 create mode 100644 libmultipath/generic.c
 create mode 100644 libmultipath/generic.h

diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 25b052729d48..0099d9d6cc39 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -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
index 000000000000..42a26085d087
--- /dev/null
+++ b/libmultipath/dm-generic.c
@@ -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
index 000000000000..5d5972406819
--- /dev/null
+++ b/libmultipath/dm-generic.h
@@ -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
index 000000000000..45012d0e1d95
--- /dev/null
+++ b/libmultipath/generic.c
@@ -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
index 000000000000..7f7fe6661c36
--- /dev/null
+++ b/libmultipath/generic.h
@@ -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 */
diff --git a/libmultipath/list.h b/libmultipath/list.h
index c9110ac9de7e..ced021f5a633 100644
--- a/libmultipath/list.h
+++ b/libmultipath/list.h
@@ -18,6 +18,10 @@
  * @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) );})
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 594ca567e22a..e9b8fdd6e581 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -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)
 {
diff --git a/libmultipath/print.h b/libmultipath/print.h
index 02c5b072cc2b..214777c1e4f8 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -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 */
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 4db08451824d..991095cb2bc1 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -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;
 }
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index bccc845a1222..88a4b7862393 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -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 {
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 13/23] libmultipath: print: convert API to generic data type
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (10 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 12/23] libmultipath: "generic multipath" interface Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:11   ` Hannes Reinecke
  2018-03-07 19:02   ` Benjamin Marzinski
  2018-03-05 23:14 ` [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout() Martin Wilck
                   ` (10 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Convert higher level API (snprint_multipath_topology() etc) to
using the generic multipath API. This will allow "foreign"
multipath objects that implement the generic API to be printed
exactly like native multipathd objects.

The previous API (using "struct multipath*" and "struct path" remains
in place through macros mapping to the new functions. By doing this
and testing in regular setups, it's easily verified that the new
API works and produces the same results.

Moreover, abstract out the code to determine the output format from multipath
properties into snprint_multipath_style(), to be able to use it as generic
->style() method.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/configure.c  |   1 +
 libmultipath/dm-generic.c |   2 +-
 libmultipath/print.c      | 115 +++++++++++++++++++++++++++++-----------------
 libmultipath/print.h      |  24 +++++++---
 multipath/main.c          |   1 +
 multipathd/cli_handlers.c |   1 +
 6 files changed, 95 insertions(+), 49 deletions(-)

diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 13e14cc25fff..42b7c896ee65 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -30,6 +30,7 @@
 #include "discovery.h"
 #include "debug.h"
 #include "switchgroup.h"
+#include "dm-generic.h"
 #include "print.h"
 #include "configure.h"
 #include "pgpolicies.h"
diff --git a/libmultipath/dm-generic.c b/libmultipath/dm-generic.c
index 42a26085d087..bdc9ca0a488b 100644
--- a/libmultipath/dm-generic.c
+++ b/libmultipath/dm-generic.c
@@ -56,7 +56,7 @@ 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 */
+	.style = snprint_multipath_style,
 };
 
 const struct gen_pathgroup_ops dm_gen_pathgroup_ops = {
diff --git a/libmultipath/print.c b/libmultipath/print.c
index e9b8fdd6e581..8701a3584859 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -30,7 +30,8 @@
 #include "debug.h"
 #include "discovery.h"
 
-#define MAX(x,y) (x > y) ? x : y
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MIN(x,y) (((x) > (y)) ? (y) : (x))
 #define TAIL     (line + len - 1 - c)
 #define NOPAD    s = c
 #define PAD(x) \
@@ -845,8 +846,8 @@ snprint_multipath_header (char * line, int len, const char * format)
 }
 
 int
-snprint_multipath (char * line, int len, const char * format,
-	     const struct multipath * mpp, int pad)
+_snprint_multipath (const struct gen_multipath * gmp,
+		    char * line, int len, const char * format, int pad)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
@@ -869,7 +870,7 @@ snprint_multipath (char * line, int len, const char * format,
 		if (!(data = mpd_lookup(*f)))
 			continue;
 
-		data->snprint(buff, MAX_FIELD_LEN, mpp);
+		gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
 		PRINT(c, TAIL, "%s", buff);
 		if (pad)
 			PAD(data->width);
@@ -912,8 +913,8 @@ snprint_path_header (char * line, int len, const char * format)
 }
 
 int
-snprint_path (char * line, int len, const char * format,
-	     const struct path * pp, int pad)
+_snprint_path (const struct gen_path * gp, char * line, int len,
+	       const char * format, int pad)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
@@ -936,7 +937,7 @@ snprint_path (char * line, int len, const char * format,
 		if (!(data = pd_lookup(*f)))
 			continue;
 
-		data->snprint(buff, MAX_FIELD_LEN, pp);
+		gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
 		PRINT(c, TAIL, "%s", buff);
 		if (pad)
 			PAD(data->width);
@@ -947,8 +948,8 @@ snprint_path (char * line, int len, const char * format,
 }
 
 int
-snprint_pathgroup (char * line, int len, char * format,
-		   const struct pathgroup * pgp)
+_snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
+		    char * format)
 {
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
@@ -971,7 +972,7 @@ snprint_pathgroup (char * line, int len, char * format,
 		if (!(data = pgd_lookup(*f)))
 			continue;
 
-		data->snprint(buff, MAX_FIELD_LEN, pgp);
+		ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
 		PRINT(c, TAIL, "%s", buff);
 		PAD(data->width);
 	} while (*f++);
@@ -979,8 +980,10 @@ snprint_pathgroup (char * line, int len, char * format,
 	__endline(line, len, c);
 	return (c - line);
 }
+#define snprint_pathgroup(line, len, fmt, pgp) \
+	_snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
 
-void print_multipath_topology(struct multipath *mpp, int verbosity)
+void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
 {
 	int resize;
 	char *buff = NULL;
@@ -997,7 +1000,7 @@ void print_multipath_topology(struct multipath *mpp, int verbosity)
 			return;
 		}
 
-		len = snprint_multipath_topology(buff, maxlen, mpp, verbosity);
+		len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
 		resize = (len == maxlen - 1);
 
 		if (resize) {
@@ -1010,12 +1013,30 @@ void print_multipath_topology(struct multipath *mpp, int verbosity)
 	FREE(buff);
 }
 
-int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp,
-			       int verbosity)
+int
+snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
+			int verbosity)
+{
+	int n;
+	const struct multipath *mpp = gen_multipath_to_dm(gmp);
+	bool need_action = (verbosity > 1 &&
+			    mpp->action != ACT_NOTHING &&
+			    mpp->action != ACT_UNDEF &&
+			    mpp->action != ACT_IMPOSSIBLE);
+	bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
+
+	n = snprintf(style, len, "%s%s%s%s",
+		     need_action ? "%A: " : "", "%n",
+		     need_wwid ? " (%w)" : "", " %d %s");
+	return MIN(n, len - 1);
+}
+
+int _snprint_multipath_topology(const struct gen_multipath *gmp,
+				char *buff, int len, int verbosity)
 {
 	int j, i, fwd = 0;
-	struct path * pp = NULL;
-	struct pathgroup * pgp = NULL;
+	const struct _vector *pgvec;
+	const struct gen_pathgroup *gpg;
 	char style[64];
 	char * c = style;
 	char fmt[64];
@@ -1027,60 +1048,70 @@ int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp,
 	reset_multipath_layout();
 
 	if (verbosity == 1)
-		return snprint_multipath(buff, len, "%n", mpp, 1);
+		return _snprint_multipath(gmp, buff, len, "%n", 1);
 
 	if(isatty(1))
 		c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
 
-	if (verbosity > 1 &&
-	    mpp->action != ACT_NOTHING &&
-	    mpp->action != ACT_UNDEF && mpp->action != ACT_IMPOSSIBLE)
-			c += sprintf(c, "%%A: ");
-
-	c += sprintf(c, "%%n");
-
-	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
-		c += sprintf(c, " (%%w)");
-
-	c += sprintf(c, " %%d %%s");
+	c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
+			     verbosity);
 	if(isatty(1))
 		c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
 
-	fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1);
+	fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
 	if (fwd >= len)
 		return len;
-	fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp,
-				 1);
+	fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
+				  PRINT_MAP_PROPS, 1);
 	if (fwd >= len)
 		return len;
 
-	if (!mpp->pg)
+	pgvec = gmp->ops->get_pathgroups(gmp);
+	if (pgvec == NULL)
 		return fwd;
 
-	vector_foreach_slot (mpp->pg, pgp, j) {
+	vector_foreach_slot (pgvec, gpg, j) {
+		const struct _vector *pathvec;
+		struct gen_path *gp;
+
 		f=fmt;
-		if (j + 1 < VECTOR_SIZE(mpp->pg)) {
+
+		if (j + 1 < VECTOR_SIZE(pgvec)) {
 			strcpy(f, "|-+- " PRINT_PG_INDENT);
 		} else
 			strcpy(f, "`-+- " PRINT_PG_INDENT);
-		fwd += snprint_pathgroup(buff + fwd, len - fwd, fmt, pgp);
-		if (fwd >= len)
-			return len;
+		fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
 
-		vector_foreach_slot (pgp->paths, pp, i) {
+		if (fwd >= len) {
+			fwd = len;
+			break;
+		}
+
+		pathvec = gpg->ops->get_paths(gpg);
+		if (pathvec == NULL)
+			continue;
+
+		vector_foreach_slot (pathvec, gp, i) {
 			f=fmt;
 			if (*f != '|')
 				*f=' ';
 			f++;
-			if (i + 1 < VECTOR_SIZE(pgp->paths))
+			if (i + 1 < VECTOR_SIZE(pathvec))
 				strcpy(f, " |- " PRINT_PATH_INDENT);
 			else
 				strcpy(f, " `- " PRINT_PATH_INDENT);
-			fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1);
-			if (fwd >= len)
-				return len;
+			fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
+			if (fwd >= len) {
+				fwd = len;
+				break;
+			}
 		}
+		gpg->ops->rel_paths(gpg, pathvec);
+
+		if (fwd == len)
+			break;
 	}
+	gmp->ops->rel_pathgroups(gmp, pgvec);
 	return fwd;
 }
 
diff --git a/libmultipath/print.h b/libmultipath/print.h
index 214777c1e4f8..b8b9ecbd204f 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -98,11 +98,17 @@ void get_path_layout (vector pathvec, int header);
 void get_multipath_layout (vector mpvec, int header);
 int snprint_path_header (char *, int, const char *);
 int snprint_multipath_header (char *, int, const char *);
-int snprint_path (char *, int, const char *, const struct path *, int);
-int snprint_multipath (char *, int, const char *,
-		       const struct multipath *, int);
-int snprint_multipath_topology (char *, int, const struct multipath * mpp,
-				int verbosity);
+int _snprint_path (const struct gen_path *, char *, int, const char *, int);
+#define snprint_path(buf, len, fmt, pp, v) \
+	_snprint_path(dm_path_to_gen(pp), buf, len, fmt,  v)
+int _snprint_multipath (const struct gen_multipath *, char *, int,
+			const char *, int);
+#define snprint_multipath(buf, len, fmt, mp, v)				\
+	_snprint_multipath(dm_multipath_to_gen(mp), buf, len, fmt,  v)
+int _snprint_multipath_topology (const struct gen_multipath *, char *, int, 
+				 int verbosity);
+#define snprint_multipath_topology(buf, len, mpp, v) \
+	_snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, len, v)
 int snprint_multipath_topology_json (char * buff, int len,
 				const struct vectors * vecs);
 int snprint_multipath_map_json (char * buff, int len,
@@ -123,7 +129,11 @@ int snprint_host_wwpn (char *, size_t, const struct path *);
 int snprint_tgt_wwnn (char *, size_t, const struct path *);
 int snprint_tgt_wwpn (char *, size_t, const struct path *);
 
-void print_multipath_topology (struct multipath * mpp, int verbosity);
+void _print_multipath_topology (const struct gen_multipath * gmp,
+				int verbosity);
+#define print_multipath_topology(mpp, v) \
+	_print_multipath_topology(dm_multipath_to_gen(mpp), v)
+
 void print_all_paths (vector pathvec, int banner);
 void print_all_paths_custo (vector pathvec, int banner, char *fmt);
 
@@ -133,4 +143,6 @@ 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);
+int snprint_multipath_style(const struct gen_multipath *gmp,
+			    char *style, int len, int verbosity);
 #endif /* _PRINT_H */
diff --git a/multipath/main.c b/multipath/main.c
index 52bf1658bbca..a0c750e6f623 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -47,6 +47,7 @@
 #include "discovery.h"
 #include "debug.h"
 #include "switchgroup.h"
+#include "dm-generic.h"
 #include "print.h"
 #include "alias.h"
 #include "configure.h"
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 7f13bc9d6f32..78f2a12bc2f8 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -16,6 +16,7 @@
 #include "configure.h"
 #include "blacklist.h"
 #include "debug.h"
+#include "dm-generic.h"
 #include "print.h"
 #include "sysfs.h"
 #include <errno.h>
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout()
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (11 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 13/23] libmultipath: print: convert API to generic data type Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:12   ` Hannes Reinecke
  2018-03-05 23:14 ` [PATCH v2 15/23] libmultipath: API for foreign multipath handling Martin Wilck
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Introduce new functions _get_path_layout and _get_multipath_layout
using the new "generic" API to determine field widths, and map the
old API to them.

Furthermore, replace the boolean "header" by an enum with 3 possible
values. The new value LAYOUT_RESET_NOT allows calling the get_x_layout
function several times and determine the overall field width.

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/print.c | 73 ++++++++++++++++++++++++++++++++++++++++------------
 libmultipath/print.h |  8 ++++++
 2 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/libmultipath/print.c b/libmultipath/print.c
index 8701a3584859..01e7483e3e44 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -697,20 +697,48 @@ snprint_wildcards (char * buff, int len)
 }
 
 void
-get_path_layout (vector pathvec, int header)
+get_path_layout(vector pathvec, int header)
+{
+	vector gpvec = vector_convert(NULL, pathvec, struct path,
+				      dm_path_to_gen);
+	_get_path_layout(gpvec,
+			 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+	vector_free(gpvec);
+}
+
+static void
+reset_width(int *width, enum layout_reset reset, const char *header)
+{
+	switch (reset) {
+	case LAYOUT_RESET_HEADER:
+		*width = strlen(header);
+		break;
+	case LAYOUT_RESET_ZERO:
+		*width = 0;
+		break;
+	default:
+		/* don't reset */
+		break;
+	}
+}
+
+void
+_get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
 {
 	int i, j;
 	char buff[MAX_FIELD_LEN];
-	struct path * pp;
+	const struct gen_path *gp;
 
 	for (j = 0; pd[j].header; j++) {
-		if (header)
-			pd[j].width = strlen(pd[j].header);
-		else
-			pd[j].width = 0;
 
-		vector_foreach_slot (pathvec, pp, i) {
-			pd[j].snprint(buff, MAX_FIELD_LEN, pp);
+		reset_width(&pd[j].width, reset, pd[j].header);
+
+		if (gpvec == NULL)
+			continue;
+
+		vector_foreach_slot (gpvec, gp, i) {
+			gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
+					 pd[j].wildcard);
 			pd[j].width = MAX(pd[j].width, strlen(buff));
 		}
 	}
@@ -726,22 +754,35 @@ reset_multipath_layout (void)
 }
 
 void
-get_multipath_layout (vector mpvec, int header)
+get_multipath_layout (vector mpvec, int header) {
+	vector gmvec = vector_convert(NULL, mpvec, struct multipath,
+				      dm_multipath_to_gen);
+	_get_multipath_layout(gmvec,
+			 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+	vector_free(gmvec);
+}
+
+void
+_get_multipath_layout (const struct _vector *gmvec,
+			    enum layout_reset reset)
 {
 	int i, j;
 	char buff[MAX_FIELD_LEN];
-	struct multipath * mpp;
+	const struct gen_multipath * gm;
 
 	for (j = 0; mpd[j].header; j++) {
-		if (header)
-			mpd[j].width = strlen(mpd[j].header);
-		else
-			mpd[j].width = 0;
 
-		vector_foreach_slot (mpvec, mpp, i) {
-			mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
+		reset_width(&mpd[j].width, reset, mpd[j].header);
+
+		if (gmvec == NULL)
+			continue;
+
+		vector_foreach_slot (gmvec, gm, i) {
+			gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
+					 mpd[j].wildcard);
 			mpd[j].width = MAX(mpd[j].width, strlen(buff));
 		}
+		condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
 	}
 }
 
diff --git a/libmultipath/print.h b/libmultipath/print.h
index b8b9ecbd204f..7ba643892579 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -94,7 +94,15 @@ struct pathgroup_data {
 	int (*snprint)(char * buff, size_t len, const struct pathgroup * pgp);
 };
 
+enum layout_reset {
+	LAYOUT_RESET_NOT,
+	LAYOUT_RESET_ZERO,
+	LAYOUT_RESET_HEADER,
+};
+
+void _get_path_layout (const struct _vector *gpvec, enum layout_reset);
 void get_path_layout (vector pathvec, int header);
+void _get_multipath_layout (const struct _vector *gmvec, enum layout_reset);
 void get_multipath_layout (vector mpvec, int header);
 int snprint_path_header (char *, int, const char *);
 int snprint_multipath_header (char *, int, const char *);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 15/23] libmultipath: API for foreign multipath handling
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (12 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout() Martin Wilck
@ 2018-03-05 23:14 ` Martin Wilck
  2018-03-06  7:12   ` Hannes Reinecke
  2018-03-07 19:08   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
                   ` (8 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:14 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Add an API for "foreign" multipaths. Foreign libraries are loaded
from ${multipath_dir}/libforeign-*.so, as we do for checkers.

Refer to "foreign.h" for details about the API itself. Like we do for
checkers, high-level multipath code isn't supposed to call the API directly,
but rather the wrapper functions declared in "foreign.h".

This API is used only for displaying information and for logging. An extension to
other functionality (such as monitoring or administration) might be feasible,
but is not planned.

Foreign libraries communicate with libmultipath through the API defined in
"foreign.h". The foreign library can implement multipath maps, pathgroups,
and paths as it likes, they just need to provide the simple interfaces
defined in "generic.h" to libmultipath. These interfaces are used in libmultipath's
"print" implementation to convey various bits of information to users. By
using the same interfaces for printing that libmultipath uses internally,
foreign library implementations can focus on the technical side without
worrying about output formatting compatibility.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/Makefile  |   2 +-
 libmultipath/foreign.c | 602 +++++++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/foreign.h | 322 ++++++++++++++++++++++++++
 3 files changed, 925 insertions(+), 1 deletion(-)
 create mode 100644 libmultipath/foreign.c
 create mode 100644 libmultipath/foreign.h

diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 0099d9d6cc39..806aaa24f84e 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -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 dm-generic.o generic.o
+	io_err_stat.o dm-generic.o generic.o foreign.o
 
 all: $(LIBS)
 
diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c
new file mode 100644
index 000000000000..72171840e995
--- /dev/null
+++ b/libmultipath/foreign.c
@@ -0,0 +1,602 @@
+/*
+  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 <sys/sysmacros.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <dlfcn.h>
+#include <libudev.h>
+#include "vector.h"
+#include "debug.h"
+#include "util.h"
+#include "foreign.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "print.h"
+
+static vector foreigns;
+
+/* This protects vector foreigns */
+static pthread_rwlock_t foreign_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+static void rdlock_foreigns(void)
+{
+	pthread_rwlock_rdlock(&foreign_lock);
+}
+
+static void wrlock_foreigns(void)
+{
+	pthread_rwlock_wrlock(&foreign_lock);
+}
+
+static void unlock_foreigns(void *unused)
+{
+	pthread_rwlock_unlock(&foreign_lock);
+}
+
+#define get_dlsym(foreign, sym, lbl)					\
+	do {								\
+		foreign->sym =	dlsym(foreign->handle, #sym);		\
+		if (foreign->sym == NULL) {				\
+			condlog(0, "%s: symbol \"%s\" not found in \"%s\"", \
+				__func__, #sym, foreign->name);		\
+			goto lbl;					\
+		}							\
+	} while(0)
+
+static void free_foreign(struct foreign *fgn)
+{
+	struct context *ctx;
+
+	if (fgn == NULL)
+		return;
+
+	ctx = fgn->context;
+	fgn->context = NULL;
+	if (ctx != NULL)
+		fgn->cleanup(ctx);
+
+	if (fgn->handle != NULL)
+		dlclose(fgn->handle);
+	free(fgn);
+}
+
+void _cleanup_foreign(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	if (foreigns == NULL)
+		return;
+
+	vector_foreach_slot_backwards(foreigns, fgn, i) {
+		vector_del_slot(foreigns, i);
+		free_foreign(fgn);
+	}
+	vector_free(foreigns);
+	foreigns = NULL;
+}
+
+void cleanup_foreign(void)
+{
+	wrlock_foreigns();
+	_cleanup_foreign();
+	unlock_foreigns(NULL);
+}
+
+static const char foreign_pattern[] = "libforeign-*.so";
+
+static int select_foreign_libs(const struct dirent *di)
+{
+
+	return fnmatch(foreign_pattern, di->d_name, FNM_FILE_NAME) == 0;
+}
+
+static int _init_foreign(const char *multipath_dir)
+{
+	char pathbuf[PATH_MAX];
+	struct dirent **di;
+	int r, i;
+
+	foreigns = vector_alloc();
+	if (foreigns == NULL)
+		return -ENOMEM;
+
+	r = scandir(multipath_dir, &di, select_foreign_libs, alphasort);
+
+	if (r == 0) {
+		condlog(3, "%s: no foreign multipath libraries found",
+			__func__);
+		return 0;
+	} else if (r < 0) {
+		r = errno;
+		condlog(1, "%s: error %d scanning foreign multipath libraries",
+			__func__, r);
+		_cleanup_foreign();
+		return -r;
+	}
+
+	pthread_cleanup_push(free, di);
+	for (i = 0; i < r; i++) {
+		const char *msg, *fn, *c;
+		struct foreign *fgn;
+		int len, namesz;
+
+		fn = di[i]->d_name;
+
+		len = strlen(fn);
+		c = strchr(fn, '-');
+		if (len < sizeof(foreign_pattern) - 1 || c == NULL) {
+			condlog(0, "%s: bad file name %s, fnmatch error?",
+				__func__, fn);
+			continue;
+		}
+		c++;
+		condlog(4, "%s: found %s", __func__, fn);
+
+		namesz = len - sizeof(foreign_pattern) + 3;
+		fgn = malloc(sizeof(*fgn) + namesz);
+		if (fgn == NULL)
+			continue;
+		memset(fgn, 0, sizeof(*fgn));
+		strlcpy((char*)fgn + offsetof(struct foreign, name), c, namesz);
+
+		snprintf(pathbuf, sizeof(pathbuf), "%s/%s", multipath_dir, fn);
+		fgn->handle = dlopen(pathbuf, RTLD_NOW|RTLD_LOCAL);
+		msg = dlerror();
+		if (fgn->handle == NULL) {
+			condlog(1, "%s: failed to dlopen %s: %s", __func__,
+				pathbuf, msg);
+			goto dl_err;
+		}
+
+		get_dlsym(fgn, init, dl_err);
+		get_dlsym(fgn, cleanup, dl_err);
+		get_dlsym(fgn, add, dl_err);
+		get_dlsym(fgn, change, dl_err);
+		get_dlsym(fgn, delete, dl_err);
+		get_dlsym(fgn, delete_all, dl_err);
+		get_dlsym(fgn, check, dl_err);
+		get_dlsym(fgn, lock, dl_err);
+		get_dlsym(fgn, unlock, dl_err);
+		get_dlsym(fgn, get_multipaths, dl_err);
+		get_dlsym(fgn, release_multipaths, dl_err);
+		get_dlsym(fgn, get_paths, dl_err);
+		get_dlsym(fgn, release_paths, dl_err);
+
+		fgn->context = fgn->init(LIBMP_FOREIGN_API, fgn->name);
+		if (fgn->context == NULL) {
+			condlog(0, "%s: init() failed for %s", __func__, fn);
+			goto dl_err;
+		}
+
+		if (vector_alloc_slot(foreigns) == NULL) {
+			goto dl_err;
+		}
+
+		vector_set_slot(foreigns, fgn);
+		condlog(3, "foreign library \"%s\" loaded successfully",
+			fgn->name);
+
+		continue;
+
+	dl_err:
+		free_foreign(fgn);
+	}
+	pthread_cleanup_pop(1);
+	return 0;
+}
+
+int init_foreign(const char *multipath_dir)
+{
+	int ret;
+
+	wrlock_foreigns();
+
+	if (foreigns != NULL) {
+		unlock_foreigns(NULL);
+		condlog(0, "%s: already initialized", __func__);
+		return -EEXIST;
+	}
+
+	pthread_cleanup_push(unlock_foreigns, NULL);
+	ret = _init_foreign(multipath_dir);
+	pthread_cleanup_pop(1);
+
+	return ret;
+}
+
+int add_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	dev_t dt;
+	int j;
+	int r = FOREIGN_IGNORED;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return FOREIGN_ERR;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		r = fgn->add(fgn->context, udev);
+
+		if (r == FOREIGN_CLAIMED) {
+			condlog(3, "%s: foreign \"%s\" claims device %d:%d",
+				__func__, fgn->name, major(dt), minor(dt));
+			break;
+		} else if (r == FOREIGN_OK) {
+			condlog(4, "%s: foreign \"%s\" owns device %d:%d",
+				__func__, fgn->name, major(dt), minor(dt));
+			break;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+
+	pthread_cleanup_pop(1);
+	return r;
+}
+
+int change_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	int j;
+	dev_t dt;
+	int r = FOREIGN_IGNORED;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return FOREIGN_ERR;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		r = fgn->change(fgn->context, udev);
+
+		if (r == FOREIGN_OK) {
+			condlog(4, "%s: foreign \"%s\" completed %d:%d",
+				__func__, fgn->name, major(dt), minor(dt));
+			break;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+
+	pthread_cleanup_pop(1);
+	return r;
+}
+
+int delete_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	int j;
+	dev_t dt;
+	int r = FOREIGN_IGNORED;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return FOREIGN_ERR;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		r = fgn->delete(fgn->context, udev);
+
+		if (r == FOREIGN_OK) {
+			condlog(3, "%s: foreign \"%s\" deleted device %d:%d",
+				__func__, fgn->name, major(dt), minor(dt));
+			break;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+
+	pthread_cleanup_pop(1);
+	return r;
+}
+
+int delete_all_foreign(void)
+{
+	struct foreign *fgn;
+	int j;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return FOREIGN_ERR;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, j) {
+		int r;
+
+		r = fgn->delete_all(fgn->context);
+		if (r != FOREIGN_IGNORED && r != FOREIGN_OK) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+
+	pthread_cleanup_pop(1);
+	return FOREIGN_OK;
+}
+
+void check_foreign(void)
+{
+	struct foreign *fgn;
+	int j;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, j) {
+		fgn->check(fgn->context);
+	}
+
+	pthread_cleanup_pop(1);
+}
+
+/* Call this after get_path_layout */
+void foreign_path_layout(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+
+		fgn->lock(fgn->context);
+		pthread_cleanup_push(fgn->unlock, fgn->context);
+
+		vec = fgn->get_paths(fgn->context);
+		if (vec != NULL) {
+			_get_path_layout(vec, LAYOUT_RESET_NOT);
+		}
+		fgn->release_paths(fgn->context, vec);
+
+		pthread_cleanup_pop(1);
+	}
+
+	pthread_cleanup_pop(1);
+}
+
+/* Call this after get_multipath_layout */
+void foreign_multipath_layout(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+
+		fgn->lock(fgn->context);
+		pthread_cleanup_push(fgn->unlock, fgn->context);
+
+		vec = fgn->get_multipaths(fgn->context);
+		if (vec != NULL) {
+			_get_multipath_layout(vec, LAYOUT_RESET_NOT);
+		}
+		fgn->release_multipaths(fgn->context, vec);
+
+		pthread_cleanup_pop(1);
+	}
+
+	pthread_cleanup_pop(1);
+}
+
+int snprint_foreign_topology(char *buf, int len, int verbosity)
+{
+	struct foreign *fgn;
+	int i;
+	char *c = buf;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return 0;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+		const struct gen_multipath *gm;
+		int j;
+
+		fgn->lock(fgn->context);
+		pthread_cleanup_push(fgn->unlock, fgn->context);
+
+		vec = fgn->get_multipaths(fgn->context);
+		if (vec != NULL) {
+			vector_foreach_slot(vec, gm, j) {
+
+				c += _snprint_multipath_topology(gm, c,
+								 buf + len - c,
+								 verbosity);
+				if (c >= buf + len - 1)
+					break;
+			}
+			if (c >= buf + len - 1)
+				break;
+		}
+		fgn->release_multipaths(fgn->context, vec);
+		pthread_cleanup_pop(1);
+	}
+
+	pthread_cleanup_pop(1);
+	return c - buf;
+}
+
+void print_foreign_topology(int verbosity)
+{
+	int buflen = MAX_LINE_LEN * MAX_LINES;
+	char *buf = NULL, *tmp = NULL;
+
+	buf = malloc(buflen);
+	buf[0] = '\0';
+	while (buf != NULL) {
+		char *c = buf;
+
+		c += snprint_foreign_topology(buf, buflen,
+						   verbosity);
+		if (c < buf + buflen - 1)
+			break;
+
+		buflen *= 2;
+		tmp = buf;
+		buf = realloc(buf, buflen);
+	}
+
+	if (buf == NULL && tmp != NULL)
+		buf = tmp;
+
+	if (buf != NULL) {
+		printf("%s", buf);
+		free(buf);
+	}
+}
+
+int snprint_foreign_paths(char *buf, int len, const char *style, int pretty)
+{
+	struct foreign *fgn;
+	int i;
+	char *c = buf;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return 0;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+		const struct gen_path *gp;
+		int j;
+
+		fgn->lock(fgn->context);
+		pthread_cleanup_push(fgn->unlock, fgn->context);
+
+		vec = fgn->get_paths(fgn->context);
+		if (vec != NULL) {
+			vector_foreach_slot(vec, gp, j) {
+				c += _snprint_path(gp, c, buf + len - c,
+						   style, pretty);
+				if (c >= buf + len - 1)
+					break;
+			}
+			if (c >= buf + len - 1)
+				break;
+		}
+		fgn->release_paths(fgn->context, vec);
+		pthread_cleanup_pop(1);
+	}
+
+	pthread_cleanup_pop(1);
+	return c - buf;
+}
+
+int snprint_foreign_multipaths(char *buf, int len,
+			       const char *style, int pretty)
+{
+	struct foreign *fgn;
+	int i;
+	char *c = buf;
+
+	rdlock_foreigns();
+	if (foreigns == NULL) {
+		unlock_foreigns(NULL);
+		return 0;
+	}
+	pthread_cleanup_push(unlock_foreigns, NULL);
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+		const struct gen_multipath *gm;
+		int j;
+
+		fgn->lock(fgn->context);
+		pthread_cleanup_push(fgn->unlock, fgn->context);
+
+		vec = fgn->get_multipaths(fgn->context);
+		if (vec != NULL) {
+			vector_foreach_slot(vec, gm, j) {
+				c += _snprint_multipath(gm, c, buf + len - c,
+							style, pretty);
+				if (c >= buf + len - 1)
+					break;
+			}
+			if (c >= buf + len - 1)
+				break;
+		}
+		fgn->release_multipaths(fgn->context, vec);
+		pthread_cleanup_pop(1);
+	}
+
+	pthread_cleanup_pop(1);
+	return c - buf;
+}
diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h
new file mode 100644
index 000000000000..0ade2d7485c4
--- /dev/null
+++ b/libmultipath/foreign.h
@@ -0,0 +1,322 @@
+/*
+  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 _FOREIGN_H
+#define _FOREIGN_H
+#include <stdbool.h>
+#include <libudev.h>
+
+#define LIBMP_FOREIGN_API ((1 << 8) | 0)
+
+struct context;
+
+/* return codes of functions below returning "int" */
+enum foreign_retcode {
+	FOREIGN_OK,
+	FOREIGN_CLAIMED,
+	FOREIGN_IGNORED,
+	FOREIGN_UNCLAIMED,
+	FOREIGN_NODEV,
+	FOREIGN_ERR,
+	__LAST_FOREIGN_RETCODE,
+};
+
+/**
+ * Foreign multipath library API
+ * Foreign libraries must implement the following methods.
+ */
+struct foreign {
+	/**
+	 * method: init(api, name)
+	 * Initialize foreign library, and check API compatibility
+	 * return pointer to opaque internal data strucure if successful,
+	 * NULL otherwise.
+	 *
+	 * @param[in] api: API version
+	 * @param[in] name: name to use for references to self in log messages,
+	 *     doesn't need to be strdup'd
+	 * @returns context pointer to use in future method calls.
+	 */
+	struct context* (*init)(unsigned int api, const char *name);
+
+	/**
+	 * method: cleanup(context)
+	 * Free data structures used by foreign library, including
+	 * context itself.
+	 *
+	 * @param[in] context foreign library context. This shouldn't be
+	 * referenced any more after calling cleanup().
+	 */
+	void (*cleanup)(struct context *);
+
+	/**
+	 * method: add(context, udev)
+	 * This is called during path detection, and for udev ADD events.
+	 *
+	 * @param[in] context foreign library context
+	 * @param[in] udev udev device to add
+	 * @returns status code
+	 * @retval FOREIGN_CLAIMED: device newly claimed
+	 * @retval FOREIGN_OK: device already registered, no action taken
+	 * @retval FOREIGN_IGNORED: device is ignored, no action taken
+	 * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
+	 */
+	int (*add)(struct context *, struct udev_device *);
+
+	/**
+	 * method: change
+	 * This is called on udev CHANGE events.
+	 *
+	 * @param[in] context foreign library context
+	 * @param[in] udev udev device that has generated the event
+	 * @returns status code
+	 * @retval FOREIGN_OK: event processed
+	 * @retval FOREIGN_IGNORED: the device is ignored
+	 * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
+	 *
+	 * Note: theoretically it can happen that the status of a foreign device
+	 * (claimed vs. not claimed) changes in a change event.
+	 * Supporting this correctly would require big efforts. For now, we
+	 * don't support it. "multipathd reconfigure" starts foreign device
+	 * detection from scratch and should be able to handle this situation.
+	 */
+	int (*change)(struct context *, struct udev_device *);
+
+	/**
+	 * method: delete
+	 * This is called on udev DELETE events.
+	 *
+	 * @param[in] context foreign library context
+	 * @param[in] udev udev device that has generated the event and
+	 *	should be deleted
+	 * @returns status code
+	 * @retval FOREIGN_OK: processed correctly (device deleted)
+	 * @retval FOREIGN_IGNORED: device wasn't registered internally
+	 * @retval FOREIGN_ERR: error occured.
+	 */
+	int (*delete)(struct context *, struct udev_device *);
+
+	/**
+	 * method: delete_all
+	 * This is called if multipathd reconfigures itself.
+	 * Deletes all registered devices (maps and paths)
+	 *
+	 * @param[in] context foreign library context
+	 * @returns status code
+	 * @retval FOREIGN_OK: processed correctly
+	 * @retval FOREIGN_IGNORED: nothing to delete
+	 * @retval FOREIGN_ERR: error occured
+	 */
+	int (*delete_all)(struct context*);
+
+	/**
+	 * method: check
+	 * This is called from multipathd's checker loop.
+	 *
+	 * Check status of managed devices, update internal status, and print
+	 * log messages if appropriate.
+	 * @param[in] context foreign library context
+	 */
+	void (*check)(struct context *);
+
+	/**
+	 * lock internal data stuctures.
+	 * @param[in] ctx: foreign context
+	 */
+	void (*lock)(struct context *ctx);
+
+	/**
+	 * unlock internal data stuctures.
+	 * @param[in] ctx: foreign context (void* in order to use the function
+	 *	as argument to pthread_cleanup_push())
+	 */
+	void (*unlock)(void *ctx);
+
+	/**
+	 * method: get_multipaths(context)
+	 * Returned vector must be freed by calling release_multipaths().
+	 * Lock must be held until release_multipaths() is called.
+	 *
+	 * @param[in] context foreign library context
+	 * @returns a vector of "struct gen_multipath*" with the map devices
+	 * belonging to this library (see generic.h).
+	 */
+	const struct _vector* (*get_multipaths)(const struct context *);
+
+	/**
+	 * method: release_multipaths(context, mpvec)
+	 * release data structures obtained with get_multipaths (if any)
+	 *
+	 * @param[in] ctx the foreign context
+	 * @param[in] mpvec the vector allocated with get_multipaths()
+	 */
+	void (*release_multipaths)(const struct context *ctx,
+				   const struct _vector* mpvec);
+
+	/**
+	 * method: get_paths
+	 * Returned vector must be freed by calling release_paths().
+	 * Lock must be held until release_paths() is called.
+	 *
+	 * @param[in] context foreign library context
+	 * @returns a vector of "struct gen_path*" with the path devices
+	 * belonging to this library (see generic.h)
+	 */
+	const struct _vector* (*get_paths)(const struct context *);
+
+	/**
+	 * release data structures obtained with get_multipaths (if any)
+	 *
+	 * @param[in] ctx the foreign context
+	 * @param[in] ppvec the vector allocated with get_paths()
+	 */
+	void (*release_paths)(const struct context *ctx,
+			      const struct _vector* ppvec);
+
+	void *handle;
+	struct context *context;
+	const char name[0];
+};
+
+/**
+ * init_foreign(dir)
+ * load and initialize foreign multipath libraries in dir (libforeign-*.so).
+ * @param dir: directory to search
+ * @returns: 0 on success, negative value on failure.
+ */
+int init_foreign(const char *multipath_dir);
+
+/**
+ * cleanup_foreign(dir)
+ * cleanup and free all data structures owned by foreign libraries
+ */
+void cleanup_foreign(void);
+
+/**
+ * add_foreign(udev)
+ * check if a device belongs to any foreign library.
+ * calls add() for all known foreign libs, in the order registered,
+ * until the first one returns FOREIGN_CLAIMED or FOREIGN_OK.
+ * @param udev: udev device to check
+ * @returns: status code
+ * @retval FOREIGN_CLAIMED: newly claimed by a foreign lib
+ * @retval FOREIGN_OK: already claimed by a foreign lib
+ * @retval FOREIGN_IGNORED: ignored by all foreign libs
+ * @retval FOREIGN_ERR: an error occured
+ */
+int add_foreign(struct udev_device *);
+
+/**
+ * change_foreign(udev)
+ * Notify foreign libraries of an udev CHANGE event
+ * @param udev: udev device to check
+ * @returns: status code (see change() method above).
+ */
+int change_foreign(struct udev_device *);
+
+/**
+ * delete_foreign(udev)
+ * @param udev: udev device being removed
+ * @returns: status code (see remove() above)
+ */
+int delete_foreign(struct udev_device *);
+
+/**
+ * delete_all_foreign()
+ * call delete_all() for all foreign libraries
+ * @returns: status code (see delete_all() above)
+ */
+int delete_all_foreign(void);
+
+/**
+ * check_foreign()
+ * call check() (see above) for all foreign libraries
+ */
+void check_foreign(void);
+
+/**
+ * foreign_path_layout()
+ * call this before printing paths, after get_path_layout(), to determine
+ * output field width.
+ */
+void foreign_path_layout(void);
+
+/**
+ * foreign_multipath_layout()
+ * call this before printing maps, after get_multipath_layout(), to determine
+ * output field width.
+ */
+void foreign_multipath_layout(void);
+
+/**
+ * snprint_foreign_topology(buf, len, verbosity);
+ * prints topology information from foreign libraries into buffer,
+ * '\0' - terminated.
+ * @param buf: output buffer
+ * @param len: size of output buffer
+ * @param verbosity: verbosity level
+ * @returns: number of printed characters excluding trailing '\0'.
+ */
+int snprint_foreign_topology(char *buf, int len, int verbosity);
+
+/**
+ * snprint_foreign_paths(buf, len, style, pad);
+ * prints formatted path information from foreign libraries into buffer,
+ * '\0' - terminated.
+ * @param buf: output buffer
+ * @param len: size of output buffer
+ * @param style: format string
+ * @param pad: whether to pad field width
+ * @returns: number of printed characters excluding trailing '\0'.
+ */
+int snprint_foreign_paths(char *buf, int len, const char *style, int pad);
+
+/**
+ * snprint_foreign_multipaths(buf, len, style, pad);
+ * prints formatted map information from foreign libraries into buffer,
+ * '\0' - terminated.
+ * @param buf: output buffer
+ * @param len: size of output buffer
+ * @param style: format string
+ * @param pad: whether to pad field width
+ * @returns: number of printed characters excluding trailing '\0'.
+ */
+int snprint_foreign_multipaths(char *buf, int len,
+			       const char *style, int pretty);
+
+/**
+ * print_foreign_topology(v)
+ * print foreign topology to stdout
+ * @param verbosity: verbosity level
+ */
+void print_foreign_topology(int verbosity);
+
+/**
+ * is_claimed_by_foreign(ud)
+ * @param udev: udev device
+ * @returns: true iff device is (newly or already) claimed by a foreign lib
+ */
+static inline bool
+is_claimed_by_foreign(struct udev_device *ud)
+{
+	int rc = add_foreign(ud);
+
+	return (rc == FOREIGN_CLAIMED || rc == FOREIGN_OK);
+}
+
+#endif /*  _FOREIGN_H */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (13 preceding siblings ...)
  2018-03-05 23:14 ` [PATCH v2 15/23] libmultipath: API for foreign multipath handling Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:13   ` Hannes Reinecke
  2018-03-05 23:15 ` [PATCH v2 17/23] libmultipath/foreign: nvme foreign library Martin Wilck
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

This adds a format field to identify foreign maps as such, and
uses it in default-formatted topology output (generic_style()).

Signed-off-by: Martin Wilck <mwilck@suse.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/generic.c |  2 +-
 libmultipath/print.c   | 14 ++++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/libmultipath/generic.c b/libmultipath/generic.c
index 45012d0e1d95..6f7a2cdcad3e 100644
--- a/libmultipath/generic.c
+++ b/libmultipath/generic.c
@@ -32,7 +32,7 @@ int generic_style(const struct gen_multipath* gm,
 	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",
+	n += snprintf(buf, len, "%%n %s[%%G]:%%d %%s",
 		      strcmp(alias_buf, wwid_buf) ? "(%w) " : "");
 
 	return (n < len ? n : len - 1);
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 01e7483e3e44..d5329942e795 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -341,6 +341,12 @@ snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
 	return snprintf(buff, len, "##");
 }
 
+static int
+snprint_multipath_foreign (char * buff, size_t len, const struct multipath * pp)
+{
+	return snprintf(buff, len, "%s", "--");
+}
+
 static int
 snprint_action (char * buff, size_t len, const struct multipath * mpp)
 {
@@ -620,6 +626,12 @@ snprint_path_checker (char * buff, size_t len, const struct path * pp)
 	return snprint_str(buff, len, c->name);
 }
 
+static int
+snprint_path_foreign (char * buff, size_t len, const struct path * pp)
+{
+	return snprintf(buff, len, "%s", "--");
+}
+
 struct multipath_data mpd[] = {
 	{'n', "name",          0, snprint_name},
 	{'w', "uuid",          0, snprint_multipath_uuid},
@@ -643,6 +655,7 @@ struct multipath_data mpd[] = {
 	{'v', "vend",          0, snprint_multipath_vend},
 	{'p', "prod",          0, snprint_multipath_prod},
 	{'e', "rev",           0, snprint_multipath_rev},
+	{'G', "foreign",       0, snprint_multipath_foreign},
 	{0, NULL, 0 , NULL}
 };
 
@@ -666,6 +679,7 @@ struct path_data pd[] = {
 	{'R', "host WWPN",     0, snprint_host_wwpn},
 	{'r', "target WWPN",   0, snprint_tgt_wwpn},
 	{'a', "host adapter",  0, snprint_host_adapter},
+	{'G', "foreign",       0, snprint_path_foreign},
 	{0, NULL, 0 , NULL}
 };
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 17/23] libmultipath/foreign: nvme foreign library
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (14 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:13   ` Hannes Reinecke
  2018-03-07 19:09   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 18/23] libmultipath: pathinfo: call into " Martin Wilck
                   ` (6 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

This still contains stubs for path handling and checking, but it's functional
for printing already.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 Makefile                      |   1 +
 libmultipath/foreign/Makefile |  30 +++
 libmultipath/foreign/nvme.c   | 455 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 486 insertions(+)
 create mode 100644 libmultipath/foreign/Makefile
 create mode 100644 libmultipath/foreign/nvme.c

diff --git a/Makefile b/Makefile
index 11c46eb4dbc9..4b145c593605 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ BUILDDIRS = \
 	libmultipath \
 	libmultipath/prioritizers \
 	libmultipath/checkers \
+	libmultipath/foreign \
 	libmpathpersist \
 	multipath \
 	multipathd \
diff --git a/libmultipath/foreign/Makefile b/libmultipath/foreign/Makefile
new file mode 100644
index 000000000000..dfba11e86d76
--- /dev/null
+++ b/libmultipath/foreign/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
+#
+include ../../Makefile.inc
+
+CFLAGS += $(LIB_CFLAGS) -I..
+
+# If you add or remove a checker also update multipath/multipath.conf.5
+LIBS= \
+	libforeign-nvme.so
+
+all: $(LIBS)
+
+libforeign-%.so: %.o
+	$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^
+
+install:
+	$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)
+
+uninstall:
+	for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done
+
+clean: dep_clean
+	$(RM) core *.a *.o *.gz *.so
+
+OBJS := $(LIBS:libforeign-%.so=%.o)
+include $(wildcard $(OBJS:.o=.d))
+
+dep_clean:
+	$(RM) $(OBJS:.o=.d)
diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
new file mode 100644
index 000000000000..32bd5c96c44a
--- /dev/null
+++ b/libmultipath/foreign/nvme.c
@@ -0,0 +1,455 @@
+/*
+  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 <sys/sysmacros.h>
+#include <libudev.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <libudev.h>
+#include <pthread.h>
+#include "vector.h"
+#include "generic.h"
+#include "foreign.h"
+#include "debug.h"
+
+const char *THIS;
+
+struct nvme_map {
+	struct gen_multipath gen;
+	struct udev_device *udev;
+	struct udev_device *subsys;
+	dev_t devt;
+};
+
+#define NAME_LEN 64 /* buffer length temp model name */
+#define const_gen_mp_to_nvme(g) ((const struct nvme_map*)(g))
+#define gen_mp_to_nvme(g) ((struct nvme_map*)(g))
+#define nvme_mp_to_gen(n) &((n)->gen)
+
+static void cleanup_nvme_map(struct nvme_map *map)
+{
+	if (map->udev)
+		udev_device_unref(map->udev);
+	if (map->subsys)
+		udev_device_unref(map->subsys);
+	free(map);
+}
+
+static const struct _vector*
+nvme_mp_get_pgs(const struct gen_multipath *gmp) {
+	return NULL;
+}
+
+static void
+nvme_mp_rel_pgs(const struct gen_multipath *gmp, const struct _vector *v)
+{
+}
+
+static void rstrip(char *str)
+{
+	int n;
+
+	for (n = strlen(str) - 1; n >= 0 && str[n] == ' '; n--);
+	str[n+1] = '\0';
+}
+
+static int snprint_nvme_map(const struct gen_multipath *gmp,
+			    char *buff, int len, char wildcard)
+{
+	const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
+	static const char nvme_vendor[] = "NVMe";
+	char fld[NAME_LEN];
+	const char *val;
+
+	switch (wildcard) {
+	case 'd':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysname(nvm->udev));
+	case 'n':
+		return snprintf(buff, len, "%s:NQN:%s",
+				udev_device_get_sysname(nvm->subsys),
+				udev_device_get_sysattr_value(nvm->subsys,
+							      "subsysnqn"));
+	case 'w':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysattr_value(nvm->udev,
+							      "wwid"));
+	case 'S':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysattr_value(nvm->udev,
+							      "size"));
+	case 'v':
+		return snprintf(buff, len, "%s", nvme_vendor);
+	case 's':
+	case 'p':
+		snprintf(fld, sizeof(fld), "%s",
+			 udev_device_get_sysattr_value(nvm->subsys,
+						      "model"));
+		rstrip(fld);
+		if (wildcard == 'p')
+			return snprintf(buff, len, "%s", fld);
+		return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
+				udev_device_get_sysattr_value(nvm->subsys,
+							      "firmware_rev"));
+	case 'e':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysattr_value(nvm->subsys,
+							      "firmware_rev"));
+	case 'r':
+		val = udev_device_get_sysattr_value(nvm->udev, "ro");
+		if (val[0] == 1)
+			return snprintf(buff, len, "%s", "ro");
+		else
+			return snprintf(buff, len, "%s", "rw");
+	case 'G':
+		return snprintf(buff, len, "%s", THIS);
+	default:
+		return snprintf(buff, len, "N/A");
+		break;
+	}
+	return 0;
+}
+
+static const struct _vector*
+nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
+	return NULL;
+}
+
+static void
+nvme_pg_rel_paths(const struct gen_pathgroup *gpg, const struct _vector *v)
+{
+}
+
+static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
+			   char *buff, int len, char wildcard)
+{
+	return 0;
+}
+
+static int snprint_nvme_path(const struct gen_path *gmp,
+			     char *buff, int len, char wildcard)
+{
+	switch (wildcard) {
+	case 'R':
+		return snprintf(buff, len, "[foreign: %s]", THIS);
+	default:
+		break;
+	}
+	return 0;
+}
+
+static const struct gen_multipath_ops nvme_map_ops = {
+	.get_pathgroups = nvme_mp_get_pgs,
+	.rel_pathgroups = nvme_mp_rel_pgs,
+	.style = generic_style,
+	.snprint = snprint_nvme_map,
+};
+
+static const struct gen_pathgroup_ops nvme_pg_ops __attribute__((unused)) = {
+	.get_paths = nvme_pg_get_paths,
+	.rel_paths = nvme_pg_rel_paths,
+	.snprint = snprint_nvme_pg,
+};
+
+static const struct gen_path_ops nvme_path_ops __attribute__((unused)) = {
+	.snprint = snprint_nvme_path,
+};
+
+struct context {
+	pthread_mutex_t mutex;
+	vector mpvec;
+};
+
+void lock(struct context *ctx)
+{
+	pthread_mutex_lock(&ctx->mutex);
+}
+
+void unlock(void *arg)
+{
+	struct context *ctx = arg;
+
+	pthread_mutex_unlock(&ctx->mutex);
+}
+
+static int _delete_all(struct context *ctx)
+{
+	struct nvme_map *nm;
+	int n = VECTOR_SIZE(ctx->mpvec), i;
+
+	if (n == 0)
+		return FOREIGN_IGNORED;
+
+	vector_foreach_slot_backwards(ctx->mpvec, nm, i) {
+		vector_del_slot(ctx->mpvec, i);
+		cleanup_nvme_map(nm);
+	}
+	return FOREIGN_OK;
+}
+
+int delete_all(struct context *ctx)
+{
+	int rc;
+
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+
+	lock(ctx);
+	pthread_cleanup_push(unlock, ctx);
+	rc = _delete_all(ctx);
+	pthread_cleanup_pop(1);
+
+	return rc;
+}
+
+void cleanup(struct context *ctx)
+{
+	(void)delete_all(ctx);
+
+	lock(ctx);
+	/*
+	 * Locking is not strictly necessary here, locking in foreign.c
+	 * makes sure that no other code is called with this ctx any more.
+	 * But this should make static checkers feel better.
+	 */
+	pthread_cleanup_push(unlock, ctx);
+	if (ctx->udev)
+		udev_unref(ctx->udev);
+	if (ctx->mpvec)
+		vector_free(ctx->mpvec);
+	ctx->mpvec = NULL;
+	ctx->udev = NULL;
+	pthread_cleanup_pop(1);
+	pthread_mutex_destroy(&ctx->mutex);
+
+	free(ctx);
+}
+
+struct context *init(unsigned int api, const char *name)
+{
+	struct context *ctx;
+
+	if (api > LIBMP_FOREIGN_API) {
+		condlog(0, "%s: api version mismatch: %08x > %08x\n",
+			__func__, api, LIBMP_FOREIGN_API);
+		return NULL;
+	}
+
+	if ((ctx = calloc(1, sizeof(*ctx)))== NULL)
+		return NULL;
+
+	pthread_mutex_init(&ctx->mutex, NULL);
+
+	ctx->mpvec = vector_alloc();
+	if (ctx->mpvec == NULL)
+		goto err;
+
+	THIS = name;
+	return ctx;
+err:
+	cleanup(ctx);
+	return NULL;
+}
+
+static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
+					      dev_t devt)
+{
+	struct nvme_map *nm;
+	int i;
+
+	if (ctx->mpvec == NULL)
+		return NULL;
+
+	vector_foreach_slot(ctx->mpvec, nm, i) {
+		if (nm->devt == devt)
+			return nm;
+	}
+
+	return NULL;
+}
+
+static int _add_map(struct context *ctx, struct udev_device *ud,
+		    struct udev_device *subsys)
+{
+	dev_t devt = udev_device_get_devnum(ud);
+	struct nvme_map *map;
+
+	if (_find_nvme_map_by_devt(ctx, devt) != NULL)
+		return FOREIGN_OK;
+
+	map = calloc(1, sizeof(*map));
+	if (map == NULL)
+		return FOREIGN_ERR;
+
+	map->devt = devt;
+	map->udev = udev_device_ref(ud);
+	/*
+	 * subsys is implicitly referenced by map->udev,
+	 * no need to take a reference here.
+	 */
+	map->subsys = subsys;
+	map->gen.ops = &nvme_map_ops;
+
+	if (vector_alloc_slot(ctx->mpvec) == NULL) {
+		cleanup_nvme_map(map);
+		return FOREIGN_ERR;
+	}
+
+	vector_set_slot(ctx->mpvec, map);
+
+	return FOREIGN_CLAIMED;
+}
+
+int add(struct context *ctx, struct udev_device *ud)
+{
+	struct udev_device *subsys;
+	int rc;
+
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+
+	if (ud == NULL)
+		return FOREIGN_ERR;
+	if (strcmp("disk", udev_device_get_devtype(ud)))
+		return FOREIGN_IGNORED;
+
+	subsys = udev_device_get_parent_with_subsystem_devtype(ud,
+							       "nvme-subsystem",
+							       NULL);
+	if (subsys == NULL)
+		return FOREIGN_IGNORED;
+
+	lock(ctx);
+	pthread_cleanup_push(unlock, ctx);
+	rc = _add_map(ctx, ud, subsys);
+	pthread_cleanup_pop(1);
+
+	if (rc == FOREIGN_CLAIMED)
+		condlog(3, "%s: %s: added map %s", __func__, THIS,
+			udev_device_get_sysname(ud));
+	else if (rc != FOREIGN_OK)
+		condlog(1, "%s: %s: retcode %d adding %s",
+			__func__, THIS, rc, udev_device_get_sysname(ud));
+
+	return rc;
+}
+
+int change(struct context *ctx, struct udev_device *ud)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	return FOREIGN_IGNORED;
+}
+
+static int _delete_map(struct context *ctx, struct udev_device *ud)
+{
+	int k;
+	struct nvme_map *map;
+	dev_t devt = udev_device_get_devnum(ud);
+
+	map = _find_nvme_map_by_devt(ctx, devt);
+	if (map ==NULL)
+		return FOREIGN_IGNORED;
+
+	k = find_slot(ctx->mpvec, map);
+	if (k == -1)
+		return FOREIGN_ERR;
+	else
+		vector_del_slot(ctx->mpvec, k);
+
+	cleanup_nvme_map(map);
+
+	return FOREIGN_OK;
+}
+
+int delete(struct context *ctx, struct udev_device *ud)
+{
+	int rc;
+
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+
+	if (ud == NULL)
+		return FOREIGN_ERR;
+
+	lock(ctx);
+	pthread_cleanup_push(unlock, ctx);
+	rc = _delete_map(ctx, ud);
+	pthread_cleanup_pop(1);
+
+	if (rc == FOREIGN_OK)
+		condlog(3, "%s: %s: map %s deleted", __func__, THIS,
+			udev_device_get_sysname(ud));
+	else if (rc != FOREIGN_IGNORED)
+		condlog(1, "%s: %s: retcode %d deleting map %s", __func__,
+			THIS, rc, udev_device_get_sysname(ud));
+
+	return rc;
+}
+
+void check(struct context *ctx)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	return;
+}
+
+/*
+ * It's safe to pass our internal pointer, this is only used under the lock.
+ */
+const struct _vector *get_multipaths(const struct context *ctx)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	return ctx->mpvec;
+}
+
+void release_multipaths(const struct context *ctx, const struct _vector *mpvec)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	/* NOP */
+}
+
+/*
+ * It's safe to pass our internal pointer, this is only used under the lock.
+ */
+const struct _vector * get_paths(const struct context *ctx)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	return NULL;
+}
+
+void release_paths(const struct context *ctx, const struct _vector *mpvec)
+{
+	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	/* NOP */
+}
+
+/* compile-time check whether all methods are present and correctly typed */
+#define _METHOD_INIT(x) .x = x
+static struct foreign __methods __attribute__((unused)) = {
+	_METHOD_INIT(init),
+	_METHOD_INIT(cleanup),
+	_METHOD_INIT(change),
+	_METHOD_INIT(delete),
+	_METHOD_INIT(delete_all),
+	_METHOD_INIT(check),
+	_METHOD_INIT(lock),
+	_METHOD_INIT(unlock),
+	_METHOD_INIT(get_multipaths),
+	_METHOD_INIT(release_multipaths),
+	_METHOD_INIT(get_paths),
+	_METHOD_INIT(release_paths),
+};
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 18/23] libmultipath: pathinfo: call into foreign library
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (15 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 17/23] libmultipath/foreign: nvme foreign library Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:14   ` Hannes Reinecke
  2018-03-07 19:10   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 19/23] multipath: use foreign API Martin Wilck
                   ` (5 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

This actually enables the use of foreign paths.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/discovery.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 645224c1029c..45a4d8378893 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -31,6 +31,7 @@
 #include "prio.h"
 #include "defaults.h"
 #include "prioritizers/alua_rtpg.h"
+#include "foreign.h"
 
 int
 alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
@@ -1909,7 +1910,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
 	 * limited by DI_BLACKLIST and occurs before this debug
 	 * message with the mask value.
 	 */
-	if (pp->udev && filter_property(conf, pp->udev) > 0)
+	if (pp->udev && (is_claimed_by_foreign(pp->udev) ||
+			 filter_property(conf, pp->udev) > 0))
 		return PATHINFO_SKIPPED;
 
 	if (filter_devnode(conf->blist_devnode,
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 19/23] multipath: use foreign API
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (16 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 18/23] libmultipath: pathinfo: call into " Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:14   ` Hannes Reinecke
  2018-03-07 19:11   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 20/23] multipathd: " Martin Wilck
                   ` (4 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Use the "foreign" code to print information about multipath maps
owned by foreign libraries in print mode (multipath -ll, -l).

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipath/main.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/multipath/main.c b/multipath/main.c
index a0c750e6f623..4fae49ee4325 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -59,6 +59,7 @@
 #include "wwids.h"
 #include "uxsock.h"
 #include "mpath_cmd.h"
+#include "foreign.h"
 
 int logsink;
 struct udev *udev;
@@ -257,6 +258,14 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
 		if (cmd == CMD_CREATE)
 			reinstate_paths(mpp);
 	}
+
+	if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) {
+		struct config *conf = get_multipath_config();
+
+		print_foreign_topology(conf->verbosity);
+		put_multipath_config(conf);
+	}
+
 	return 0;
 }
 
@@ -460,6 +469,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
 		print_all_paths(pathvec, 1);
 
 	get_path_layout(pathvec, 0);
+	foreign_path_layout();
 
 	if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
 		goto out;
@@ -817,6 +827,8 @@ main (int argc, char *argv[])
 		condlog(0, "failed to initialize prioritizers");
 		goto out;
 	}
+	/* Failing here is non-fatal */
+	init_foreign(conf->multipath_dir);
 	if (cmd == CMD_USABLE_PATHS) {
 		r = check_usable_paths(conf, dev, dev_type);
 		goto out;
@@ -892,6 +904,7 @@ out:
 	dm_lib_release();
 	dm_lib_exit();
 
+	cleanup_foreign();
 	cleanup_prio();
 	cleanup_checkers();
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 20/23] multipathd: use foreign API
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (17 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 19/23] multipath: use foreign API Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:15   ` Hannes Reinecke
  2018-03-07 19:25   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display Martin Wilck
                   ` (3 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

Call into the foreign library code when paths are discovered, uevents
are received, and in the checker loop. Furthermore, use the foreign
code to print information in the "multipathd show paths", "multipathd
show maps", and "multipathd show topology" client commands.

We don't support foreign data in the individual "show map" and "show path"
commands, and neither in the "json" commands. The former is a deliberate
decision, the latter could be added if desired.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-----
 multipathd/main.c         | 34 +++++++++++++++++++++++++++++++---
 2 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 78f2a12bc2f8..c0ae54aae841 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -27,6 +27,7 @@
 #include "main.h"
 #include "cli.h"
 #include "uevent.h"
+#include "foreign.h"
 
 int
 show_paths (char ** r, int * len, struct vectors * vecs, char * style,
@@ -35,11 +36,13 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
 	int i;
 	struct path * pp;
 	char * c;
-	char * reply;
+	char * reply, * header;
 	unsigned int maxlen = INITIAL_REPLY_LEN;
 	int again = 1;
 
 	get_path_layout(vecs->pathvec, 1);
+	foreign_path_layout();
+
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -48,18 +51,29 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
 
 		c = reply;
 
-		if (pretty && VECTOR_SIZE(vecs->pathvec) > 0)
+		if (pretty)
 			c += snprint_path_header(c, reply + maxlen - c,
 						 style);
+		header = c;
 
 		vector_foreach_slot(vecs->pathvec, pp, i)
 			c += snprint_path(c, reply + maxlen - c,
 					  style, pp, pretty);
 
+		c += snprint_foreign_paths(c, reply + maxlen - c,
+					   style, pretty);
+
 		again = ((c - reply) == (maxlen - 1));
 
 		REALLOC_REPLY(reply, again, maxlen);
 	}
+
+	if (pretty && c == header) {
+		/* No output - clear header */
+		*reply = '\0';
+		c = reply;
+	}
+
 	*r = reply;
 	*len = (int)(c - reply + 1);
 	return 0;
@@ -134,6 +148,8 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
 	int again = 1;
 
 	get_path_layout(vecs->pathvec, 0);
+	foreign_path_layout();
+
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -150,11 +166,13 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
 			c += snprint_multipath_topology(c, reply + maxlen - c,
 							mpp, 2);
 		}
+		c += snprint_foreign_topology(c, reply + maxlen - c, 2);
 
 		again = ((c - reply) == (maxlen - 1));
 
 		REALLOC_REPLY(reply, again, maxlen);
 	}
+
 	*r = reply;
 	*len = (int)(c - reply + 1);
 	return 0;
@@ -499,12 +517,14 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
 {
 	int i;
 	struct multipath * mpp;
-	char * c;
+	char * c, *header;
 	char * reply;
 	unsigned int maxlen = INITIAL_REPLY_LEN;
 	int again = 1;
 
 	get_multipath_layout(vecs->mpvec, 1);
+	foreign_multipath_layout();
+
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -512,9 +532,10 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
 			return 1;
 
 		c = reply;
-		if (pretty && VECTOR_SIZE(vecs->mpvec) > 0)
+		if (pretty)
 			c += snprint_multipath_header(c, reply + maxlen - c,
 						      style);
+		header = c;
 
 		vector_foreach_slot(vecs->mpvec, mpp, i) {
 			if (update_multipath(vecs, mpp->alias, 0)) {
@@ -523,12 +544,20 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
 			}
 			c += snprint_multipath(c, reply + maxlen - c,
 					       style, mpp, pretty);
-		}
 
+		}
+		c += snprint_foreign_multipaths(c, reply + maxlen - c,
+						style, pretty);
 		again = ((c - reply) == (maxlen - 1));
 
 		REALLOC_REPLY(reply, again, maxlen);
 	}
+
+	if (pretty && c == header) {
+		/* No output - clear header */
+		*reply = '\0';
+		c = reply;
+	}
 	*r = reply;
 	*len = (int)(c - reply + 1);
 	return 0;
diff --git a/multipathd/main.c b/multipathd/main.c
index cb26c58f6ba9..465a1e291226 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -84,6 +84,7 @@ static int use_watchdog;
 #include "waiter.h"
 #include "io_err_stat.h"
 #include "wwids.h"
+#include "foreign.h"
 #include "../third-party/valgrind/drd.h"
 
 #define FILE_NAME_SIZE 256
@@ -798,6 +799,8 @@ uev_remove_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
 	int ret;
 
 	condlog(2, "%s: remove path (uevent)", uev->kernel);
+	delete_foreign(uev->udev);
+
 	pthread_cleanup_push(cleanup_lock, &vecs->lock);
 	lock(&vecs->lock);
 	pthread_testcancel();
@@ -917,12 +920,27 @@ fail:
 static int
 uev_update_path (struct uevent *uev, struct vectors * vecs)
 {
-	int ro, retval = 0;
+	int ro, retval = 0, rc;
 	struct path * pp;
 	struct config *conf;
 	int disable_changed_wwids;
 	int needs_reinit = 0;
 
+	switch ((rc = change_foreign(uev->udev))) {
+	case FOREIGN_OK:
+		/* known foreign path, ignore event */
+		return 0;
+	case FOREIGN_IGNORED:
+		break;
+	case FOREIGN_ERR:
+		condlog(3, "%s: error in change_foreign", __func__);
+		break;
+	default:
+		condlog(1, "%s: return code %d of change_forein is unsupported",
+			__func__, rc);
+		break;
+	}
+
 	conf = get_multipath_config();
 	disable_changed_wwids = conf->disable_changed_wwids;
 	put_multipath_config(conf);
@@ -1122,8 +1140,13 @@ uev_trigger (struct uevent * uev, void * trigger_data)
 	 * are not fully initialised then.
 	 */
 	if (!strncmp(uev->kernel, "dm-", 3)) {
-		if (!uevent_is_mpath(uev))
+		if (!uevent_is_mpath(uev)) {
+			if (!strncmp(uev->action, "change", 6))
+				(void)add_foreign(uev->udev);
+			else if (!strncmp(uev->action, "remove", 6))
+				(void)delete_foreign(uev->udev);
 			goto out;
+		}
 		if (!strncmp(uev->action, "change", 6)) {
 			r = uev_add_map(uev, vecs);
 
@@ -1932,7 +1955,7 @@ checkerloop (void *ap)
 						diff_time.tv_sec);
 			}
 		}
-
+		check_foreign();
 		post_config_state(DAEMON_IDLE);
 		conf = get_multipath_config();
 		strict_timing = conf->strict_timing;
@@ -2121,6 +2144,7 @@ reconfigure (struct vectors * vecs)
 
 	free_pathvec(vecs->pathvec, FREE_PATHS);
 	vecs->pathvec = NULL;
+	delete_all_foreign();
 
 	/* Re-read any timezone changes */
 	tzset();
@@ -2372,6 +2396,9 @@ child (void * param)
 		condlog(0, "failed to initialize prioritizers");
 		goto failed;
 	}
+	/* Failing this is non-fatal */
+
+	init_foreign(conf->multipath_dir);
 
 	setlogmask(LOG_UPTO(conf->verbosity + 3));
 
@@ -2529,6 +2556,7 @@ child (void * param)
 	FREE(vecs);
 	vecs = NULL;
 
+	cleanup_foreign();
 	cleanup_checkers();
 	cleanup_prio();
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (18 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 20/23] multipathd: " Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:15   ` Hannes Reinecke
  2018-03-07 19:27   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 22/23] multipathd: update path group prio in check_path Martin Wilck
                   ` (2 subsequent siblings)
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

implement display of path information for NVMe foreign paths and maps.
With this patch, I get output like this for Linux NVMe soft targets:

nvme-submultipathd show topology
sys0:NQN:subsysname (uuid.96926ba3-b207-437c-902c-4a4df6538c3f) [nvme] nvme0n1 NVMe,Linux,4.15.0-r
size=2097152 features='n/a' hwhandler='n/a' wp=rw
`-+- policy='n/a' prio=n/a status=n/a
  |- 0:1:1 nvme0c1n1 0:0 n/a n/a live
  |- 0:2:1 nvme0c2n1 0:0 n/a n/a live
  |- 0:3:1 nvme0c3n1 0:0 n/a n/a live
  `- 0:4:1 nvme0c4n1 0:0 n/a n/a live

multipathd show paths format '%G %d %i %o %z %m %N'
foreign dev       hcil  dev_st serial           multipath host WWNN
[nvme]  nvme0c1n1 0:1:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.201.101,trsvcid=4420
[nvme]  nvme0c2n1 0:2:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.202.101,trsvcid=4420
[nvme]  nvme0c3n1 0:3:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.203.101,trsvcid=4420
[nvme]  nvme0c4n1 0:4:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.204.101,trsvcid=4420

(admittedly, I abused the 'WWNN' wildcard here a bit to display information
which is helpful for NVMe over RDMA).

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/foreign/nvme.c | 334 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 320 insertions(+), 14 deletions(-)

diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
index 32bd5c96c44a..235f75dd2add 100644
--- a/libmultipath/foreign/nvme.c
+++ b/libmultipath/foreign/nvme.c
@@ -25,42 +25,98 @@
 #include <stdbool.h>
 #include <libudev.h>
 #include <pthread.h>
+#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
 #include "vector.h"
 #include "generic.h"
 #include "foreign.h"
 #include "debug.h"
+#include "structs.h"
+#include "sysfs.h"
 
+static const char nvme_vendor[] = "NVMe";
+static const char N_A[] = "n/a";
 const char *THIS;
 
+struct nvme_map;
+struct nvme_path {
+	struct gen_path gen;
+	struct udev_device *udev;
+	struct udev_device *ctl;
+	struct nvme_map *map;
+	bool seen;
+};
+
+struct nvme_pathgroup {
+	struct gen_pathgroup gen;
+	vector pathvec;
+};
+
 struct nvme_map {
 	struct gen_multipath gen;
 	struct udev_device *udev;
 	struct udev_device *subsys;
 	dev_t devt;
+	/* Just one static pathgroup for NVMe for now */
+	struct nvme_pathgroup pg;
+	struct gen_pathgroup *gpg;
+	struct _vector pgvec;
+	vector pathvec;
+	int nr_live;
 };
 
-#define NAME_LEN 64 /* buffer length temp model name */
+#define NAME_LEN 64 /* buffer length for temp attributes */
 #define const_gen_mp_to_nvme(g) ((const struct nvme_map*)(g))
 #define gen_mp_to_nvme(g) ((struct nvme_map*)(g))
 #define nvme_mp_to_gen(n) &((n)->gen)
+#define const_gen_pg_to_nvme(g) ((const struct nvme_pathgroup*)(g))
+#define gen_pg_to_nvme(g) ((struct nvme_pathgroup*)(g))
+#define nvme_pg_to_gen(n) &((n)->gen)
+#define const_gen_path_to_nvme(g) ((const struct nvme_path*)(g))
+#define gen_path_to_nvme(g) ((struct nvme_path*)(g))
+#define nvme_path_to_gen(n) &((n)->gen)
+
+static void cleanup_nvme_path(struct nvme_path *path)
+{
+	condlog(5, "%s: %p %p", __func__, path, path->udev);
+	if (path->udev)
+		udev_device_unref(path->udev);
+	/* ctl is implicitly referenced by udev, no need to unref */
+	free(path);
+}
 
 static void cleanup_nvme_map(struct nvme_map *map)
 {
+	if (map->pathvec) {
+		struct nvme_path *path;
+		int i;
+
+		vector_foreach_slot_backwards(map->pathvec, path, i) {
+			condlog(5, "%s: %d %p", __func__, i, path);
+			cleanup_nvme_path(path);
+			vector_del_slot(map->pathvec, i);
+		}
+	}
+	vector_free(map->pathvec);
 	if (map->udev)
 		udev_device_unref(map->udev);
-	if (map->subsys)
-		udev_device_unref(map->subsys);
+	/* subsys is implicitly referenced by udev, no need to unref */
 	free(map);
 }
 
 static const struct _vector*
 nvme_mp_get_pgs(const struct gen_multipath *gmp) {
-	return NULL;
+	const struct nvme_map *nvme = const_gen_mp_to_nvme(gmp);
+
+	/* This is all used under the lock, no need to copy */
+	return &nvme->pgvec;
 }
 
 static void
 nvme_mp_rel_pgs(const struct gen_multipath *gmp, const struct _vector *v)
 {
+	/* empty */
 }
 
 static void rstrip(char *str)
@@ -75,7 +131,6 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
 			    char *buff, int len, char wildcard)
 {
 	const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
-	static const char nvme_vendor[] = "NVMe";
 	char fld[NAME_LEN];
 	const char *val;
 
@@ -92,6 +147,8 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
 		return snprintf(buff, len, "%s",
 				udev_device_get_sysattr_value(nvm->udev,
 							      "wwid"));
+	case 'N':
+		return snprintf(buff, len, "%u", nvm->nr_live);
 	case 'S':
 		return snprintf(buff, len, "%s",
 				udev_device_get_sysattr_value(nvm->udev,
@@ -122,7 +179,7 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
 	case 'G':
 		return snprintf(buff, len, "%s", THIS);
 	default:
-		return snprintf(buff, len, "N/A");
+		return snprintf(buff, len, N_A);
 		break;
 	}
 	return 0;
@@ -130,27 +187,101 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
 
 static const struct _vector*
 nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
-	return NULL;
+	const struct nvme_pathgroup *gp = const_gen_pg_to_nvme(gpg);
+
+	/* This is all used under the lock, no need to copy */
+	return gp->pathvec;
 }
 
 static void
 nvme_pg_rel_paths(const struct gen_pathgroup *gpg, const struct _vector *v)
 {
+	/* empty */
 }
 
 static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
 			   char *buff, int len, char wildcard)
 {
-	return 0;
+	return snprintf(buff, len, N_A);
 }
 
-static int snprint_nvme_path(const struct gen_path *gmp,
+static int snprint_hcil(const struct nvme_path *np, char *buf, int len)
+{
+	unsigned int nvmeid, ctlid, nsid;
+	int rc;
+	const char *sysname = udev_device_get_sysname(np->udev);
+
+	rc = sscanf(sysname, "nvme%uc%un%u", &nvmeid, &ctlid, &nsid);
+	if (rc != 3) {
+		condlog(1, "%s: failed to scan %s", __func__, sysname);
+		rc = snprintf(buf, len, "(ERR:%s)", sysname);
+	} else
+		rc = snprintf(buf, len, "%u:%u:%u", nvmeid, ctlid, nsid);
+	return (rc < len ? rc : len);
+}
+
+static int snprint_nvme_path(const struct gen_path *gp,
 			     char *buff, int len, char wildcard)
 {
+	const struct nvme_path *np = const_gen_path_to_nvme(gp);
+	dev_t devt;
+	char fld[NAME_LEN];
+	struct udev_device *pci;
+
 	switch (wildcard) {
+	case 'w':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysattr_value(np->udev,
+							      "wwid"));
+	case 'd':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysname(np->udev));
+	case 'i':
+		return snprint_hcil(np, buff, len);
+	case 'D':
+		devt = udev_device_get_devnum(np->udev);
+		return snprintf(buff, len, "%u:%u", major(devt), minor(devt));
+	case 'o':
+		sysfs_attr_get_value(np->ctl, "state", fld, sizeof(fld));
+		return snprintf(buff, len, "%s", fld);
+	case 's':
+		snprintf(fld, sizeof(fld), "%s",
+			 udev_device_get_sysattr_value(np->ctl,
+						      "model"));
+		rstrip(fld);
+		return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
+				udev_device_get_sysattr_value(np->ctl,
+							      "firmware_rev"));
+	case 'S':
+		return snprintf(buff, len, "%s",
+			udev_device_get_sysattr_value(np->udev,
+						      "size"));
+	case 'z':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysattr_value(np->ctl,
+							      "serial"));
+	case 'm':
+		return snprintf(buff, len, "%s",
+				udev_device_get_sysname(np->map->udev));
+	case 'N':
 	case 'R':
-		return snprintf(buff, len, "[foreign: %s]", THIS);
+		return snprintf(buff, len, "%s:%s",
+			udev_device_get_sysattr_value(np->ctl,
+						      "transport"),
+			udev_device_get_sysattr_value(np->ctl,
+						      "address"));
+	case 'G':
+		return snprintf(buff, len, "[%s]", THIS);
+	case 'a':
+		pci = udev_device_get_parent_with_subsystem_devtype(np->ctl,
+								    "pci",
+								    NULL);
+		if (pci != NULL)
+			return snprintf(buff, len, "PCI:%s",
+					udev_device_get_sysname(pci));
+		/* fall through */
 	default:
+		return snprintf(buff, len, "%s", N_A);
 		break;
 	}
 	return 0;
@@ -176,6 +307,7 @@ static const struct gen_path_ops nvme_path_ops __attribute__((unused)) = {
 struct context {
 	pthread_mutex_t mutex;
 	vector mpvec;
+	struct udev *udev;
 };
 
 void lock(struct context *ctx)
@@ -257,6 +389,10 @@ struct context *init(unsigned int api, const char *name)
 
 	pthread_mutex_init(&ctx->mutex, NULL);
 
+	ctx->udev = udev_new();
+	if (ctx->udev == NULL)
+		goto err;
+
 	ctx->mpvec = vector_alloc();
 	if (ctx->mpvec == NULL)
 		goto err;
@@ -285,6 +421,138 @@ static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
 	return NULL;
 }
 
+static struct nvme_path *
+_find_path_by_syspath(struct nvme_map *map, const char *syspath)
+{
+	struct nvme_path *path;
+	char real[PATH_MAX];
+	const char *ppath;
+	int i;
+
+	ppath = realpath(syspath, real);
+	if (ppath == NULL) {
+		condlog(1, "%s: %s: error in realpath", __func__, THIS);
+		ppath = syspath;
+	}
+
+	vector_foreach_slot(map->pathvec, path, i) {
+		if (!strcmp(ppath,
+			    udev_device_get_syspath(path->udev)))
+			return path;
+	}
+	condlog(4, "%s: %s: %s not found", __func__, THIS, ppath);
+	return NULL;
+}
+
+static int no_dotfiles(const struct dirent *di)
+{
+	return di->d_name[0] != '.';
+}
+
+static void _find_slaves(struct context *ctx, struct nvme_map *map)
+{
+	char pathbuf[PATH_MAX];
+	struct dirent **di = NULL;
+	struct nvme_path *path;
+	int r, i;
+
+	if (map == NULL || map->udev == NULL)
+		return;
+
+	vector_foreach_slot(map->pathvec, path, i)
+		path->seen = false;
+
+	snprintf(pathbuf, sizeof(pathbuf),
+		"%s/slaves",
+		udev_device_get_syspath(map->udev));
+
+	r = scandir(pathbuf, &di, no_dotfiles, alphasort);
+
+	if (r == 0) {
+		condlog(3, "%s: %s: no paths for %s", __func__, THIS,
+			udev_device_get_sysname(map->udev));
+		return;
+	} else if (r < 0) {
+		condlog(1, "%s: %s: error %d scanning paths of %s", __func__,
+			THIS, errno, udev_device_get_sysname(map->udev));
+		return;
+	}
+
+	pthread_cleanup_push(free, di);
+	for (i = 0; i < r; i++) {
+		char *fn = di[i]->d_name;
+		struct udev_device *udev;
+
+		if (snprintf(pathbuf, sizeof(pathbuf), "%s/slaves/%s",
+			     udev_device_get_syspath(map->udev), fn)
+		    >= sizeof(pathbuf))
+			continue;
+
+		path = _find_path_by_syspath(map, pathbuf);
+		if (path != NULL) {
+			path->seen = true;
+			condlog(4, "%s: %s already known",
+				__func__, fn);
+			continue;
+		}
+
+		udev = udev_device_new_from_syspath(ctx->udev, pathbuf);
+		if (udev == NULL) {
+			condlog(1, "%s: %s: failed to get udev device for %s",
+				__func__, THIS, fn);
+			continue;
+		}
+
+		path = calloc(1, sizeof(*path));
+		if (path == NULL)
+			continue;
+
+		path->gen.ops = &nvme_path_ops;
+		path->udev = udev;
+		path->seen = true;
+		path->map = map;
+		path->ctl = udev_device_get_parent_with_subsystem_devtype
+			(udev, "nvme", NULL);
+		if (path->ctl == NULL) {
+			condlog(1, "%s: %s: failed to get controller for %s",
+				__func__, THIS, fn);
+			cleanup_nvme_path(path);
+			continue;
+		}
+
+		if (vector_alloc_slot(map->pathvec) == NULL) {
+			cleanup_nvme_path(path);
+			continue;
+		}
+		condlog(3, "%s: %s: new path %s added to %s",
+			__func__, THIS, udev_device_get_sysname(udev),
+			udev_device_get_sysname(map->udev));
+		vector_set_slot(map->pathvec, path);
+	}
+	pthread_cleanup_pop(1);
+
+	map->nr_live = 0;
+	vector_foreach_slot_backwards(map->pathvec, path, i) {
+		if (!path->seen) {
+			condlog(1, "path %d not found in %s any more",
+				i, udev_device_get_sysname(map->udev));
+			vector_del_slot(map->pathvec, i);
+			cleanup_nvme_path(path);
+		} else {
+			static const char live_state[] = "live";
+			char state[16];
+
+			if ((sysfs_attr_get_value(path->ctl, "state", state,
+						  sizeof(state)) > 0) &&
+			    !strncmp(state, live_state, sizeof(live_state) - 1))
+				map->nr_live++;
+		}
+	}
+	condlog(3, "%s: %s: map %s has %d/%d live paths", __func__, THIS,
+		udev_device_get_sysname(map->udev), map->nr_live,
+		VECTOR_SIZE(map->pathvec));
+}
+
 static int _add_map(struct context *ctx, struct udev_device *ud,
 		    struct udev_device *subsys)
 {
@@ -307,12 +575,25 @@ static int _add_map(struct context *ctx, struct udev_device *ud,
 	map->subsys = subsys;
 	map->gen.ops = &nvme_map_ops;
 
-	if (vector_alloc_slot(ctx->mpvec) == NULL) {
+	map->pathvec = vector_alloc();
+	if (map->pathvec == NULL) {
 		cleanup_nvme_map(map);
 		return FOREIGN_ERR;
 	}
 
+	map->pg.gen.ops = &nvme_pg_ops;
+	map->pg.pathvec = map->pathvec;
+	map->gpg = nvme_pg_to_gen(&map->pg);
+
+	map->pgvec.allocated = 1;
+	map->pgvec.slot = (void**)&map->gpg;
+
+	if (vector_alloc_slot(ctx->mpvec) == NULL) {
+		cleanup_nvme_map(map);
+		return FOREIGN_ERR;
+	}
 	vector_set_slot(ctx->mpvec, map);
+	_find_slaves(ctx, map);
 
 	return FOREIGN_CLAIMED;
 }
@@ -401,9 +682,25 @@ int delete(struct context *ctx, struct udev_device *ud)
 	return rc;
 }
 
+void _check(struct context *ctx)
+{
+	struct gen_multipath *gm;
+	int i;
+
+	vector_foreach_slot(ctx->mpvec, gm, i) {
+		struct nvme_map *map = gen_mp_to_nvme(gm);
+
+		_find_slaves(ctx, map);
+	}
+}
+
 void check(struct context *ctx)
 {
-	condlog(5, "%s called for \"%s\"", __func__, THIS);
+	condlog(4, "%s called for \"%s\"", __func__, THIS);
+	lock(ctx);
+	pthread_cleanup_push(unlock, ctx);
+	_check(ctx);
+	pthread_cleanup_pop(1);
 	return;
 }
 
@@ -427,14 +724,23 @@ void release_multipaths(const struct context *ctx, const struct _vector *mpvec)
  */
 const struct _vector * get_paths(const struct context *ctx)
 {
+	vector paths = NULL;
+	const struct gen_multipath *gm;
+	int i;
+
 	condlog(5, "%s called for \"%s\"", __func__, THIS);
-	return NULL;
+	vector_foreach_slot(ctx->mpvec, gm, i) {
+		const struct nvme_map *nm = const_gen_mp_to_nvme(gm);
+		paths = vector_convert(paths, nm->pathvec,
+				       struct gen_path, identity);
+	}
+	return paths;
 }
 
 void release_paths(const struct context *ctx, const struct _vector *mpvec)
 {
 	condlog(5, "%s called for \"%s\"", __func__, THIS);
-	/* NOP */
+	vector_free_const(mpvec);
 }
 
 /* compile-time check whether all methods are present and correctly typed */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 22/23] multipathd: update path group prio in check_path
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (19 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:16   ` Hannes Reinecke
  2018-03-07 20:01   ` Benjamin Marzinski
  2018-03-05 23:15 ` [PATCH v2 23/23] multipathd: fix signal blocking logic Martin Wilck
       [not found] ` <20180305231507.10386-9-mwilck@suse.com>
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

The previous patch "libmultipath: don't update path groups when printing"
removed the call to path_group_prio_update() in the printing code path.
To compensate for that, recalculate path group prio also when it's not
strictly necessary (i.e. if failback "manual" is set).

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipathd/main.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/multipathd/main.c b/multipathd/main.c
index 465a1e291226..4abdd8f071c3 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -252,8 +252,9 @@ need_switch_pathgroup (struct multipath * mpp, int refresh)
 	struct path * pp;
 	unsigned int i, j;
 	struct config *conf;
+	int bestpg;
 
-	if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
+	if (!mpp)
 		return 0;
 
 	/*
@@ -272,8 +273,11 @@ need_switch_pathgroup (struct multipath * mpp, int refresh)
 	if (!mpp->pg || VECTOR_SIZE(mpp->paths) == 0)
 		return 0;
 
-	mpp->bestpg = select_path_group(mpp);
+	bestpg = select_path_group(mpp);
+	if (mpp->pgfailback == -FAILBACK_MANUAL)
+		return 0;
 
+	mpp->bestpg = bestpg;
 	if (mpp->bestpg != mpp->nextpg)
 		return 1;
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v2 23/23] multipathd: fix signal blocking logic
  2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (20 preceding siblings ...)
  2018-03-05 23:15 ` [PATCH v2 22/23] multipathd: update path group prio in check_path Martin Wilck
@ 2018-03-05 23:15 ` Martin Wilck
  2018-03-06  7:16   ` Hannes Reinecke
  2018-03-07 20:24   ` Benjamin Marzinski
       [not found] ` <20180305231507.10386-9-mwilck@suse.com>
  22 siblings, 2 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-05 23:15 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: dm-devel, Martin Wilck

multipathd is supposed to block all signals in all threads, except
the uxlsnr thread which handles termination and reconfiguration
signals (SIGUSR1) in its ppoll() call, SIGUSR2 in the waiter thread
and the marginal path checker thread, and occasional SIGALRM. The current
logic does exactly the oppsite, it blocks termination signals in SIGPOLL and
allows multipathd to be killed e.g. by SIGALRM.

Fix that by inverting the logic. The argument to pthread_sigmask and
ppoll is the set of *blocked* signals, not vice versa.

The marginal paths code needs to unblock SIGUSR2 now explicity, as
the dm-event waiter code already does. Doing this with pselect()
avoids asynchronous cancellation.

Fixes: 810082e "libmultipath, multipathd: Rework SIGPIPE handling"
Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and SIGUSR1
are delivered to the uxsock thread"

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/io_err_stat.c | 17 ++++++++++++++++-
 multipathd/main.c          |  7 +++++--
 multipathd/uxlsnr.c        | 10 +++++-----
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
index 5b10f0372f9f..00bac9e0e755 100644
--- a/libmultipath/io_err_stat.c
+++ b/libmultipath/io_err_stat.c
@@ -21,6 +21,7 @@
 #include <libaio.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/select.h>
 
 #include "vector.h"
 #include "memory.h"
@@ -691,14 +692,28 @@ static void service_paths(void)
 
 static void *io_err_stat_loop(void *data)
 {
+	sigset_t set;
+
 	vecs = (struct vectors *)data;
 	pthread_cleanup_push(rcu_unregister, NULL);
 	rcu_register_thread();
 
+	sigfillset(&set);
+	sigdelset(&set, SIGUSR2);
+
 	mlockall(MCL_CURRENT | MCL_FUTURE);
 	while (1) {
+		struct timespec ts;
+
 		service_paths();
-		usleep(100000);
+
+		ts.tv_sec = 0;
+		ts.tv_nsec = 100 * 1000 * 1000;
+		/*
+		 * pselect() with no fds, a timeout, and a sigmask:
+		 * sleep for 100ms and react on SIGUSR2.
+		 */
+		pselect(1, NULL, NULL, NULL, &ts, &set);
 	}
 
 	pthread_cleanup_pop(1);
diff --git a/multipathd/main.c b/multipathd/main.c
index 4abdd8f071c3..68595836d723 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2261,10 +2261,13 @@ signal_init(void)
 {
 	sigset_t set;
 
-	sigemptyset(&set);
-	sigaddset(&set, SIGUSR2);
+	/* block all signals */
+	sigfillset(&set);
+	/* SIGPIPE occurs if logging fails */
+	sigdelset(&set, SIGPIPE);
 	pthread_sigmask(SIG_SETMASK, &set, NULL);
 
+	/* Other signals will be unblocked in the uxlsnr thread */
 	signal_set(SIGHUP, sighup);
 	signal_set(SIGUSR1, sigusr1);
 	signal_set(SIGUSR2, sigusr2);
diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
index 98ac25a68c43..a2ca36ba1653 100644
--- a/multipathd/uxlsnr.c
+++ b/multipathd/uxlsnr.c
@@ -170,11 +170,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
 		condlog(0, "uxsock: failed to allocate poll fds");
 		return NULL;
 	}
-	sigemptyset(&mask);
-	sigaddset(&mask, SIGINT);
-	sigaddset(&mask, SIGTERM);
-	sigaddset(&mask, SIGHUP);
-	sigaddset(&mask, SIGUSR1);
+	sigfillset(&mask);
+	sigdelset(&mask, SIGINT);
+	sigdelset(&mask, SIGTERM);
+	sigdelset(&mask, SIGHUP);
+	sigdelset(&mask, SIGUSR1);
 	while (1) {
 		struct client *c, *tmp;
 		int i, poll_count, num_clients;
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 10/23] libmultipath: add vector_free_const()
  2018-03-05 23:14 ` [PATCH v2 10/23] libmultipath: add vector_free_const() Martin Wilck
@ 2018-03-06  1:01   ` Bart Van Assche
  2018-03-06  7:08   ` Hannes Reinecke
  1 sibling, 0 replies; 59+ messages in thread
From: Bart Van Assche @ 2018-03-06  1:01 UTC (permalink / raw)
  To: mwilck, christophe.varoqui; +Cc: dm-devel

On Tue, 2018-03-06 at 00:14 +0100, Martin Wilck wrote:
> ... to dispose of constant vectors (const struct _vector*).

This patch is not useful by itself so if you repost this series please
combine it with the next patch.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries
  2018-03-05 23:14 ` [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
@ 2018-03-06  7:04   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:04 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Otherwise the binaries won't be re-linked if the libraries change.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  multipath/Makefile  | 2 +-
>  multipathd/Makefile | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 02/23] libmultipath: remove unused "stdout helpers"
  2018-03-05 23:14 ` [PATCH v2 02/23] libmultipath: remove unused "stdout helpers" Martin Wilck
@ 2018-03-06  7:04   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:04 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/print.c | 26 --------------------------
>  libmultipath/print.h |  5 -----
>  2 files changed, 31 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c
  2018-03-05 23:14 ` [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c Martin Wilck
@ 2018-03-06  7:05   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:05 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> By properly linking the path groups with their parent multipath,
> we don't need this "hack" any more.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/dmparser.c   |  2 +-
>  libmultipath/pgpolicies.c | 11 ++++++-----
>  libmultipath/print.c      |  6 +++---
>  libmultipath/structs.c    | 10 ++++++++++
>  libmultipath/structs.h    |  3 ++-
>  5 files changed, 22 insertions(+), 10 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods
  2018-03-05 23:14 ` [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
@ 2018-03-06  7:05   ` Hannes Reinecke
  2018-03-15 14:25   ` Bart Van Assche
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:05 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Convert the snprint methods for all keywords to call-by-value,
> and use "const" qualifier for the "data" argument. This makes sure
> that "snprint" type functions don't modify the data they're print,
> helps compile-time correctness checking, and allows more proper
> "const" cleanups in the future.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/dict.c   | 206 ++++++++++++++++++++++++--------------------------
>  libmultipath/parser.c |   9 ++-
>  libmultipath/parser.h |  12 ++-
>  3 files changed, 112 insertions(+), 115 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 05/23] libmultipath: don't update path groups when printing
  2018-03-05 23:14 ` [PATCH v2 05/23] libmultipath: don't update path groups when printing Martin Wilck
@ 2018-03-06  7:06   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:06 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Updating the prio values for printing makes no sense. The user wants to see
> the prio values multipath is actually using for path group selection, and
> updating the values here means actually lying to the user if the prio values
> have changed, but multipathd hasn't updated them internally.
> 
> If we really don't update the pathgroup prios when we need to, this should be
> fixed elsewhere. The current wrong output would just hide that if it occured.
> 
> Moreover, correctness forbids changing properties so deeply in a code path
> that's supposed to print them only. Finally, this piece of code prevents the
> print.c code to be converted to proper "const" usage.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/print.c | 7 -------
>  1 file changed, 7 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 06/23] libmultipath/print: use "const" where appropriate
  2018-03-05 23:14 ` [PATCH v2 06/23] libmultipath/print: use "const" where appropriate Martin Wilck
@ 2018-03-06  7:07   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:07 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Convert the print.h/print.c code to use "const" qualifiers
> properly. This is generally considered good programming practice,
> and the printing code shouldn't change any objects anyway.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/configure.h |   1 -
>  libmultipath/discovery.c |   6 +--
>  libmultipath/discovery.h |   6 ++-
>  libmultipath/print.c     | 133 ++++++++++++++++++++++++-----------------------
>  libmultipath/print.h     |  41 ++++++++-------
>  5 files changed, 95 insertions(+), 92 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 07/23] libmultipath: use "const" in devmapper code
  2018-03-05 23:14 ` [PATCH v2 07/23] libmultipath: use "const" in devmapper code Martin Wilck
@ 2018-03-06  7:07   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:07 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Improve use of "const" qualifiers in libmultipath's devmapper code.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/devmapper.c | 32 ++++++++++++++++----------------
>  libmultipath/devmapper.h | 16 ++++++++--------
>  2 files changed, 24 insertions(+), 24 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 08/23] libmultipath: fix compiler warnings for -Wcast-qual
       [not found] ` <20180305231507.10386-9-mwilck@suse.com>
@ 2018-03-06  7:08   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:08 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Fix the warnings that were caused by adding the -Wcast-qual compiler
> flag in the previous patch.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  kpartx/devmapper.c          |  3 ++-
>  libmpathcmd/mpath_cmd.c     |  2 +-
>  libmultipath/checkers/rbd.c |  4 ++--
>  libmultipath/devmapper.c    |  3 ++-
>  libmultipath/discovery.c    | 12 ++++++------
>  libmultipath/list.h         |  4 ++--
>  libmultipath/memory.h       |  8 +++++++-
>  libmultipath/structs.c      |  2 +-
>  libmultipath/structs.h      |  2 +-
>  libmultipath/uevent.c       |  6 +++---
>  libmultipath/util.c         |  6 +++---
>  multipathd/main.c           | 10 +++++-----
>  12 files changed, 35 insertions(+), 27 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual
  2018-03-05 23:14 ` [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
@ 2018-03-06  7:08   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:08 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Casting "const" away is often an indicator for wrong code.
> Add a compiler flag to warn about such possible breakage.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  Makefile.inc | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Makefile.inc b/Makefile.inc
> index eb99c36010c1..a5b9d4e3fa74 100644
> --- a/Makefile.inc
> +++ b/Makefile.inc
> @@ -87,6 +87,7 @@ STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
>  OPTFLAGS	= -O2 -g -pipe -Wall -Wextra -Wformat=2 -Werror=implicit-int \
>  		  -Werror=implicit-function-declaration -Werror=format-security \
>  		  -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered \
> +		  -Werror=cast-qual -Werror=discarded-qualifiers \
>  		  -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \
>  		  --param=ssp-buffer-size=4
>  
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 10/23] libmultipath: add vector_free_const()
  2018-03-05 23:14 ` [PATCH v2 10/23] libmultipath: add vector_free_const() Martin Wilck
  2018-03-06  1:01   ` Bart Van Assche
@ 2018-03-06  7:08   ` Hannes Reinecke
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:08 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> ... to dispose of constant vectors (const struct _vector*).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/vector.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/libmultipath/vector.h b/libmultipath/vector.h
> index 5cfd4d060412..3f6e579ae19a 100644
> --- a/libmultipath/vector.h
> +++ b/libmultipath/vector.h
> @@ -46,6 +46,7 @@ typedef struct _vector *vector;
>  extern vector vector_alloc(void);
>  extern void *vector_alloc_slot(vector v);
>  extern void vector_free(vector v);
> +#define vector_free_const(x) vector_free((vector)(long)(x))
>  extern void free_strvec(vector strvec);
>  extern void vector_set_slot(vector v, void *value);
>  extern void vector_del_slot(vector v, int slot);
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 11/23] libmultipath: add vector_convert()
  2018-03-05 23:14 ` [PATCH v2 11/23] libmultipath: add vector_convert() Martin Wilck
@ 2018-03-06  7:10   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:10 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> This is a handy helper for creating one vector from another,
> mapping each element of the origin vector to an element of
> the target vector with a given conversion function. It can
> also be used to "concatenate" vectors by passing in a non-NULL first
> argument.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/vector.h | 29 +++++++++++++++++++++++++++++
>  1 file changed, 29 insertions(+)
>
At one point we should consider moving vectors to lists ...
Anyway:

Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 12/23] libmultipath: "generic multipath" interface
  2018-03-05 23:14 ` [PATCH v2 12/23] libmultipath: "generic multipath" interface Martin Wilck
@ 2018-03-06  7:10   ` Hannes Reinecke
  2018-03-07 19:01   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:10 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> 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     |   2 +-
>  libmultipath/dm-generic.c |  70 ++++++++++++++++++++++++
>  libmultipath/dm-generic.h |  41 ++++++++++++++
>  libmultipath/generic.c    |  39 +++++++++++++
>  libmultipath/generic.h    | 136 ++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/list.h       |   4 ++
>  libmultipath/print.c      |  33 +++++++++++
>  libmultipath/print.h      |  12 ++++
>  libmultipath/structs.c    |   4 ++
>  libmultipath/structs.h    |   4 ++
>  10 files changed, 344 insertions(+), 1 deletion(-)
>  create mode 100644 libmultipath/dm-generic.c
>  create mode 100644 libmultipath/dm-generic.h
>  create mode 100644 libmultipath/generic.c
>  create mode 100644 libmultipath/generic.h
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 13/23] libmultipath: print: convert API to generic data type
  2018-03-05 23:14 ` [PATCH v2 13/23] libmultipath: print: convert API to generic data type Martin Wilck
@ 2018-03-06  7:11   ` Hannes Reinecke
  2018-03-07 19:02   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:11 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Convert higher level API (snprint_multipath_topology() etc) to
> using the generic multipath API. This will allow "foreign"
> multipath objects that implement the generic API to be printed
> exactly like native multipathd objects.
> 
> The previous API (using "struct multipath*" and "struct path" remains
> in place through macros mapping to the new functions. By doing this
> and testing in regular setups, it's easily verified that the new
> API works and produces the same results.
> 
> Moreover, abstract out the code to determine the output format from multipath
> properties into snprint_multipath_style(), to be able to use it as generic
> ->style() method.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/configure.c  |   1 +
>  libmultipath/dm-generic.c |   2 +-
>  libmultipath/print.c      | 115 +++++++++++++++++++++++++++++-----------------
>  libmultipath/print.h      |  24 +++++++---
>  multipath/main.c          |   1 +
>  multipathd/cli_handlers.c |   1 +
>  6 files changed, 95 insertions(+), 49 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout()
  2018-03-05 23:14 ` [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout() Martin Wilck
@ 2018-03-06  7:12   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:12 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Introduce new functions _get_path_layout and _get_multipath_layout
> using the new "generic" API to determine field widths, and map the
> old API to them.
> 
> Furthermore, replace the boolean "header" by an enum with 3 possible
> values. The new value LAYOUT_RESET_NOT allows calling the get_x_layout
> function several times and determine the overall field width.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/print.c | 73 ++++++++++++++++++++++++++++++++++++++++------------
>  libmultipath/print.h |  8 ++++++
>  2 files changed, 65 insertions(+), 16 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 15/23] libmultipath: API for foreign multipath handling
  2018-03-05 23:14 ` [PATCH v2 15/23] libmultipath: API for foreign multipath handling Martin Wilck
@ 2018-03-06  7:12   ` Hannes Reinecke
  2018-03-07 19:08   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:12 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:14 AM, Martin Wilck wrote:
> Add an API for "foreign" multipaths. Foreign libraries are loaded
> from ${multipath_dir}/libforeign-*.so, as we do for checkers.
> 
> Refer to "foreign.h" for details about the API itself. Like we do for
> checkers, high-level multipath code isn't supposed to call the API directly,
> but rather the wrapper functions declared in "foreign.h".
> 
> This API is used only for displaying information and for logging. An extension to
> other functionality (such as monitoring or administration) might be feasible,
> but is not planned.
> 
> Foreign libraries communicate with libmultipath through the API defined in
> "foreign.h". The foreign library can implement multipath maps, pathgroups,
> and paths as it likes, they just need to provide the simple interfaces
> defined in "generic.h" to libmultipath. These interfaces are used in libmultipath's
> "print" implementation to convey various bits of information to users. By
> using the same interfaces for printing that libmultipath uses internally,
> foreign library implementations can focus on the technical side without
> worrying about output formatting compatibility.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/Makefile  |   2 +-
>  libmultipath/foreign.c | 602 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/foreign.h | 322 ++++++++++++++++++++++++++
>  3 files changed, 925 insertions(+), 1 deletion(-)
>  create mode 100644 libmultipath/foreign.c
>  create mode 100644 libmultipath/foreign.h
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard
  2018-03-05 23:15 ` [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
@ 2018-03-06  7:13   ` Hannes Reinecke
  0 siblings, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:13 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> This adds a format field to identify foreign maps as such, and
> uses it in default-formatted topology output (generic_style()).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/generic.c |  2 +-
>  libmultipath/print.c   | 14 ++++++++++++++
>  2 files changed, 15 insertions(+), 1 deletion(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 17/23] libmultipath/foreign: nvme foreign library
  2018-03-05 23:15 ` [PATCH v2 17/23] libmultipath/foreign: nvme foreign library Martin Wilck
@ 2018-03-06  7:13   ` Hannes Reinecke
  2018-03-07 19:09   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:13 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> This still contains stubs for path handling and checking, but it's functional
> for printing already.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  Makefile                      |   1 +
>  libmultipath/foreign/Makefile |  30 +++
>  libmultipath/foreign/nvme.c   | 455 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 486 insertions(+)
>  create mode 100644 libmultipath/foreign/Makefile
>  create mode 100644 libmultipath/foreign/nvme.c
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 18/23] libmultipath: pathinfo: call into foreign library
  2018-03-05 23:15 ` [PATCH v2 18/23] libmultipath: pathinfo: call into " Martin Wilck
@ 2018-03-06  7:14   ` Hannes Reinecke
  2018-03-07 19:10   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:14 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> This actually enables the use of foreign paths.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/discovery.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 19/23] multipath: use foreign API
  2018-03-05 23:15 ` [PATCH v2 19/23] multipath: use foreign API Martin Wilck
@ 2018-03-06  7:14   ` Hannes Reinecke
  2018-03-07 19:11   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:14 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> Use the "foreign" code to print information about multipath maps
> owned by foreign libraries in print mode (multipath -ll, -l).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipath/main.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 20/23] multipathd: use foreign API
  2018-03-05 23:15 ` [PATCH v2 20/23] multipathd: " Martin Wilck
@ 2018-03-06  7:15   ` Hannes Reinecke
  2018-03-07 19:25   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:15 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> Call into the foreign library code when paths are discovered, uevents
> are received, and in the checker loop. Furthermore, use the foreign
> code to print information in the "multipathd show paths", "multipathd
> show maps", and "multipathd show topology" client commands.
> 
> We don't support foreign data in the individual "show map" and "show path"
> commands, and neither in the "json" commands. The former is a deliberate
> decision, the latter could be added if desired.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-----
>  multipathd/main.c         | 34 +++++++++++++++++++++++++++++++---
>  2 files changed, 65 insertions(+), 8 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display
  2018-03-05 23:15 ` [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display Martin Wilck
@ 2018-03-06  7:15   ` Hannes Reinecke
  2018-03-07 19:27   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:15 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> implement display of path information for NVMe foreign paths and maps.
> With this patch, I get output like this for Linux NVMe soft targets:
> 
> nvme-submultipathd show topology
> sys0:NQN:subsysname (uuid.96926ba3-b207-437c-902c-4a4df6538c3f) [nvme] nvme0n1 NVMe,Linux,4.15.0-r
> size=2097152 features='n/a' hwhandler='n/a' wp=rw
> `-+- policy='n/a' prio=n/a status=n/a
>   |- 0:1:1 nvme0c1n1 0:0 n/a n/a live
>   |- 0:2:1 nvme0c2n1 0:0 n/a n/a live
>   |- 0:3:1 nvme0c3n1 0:0 n/a n/a live
>   `- 0:4:1 nvme0c4n1 0:0 n/a n/a live
> 
> multipathd show paths format '%G %d %i %o %z %m %N'
> foreign dev       hcil  dev_st serial           multipath host WWNN
> [nvme]  nvme0c1n1 0:1:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.201.101,trsvcid=4420
> [nvme]  nvme0c2n1 0:2:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.202.101,trsvcid=4420
> [nvme]  nvme0c3n1 0:3:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.203.101,trsvcid=4420
> [nvme]  nvme0c4n1 0:4:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.204.101,trsvcid=4420
> 
> (admittedly, I abused the 'WWNN' wildcard here a bit to display information
> which is helpful for NVMe over RDMA).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/foreign/nvme.c | 334 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 320 insertions(+), 14 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 22/23] multipathd: update path group prio in check_path
  2018-03-05 23:15 ` [PATCH v2 22/23] multipathd: update path group prio in check_path Martin Wilck
@ 2018-03-06  7:16   ` Hannes Reinecke
  2018-03-07 20:01   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:16 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> The previous patch "libmultipath: don't update path groups when printing"
> removed the call to path_group_prio_update() in the printing code path.
> To compensate for that, recalculate path group prio also when it's not
> strictly necessary (i.e. if failback "manual" is set).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/main.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 23/23] multipathd: fix signal blocking logic
  2018-03-05 23:15 ` [PATCH v2 23/23] multipathd: fix signal blocking logic Martin Wilck
@ 2018-03-06  7:16   ` Hannes Reinecke
  2018-03-06  8:55     ` Martin Wilck
  2018-03-07 20:24   ` Benjamin Marzinski
  1 sibling, 1 reply; 59+ messages in thread
From: Hannes Reinecke @ 2018-03-06  7:16 UTC (permalink / raw)
  To: Martin Wilck, Christophe Varoqui; +Cc: dm-devel

On 03/06/2018 12:15 AM, Martin Wilck wrote:
> multipathd is supposed to block all signals in all threads, except
> the uxlsnr thread which handles termination and reconfiguration
> signals (SIGUSR1) in its ppoll() call, SIGUSR2 in the waiter thread
> and the marginal path checker thread, and occasional SIGALRM. The current
> logic does exactly the oppsite, it blocks termination signals in SIGPOLL and
> allows multipathd to be killed e.g. by SIGALRM.
> 
> Fix that by inverting the logic. The argument to pthread_sigmask and
> ppoll is the set of *blocked* signals, not vice versa.
> 
> The marginal paths code needs to unblock SIGUSR2 now explicity, as
> the dm-event waiter code already does. Doing this with pselect()
> avoids asynchronous cancellation.
> 
> Fixes: 810082e "libmultipath, multipathd: Rework SIGPIPE handling"
> Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and SIGUSR1
> are delivered to the uxsock thread"
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/io_err_stat.c | 17 ++++++++++++++++-
>  multipathd/main.c          |  7 +++++--
>  multipathd/uxlsnr.c        | 10 +++++-----
>  3 files changed, 26 insertions(+), 8 deletions(-)
> 
Sigh.
Will we ever get signal handling correct?

Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 23/23] multipathd: fix signal blocking logic
  2018-03-06  7:16   ` Hannes Reinecke
@ 2018-03-06  8:55     ` Martin Wilck
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Wilck @ 2018-03-06  8:55 UTC (permalink / raw)
  To: Hannes Reinecke, Christophe Varoqui; +Cc: dm-devel

On Tue, 2018-03-06 at 08:16 +0100, Hannes Reinecke wrote:
> On 03/06/2018 12:15 AM, Martin Wilck wrote:
> > multipathd is supposed to block all signals in all threads, except
> > the uxlsnr thread which handles termination and reconfiguration
> > signals (SIGUSR1) in its ppoll() call, SIGUSR2 in the waiter thread
> > and the marginal path checker thread, and occasional SIGALRM. The
> > current
> > logic does exactly the oppsite, it blocks termination signals in
> > SIGPOLL and
> > allows multipathd to be killed e.g. by SIGALRM.
> > 
> > Fix that by inverting the logic. The argument to pthread_sigmask
> > and
> > ppoll is the set of *blocked* signals, not vice versa.
> > 
> > The marginal paths code needs to unblock SIGUSR2 now explicity, as
> > the dm-event waiter code already does. Doing this with pselect()
> > avoids asynchronous cancellation.
> > 
> > Fixes: 810082e "libmultipath, multipathd: Rework SIGPIPE handling"
> > Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and
> > SIGUSR1
> > are delivered to the uxsock thread"
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/io_err_stat.c | 17 ++++++++++++++++-
> >  multipathd/main.c          |  7 +++++--
> >  multipathd/uxlsnr.c        | 10 +++++-----
> >  3 files changed, 26 insertions(+), 8 deletions(-)
> > 
> 
> Sigh.
> Will we ever get signal handling correct?

I'm quite confident that we're close now.
But time will tell.

Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 12/23] libmultipath: "generic multipath" interface
  2018-03-05 23:14 ` [PATCH v2 12/23] libmultipath: "generic multipath" interface Martin Wilck
  2018-03-06  7:10   ` Hannes Reinecke
@ 2018-03-07 19:01   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:01 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:14:56AM +0100, Martin Wilck wrote:
> 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.
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/Makefile     |   2 +-
>  libmultipath/dm-generic.c |  70 ++++++++++++++++++++++++
>  libmultipath/dm-generic.h |  41 ++++++++++++++
>  libmultipath/generic.c    |  39 +++++++++++++
>  libmultipath/generic.h    | 136 ++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/list.h       |   4 ++
>  libmultipath/print.c      |  33 +++++++++++
>  libmultipath/print.h      |  12 ++++
>  libmultipath/structs.c    |   4 ++
>  libmultipath/structs.h    |   4 ++
>  10 files changed, 344 insertions(+), 1 deletion(-)
>  create mode 100644 libmultipath/dm-generic.c
>  create mode 100644 libmultipath/dm-generic.h
>  create mode 100644 libmultipath/generic.c
>  create mode 100644 libmultipath/generic.h
> 
> diff --git a/libmultipath/Makefile b/libmultipath/Makefile
> index 25b052729d48..0099d9d6cc39 100644
> --- a/libmultipath/Makefile
> +++ b/libmultipath/Makefile
> @@ -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
> index 000000000000..42a26085d087
> --- /dev/null
> +++ b/libmultipath/dm-generic.c
> @@ -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
> index 000000000000..5d5972406819
> --- /dev/null
> +++ b/libmultipath/dm-generic.h
> @@ -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
> index 000000000000..45012d0e1d95
> --- /dev/null
> +++ b/libmultipath/generic.c
> @@ -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
> index 000000000000..7f7fe6661c36
> --- /dev/null
> +++ b/libmultipath/generic.h
> @@ -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 */
> diff --git a/libmultipath/list.h b/libmultipath/list.h
> index c9110ac9de7e..ced021f5a633 100644
> --- a/libmultipath/list.h
> +++ b/libmultipath/list.h
> @@ -18,6 +18,10 @@
>   * @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) );})
> diff --git a/libmultipath/print.c b/libmultipath/print.c
> index 594ca567e22a..e9b8fdd6e581 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -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)
>  {
> diff --git a/libmultipath/print.h b/libmultipath/print.h
> index 02c5b072cc2b..214777c1e4f8 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -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 */
> diff --git a/libmultipath/structs.c b/libmultipath/structs.c
> index 4db08451824d..991095cb2bc1 100644
> --- a/libmultipath/structs.c
> +++ b/libmultipath/structs.c
> @@ -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;
>  }
> diff --git a/libmultipath/structs.h b/libmultipath/structs.h
> index bccc845a1222..88a4b7862393 100644
> --- a/libmultipath/structs.h
> +++ b/libmultipath/structs.h
> @@ -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 {
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 13/23] libmultipath: print: convert API to generic data type
  2018-03-05 23:14 ` [PATCH v2 13/23] libmultipath: print: convert API to generic data type Martin Wilck
  2018-03-06  7:11   ` Hannes Reinecke
@ 2018-03-07 19:02   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:02 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:14:57AM +0100, Martin Wilck wrote:
> Convert higher level API (snprint_multipath_topology() etc) to
> using the generic multipath API. This will allow "foreign"
> multipath objects that implement the generic API to be printed
> exactly like native multipathd objects.
> 
> The previous API (using "struct multipath*" and "struct path" remains
> in place through macros mapping to the new functions. By doing this
> and testing in regular setups, it's easily verified that the new
> API works and produces the same results.
> 
> Moreover, abstract out the code to determine the output format from multipath
> properties into snprint_multipath_style(), to be able to use it as generic
> ->style() method.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> ---
>  libmultipath/configure.c  |   1 +
>  libmultipath/dm-generic.c |   2 +-
>  libmultipath/print.c      | 115 +++++++++++++++++++++++++++++-----------------
>  libmultipath/print.h      |  24 +++++++---
>  multipath/main.c          |   1 +
>  multipathd/cli_handlers.c |   1 +
>  6 files changed, 95 insertions(+), 49 deletions(-)
> 
> diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> index 13e14cc25fff..42b7c896ee65 100644
> --- a/libmultipath/configure.c
> +++ b/libmultipath/configure.c
> @@ -30,6 +30,7 @@
>  #include "discovery.h"
>  #include "debug.h"
>  #include "switchgroup.h"
> +#include "dm-generic.h"
>  #include "print.h"
>  #include "configure.h"
>  #include "pgpolicies.h"
> diff --git a/libmultipath/dm-generic.c b/libmultipath/dm-generic.c
> index 42a26085d087..bdc9ca0a488b 100644
> --- a/libmultipath/dm-generic.c
> +++ b/libmultipath/dm-generic.c
> @@ -56,7 +56,7 @@ 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 */
> +	.style = snprint_multipath_style,
>  };
>  
>  const struct gen_pathgroup_ops dm_gen_pathgroup_ops = {
> diff --git a/libmultipath/print.c b/libmultipath/print.c
> index e9b8fdd6e581..8701a3584859 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -30,7 +30,8 @@
>  #include "debug.h"
>  #include "discovery.h"
>  
> -#define MAX(x,y) (x > y) ? x : y
> +#define MAX(x,y) (((x) > (y)) ? (x) : (y))
> +#define MIN(x,y) (((x) > (y)) ? (y) : (x))
>  #define TAIL     (line + len - 1 - c)
>  #define NOPAD    s = c
>  #define PAD(x) \
> @@ -845,8 +846,8 @@ snprint_multipath_header (char * line, int len, const char * format)
>  }
>  
>  int
> -snprint_multipath (char * line, int len, const char * format,
> -	     const struct multipath * mpp, int pad)
> +_snprint_multipath (const struct gen_multipath * gmp,
> +		    char * line, int len, const char * format, int pad)
>  {
>  	char * c = line;   /* line cursor */
>  	char * s = line;   /* for padding */
> @@ -869,7 +870,7 @@ snprint_multipath (char * line, int len, const char * format,
>  		if (!(data = mpd_lookup(*f)))
>  			continue;
>  
> -		data->snprint(buff, MAX_FIELD_LEN, mpp);
> +		gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
>  		PRINT(c, TAIL, "%s", buff);
>  		if (pad)
>  			PAD(data->width);
> @@ -912,8 +913,8 @@ snprint_path_header (char * line, int len, const char * format)
>  }
>  
>  int
> -snprint_path (char * line, int len, const char * format,
> -	     const struct path * pp, int pad)
> +_snprint_path (const struct gen_path * gp, char * line, int len,
> +	       const char * format, int pad)
>  {
>  	char * c = line;   /* line cursor */
>  	char * s = line;   /* for padding */
> @@ -936,7 +937,7 @@ snprint_path (char * line, int len, const char * format,
>  		if (!(data = pd_lookup(*f)))
>  			continue;
>  
> -		data->snprint(buff, MAX_FIELD_LEN, pp);
> +		gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
>  		PRINT(c, TAIL, "%s", buff);
>  		if (pad)
>  			PAD(data->width);
> @@ -947,8 +948,8 @@ snprint_path (char * line, int len, const char * format,
>  }
>  
>  int
> -snprint_pathgroup (char * line, int len, char * format,
> -		   const struct pathgroup * pgp)
> +_snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
> +		    char * format)
>  {
>  	char * c = line;   /* line cursor */
>  	char * s = line;   /* for padding */
> @@ -971,7 +972,7 @@ snprint_pathgroup (char * line, int len, char * format,
>  		if (!(data = pgd_lookup(*f)))
>  			continue;
>  
> -		data->snprint(buff, MAX_FIELD_LEN, pgp);
> +		ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
>  		PRINT(c, TAIL, "%s", buff);
>  		PAD(data->width);
>  	} while (*f++);
> @@ -979,8 +980,10 @@ snprint_pathgroup (char * line, int len, char * format,
>  	__endline(line, len, c);
>  	return (c - line);
>  }
> +#define snprint_pathgroup(line, len, fmt, pgp) \
> +	_snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
>  
> -void print_multipath_topology(struct multipath *mpp, int verbosity)
> +void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
>  {
>  	int resize;
>  	char *buff = NULL;
> @@ -997,7 +1000,7 @@ void print_multipath_topology(struct multipath *mpp, int verbosity)
>  			return;
>  		}
>  
> -		len = snprint_multipath_topology(buff, maxlen, mpp, verbosity);
> +		len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
>  		resize = (len == maxlen - 1);
>  
>  		if (resize) {
> @@ -1010,12 +1013,30 @@ void print_multipath_topology(struct multipath *mpp, int verbosity)
>  	FREE(buff);
>  }
>  
> -int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp,
> -			       int verbosity)
> +int
> +snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
> +			int verbosity)
> +{
> +	int n;
> +	const struct multipath *mpp = gen_multipath_to_dm(gmp);
> +	bool need_action = (verbosity > 1 &&
> +			    mpp->action != ACT_NOTHING &&
> +			    mpp->action != ACT_UNDEF &&
> +			    mpp->action != ACT_IMPOSSIBLE);
> +	bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
> +
> +	n = snprintf(style, len, "%s%s%s%s",
> +		     need_action ? "%A: " : "", "%n",
> +		     need_wwid ? " (%w)" : "", " %d %s");
> +	return MIN(n, len - 1);
> +}
> +
> +int _snprint_multipath_topology(const struct gen_multipath *gmp,
> +				char *buff, int len, int verbosity)
>  {
>  	int j, i, fwd = 0;
> -	struct path * pp = NULL;
> -	struct pathgroup * pgp = NULL;
> +	const struct _vector *pgvec;
> +	const struct gen_pathgroup *gpg;
>  	char style[64];
>  	char * c = style;
>  	char fmt[64];
> @@ -1027,60 +1048,70 @@ int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp,
>  	reset_multipath_layout();
>  
>  	if (verbosity == 1)
> -		return snprint_multipath(buff, len, "%n", mpp, 1);
> +		return _snprint_multipath(gmp, buff, len, "%n", 1);
>  
>  	if(isatty(1))
>  		c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
>  
> -	if (verbosity > 1 &&
> -	    mpp->action != ACT_NOTHING &&
> -	    mpp->action != ACT_UNDEF && mpp->action != ACT_IMPOSSIBLE)
> -			c += sprintf(c, "%%A: ");
> -
> -	c += sprintf(c, "%%n");
> -
> -	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
> -		c += sprintf(c, " (%%w)");
> -
> -	c += sprintf(c, " %%d %%s");
> +	c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
> +			     verbosity);
>  	if(isatty(1))
>  		c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
>  
> -	fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1);
> +	fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
>  	if (fwd >= len)
>  		return len;
> -	fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp,
> -				 1);
> +	fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
> +				  PRINT_MAP_PROPS, 1);
>  	if (fwd >= len)
>  		return len;
>  
> -	if (!mpp->pg)
> +	pgvec = gmp->ops->get_pathgroups(gmp);
> +	if (pgvec == NULL)
>  		return fwd;
>  
> -	vector_foreach_slot (mpp->pg, pgp, j) {
> +	vector_foreach_slot (pgvec, gpg, j) {
> +		const struct _vector *pathvec;
> +		struct gen_path *gp;
> +
>  		f=fmt;
> -		if (j + 1 < VECTOR_SIZE(mpp->pg)) {
> +
> +		if (j + 1 < VECTOR_SIZE(pgvec)) {
>  			strcpy(f, "|-+- " PRINT_PG_INDENT);
>  		} else
>  			strcpy(f, "`-+- " PRINT_PG_INDENT);
> -		fwd += snprint_pathgroup(buff + fwd, len - fwd, fmt, pgp);
> -		if (fwd >= len)
> -			return len;
> +		fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
>  
> -		vector_foreach_slot (pgp->paths, pp, i) {
> +		if (fwd >= len) {
> +			fwd = len;
> +			break;
> +		}
> +
> +		pathvec = gpg->ops->get_paths(gpg);
> +		if (pathvec == NULL)
> +			continue;
> +
> +		vector_foreach_slot (pathvec, gp, i) {
>  			f=fmt;
>  			if (*f != '|')
>  				*f=' ';
>  			f++;
> -			if (i + 1 < VECTOR_SIZE(pgp->paths))
> +			if (i + 1 < VECTOR_SIZE(pathvec))
>  				strcpy(f, " |- " PRINT_PATH_INDENT);
>  			else
>  				strcpy(f, " `- " PRINT_PATH_INDENT);
> -			fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1);
> -			if (fwd >= len)
> -				return len;
> +			fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
> +			if (fwd >= len) {
> +				fwd = len;
> +				break;
> +			}
>  		}
> +		gpg->ops->rel_paths(gpg, pathvec);
> +
> +		if (fwd == len)
> +			break;
>  	}
> +	gmp->ops->rel_pathgroups(gmp, pgvec);
>  	return fwd;
>  }
>  
> diff --git a/libmultipath/print.h b/libmultipath/print.h
> index 214777c1e4f8..b8b9ecbd204f 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -98,11 +98,17 @@ void get_path_layout (vector pathvec, int header);
>  void get_multipath_layout (vector mpvec, int header);
>  int snprint_path_header (char *, int, const char *);
>  int snprint_multipath_header (char *, int, const char *);
> -int snprint_path (char *, int, const char *, const struct path *, int);
> -int snprint_multipath (char *, int, const char *,
> -		       const struct multipath *, int);
> -int snprint_multipath_topology (char *, int, const struct multipath * mpp,
> -				int verbosity);
> +int _snprint_path (const struct gen_path *, char *, int, const char *, int);
> +#define snprint_path(buf, len, fmt, pp, v) \
> +	_snprint_path(dm_path_to_gen(pp), buf, len, fmt,  v)
> +int _snprint_multipath (const struct gen_multipath *, char *, int,
> +			const char *, int);
> +#define snprint_multipath(buf, len, fmt, mp, v)				\
> +	_snprint_multipath(dm_multipath_to_gen(mp), buf, len, fmt,  v)
> +int _snprint_multipath_topology (const struct gen_multipath *, char *, int, 
> +				 int verbosity);
> +#define snprint_multipath_topology(buf, len, mpp, v) \
> +	_snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, len, v)
>  int snprint_multipath_topology_json (char * buff, int len,
>  				const struct vectors * vecs);
>  int snprint_multipath_map_json (char * buff, int len,
> @@ -123,7 +129,11 @@ int snprint_host_wwpn (char *, size_t, const struct path *);
>  int snprint_tgt_wwnn (char *, size_t, const struct path *);
>  int snprint_tgt_wwpn (char *, size_t, const struct path *);
>  
> -void print_multipath_topology (struct multipath * mpp, int verbosity);
> +void _print_multipath_topology (const struct gen_multipath * gmp,
> +				int verbosity);
> +#define print_multipath_topology(mpp, v) \
> +	_print_multipath_topology(dm_multipath_to_gen(mpp), v)
> +
>  void print_all_paths (vector pathvec, int banner);
>  void print_all_paths_custo (vector pathvec, int banner, char *fmt);
>  
> @@ -133,4 +143,6 @@ 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);
> +int snprint_multipath_style(const struct gen_multipath *gmp,
> +			    char *style, int len, int verbosity);
>  #endif /* _PRINT_H */
> diff --git a/multipath/main.c b/multipath/main.c
> index 52bf1658bbca..a0c750e6f623 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -47,6 +47,7 @@
>  #include "discovery.h"
>  #include "debug.h"
>  #include "switchgroup.h"
> +#include "dm-generic.h"
>  #include "print.h"
>  #include "alias.h"
>  #include "configure.h"
> diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
> index 7f13bc9d6f32..78f2a12bc2f8 100644
> --- a/multipathd/cli_handlers.c
> +++ b/multipathd/cli_handlers.c
> @@ -16,6 +16,7 @@
>  #include "configure.h"
>  #include "blacklist.h"
>  #include "debug.h"
> +#include "dm-generic.h"
>  #include "print.h"
>  #include "sysfs.h"
>  #include <errno.h>
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 15/23] libmultipath: API for foreign multipath handling
  2018-03-05 23:14 ` [PATCH v2 15/23] libmultipath: API for foreign multipath handling Martin Wilck
  2018-03-06  7:12   ` Hannes Reinecke
@ 2018-03-07 19:08   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:08 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:14:59AM +0100, Martin Wilck wrote:
> Add an API for "foreign" multipaths. Foreign libraries are loaded
> from ${multipath_dir}/libforeign-*.so, as we do for checkers.
> 
> Refer to "foreign.h" for details about the API itself. Like we do for
> checkers, high-level multipath code isn't supposed to call the API directly,
> but rather the wrapper functions declared in "foreign.h".
> 
> This API is used only for displaying information and for logging. An extension to
> other functionality (such as monitoring or administration) might be feasible,
> but is not planned.
> 
> Foreign libraries communicate with libmultipath through the API defined in
> "foreign.h". The foreign library can implement multipath maps, pathgroups,
> and paths as it likes, they just need to provide the simple interfaces
> defined in "generic.h" to libmultipath. These interfaces are used in libmultipath's
> "print" implementation to convey various bits of information to users. By
> using the same interfaces for printing that libmultipath uses internally,
> foreign library implementations can focus on the technical side without
> worrying about output formatting compatibility.
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

I don't think the foreign_lock is strictly necessary, since I can't see
any way of any for the readers to be running at the same time as the
writers, simply because the readers all happen in threads that have
either not been created yet, or have already been joined when the
writers run.  But the locking code all makes sense, and I'm fine with
it.

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/Makefile  |   2 +-
>  libmultipath/foreign.c | 602 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/foreign.h | 322 ++++++++++++++++++++++++++
>  3 files changed, 925 insertions(+), 1 deletion(-)
>  create mode 100644 libmultipath/foreign.c
>  create mode 100644 libmultipath/foreign.h
> 
> diff --git a/libmultipath/Makefile b/libmultipath/Makefile
> index 0099d9d6cc39..806aaa24f84e 100644
> --- a/libmultipath/Makefile
> +++ b/libmultipath/Makefile
> @@ -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 dm-generic.o generic.o
> +	io_err_stat.o dm-generic.o generic.o foreign.o
>  
>  all: $(LIBS)
>  
> diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c
> new file mode 100644
> index 000000000000..72171840e995
> --- /dev/null
> +++ b/libmultipath/foreign.c
> @@ -0,0 +1,602 @@
> +/*
> +  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 <sys/sysmacros.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <limits.h>
> +#include <dirent.h>
> +#include <fnmatch.h>
> +#include <dlfcn.h>
> +#include <libudev.h>
> +#include "vector.h"
> +#include "debug.h"
> +#include "util.h"
> +#include "foreign.h"
> +#include "structs.h"
> +#include "structs_vec.h"
> +#include "print.h"
> +
> +static vector foreigns;
> +
> +/* This protects vector foreigns */
> +static pthread_rwlock_t foreign_lock = PTHREAD_RWLOCK_INITIALIZER;
> +
> +static void rdlock_foreigns(void)
> +{
> +	pthread_rwlock_rdlock(&foreign_lock);
> +}
> +
> +static void wrlock_foreigns(void)
> +{
> +	pthread_rwlock_wrlock(&foreign_lock);
> +}
> +
> +static void unlock_foreigns(void *unused)
> +{
> +	pthread_rwlock_unlock(&foreign_lock);
> +}
> +
> +#define get_dlsym(foreign, sym, lbl)					\
> +	do {								\
> +		foreign->sym =	dlsym(foreign->handle, #sym);		\
> +		if (foreign->sym == NULL) {				\
> +			condlog(0, "%s: symbol \"%s\" not found in \"%s\"", \
> +				__func__, #sym, foreign->name);		\
> +			goto lbl;					\
> +		}							\
> +	} while(0)
> +
> +static void free_foreign(struct foreign *fgn)
> +{
> +	struct context *ctx;
> +
> +	if (fgn == NULL)
> +		return;
> +
> +	ctx = fgn->context;
> +	fgn->context = NULL;
> +	if (ctx != NULL)
> +		fgn->cleanup(ctx);
> +
> +	if (fgn->handle != NULL)
> +		dlclose(fgn->handle);
> +	free(fgn);
> +}
> +
> +void _cleanup_foreign(void)
> +{
> +	struct foreign *fgn;
> +	int i;
> +
> +	if (foreigns == NULL)
> +		return;
> +
> +	vector_foreach_slot_backwards(foreigns, fgn, i) {
> +		vector_del_slot(foreigns, i);
> +		free_foreign(fgn);
> +	}
> +	vector_free(foreigns);
> +	foreigns = NULL;
> +}
> +
> +void cleanup_foreign(void)
> +{
> +	wrlock_foreigns();
> +	_cleanup_foreign();
> +	unlock_foreigns(NULL);
> +}
> +
> +static const char foreign_pattern[] = "libforeign-*.so";
> +
> +static int select_foreign_libs(const struct dirent *di)
> +{
> +
> +	return fnmatch(foreign_pattern, di->d_name, FNM_FILE_NAME) == 0;
> +}
> +
> +static int _init_foreign(const char *multipath_dir)
> +{
> +	char pathbuf[PATH_MAX];
> +	struct dirent **di;
> +	int r, i;
> +
> +	foreigns = vector_alloc();
> +	if (foreigns == NULL)
> +		return -ENOMEM;
> +
> +	r = scandir(multipath_dir, &di, select_foreign_libs, alphasort);
> +
> +	if (r == 0) {
> +		condlog(3, "%s: no foreign multipath libraries found",
> +			__func__);
> +		return 0;
> +	} else if (r < 0) {
> +		r = errno;
> +		condlog(1, "%s: error %d scanning foreign multipath libraries",
> +			__func__, r);
> +		_cleanup_foreign();
> +		return -r;
> +	}
> +
> +	pthread_cleanup_push(free, di);
> +	for (i = 0; i < r; i++) {
> +		const char *msg, *fn, *c;
> +		struct foreign *fgn;
> +		int len, namesz;
> +
> +		fn = di[i]->d_name;
> +
> +		len = strlen(fn);
> +		c = strchr(fn, '-');
> +		if (len < sizeof(foreign_pattern) - 1 || c == NULL) {
> +			condlog(0, "%s: bad file name %s, fnmatch error?",
> +				__func__, fn);
> +			continue;
> +		}
> +		c++;
> +		condlog(4, "%s: found %s", __func__, fn);
> +
> +		namesz = len - sizeof(foreign_pattern) + 3;
> +		fgn = malloc(sizeof(*fgn) + namesz);
> +		if (fgn == NULL)
> +			continue;
> +		memset(fgn, 0, sizeof(*fgn));
> +		strlcpy((char*)fgn + offsetof(struct foreign, name), c, namesz);
> +
> +		snprintf(pathbuf, sizeof(pathbuf), "%s/%s", multipath_dir, fn);
> +		fgn->handle = dlopen(pathbuf, RTLD_NOW|RTLD_LOCAL);
> +		msg = dlerror();
> +		if (fgn->handle == NULL) {
> +			condlog(1, "%s: failed to dlopen %s: %s", __func__,
> +				pathbuf, msg);
> +			goto dl_err;
> +		}
> +
> +		get_dlsym(fgn, init, dl_err);
> +		get_dlsym(fgn, cleanup, dl_err);
> +		get_dlsym(fgn, add, dl_err);
> +		get_dlsym(fgn, change, dl_err);
> +		get_dlsym(fgn, delete, dl_err);
> +		get_dlsym(fgn, delete_all, dl_err);
> +		get_dlsym(fgn, check, dl_err);
> +		get_dlsym(fgn, lock, dl_err);
> +		get_dlsym(fgn, unlock, dl_err);
> +		get_dlsym(fgn, get_multipaths, dl_err);
> +		get_dlsym(fgn, release_multipaths, dl_err);
> +		get_dlsym(fgn, get_paths, dl_err);
> +		get_dlsym(fgn, release_paths, dl_err);
> +
> +		fgn->context = fgn->init(LIBMP_FOREIGN_API, fgn->name);
> +		if (fgn->context == NULL) {
> +			condlog(0, "%s: init() failed for %s", __func__, fn);
> +			goto dl_err;
> +		}
> +
> +		if (vector_alloc_slot(foreigns) == NULL) {
> +			goto dl_err;
> +		}
> +
> +		vector_set_slot(foreigns, fgn);
> +		condlog(3, "foreign library \"%s\" loaded successfully",
> +			fgn->name);
> +
> +		continue;
> +
> +	dl_err:
> +		free_foreign(fgn);
> +	}
> +	pthread_cleanup_pop(1);
> +	return 0;
> +}
> +
> +int init_foreign(const char *multipath_dir)
> +{
> +	int ret;
> +
> +	wrlock_foreigns();
> +
> +	if (foreigns != NULL) {
> +		unlock_foreigns(NULL);
> +		condlog(0, "%s: already initialized", __func__);
> +		return -EEXIST;
> +	}
> +
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +	ret = _init_foreign(multipath_dir);
> +	pthread_cleanup_pop(1);
> +
> +	return ret;
> +}
> +
> +int add_foreign(struct udev_device *udev)
> +{
> +	struct foreign *fgn;
> +	dev_t dt;
> +	int j;
> +	int r = FOREIGN_IGNORED;
> +
> +	if (udev == NULL) {
> +		condlog(1, "%s called with NULL udev", __func__);
> +		return FOREIGN_ERR;
> +	}
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return FOREIGN_ERR;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	dt = udev_device_get_devnum(udev);
> +	vector_foreach_slot(foreigns, fgn, j) {
> +		r = fgn->add(fgn->context, udev);
> +
> +		if (r == FOREIGN_CLAIMED) {
> +			condlog(3, "%s: foreign \"%s\" claims device %d:%d",
> +				__func__, fgn->name, major(dt), minor(dt));
> +			break;
> +		} else if (r == FOREIGN_OK) {
> +			condlog(4, "%s: foreign \"%s\" owns device %d:%d",
> +				__func__, fgn->name, major(dt), minor(dt));
> +			break;
> +		} else if (r != FOREIGN_IGNORED) {
> +			condlog(1, "%s: unexpected return value %d from \"%s\"",
> +				__func__, r, fgn->name);
> +		}
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return r;
> +}
> +
> +int change_foreign(struct udev_device *udev)
> +{
> +	struct foreign *fgn;
> +	int j;
> +	dev_t dt;
> +	int r = FOREIGN_IGNORED;
> +
> +	if (udev == NULL) {
> +		condlog(1, "%s called with NULL udev", __func__);
> +		return FOREIGN_ERR;
> +	}
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return FOREIGN_ERR;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	dt = udev_device_get_devnum(udev);
> +	vector_foreach_slot(foreigns, fgn, j) {
> +		r = fgn->change(fgn->context, udev);
> +
> +		if (r == FOREIGN_OK) {
> +			condlog(4, "%s: foreign \"%s\" completed %d:%d",
> +				__func__, fgn->name, major(dt), minor(dt));
> +			break;
> +		} else if (r != FOREIGN_IGNORED) {
> +			condlog(1, "%s: unexpected return value %d from \"%s\"",
> +				__func__, r, fgn->name);
> +		}
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return r;
> +}
> +
> +int delete_foreign(struct udev_device *udev)
> +{
> +	struct foreign *fgn;
> +	int j;
> +	dev_t dt;
> +	int r = FOREIGN_IGNORED;
> +
> +	if (udev == NULL) {
> +		condlog(1, "%s called with NULL udev", __func__);
> +		return FOREIGN_ERR;
> +	}
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return FOREIGN_ERR;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	dt = udev_device_get_devnum(udev);
> +	vector_foreach_slot(foreigns, fgn, j) {
> +		r = fgn->delete(fgn->context, udev);
> +
> +		if (r == FOREIGN_OK) {
> +			condlog(3, "%s: foreign \"%s\" deleted device %d:%d",
> +				__func__, fgn->name, major(dt), minor(dt));
> +			break;
> +		} else if (r != FOREIGN_IGNORED) {
> +			condlog(1, "%s: unexpected return value %d from \"%s\"",
> +				__func__, r, fgn->name);
> +		}
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return r;
> +}
> +
> +int delete_all_foreign(void)
> +{
> +	struct foreign *fgn;
> +	int j;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return FOREIGN_ERR;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, j) {
> +		int r;
> +
> +		r = fgn->delete_all(fgn->context);
> +		if (r != FOREIGN_IGNORED && r != FOREIGN_OK) {
> +			condlog(1, "%s: unexpected return value %d from \"%s\"",
> +				__func__, r, fgn->name);
> +		}
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return FOREIGN_OK;
> +}
> +
> +void check_foreign(void)
> +{
> +	struct foreign *fgn;
> +	int j;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, j) {
> +		fgn->check(fgn->context);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +}
> +
> +/* Call this after get_path_layout */
> +void foreign_path_layout(void)
> +{
> +	struct foreign *fgn;
> +	int i;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, i) {
> +		const struct _vector *vec;
> +
> +		fgn->lock(fgn->context);
> +		pthread_cleanup_push(fgn->unlock, fgn->context);
> +
> +		vec = fgn->get_paths(fgn->context);
> +		if (vec != NULL) {
> +			_get_path_layout(vec, LAYOUT_RESET_NOT);
> +		}
> +		fgn->release_paths(fgn->context, vec);
> +
> +		pthread_cleanup_pop(1);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +}
> +
> +/* Call this after get_multipath_layout */
> +void foreign_multipath_layout(void)
> +{
> +	struct foreign *fgn;
> +	int i;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, i) {
> +		const struct _vector *vec;
> +
> +		fgn->lock(fgn->context);
> +		pthread_cleanup_push(fgn->unlock, fgn->context);
> +
> +		vec = fgn->get_multipaths(fgn->context);
> +		if (vec != NULL) {
> +			_get_multipath_layout(vec, LAYOUT_RESET_NOT);
> +		}
> +		fgn->release_multipaths(fgn->context, vec);
> +
> +		pthread_cleanup_pop(1);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +}
> +
> +int snprint_foreign_topology(char *buf, int len, int verbosity)
> +{
> +	struct foreign *fgn;
> +	int i;
> +	char *c = buf;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return 0;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, i) {
> +		const struct _vector *vec;
> +		const struct gen_multipath *gm;
> +		int j;
> +
> +		fgn->lock(fgn->context);
> +		pthread_cleanup_push(fgn->unlock, fgn->context);
> +
> +		vec = fgn->get_multipaths(fgn->context);
> +		if (vec != NULL) {
> +			vector_foreach_slot(vec, gm, j) {
> +
> +				c += _snprint_multipath_topology(gm, c,
> +								 buf + len - c,
> +								 verbosity);
> +				if (c >= buf + len - 1)
> +					break;
> +			}
> +			if (c >= buf + len - 1)
> +				break;
> +		}
> +		fgn->release_multipaths(fgn->context, vec);
> +		pthread_cleanup_pop(1);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return c - buf;
> +}
> +
> +void print_foreign_topology(int verbosity)
> +{
> +	int buflen = MAX_LINE_LEN * MAX_LINES;
> +	char *buf = NULL, *tmp = NULL;
> +
> +	buf = malloc(buflen);
> +	buf[0] = '\0';
> +	while (buf != NULL) {
> +		char *c = buf;
> +
> +		c += snprint_foreign_topology(buf, buflen,
> +						   verbosity);
> +		if (c < buf + buflen - 1)
> +			break;
> +
> +		buflen *= 2;
> +		tmp = buf;
> +		buf = realloc(buf, buflen);
> +	}
> +
> +	if (buf == NULL && tmp != NULL)
> +		buf = tmp;
> +
> +	if (buf != NULL) {
> +		printf("%s", buf);
> +		free(buf);
> +	}
> +}
> +
> +int snprint_foreign_paths(char *buf, int len, const char *style, int pretty)
> +{
> +	struct foreign *fgn;
> +	int i;
> +	char *c = buf;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return 0;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, i) {
> +		const struct _vector *vec;
> +		const struct gen_path *gp;
> +		int j;
> +
> +		fgn->lock(fgn->context);
> +		pthread_cleanup_push(fgn->unlock, fgn->context);
> +
> +		vec = fgn->get_paths(fgn->context);
> +		if (vec != NULL) {
> +			vector_foreach_slot(vec, gp, j) {
> +				c += _snprint_path(gp, c, buf + len - c,
> +						   style, pretty);
> +				if (c >= buf + len - 1)
> +					break;
> +			}
> +			if (c >= buf + len - 1)
> +				break;
> +		}
> +		fgn->release_paths(fgn->context, vec);
> +		pthread_cleanup_pop(1);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return c - buf;
> +}
> +
> +int snprint_foreign_multipaths(char *buf, int len,
> +			       const char *style, int pretty)
> +{
> +	struct foreign *fgn;
> +	int i;
> +	char *c = buf;
> +
> +	rdlock_foreigns();
> +	if (foreigns == NULL) {
> +		unlock_foreigns(NULL);
> +		return 0;
> +	}
> +	pthread_cleanup_push(unlock_foreigns, NULL);
> +
> +	vector_foreach_slot(foreigns, fgn, i) {
> +		const struct _vector *vec;
> +		const struct gen_multipath *gm;
> +		int j;
> +
> +		fgn->lock(fgn->context);
> +		pthread_cleanup_push(fgn->unlock, fgn->context);
> +
> +		vec = fgn->get_multipaths(fgn->context);
> +		if (vec != NULL) {
> +			vector_foreach_slot(vec, gm, j) {
> +				c += _snprint_multipath(gm, c, buf + len - c,
> +							style, pretty);
> +				if (c >= buf + len - 1)
> +					break;
> +			}
> +			if (c >= buf + len - 1)
> +				break;
> +		}
> +		fgn->release_multipaths(fgn->context, vec);
> +		pthread_cleanup_pop(1);
> +	}
> +
> +	pthread_cleanup_pop(1);
> +	return c - buf;
> +}
> diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h
> new file mode 100644
> index 000000000000..0ade2d7485c4
> --- /dev/null
> +++ b/libmultipath/foreign.h
> @@ -0,0 +1,322 @@
> +/*
> +  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 _FOREIGN_H
> +#define _FOREIGN_H
> +#include <stdbool.h>
> +#include <libudev.h>
> +
> +#define LIBMP_FOREIGN_API ((1 << 8) | 0)
> +
> +struct context;
> +
> +/* return codes of functions below returning "int" */
> +enum foreign_retcode {
> +	FOREIGN_OK,
> +	FOREIGN_CLAIMED,
> +	FOREIGN_IGNORED,
> +	FOREIGN_UNCLAIMED,
> +	FOREIGN_NODEV,
> +	FOREIGN_ERR,
> +	__LAST_FOREIGN_RETCODE,
> +};
> +
> +/**
> + * Foreign multipath library API
> + * Foreign libraries must implement the following methods.
> + */
> +struct foreign {
> +	/**
> +	 * method: init(api, name)
> +	 * Initialize foreign library, and check API compatibility
> +	 * return pointer to opaque internal data strucure if successful,
> +	 * NULL otherwise.
> +	 *
> +	 * @param[in] api: API version
> +	 * @param[in] name: name to use for references to self in log messages,
> +	 *     doesn't need to be strdup'd
> +	 * @returns context pointer to use in future method calls.
> +	 */
> +	struct context* (*init)(unsigned int api, const char *name);
> +
> +	/**
> +	 * method: cleanup(context)
> +	 * Free data structures used by foreign library, including
> +	 * context itself.
> +	 *
> +	 * @param[in] context foreign library context. This shouldn't be
> +	 * referenced any more after calling cleanup().
> +	 */
> +	void (*cleanup)(struct context *);
> +
> +	/**
> +	 * method: add(context, udev)
> +	 * This is called during path detection, and for udev ADD events.
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @param[in] udev udev device to add
> +	 * @returns status code
> +	 * @retval FOREIGN_CLAIMED: device newly claimed
> +	 * @retval FOREIGN_OK: device already registered, no action taken
> +	 * @retval FOREIGN_IGNORED: device is ignored, no action taken
> +	 * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
> +	 */
> +	int (*add)(struct context *, struct udev_device *);
> +
> +	/**
> +	 * method: change
> +	 * This is called on udev CHANGE events.
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @param[in] udev udev device that has generated the event
> +	 * @returns status code
> +	 * @retval FOREIGN_OK: event processed
> +	 * @retval FOREIGN_IGNORED: the device is ignored
> +	 * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
> +	 *
> +	 * Note: theoretically it can happen that the status of a foreign device
> +	 * (claimed vs. not claimed) changes in a change event.
> +	 * Supporting this correctly would require big efforts. For now, we
> +	 * don't support it. "multipathd reconfigure" starts foreign device
> +	 * detection from scratch and should be able to handle this situation.
> +	 */
> +	int (*change)(struct context *, struct udev_device *);
> +
> +	/**
> +	 * method: delete
> +	 * This is called on udev DELETE events.
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @param[in] udev udev device that has generated the event and
> +	 *	should be deleted
> +	 * @returns status code
> +	 * @retval FOREIGN_OK: processed correctly (device deleted)
> +	 * @retval FOREIGN_IGNORED: device wasn't registered internally
> +	 * @retval FOREIGN_ERR: error occured.
> +	 */
> +	int (*delete)(struct context *, struct udev_device *);
> +
> +	/**
> +	 * method: delete_all
> +	 * This is called if multipathd reconfigures itself.
> +	 * Deletes all registered devices (maps and paths)
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @returns status code
> +	 * @retval FOREIGN_OK: processed correctly
> +	 * @retval FOREIGN_IGNORED: nothing to delete
> +	 * @retval FOREIGN_ERR: error occured
> +	 */
> +	int (*delete_all)(struct context*);
> +
> +	/**
> +	 * method: check
> +	 * This is called from multipathd's checker loop.
> +	 *
> +	 * Check status of managed devices, update internal status, and print
> +	 * log messages if appropriate.
> +	 * @param[in] context foreign library context
> +	 */
> +	void (*check)(struct context *);
> +
> +	/**
> +	 * lock internal data stuctures.
> +	 * @param[in] ctx: foreign context
> +	 */
> +	void (*lock)(struct context *ctx);
> +
> +	/**
> +	 * unlock internal data stuctures.
> +	 * @param[in] ctx: foreign context (void* in order to use the function
> +	 *	as argument to pthread_cleanup_push())
> +	 */
> +	void (*unlock)(void *ctx);
> +
> +	/**
> +	 * method: get_multipaths(context)
> +	 * Returned vector must be freed by calling release_multipaths().
> +	 * Lock must be held until release_multipaths() is called.
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @returns a vector of "struct gen_multipath*" with the map devices
> +	 * belonging to this library (see generic.h).
> +	 */
> +	const struct _vector* (*get_multipaths)(const struct context *);
> +
> +	/**
> +	 * method: release_multipaths(context, mpvec)
> +	 * release data structures obtained with get_multipaths (if any)
> +	 *
> +	 * @param[in] ctx the foreign context
> +	 * @param[in] mpvec the vector allocated with get_multipaths()
> +	 */
> +	void (*release_multipaths)(const struct context *ctx,
> +				   const struct _vector* mpvec);
> +
> +	/**
> +	 * method: get_paths
> +	 * Returned vector must be freed by calling release_paths().
> +	 * Lock must be held until release_paths() is called.
> +	 *
> +	 * @param[in] context foreign library context
> +	 * @returns a vector of "struct gen_path*" with the path devices
> +	 * belonging to this library (see generic.h)
> +	 */
> +	const struct _vector* (*get_paths)(const struct context *);
> +
> +	/**
> +	 * release data structures obtained with get_multipaths (if any)
> +	 *
> +	 * @param[in] ctx the foreign context
> +	 * @param[in] ppvec the vector allocated with get_paths()
> +	 */
> +	void (*release_paths)(const struct context *ctx,
> +			      const struct _vector* ppvec);
> +
> +	void *handle;
> +	struct context *context;
> +	const char name[0];
> +};
> +
> +/**
> + * init_foreign(dir)
> + * load and initialize foreign multipath libraries in dir (libforeign-*.so).
> + * @param dir: directory to search
> + * @returns: 0 on success, negative value on failure.
> + */
> +int init_foreign(const char *multipath_dir);
> +
> +/**
> + * cleanup_foreign(dir)
> + * cleanup and free all data structures owned by foreign libraries
> + */
> +void cleanup_foreign(void);
> +
> +/**
> + * add_foreign(udev)
> + * check if a device belongs to any foreign library.
> + * calls add() for all known foreign libs, in the order registered,
> + * until the first one returns FOREIGN_CLAIMED or FOREIGN_OK.
> + * @param udev: udev device to check
> + * @returns: status code
> + * @retval FOREIGN_CLAIMED: newly claimed by a foreign lib
> + * @retval FOREIGN_OK: already claimed by a foreign lib
> + * @retval FOREIGN_IGNORED: ignored by all foreign libs
> + * @retval FOREIGN_ERR: an error occured
> + */
> +int add_foreign(struct udev_device *);
> +
> +/**
> + * change_foreign(udev)
> + * Notify foreign libraries of an udev CHANGE event
> + * @param udev: udev device to check
> + * @returns: status code (see change() method above).
> + */
> +int change_foreign(struct udev_device *);
> +
> +/**
> + * delete_foreign(udev)
> + * @param udev: udev device being removed
> + * @returns: status code (see remove() above)
> + */
> +int delete_foreign(struct udev_device *);
> +
> +/**
> + * delete_all_foreign()
> + * call delete_all() for all foreign libraries
> + * @returns: status code (see delete_all() above)
> + */
> +int delete_all_foreign(void);
> +
> +/**
> + * check_foreign()
> + * call check() (see above) for all foreign libraries
> + */
> +void check_foreign(void);
> +
> +/**
> + * foreign_path_layout()
> + * call this before printing paths, after get_path_layout(), to determine
> + * output field width.
> + */
> +void foreign_path_layout(void);
> +
> +/**
> + * foreign_multipath_layout()
> + * call this before printing maps, after get_multipath_layout(), to determine
> + * output field width.
> + */
> +void foreign_multipath_layout(void);
> +
> +/**
> + * snprint_foreign_topology(buf, len, verbosity);
> + * prints topology information from foreign libraries into buffer,
> + * '\0' - terminated.
> + * @param buf: output buffer
> + * @param len: size of output buffer
> + * @param verbosity: verbosity level
> + * @returns: number of printed characters excluding trailing '\0'.
> + */
> +int snprint_foreign_topology(char *buf, int len, int verbosity);
> +
> +/**
> + * snprint_foreign_paths(buf, len, style, pad);
> + * prints formatted path information from foreign libraries into buffer,
> + * '\0' - terminated.
> + * @param buf: output buffer
> + * @param len: size of output buffer
> + * @param style: format string
> + * @param pad: whether to pad field width
> + * @returns: number of printed characters excluding trailing '\0'.
> + */
> +int snprint_foreign_paths(char *buf, int len, const char *style, int pad);
> +
> +/**
> + * snprint_foreign_multipaths(buf, len, style, pad);
> + * prints formatted map information from foreign libraries into buffer,
> + * '\0' - terminated.
> + * @param buf: output buffer
> + * @param len: size of output buffer
> + * @param style: format string
> + * @param pad: whether to pad field width
> + * @returns: number of printed characters excluding trailing '\0'.
> + */
> +int snprint_foreign_multipaths(char *buf, int len,
> +			       const char *style, int pretty);
> +
> +/**
> + * print_foreign_topology(v)
> + * print foreign topology to stdout
> + * @param verbosity: verbosity level
> + */
> +void print_foreign_topology(int verbosity);
> +
> +/**
> + * is_claimed_by_foreign(ud)
> + * @param udev: udev device
> + * @returns: true iff device is (newly or already) claimed by a foreign lib
> + */
> +static inline bool
> +is_claimed_by_foreign(struct udev_device *ud)
> +{
> +	int rc = add_foreign(ud);
> +
> +	return (rc == FOREIGN_CLAIMED || rc == FOREIGN_OK);
> +}
> +
> +#endif /*  _FOREIGN_H */
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 17/23] libmultipath/foreign: nvme foreign library
  2018-03-05 23:15 ` [PATCH v2 17/23] libmultipath/foreign: nvme foreign library Martin Wilck
  2018-03-06  7:13   ` Hannes Reinecke
@ 2018-03-07 19:09   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:09 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:01AM +0100, Martin Wilck wrote:
> This still contains stubs for path handling and checking, but it's functional
> for printing already.
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  Makefile                      |   1 +
>  libmultipath/foreign/Makefile |  30 +++
>  libmultipath/foreign/nvme.c   | 455 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 486 insertions(+)
>  create mode 100644 libmultipath/foreign/Makefile
>  create mode 100644 libmultipath/foreign/nvme.c
> 
> diff --git a/Makefile b/Makefile
> index 11c46eb4dbc9..4b145c593605 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -7,6 +7,7 @@ BUILDDIRS = \
>  	libmultipath \
>  	libmultipath/prioritizers \
>  	libmultipath/checkers \
> +	libmultipath/foreign \
>  	libmpathpersist \
>  	multipath \
>  	multipathd \
> diff --git a/libmultipath/foreign/Makefile b/libmultipath/foreign/Makefile
> new file mode 100644
> index 000000000000..dfba11e86d76
> --- /dev/null
> +++ b/libmultipath/foreign/Makefile
> @@ -0,0 +1,30 @@
> +#
> +# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
> +#
> +include ../../Makefile.inc
> +
> +CFLAGS += $(LIB_CFLAGS) -I..
> +
> +# If you add or remove a checker also update multipath/multipath.conf.5
> +LIBS= \
> +	libforeign-nvme.so
> +
> +all: $(LIBS)
> +
> +libforeign-%.so: %.o
> +	$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^
> +
> +install:
> +	$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)
> +
> +uninstall:
> +	for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done
> +
> +clean: dep_clean
> +	$(RM) core *.a *.o *.gz *.so
> +
> +OBJS := $(LIBS:libforeign-%.so=%.o)
> +include $(wildcard $(OBJS:.o=.d))
> +
> +dep_clean:
> +	$(RM) $(OBJS:.o=.d)
> diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
> new file mode 100644
> index 000000000000..32bd5c96c44a
> --- /dev/null
> +++ b/libmultipath/foreign/nvme.c
> @@ -0,0 +1,455 @@
> +/*
> +  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 <sys/sysmacros.h>
> +#include <libudev.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdbool.h>
> +#include <libudev.h>
> +#include <pthread.h>
> +#include "vector.h"
> +#include "generic.h"
> +#include "foreign.h"
> +#include "debug.h"
> +
> +const char *THIS;
> +
> +struct nvme_map {
> +	struct gen_multipath gen;
> +	struct udev_device *udev;
> +	struct udev_device *subsys;
> +	dev_t devt;
> +};
> +
> +#define NAME_LEN 64 /* buffer length temp model name */
> +#define const_gen_mp_to_nvme(g) ((const struct nvme_map*)(g))
> +#define gen_mp_to_nvme(g) ((struct nvme_map*)(g))
> +#define nvme_mp_to_gen(n) &((n)->gen)
> +
> +static void cleanup_nvme_map(struct nvme_map *map)
> +{
> +	if (map->udev)
> +		udev_device_unref(map->udev);
> +	if (map->subsys)
> +		udev_device_unref(map->subsys);
> +	free(map);
> +}
> +
> +static const struct _vector*
> +nvme_mp_get_pgs(const struct gen_multipath *gmp) {
> +	return NULL;
> +}
> +
> +static void
> +nvme_mp_rel_pgs(const struct gen_multipath *gmp, const struct _vector *v)
> +{
> +}
> +
> +static void rstrip(char *str)
> +{
> +	int n;
> +
> +	for (n = strlen(str) - 1; n >= 0 && str[n] == ' '; n--);
> +	str[n+1] = '\0';
> +}
> +
> +static int snprint_nvme_map(const struct gen_multipath *gmp,
> +			    char *buff, int len, char wildcard)
> +{
> +	const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
> +	static const char nvme_vendor[] = "NVMe";
> +	char fld[NAME_LEN];
> +	const char *val;
> +
> +	switch (wildcard) {
> +	case 'd':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysname(nvm->udev));
> +	case 'n':
> +		return snprintf(buff, len, "%s:NQN:%s",
> +				udev_device_get_sysname(nvm->subsys),
> +				udev_device_get_sysattr_value(nvm->subsys,
> +							      "subsysnqn"));
> +	case 'w':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysattr_value(nvm->udev,
> +							      "wwid"));
> +	case 'S':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysattr_value(nvm->udev,
> +							      "size"));
> +	case 'v':
> +		return snprintf(buff, len, "%s", nvme_vendor);
> +	case 's':
> +	case 'p':
> +		snprintf(fld, sizeof(fld), "%s",
> +			 udev_device_get_sysattr_value(nvm->subsys,
> +						      "model"));
> +		rstrip(fld);
> +		if (wildcard == 'p')
> +			return snprintf(buff, len, "%s", fld);
> +		return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
> +				udev_device_get_sysattr_value(nvm->subsys,
> +							      "firmware_rev"));
> +	case 'e':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysattr_value(nvm->subsys,
> +							      "firmware_rev"));
> +	case 'r':
> +		val = udev_device_get_sysattr_value(nvm->udev, "ro");
> +		if (val[0] == 1)
> +			return snprintf(buff, len, "%s", "ro");
> +		else
> +			return snprintf(buff, len, "%s", "rw");
> +	case 'G':
> +		return snprintf(buff, len, "%s", THIS);
> +	default:
> +		return snprintf(buff, len, "N/A");
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static const struct _vector*
> +nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
> +	return NULL;
> +}
> +
> +static void
> +nvme_pg_rel_paths(const struct gen_pathgroup *gpg, const struct _vector *v)
> +{
> +}
> +
> +static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
> +			   char *buff, int len, char wildcard)
> +{
> +	return 0;
> +}
> +
> +static int snprint_nvme_path(const struct gen_path *gmp,
> +			     char *buff, int len, char wildcard)
> +{
> +	switch (wildcard) {
> +	case 'R':
> +		return snprintf(buff, len, "[foreign: %s]", THIS);
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static const struct gen_multipath_ops nvme_map_ops = {
> +	.get_pathgroups = nvme_mp_get_pgs,
> +	.rel_pathgroups = nvme_mp_rel_pgs,
> +	.style = generic_style,
> +	.snprint = snprint_nvme_map,
> +};
> +
> +static const struct gen_pathgroup_ops nvme_pg_ops __attribute__((unused)) = {
> +	.get_paths = nvme_pg_get_paths,
> +	.rel_paths = nvme_pg_rel_paths,
> +	.snprint = snprint_nvme_pg,
> +};
> +
> +static const struct gen_path_ops nvme_path_ops __attribute__((unused)) = {
> +	.snprint = snprint_nvme_path,
> +};
> +
> +struct context {
> +	pthread_mutex_t mutex;
> +	vector mpvec;
> +};
> +
> +void lock(struct context *ctx)
> +{
> +	pthread_mutex_lock(&ctx->mutex);
> +}
> +
> +void unlock(void *arg)
> +{
> +	struct context *ctx = arg;
> +
> +	pthread_mutex_unlock(&ctx->mutex);
> +}
> +
> +static int _delete_all(struct context *ctx)
> +{
> +	struct nvme_map *nm;
> +	int n = VECTOR_SIZE(ctx->mpvec), i;
> +
> +	if (n == 0)
> +		return FOREIGN_IGNORED;
> +
> +	vector_foreach_slot_backwards(ctx->mpvec, nm, i) {
> +		vector_del_slot(ctx->mpvec, i);
> +		cleanup_nvme_map(nm);
> +	}
> +	return FOREIGN_OK;
> +}
> +
> +int delete_all(struct context *ctx)
> +{
> +	int rc;
> +
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +
> +	lock(ctx);
> +	pthread_cleanup_push(unlock, ctx);
> +	rc = _delete_all(ctx);
> +	pthread_cleanup_pop(1);
> +
> +	return rc;
> +}
> +
> +void cleanup(struct context *ctx)
> +{
> +	(void)delete_all(ctx);
> +
> +	lock(ctx);
> +	/*
> +	 * Locking is not strictly necessary here, locking in foreign.c
> +	 * makes sure that no other code is called with this ctx any more.
> +	 * But this should make static checkers feel better.
> +	 */
> +	pthread_cleanup_push(unlock, ctx);
> +	if (ctx->udev)
> +		udev_unref(ctx->udev);
> +	if (ctx->mpvec)
> +		vector_free(ctx->mpvec);
> +	ctx->mpvec = NULL;
> +	ctx->udev = NULL;
> +	pthread_cleanup_pop(1);
> +	pthread_mutex_destroy(&ctx->mutex);
> +
> +	free(ctx);
> +}
> +
> +struct context *init(unsigned int api, const char *name)
> +{
> +	struct context *ctx;
> +
> +	if (api > LIBMP_FOREIGN_API) {
> +		condlog(0, "%s: api version mismatch: %08x > %08x\n",
> +			__func__, api, LIBMP_FOREIGN_API);
> +		return NULL;
> +	}
> +
> +	if ((ctx = calloc(1, sizeof(*ctx)))== NULL)
> +		return NULL;
> +
> +	pthread_mutex_init(&ctx->mutex, NULL);
> +
> +	ctx->mpvec = vector_alloc();
> +	if (ctx->mpvec == NULL)
> +		goto err;
> +
> +	THIS = name;
> +	return ctx;
> +err:
> +	cleanup(ctx);
> +	return NULL;
> +}
> +
> +static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
> +					      dev_t devt)
> +{
> +	struct nvme_map *nm;
> +	int i;
> +
> +	if (ctx->mpvec == NULL)
> +		return NULL;
> +
> +	vector_foreach_slot(ctx->mpvec, nm, i) {
> +		if (nm->devt == devt)
> +			return nm;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int _add_map(struct context *ctx, struct udev_device *ud,
> +		    struct udev_device *subsys)
> +{
> +	dev_t devt = udev_device_get_devnum(ud);
> +	struct nvme_map *map;
> +
> +	if (_find_nvme_map_by_devt(ctx, devt) != NULL)
> +		return FOREIGN_OK;
> +
> +	map = calloc(1, sizeof(*map));
> +	if (map == NULL)
> +		return FOREIGN_ERR;
> +
> +	map->devt = devt;
> +	map->udev = udev_device_ref(ud);
> +	/*
> +	 * subsys is implicitly referenced by map->udev,
> +	 * no need to take a reference here.
> +	 */
> +	map->subsys = subsys;
> +	map->gen.ops = &nvme_map_ops;
> +
> +	if (vector_alloc_slot(ctx->mpvec) == NULL) {
> +		cleanup_nvme_map(map);
> +		return FOREIGN_ERR;
> +	}
> +
> +	vector_set_slot(ctx->mpvec, map);
> +
> +	return FOREIGN_CLAIMED;
> +}
> +
> +int add(struct context *ctx, struct udev_device *ud)
> +{
> +	struct udev_device *subsys;
> +	int rc;
> +
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +
> +	if (ud == NULL)
> +		return FOREIGN_ERR;
> +	if (strcmp("disk", udev_device_get_devtype(ud)))
> +		return FOREIGN_IGNORED;
> +
> +	subsys = udev_device_get_parent_with_subsystem_devtype(ud,
> +							       "nvme-subsystem",
> +							       NULL);
> +	if (subsys == NULL)
> +		return FOREIGN_IGNORED;
> +
> +	lock(ctx);
> +	pthread_cleanup_push(unlock, ctx);
> +	rc = _add_map(ctx, ud, subsys);
> +	pthread_cleanup_pop(1);
> +
> +	if (rc == FOREIGN_CLAIMED)
> +		condlog(3, "%s: %s: added map %s", __func__, THIS,
> +			udev_device_get_sysname(ud));
> +	else if (rc != FOREIGN_OK)
> +		condlog(1, "%s: %s: retcode %d adding %s",
> +			__func__, THIS, rc, udev_device_get_sysname(ud));
> +
> +	return rc;
> +}
> +
> +int change(struct context *ctx, struct udev_device *ud)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	return FOREIGN_IGNORED;
> +}
> +
> +static int _delete_map(struct context *ctx, struct udev_device *ud)
> +{
> +	int k;
> +	struct nvme_map *map;
> +	dev_t devt = udev_device_get_devnum(ud);
> +
> +	map = _find_nvme_map_by_devt(ctx, devt);
> +	if (map ==NULL)
> +		return FOREIGN_IGNORED;
> +
> +	k = find_slot(ctx->mpvec, map);
> +	if (k == -1)
> +		return FOREIGN_ERR;
> +	else
> +		vector_del_slot(ctx->mpvec, k);
> +
> +	cleanup_nvme_map(map);
> +
> +	return FOREIGN_OK;
> +}
> +
> +int delete(struct context *ctx, struct udev_device *ud)
> +{
> +	int rc;
> +
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +
> +	if (ud == NULL)
> +		return FOREIGN_ERR;
> +
> +	lock(ctx);
> +	pthread_cleanup_push(unlock, ctx);
> +	rc = _delete_map(ctx, ud);
> +	pthread_cleanup_pop(1);
> +
> +	if (rc == FOREIGN_OK)
> +		condlog(3, "%s: %s: map %s deleted", __func__, THIS,
> +			udev_device_get_sysname(ud));
> +	else if (rc != FOREIGN_IGNORED)
> +		condlog(1, "%s: %s: retcode %d deleting map %s", __func__,
> +			THIS, rc, udev_device_get_sysname(ud));
> +
> +	return rc;
> +}
> +
> +void check(struct context *ctx)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	return;
> +}
> +
> +/*
> + * It's safe to pass our internal pointer, this is only used under the lock.
> + */
> +const struct _vector *get_multipaths(const struct context *ctx)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	return ctx->mpvec;
> +}
> +
> +void release_multipaths(const struct context *ctx, const struct _vector *mpvec)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	/* NOP */
> +}
> +
> +/*
> + * It's safe to pass our internal pointer, this is only used under the lock.
> + */
> +const struct _vector * get_paths(const struct context *ctx)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	return NULL;
> +}
> +
> +void release_paths(const struct context *ctx, const struct _vector *mpvec)
> +{
> +	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	/* NOP */
> +}
> +
> +/* compile-time check whether all methods are present and correctly typed */
> +#define _METHOD_INIT(x) .x = x
> +static struct foreign __methods __attribute__((unused)) = {
> +	_METHOD_INIT(init),
> +	_METHOD_INIT(cleanup),
> +	_METHOD_INIT(change),
> +	_METHOD_INIT(delete),
> +	_METHOD_INIT(delete_all),
> +	_METHOD_INIT(check),
> +	_METHOD_INIT(lock),
> +	_METHOD_INIT(unlock),
> +	_METHOD_INIT(get_multipaths),
> +	_METHOD_INIT(release_multipaths),
> +	_METHOD_INIT(get_paths),
> +	_METHOD_INIT(release_paths),
> +};
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 18/23] libmultipath: pathinfo: call into foreign library
  2018-03-05 23:15 ` [PATCH v2 18/23] libmultipath: pathinfo: call into " Martin Wilck
  2018-03-06  7:14   ` Hannes Reinecke
@ 2018-03-07 19:10   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:10 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:02AM +0100, Martin Wilck wrote:
> This actually enables the use of foreign paths.
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/discovery.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index 645224c1029c..45a4d8378893 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -31,6 +31,7 @@
>  #include "prio.h"
>  #include "defaults.h"
>  #include "prioritizers/alua_rtpg.h"
> +#include "foreign.h"
>  
>  int
>  alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
> @@ -1909,7 +1910,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
>  	 * limited by DI_BLACKLIST and occurs before this debug
>  	 * message with the mask value.
>  	 */
> -	if (pp->udev && filter_property(conf, pp->udev) > 0)
> +	if (pp->udev && (is_claimed_by_foreign(pp->udev) ||
> +			 filter_property(conf, pp->udev) > 0))
>  		return PATHINFO_SKIPPED;
>  
>  	if (filter_devnode(conf->blist_devnode,
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 19/23] multipath: use foreign API
  2018-03-05 23:15 ` [PATCH v2 19/23] multipath: use foreign API Martin Wilck
  2018-03-06  7:14   ` Hannes Reinecke
@ 2018-03-07 19:11   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:11 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:03AM +0100, Martin Wilck wrote:
> Use the "foreign" code to print information about multipath maps
> owned by foreign libraries in print mode (multipath -ll, -l).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> ---
>  multipath/main.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/multipath/main.c b/multipath/main.c
> index a0c750e6f623..4fae49ee4325 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -59,6 +59,7 @@
>  #include "wwids.h"
>  #include "uxsock.h"
>  #include "mpath_cmd.h"
> +#include "foreign.h"
>  
>  int logsink;
>  struct udev *udev;
> @@ -257,6 +258,14 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
>  		if (cmd == CMD_CREATE)
>  			reinstate_paths(mpp);
>  	}
> +
> +	if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) {
> +		struct config *conf = get_multipath_config();
> +
> +		print_foreign_topology(conf->verbosity);
> +		put_multipath_config(conf);
> +	}
> +
>  	return 0;
>  }
>  
> @@ -460,6 +469,7 @@ configure (struct config *conf, enum mpath_cmds cmd,
>  		print_all_paths(pathvec, 1);
>  
>  	get_path_layout(pathvec, 0);
> +	foreign_path_layout();
>  
>  	if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
>  		goto out;
> @@ -817,6 +827,8 @@ main (int argc, char *argv[])
>  		condlog(0, "failed to initialize prioritizers");
>  		goto out;
>  	}
> +	/* Failing here is non-fatal */
> +	init_foreign(conf->multipath_dir);
>  	if (cmd == CMD_USABLE_PATHS) {
>  		r = check_usable_paths(conf, dev, dev_type);
>  		goto out;
> @@ -892,6 +904,7 @@ out:
>  	dm_lib_release();
>  	dm_lib_exit();
>  
> +	cleanup_foreign();
>  	cleanup_prio();
>  	cleanup_checkers();
>  
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 20/23] multipathd: use foreign API
  2018-03-05 23:15 ` [PATCH v2 20/23] multipathd: " Martin Wilck
  2018-03-06  7:15   ` Hannes Reinecke
@ 2018-03-07 19:25   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:25 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:04AM +0100, Martin Wilck wrote:
> Call into the foreign library code when paths are discovered, uevents
> are received, and in the checker loop. Furthermore, use the foreign
> code to print information in the "multipathd show paths", "multipathd
> show maps", and "multipathd show topology" client commands.
> 
> We don't support foreign data in the individual "show map" and "show path"
> commands, and neither in the "json" commands. The former is a deliberate
> decision, the latter could be added if desired.
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-----
>  multipathd/main.c         | 34 +++++++++++++++++++++++++++++++---
>  2 files changed, 65 insertions(+), 8 deletions(-)
> 
> diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
> index 78f2a12bc2f8..c0ae54aae841 100644
> --- a/multipathd/cli_handlers.c
> +++ b/multipathd/cli_handlers.c
> @@ -27,6 +27,7 @@
>  #include "main.h"
>  #include "cli.h"
>  #include "uevent.h"
> +#include "foreign.h"
>  
>  int
>  show_paths (char ** r, int * len, struct vectors * vecs, char * style,
> @@ -35,11 +36,13 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
>  	int i;
>  	struct path * pp;
>  	char * c;
> -	char * reply;
> +	char * reply, * header;
>  	unsigned int maxlen = INITIAL_REPLY_LEN;
>  	int again = 1;
>  
>  	get_path_layout(vecs->pathvec, 1);
> +	foreign_path_layout();
> +
>  	reply = MALLOC(maxlen);
>  
>  	while (again) {
> @@ -48,18 +51,29 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style,
>  
>  		c = reply;
>  
> -		if (pretty && VECTOR_SIZE(vecs->pathvec) > 0)
> +		if (pretty)
>  			c += snprint_path_header(c, reply + maxlen - c,
>  						 style);
> +		header = c;
>  
>  		vector_foreach_slot(vecs->pathvec, pp, i)
>  			c += snprint_path(c, reply + maxlen - c,
>  					  style, pp, pretty);
>  
> +		c += snprint_foreign_paths(c, reply + maxlen - c,
> +					   style, pretty);
> +
>  		again = ((c - reply) == (maxlen - 1));
>  
>  		REALLOC_REPLY(reply, again, maxlen);
>  	}
> +
> +	if (pretty && c == header) {
> +		/* No output - clear header */
> +		*reply = '\0';
> +		c = reply;
> +	}
> +
>  	*r = reply;
>  	*len = (int)(c - reply + 1);
>  	return 0;
> @@ -134,6 +148,8 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
>  	int again = 1;
>  
>  	get_path_layout(vecs->pathvec, 0);
> +	foreign_path_layout();
> +
>  	reply = MALLOC(maxlen);
>  
>  	while (again) {
> @@ -150,11 +166,13 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
>  			c += snprint_multipath_topology(c, reply + maxlen - c,
>  							mpp, 2);
>  		}
> +		c += snprint_foreign_topology(c, reply + maxlen - c, 2);
>  
>  		again = ((c - reply) == (maxlen - 1));
>  
>  		REALLOC_REPLY(reply, again, maxlen);
>  	}
> +
>  	*r = reply;
>  	*len = (int)(c - reply + 1);
>  	return 0;
> @@ -499,12 +517,14 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
>  {
>  	int i;
>  	struct multipath * mpp;
> -	char * c;
> +	char * c, *header;
>  	char * reply;
>  	unsigned int maxlen = INITIAL_REPLY_LEN;
>  	int again = 1;
>  
>  	get_multipath_layout(vecs->mpvec, 1);
> +	foreign_multipath_layout();
> +
>  	reply = MALLOC(maxlen);
>  
>  	while (again) {
> @@ -512,9 +532,10 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
>  			return 1;
>  
>  		c = reply;
> -		if (pretty && VECTOR_SIZE(vecs->mpvec) > 0)
> +		if (pretty)
>  			c += snprint_multipath_header(c, reply + maxlen - c,
>  						      style);
> +		header = c;
>  
>  		vector_foreach_slot(vecs->mpvec, mpp, i) {
>  			if (update_multipath(vecs, mpp->alias, 0)) {
> @@ -523,12 +544,20 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style,
>  			}
>  			c += snprint_multipath(c, reply + maxlen - c,
>  					       style, mpp, pretty);
> -		}
>  
> +		}
> +		c += snprint_foreign_multipaths(c, reply + maxlen - c,
> +						style, pretty);
>  		again = ((c - reply) == (maxlen - 1));
>  
>  		REALLOC_REPLY(reply, again, maxlen);
>  	}
> +
> +	if (pretty && c == header) {
> +		/* No output - clear header */
> +		*reply = '\0';
> +		c = reply;
> +	}
>  	*r = reply;
>  	*len = (int)(c - reply + 1);
>  	return 0;
> diff --git a/multipathd/main.c b/multipathd/main.c
> index cb26c58f6ba9..465a1e291226 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -84,6 +84,7 @@ static int use_watchdog;
>  #include "waiter.h"
>  #include "io_err_stat.h"
>  #include "wwids.h"
> +#include "foreign.h"
>  #include "../third-party/valgrind/drd.h"
>  
>  #define FILE_NAME_SIZE 256
> @@ -798,6 +799,8 @@ uev_remove_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
>  	int ret;
>  
>  	condlog(2, "%s: remove path (uevent)", uev->kernel);
> +	delete_foreign(uev->udev);
> +
>  	pthread_cleanup_push(cleanup_lock, &vecs->lock);
>  	lock(&vecs->lock);
>  	pthread_testcancel();
> @@ -917,12 +920,27 @@ fail:
>  static int
>  uev_update_path (struct uevent *uev, struct vectors * vecs)
>  {
> -	int ro, retval = 0;
> +	int ro, retval = 0, rc;
>  	struct path * pp;
>  	struct config *conf;
>  	int disable_changed_wwids;
>  	int needs_reinit = 0;
>  
> +	switch ((rc = change_foreign(uev->udev))) {
> +	case FOREIGN_OK:
> +		/* known foreign path, ignore event */
> +		return 0;
> +	case FOREIGN_IGNORED:
> +		break;
> +	case FOREIGN_ERR:
> +		condlog(3, "%s: error in change_foreign", __func__);
> +		break;
> +	default:
> +		condlog(1, "%s: return code %d of change_forein is unsupported",
> +			__func__, rc);
> +		break;
> +	}
> +
>  	conf = get_multipath_config();
>  	disable_changed_wwids = conf->disable_changed_wwids;
>  	put_multipath_config(conf);
> @@ -1122,8 +1140,13 @@ uev_trigger (struct uevent * uev, void * trigger_data)
>  	 * are not fully initialised then.
>  	 */
>  	if (!strncmp(uev->kernel, "dm-", 3)) {
> -		if (!uevent_is_mpath(uev))
> +		if (!uevent_is_mpath(uev)) {
> +			if (!strncmp(uev->action, "change", 6))
> +				(void)add_foreign(uev->udev);
> +			else if (!strncmp(uev->action, "remove", 6))
> +				(void)delete_foreign(uev->udev);
>  			goto out;
> +		}
>  		if (!strncmp(uev->action, "change", 6)) {
>  			r = uev_add_map(uev, vecs);
>  
> @@ -1932,7 +1955,7 @@ checkerloop (void *ap)
>  						diff_time.tv_sec);
>  			}
>  		}
> -
> +		check_foreign();
>  		post_config_state(DAEMON_IDLE);
>  		conf = get_multipath_config();
>  		strict_timing = conf->strict_timing;
> @@ -2121,6 +2144,7 @@ reconfigure (struct vectors * vecs)
>  
>  	free_pathvec(vecs->pathvec, FREE_PATHS);
>  	vecs->pathvec = NULL;
> +	delete_all_foreign();
>  
>  	/* Re-read any timezone changes */
>  	tzset();
> @@ -2372,6 +2396,9 @@ child (void * param)
>  		condlog(0, "failed to initialize prioritizers");
>  		goto failed;
>  	}
> +	/* Failing this is non-fatal */
> +
> +	init_foreign(conf->multipath_dir);
>  
>  	setlogmask(LOG_UPTO(conf->verbosity + 3));
>  
> @@ -2529,6 +2556,7 @@ child (void * param)
>  	FREE(vecs);
>  	vecs = NULL;
>  
> +	cleanup_foreign();
>  	cleanup_checkers();
>  	cleanup_prio();
>  
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display
  2018-03-05 23:15 ` [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display Martin Wilck
  2018-03-06  7:15   ` Hannes Reinecke
@ 2018-03-07 19:27   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 19:27 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:05AM +0100, Martin Wilck wrote:
> implement display of path information for NVMe foreign paths and maps.
> With this patch, I get output like this for Linux NVMe soft targets:
> 
> nvme-submultipathd show topology
> sys0:NQN:subsysname (uuid.96926ba3-b207-437c-902c-4a4df6538c3f) [nvme] nvme0n1 NVMe,Linux,4.15.0-r
> size=2097152 features='n/a' hwhandler='n/a' wp=rw
> `-+- policy='n/a' prio=n/a status=n/a
>   |- 0:1:1 nvme0c1n1 0:0 n/a n/a live
>   |- 0:2:1 nvme0c2n1 0:0 n/a n/a live
>   |- 0:3:1 nvme0c3n1 0:0 n/a n/a live
>   `- 0:4:1 nvme0c4n1 0:0 n/a n/a live
> 
> multipathd show paths format '%G %d %i %o %z %m %N'
> foreign dev       hcil  dev_st serial           multipath host WWNN
> [nvme]  nvme0c1n1 0:1:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.201.101,trsvcid=4420
> [nvme]  nvme0c2n1 0:2:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.202.101,trsvcid=4420
> [nvme]  nvme0c3n1 0:3:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.203.101,trsvcid=4420
> [nvme]  nvme0c4n1 0:4:1 live   1c2c86659503a02f nvme0n1   rdma:traddr=192.168.204.101,trsvcid=4420
> 
> (admittedly, I abused the 'WWNN' wildcard here a bit to display information
> which is helpful for NVMe over RDMA).
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/foreign/nvme.c | 334 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 320 insertions(+), 14 deletions(-)
> 
> diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
> index 32bd5c96c44a..235f75dd2add 100644
> --- a/libmultipath/foreign/nvme.c
> +++ b/libmultipath/foreign/nvme.c
> @@ -25,42 +25,98 @@
>  #include <stdbool.h>
>  #include <libudev.h>
>  #include <pthread.h>
> +#include <limits.h>
> +#include <dirent.h>
> +#include <errno.h>
>  #include "vector.h"
>  #include "generic.h"
>  #include "foreign.h"
>  #include "debug.h"
> +#include "structs.h"
> +#include "sysfs.h"
>  
> +static const char nvme_vendor[] = "NVMe";
> +static const char N_A[] = "n/a";
>  const char *THIS;
>  
> +struct nvme_map;
> +struct nvme_path {
> +	struct gen_path gen;
> +	struct udev_device *udev;
> +	struct udev_device *ctl;
> +	struct nvme_map *map;
> +	bool seen;
> +};
> +
> +struct nvme_pathgroup {
> +	struct gen_pathgroup gen;
> +	vector pathvec;
> +};
> +
>  struct nvme_map {
>  	struct gen_multipath gen;
>  	struct udev_device *udev;
>  	struct udev_device *subsys;
>  	dev_t devt;
> +	/* Just one static pathgroup for NVMe for now */
> +	struct nvme_pathgroup pg;
> +	struct gen_pathgroup *gpg;
> +	struct _vector pgvec;
> +	vector pathvec;
> +	int nr_live;
>  };
>  
> -#define NAME_LEN 64 /* buffer length temp model name */
> +#define NAME_LEN 64 /* buffer length for temp attributes */
>  #define const_gen_mp_to_nvme(g) ((const struct nvme_map*)(g))
>  #define gen_mp_to_nvme(g) ((struct nvme_map*)(g))
>  #define nvme_mp_to_gen(n) &((n)->gen)
> +#define const_gen_pg_to_nvme(g) ((const struct nvme_pathgroup*)(g))
> +#define gen_pg_to_nvme(g) ((struct nvme_pathgroup*)(g))
> +#define nvme_pg_to_gen(n) &((n)->gen)
> +#define const_gen_path_to_nvme(g) ((const struct nvme_path*)(g))
> +#define gen_path_to_nvme(g) ((struct nvme_path*)(g))
> +#define nvme_path_to_gen(n) &((n)->gen)
> +
> +static void cleanup_nvme_path(struct nvme_path *path)
> +{
> +	condlog(5, "%s: %p %p", __func__, path, path->udev);
> +	if (path->udev)
> +		udev_device_unref(path->udev);
> +	/* ctl is implicitly referenced by udev, no need to unref */
> +	free(path);
> +}
>  
>  static void cleanup_nvme_map(struct nvme_map *map)
>  {
> +	if (map->pathvec) {
> +		struct nvme_path *path;
> +		int i;
> +
> +		vector_foreach_slot_backwards(map->pathvec, path, i) {
> +			condlog(5, "%s: %d %p", __func__, i, path);
> +			cleanup_nvme_path(path);
> +			vector_del_slot(map->pathvec, i);
> +		}
> +	}
> +	vector_free(map->pathvec);
>  	if (map->udev)
>  		udev_device_unref(map->udev);
> -	if (map->subsys)
> -		udev_device_unref(map->subsys);
> +	/* subsys is implicitly referenced by udev, no need to unref */
>  	free(map);
>  }
>  
>  static const struct _vector*
>  nvme_mp_get_pgs(const struct gen_multipath *gmp) {
> -	return NULL;
> +	const struct nvme_map *nvme = const_gen_mp_to_nvme(gmp);
> +
> +	/* This is all used under the lock, no need to copy */
> +	return &nvme->pgvec;
>  }
>  
>  static void
>  nvme_mp_rel_pgs(const struct gen_multipath *gmp, const struct _vector *v)
>  {
> +	/* empty */
>  }
>  
>  static void rstrip(char *str)
> @@ -75,7 +131,6 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
>  			    char *buff, int len, char wildcard)
>  {
>  	const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
> -	static const char nvme_vendor[] = "NVMe";
>  	char fld[NAME_LEN];
>  	const char *val;
>  
> @@ -92,6 +147,8 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
>  		return snprintf(buff, len, "%s",
>  				udev_device_get_sysattr_value(nvm->udev,
>  							      "wwid"));
> +	case 'N':
> +		return snprintf(buff, len, "%u", nvm->nr_live);
>  	case 'S':
>  		return snprintf(buff, len, "%s",
>  				udev_device_get_sysattr_value(nvm->udev,
> @@ -122,7 +179,7 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
>  	case 'G':
>  		return snprintf(buff, len, "%s", THIS);
>  	default:
> -		return snprintf(buff, len, "N/A");
> +		return snprintf(buff, len, N_A);
>  		break;
>  	}
>  	return 0;
> @@ -130,27 +187,101 @@ static int snprint_nvme_map(const struct gen_multipath *gmp,
>  
>  static const struct _vector*
>  nvme_pg_get_paths(const struct gen_pathgroup *gpg) {
> -	return NULL;
> +	const struct nvme_pathgroup *gp = const_gen_pg_to_nvme(gpg);
> +
> +	/* This is all used under the lock, no need to copy */
> +	return gp->pathvec;
>  }
>  
>  static void
>  nvme_pg_rel_paths(const struct gen_pathgroup *gpg, const struct _vector *v)
>  {
> +	/* empty */
>  }
>  
>  static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
>  			   char *buff, int len, char wildcard)
>  {
> -	return 0;
> +	return snprintf(buff, len, N_A);
>  }
>  
> -static int snprint_nvme_path(const struct gen_path *gmp,
> +static int snprint_hcil(const struct nvme_path *np, char *buf, int len)
> +{
> +	unsigned int nvmeid, ctlid, nsid;
> +	int rc;
> +	const char *sysname = udev_device_get_sysname(np->udev);
> +
> +	rc = sscanf(sysname, "nvme%uc%un%u", &nvmeid, &ctlid, &nsid);
> +	if (rc != 3) {
> +		condlog(1, "%s: failed to scan %s", __func__, sysname);
> +		rc = snprintf(buf, len, "(ERR:%s)", sysname);
> +	} else
> +		rc = snprintf(buf, len, "%u:%u:%u", nvmeid, ctlid, nsid);
> +	return (rc < len ? rc : len);
> +}
> +
> +static int snprint_nvme_path(const struct gen_path *gp,
>  			     char *buff, int len, char wildcard)
>  {
> +	const struct nvme_path *np = const_gen_path_to_nvme(gp);
> +	dev_t devt;
> +	char fld[NAME_LEN];
> +	struct udev_device *pci;
> +
>  	switch (wildcard) {
> +	case 'w':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysattr_value(np->udev,
> +							      "wwid"));
> +	case 'd':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysname(np->udev));
> +	case 'i':
> +		return snprint_hcil(np, buff, len);
> +	case 'D':
> +		devt = udev_device_get_devnum(np->udev);
> +		return snprintf(buff, len, "%u:%u", major(devt), minor(devt));
> +	case 'o':
> +		sysfs_attr_get_value(np->ctl, "state", fld, sizeof(fld));
> +		return snprintf(buff, len, "%s", fld);
> +	case 's':
> +		snprintf(fld, sizeof(fld), "%s",
> +			 udev_device_get_sysattr_value(np->ctl,
> +						      "model"));
> +		rstrip(fld);
> +		return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
> +				udev_device_get_sysattr_value(np->ctl,
> +							      "firmware_rev"));
> +	case 'S':
> +		return snprintf(buff, len, "%s",
> +			udev_device_get_sysattr_value(np->udev,
> +						      "size"));
> +	case 'z':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysattr_value(np->ctl,
> +							      "serial"));
> +	case 'm':
> +		return snprintf(buff, len, "%s",
> +				udev_device_get_sysname(np->map->udev));
> +	case 'N':
>  	case 'R':
> -		return snprintf(buff, len, "[foreign: %s]", THIS);
> +		return snprintf(buff, len, "%s:%s",
> +			udev_device_get_sysattr_value(np->ctl,
> +						      "transport"),
> +			udev_device_get_sysattr_value(np->ctl,
> +						      "address"));
> +	case 'G':
> +		return snprintf(buff, len, "[%s]", THIS);
> +	case 'a':
> +		pci = udev_device_get_parent_with_subsystem_devtype(np->ctl,
> +								    "pci",
> +								    NULL);
> +		if (pci != NULL)
> +			return snprintf(buff, len, "PCI:%s",
> +					udev_device_get_sysname(pci));
> +		/* fall through */
>  	default:
> +		return snprintf(buff, len, "%s", N_A);
>  		break;
>  	}
>  	return 0;
> @@ -176,6 +307,7 @@ static const struct gen_path_ops nvme_path_ops __attribute__((unused)) = {
>  struct context {
>  	pthread_mutex_t mutex;
>  	vector mpvec;
> +	struct udev *udev;
>  };
>  
>  void lock(struct context *ctx)
> @@ -257,6 +389,10 @@ struct context *init(unsigned int api, const char *name)
>  
>  	pthread_mutex_init(&ctx->mutex, NULL);
>  
> +	ctx->udev = udev_new();
> +	if (ctx->udev == NULL)
> +		goto err;
> +
>  	ctx->mpvec = vector_alloc();
>  	if (ctx->mpvec == NULL)
>  		goto err;
> @@ -285,6 +421,138 @@ static struct nvme_map *_find_nvme_map_by_devt(const struct context *ctx,
>  	return NULL;
>  }
>  
> +static struct nvme_path *
> +_find_path_by_syspath(struct nvme_map *map, const char *syspath)
> +{
> +	struct nvme_path *path;
> +	char real[PATH_MAX];
> +	const char *ppath;
> +	int i;
> +
> +	ppath = realpath(syspath, real);
> +	if (ppath == NULL) {
> +		condlog(1, "%s: %s: error in realpath", __func__, THIS);
> +		ppath = syspath;
> +	}
> +
> +	vector_foreach_slot(map->pathvec, path, i) {
> +		if (!strcmp(ppath,
> +			    udev_device_get_syspath(path->udev)))
> +			return path;
> +	}
> +	condlog(4, "%s: %s: %s not found", __func__, THIS, ppath);
> +	return NULL;
> +}
> +
> +static int no_dotfiles(const struct dirent *di)
> +{
> +	return di->d_name[0] != '.';
> +}
> +
> +static void _find_slaves(struct context *ctx, struct nvme_map *map)
> +{
> +	char pathbuf[PATH_MAX];
> +	struct dirent **di = NULL;
> +	struct nvme_path *path;
> +	int r, i;
> +
> +	if (map == NULL || map->udev == NULL)
> +		return;
> +
> +	vector_foreach_slot(map->pathvec, path, i)
> +		path->seen = false;
> +
> +	snprintf(pathbuf, sizeof(pathbuf),
> +		"%s/slaves",
> +		udev_device_get_syspath(map->udev));
> +
> +	r = scandir(pathbuf, &di, no_dotfiles, alphasort);
> +
> +	if (r == 0) {
> +		condlog(3, "%s: %s: no paths for %s", __func__, THIS,
> +			udev_device_get_sysname(map->udev));
> +		return;
> +	} else if (r < 0) {
> +		condlog(1, "%s: %s: error %d scanning paths of %s", __func__,
> +			THIS, errno, udev_device_get_sysname(map->udev));
> +		return;
> +	}
> +
> +	pthread_cleanup_push(free, di);
> +	for (i = 0; i < r; i++) {
> +		char *fn = di[i]->d_name;
> +		struct udev_device *udev;
> +
> +		if (snprintf(pathbuf, sizeof(pathbuf), "%s/slaves/%s",
> +			     udev_device_get_syspath(map->udev), fn)
> +		    >= sizeof(pathbuf))
> +			continue;
> +
> +		path = _find_path_by_syspath(map, pathbuf);
> +		if (path != NULL) {
> +			path->seen = true;
> +			condlog(4, "%s: %s already known",
> +				__func__, fn);
> +			continue;
> +		}
> +
> +		udev = udev_device_new_from_syspath(ctx->udev, pathbuf);
> +		if (udev == NULL) {
> +			condlog(1, "%s: %s: failed to get udev device for %s",
> +				__func__, THIS, fn);
> +			continue;
> +		}
> +
> +		path = calloc(1, sizeof(*path));
> +		if (path == NULL)
> +			continue;
> +
> +		path->gen.ops = &nvme_path_ops;
> +		path->udev = udev;
> +		path->seen = true;
> +		path->map = map;
> +		path->ctl = udev_device_get_parent_with_subsystem_devtype
> +			(udev, "nvme", NULL);
> +		if (path->ctl == NULL) {
> +			condlog(1, "%s: %s: failed to get controller for %s",
> +				__func__, THIS, fn);
> +			cleanup_nvme_path(path);
> +			continue;
> +		}
> +
> +		if (vector_alloc_slot(map->pathvec) == NULL) {
> +			cleanup_nvme_path(path);
> +			continue;
> +		}
> +		condlog(3, "%s: %s: new path %s added to %s",
> +			__func__, THIS, udev_device_get_sysname(udev),
> +			udev_device_get_sysname(map->udev));
> +		vector_set_slot(map->pathvec, path);
> +	}
> +	pthread_cleanup_pop(1);
> +
> +	map->nr_live = 0;
> +	vector_foreach_slot_backwards(map->pathvec, path, i) {
> +		if (!path->seen) {
> +			condlog(1, "path %d not found in %s any more",
> +				i, udev_device_get_sysname(map->udev));
> +			vector_del_slot(map->pathvec, i);
> +			cleanup_nvme_path(path);
> +		} else {
> +			static const char live_state[] = "live";
> +			char state[16];
> +
> +			if ((sysfs_attr_get_value(path->ctl, "state", state,
> +						  sizeof(state)) > 0) &&
> +			    !strncmp(state, live_state, sizeof(live_state) - 1))
> +				map->nr_live++;
> +		}
> +	}
> +	condlog(3, "%s: %s: map %s has %d/%d live paths", __func__, THIS,
> +		udev_device_get_sysname(map->udev), map->nr_live,
> +		VECTOR_SIZE(map->pathvec));
> +}
> +
>  static int _add_map(struct context *ctx, struct udev_device *ud,
>  		    struct udev_device *subsys)
>  {
> @@ -307,12 +575,25 @@ static int _add_map(struct context *ctx, struct udev_device *ud,
>  	map->subsys = subsys;
>  	map->gen.ops = &nvme_map_ops;
>  
> -	if (vector_alloc_slot(ctx->mpvec) == NULL) {
> +	map->pathvec = vector_alloc();
> +	if (map->pathvec == NULL) {
>  		cleanup_nvme_map(map);
>  		return FOREIGN_ERR;
>  	}
>  
> +	map->pg.gen.ops = &nvme_pg_ops;
> +	map->pg.pathvec = map->pathvec;
> +	map->gpg = nvme_pg_to_gen(&map->pg);
> +
> +	map->pgvec.allocated = 1;
> +	map->pgvec.slot = (void**)&map->gpg;
> +
> +	if (vector_alloc_slot(ctx->mpvec) == NULL) {
> +		cleanup_nvme_map(map);
> +		return FOREIGN_ERR;
> +	}
>  	vector_set_slot(ctx->mpvec, map);
> +	_find_slaves(ctx, map);
>  
>  	return FOREIGN_CLAIMED;
>  }
> @@ -401,9 +682,25 @@ int delete(struct context *ctx, struct udev_device *ud)
>  	return rc;
>  }
>  
> +void _check(struct context *ctx)
> +{
> +	struct gen_multipath *gm;
> +	int i;
> +
> +	vector_foreach_slot(ctx->mpvec, gm, i) {
> +		struct nvme_map *map = gen_mp_to_nvme(gm);
> +
> +		_find_slaves(ctx, map);
> +	}
> +}
> +
>  void check(struct context *ctx)
>  {
> -	condlog(5, "%s called for \"%s\"", __func__, THIS);
> +	condlog(4, "%s called for \"%s\"", __func__, THIS);
> +	lock(ctx);
> +	pthread_cleanup_push(unlock, ctx);
> +	_check(ctx);
> +	pthread_cleanup_pop(1);
>  	return;
>  }
>  
> @@ -427,14 +724,23 @@ void release_multipaths(const struct context *ctx, const struct _vector *mpvec)
>   */
>  const struct _vector * get_paths(const struct context *ctx)
>  {
> +	vector paths = NULL;
> +	const struct gen_multipath *gm;
> +	int i;
> +
>  	condlog(5, "%s called for \"%s\"", __func__, THIS);
> -	return NULL;
> +	vector_foreach_slot(ctx->mpvec, gm, i) {
> +		const struct nvme_map *nm = const_gen_mp_to_nvme(gm);
> +		paths = vector_convert(paths, nm->pathvec,
> +				       struct gen_path, identity);
> +	}
> +	return paths;
>  }
>  
>  void release_paths(const struct context *ctx, const struct _vector *mpvec)
>  {
>  	condlog(5, "%s called for \"%s\"", __func__, THIS);
> -	/* NOP */
> +	vector_free_const(mpvec);
>  }
>  
>  /* compile-time check whether all methods are present and correctly typed */
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 22/23] multipathd: update path group prio in check_path
  2018-03-05 23:15 ` [PATCH v2 22/23] multipathd: update path group prio in check_path Martin Wilck
  2018-03-06  7:16   ` Hannes Reinecke
@ 2018-03-07 20:01   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 20:01 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:06AM +0100, Martin Wilck wrote:
> The previous patch "libmultipath: don't update path groups when printing"
> removed the call to path_group_prio_update() in the printing code path.
> To compensate for that, recalculate path group prio also when it's not
> strictly necessary (i.e. if failback "manual" is set).
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/main.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 465a1e291226..4abdd8f071c3 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -252,8 +252,9 @@ need_switch_pathgroup (struct multipath * mpp, int refresh)
>  	struct path * pp;
>  	unsigned int i, j;
>  	struct config *conf;
> +	int bestpg;
>  
> -	if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
> +	if (!mpp)
>  		return 0;
>  
>  	/*
> @@ -272,8 +273,11 @@ need_switch_pathgroup (struct multipath * mpp, int refresh)
>  	if (!mpp->pg || VECTOR_SIZE(mpp->paths) == 0)
>  		return 0;
>  
> -	mpp->bestpg = select_path_group(mpp);
> +	bestpg = select_path_group(mpp);
> +	if (mpp->pgfailback == -FAILBACK_MANUAL)
> +		return 0;
>  
> +	mpp->bestpg = bestpg;
>  	if (mpp->bestpg != mpp->nextpg)
>  		return 1;
>  
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 23/23] multipathd: fix signal blocking logic
  2018-03-05 23:15 ` [PATCH v2 23/23] multipathd: fix signal blocking logic Martin Wilck
  2018-03-06  7:16   ` Hannes Reinecke
@ 2018-03-07 20:24   ` Benjamin Marzinski
  1 sibling, 0 replies; 59+ messages in thread
From: Benjamin Marzinski @ 2018-03-07 20:24 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 06, 2018 at 12:15:07AM +0100, Martin Wilck wrote:
> multipathd is supposed to block all signals in all threads, except
> the uxlsnr thread which handles termination and reconfiguration
> signals (SIGUSR1) in its ppoll() call, SIGUSR2 in the waiter thread
> and the marginal path checker thread, and occasional SIGALRM. The current
> logic does exactly the oppsite, it blocks termination signals in SIGPOLL and
> allows multipathd to be killed e.g. by SIGALRM.
> 
> Fix that by inverting the logic. The argument to pthread_sigmask and
> ppoll is the set of *blocked* signals, not vice versa.
> 
> The marginal paths code needs to unblock SIGUSR2 now explicity, as
> the dm-event waiter code already does. Doing this with pselect()
> avoids asynchronous cancellation.
> 
> Fixes: 810082e "libmultipath, multipathd: Rework SIGPIPE handling"
> Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and SIGUSR1
> are delivered to the uxsock thread"
> 

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/io_err_stat.c | 17 ++++++++++++++++-
>  multipathd/main.c          |  7 +++++--
>  multipathd/uxlsnr.c        | 10 +++++-----
>  3 files changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c
> index 5b10f0372f9f..00bac9e0e755 100644
> --- a/libmultipath/io_err_stat.c
> +++ b/libmultipath/io_err_stat.c
> @@ -21,6 +21,7 @@
>  #include <libaio.h>
>  #include <errno.h>
>  #include <sys/mman.h>
> +#include <sys/select.h>
>  
>  #include "vector.h"
>  #include "memory.h"
> @@ -691,14 +692,28 @@ static void service_paths(void)
>  
>  static void *io_err_stat_loop(void *data)
>  {
> +	sigset_t set;
> +
>  	vecs = (struct vectors *)data;
>  	pthread_cleanup_push(rcu_unregister, NULL);
>  	rcu_register_thread();
>  
> +	sigfillset(&set);
> +	sigdelset(&set, SIGUSR2);
> +
>  	mlockall(MCL_CURRENT | MCL_FUTURE);
>  	while (1) {
> +		struct timespec ts;
> +
>  		service_paths();
> -		usleep(100000);
> +
> +		ts.tv_sec = 0;
> +		ts.tv_nsec = 100 * 1000 * 1000;
> +		/*
> +		 * pselect() with no fds, a timeout, and a sigmask:
> +		 * sleep for 100ms and react on SIGUSR2.
> +		 */
> +		pselect(1, NULL, NULL, NULL, &ts, &set);
>  	}
>  
>  	pthread_cleanup_pop(1);
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 4abdd8f071c3..68595836d723 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -2261,10 +2261,13 @@ signal_init(void)
>  {
>  	sigset_t set;
>  
> -	sigemptyset(&set);
> -	sigaddset(&set, SIGUSR2);
> +	/* block all signals */
> +	sigfillset(&set);
> +	/* SIGPIPE occurs if logging fails */
> +	sigdelset(&set, SIGPIPE);
>  	pthread_sigmask(SIG_SETMASK, &set, NULL);
>  
> +	/* Other signals will be unblocked in the uxlsnr thread */
>  	signal_set(SIGHUP, sighup);
>  	signal_set(SIGUSR1, sigusr1);
>  	signal_set(SIGUSR2, sigusr2);
> diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c
> index 98ac25a68c43..a2ca36ba1653 100644
> --- a/multipathd/uxlsnr.c
> +++ b/multipathd/uxlsnr.c
> @@ -170,11 +170,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
>  		condlog(0, "uxsock: failed to allocate poll fds");
>  		return NULL;
>  	}
> -	sigemptyset(&mask);
> -	sigaddset(&mask, SIGINT);
> -	sigaddset(&mask, SIGTERM);
> -	sigaddset(&mask, SIGHUP);
> -	sigaddset(&mask, SIGUSR1);
> +	sigfillset(&mask);
> +	sigdelset(&mask, SIGINT);
> +	sigdelset(&mask, SIGTERM);
> +	sigdelset(&mask, SIGHUP);
> +	sigdelset(&mask, SIGUSR1);
>  	while (1) {
>  		struct client *c, *tmp;
>  		int i, poll_count, num_clients;
> -- 
> 2.16.1

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods
  2018-03-05 23:14 ` [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
  2018-03-06  7:05   ` Hannes Reinecke
@ 2018-03-15 14:25   ` Bart Van Assche
  1 sibling, 0 replies; 59+ messages in thread
From: Bart Van Assche @ 2018-03-15 14:25 UTC (permalink / raw)
  To: mwilck, christophe.varoqui; +Cc: dm-devel

On Tue, 2018-03-06 at 00:14 +0100, Martin Wilck wrote:
> Convert the snprint methods for all keywords to call-by-value,
> and use "const" qualifier for the "data" argument. This makes sure
> that "snprint" type functions don't modify the data they're print,
> helps compile-time correctness checking, and allows more proper
> "const" cleanups in the future.

Hello Martin,

With this patch applied on top of Christophe's master branch:

diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index ea273dd91962..ac9216c4c5f3 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include "mpath_cmd.h"
+#include "dict.h"
 
 static int
 set_int(vector strvec, void *ptr)


I see a whole bunch of warnings appear (see below). Can you have a look at
this?

Thanks,

Bart.


dict.c:627:1: error: conflicting types for 'print_fast_io_fail'
 print_fast_io_fail(char * buff, int len, long v)
 ^~~~~~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:16:5: note: previous declaration of 'print_fast_io_fail' was here
 int print_fast_io_fail(char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~~~~~
dict.c:666:1: error: conflicting types for 'print_dev_loss'
 print_dev_loss(char * buff, int len, unsigned long v)
 ^~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:17:5: note: previous declaration of 'print_dev_loss' was here
 int print_dev_loss(char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~
dict.c:697:1: error: conflicting types for 'print_pgpolicy'
 print_pgpolicy(char * buff, int len, long pgpolicy)
 ^~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:14:5: note: previous declaration of 'print_pgpolicy' was here
 int print_pgpolicy(char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~
dict.c:814:1: error: conflicting types for 'print_rr_weight'
 print_rr_weight (char * buff, int len, long v)
 ^~~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:12:5: note: previous declaration of 'print_rr_weight' was here
 int print_rr_weight (char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~~
dict.c:860:1: error: conflicting types for 'print_pgfailback'
 print_pgfailback (char * buff, int len, long v)
 ^~~~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:13:5: note: previous declaration of 'print_pgfailback' was here
 int print_pgfailback (char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~~~
dict.c:907:1: error: conflicting types for 'print_no_path_retry'
 print_no_path_retry(char * buff, int len, long v)
 ^~~~~~~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:15:5: note: previous declaration of 'print_no_path_retry' was here
 int print_no_path_retry(char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~~~~~~
dict.c:1049:1: error: conflicting types for 'print_off_int_undef'
 print_off_int_undef(char * buff, int len, long v)
 ^~~~~~~~~~~~~~~~~~~
In file included from dict.c:26:0:
dict.h:19:5: note: previous declaration of 'print_off_int_undef' was here
 int print_off_int_undef(char * buff, int len, void *ptr);
     ^~~~~~~~~~~~~~~~~~~
make[1]: *** [../Makefile.inc:131: dict.o] Error 1
make: *** [Makefile:25: recurse] Error 2
install: cannot remove '/lib64/libmpathcmd.so.0': Permission denied
make[1]: *** [Makefile:19: install] Error 1
make: *** [Makefile:34: recurse_install] Error 2

Compilation exited abnormally with code 2 at Thu Mar 15 07:23:12

^ permalink raw reply related	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2018-03-15 14:25 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-05 23:14 [PATCH v2 00/23] "Foreign" NVMe support for multipath-tools Martin Wilck
2018-03-05 23:14 ` [PATCH v2 01/23] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
2018-03-06  7:04   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 02/23] libmultipath: remove unused "stdout helpers" Martin Wilck
2018-03-06  7:04   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 03/23] libmultipath: get rid of selector "hack" in print.c Martin Wilck
2018-03-06  7:05   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 04/23] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
2018-03-06  7:05   ` Hannes Reinecke
2018-03-15 14:25   ` Bart Van Assche
2018-03-05 23:14 ` [PATCH v2 05/23] libmultipath: don't update path groups when printing Martin Wilck
2018-03-06  7:06   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 06/23] libmultipath/print: use "const" where appropriate Martin Wilck
2018-03-06  7:07   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 07/23] libmultipath: use "const" in devmapper code Martin Wilck
2018-03-06  7:07   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 09/23] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
2018-03-06  7:08   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 10/23] libmultipath: add vector_free_const() Martin Wilck
2018-03-06  1:01   ` Bart Van Assche
2018-03-06  7:08   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 11/23] libmultipath: add vector_convert() Martin Wilck
2018-03-06  7:10   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 12/23] libmultipath: "generic multipath" interface Martin Wilck
2018-03-06  7:10   ` Hannes Reinecke
2018-03-07 19:01   ` Benjamin Marzinski
2018-03-05 23:14 ` [PATCH v2 13/23] libmultipath: print: convert API to generic data type Martin Wilck
2018-03-06  7:11   ` Hannes Reinecke
2018-03-07 19:02   ` Benjamin Marzinski
2018-03-05 23:14 ` [PATCH v2 14/23] libmultipath: print: use generic API for get_x_layout() Martin Wilck
2018-03-06  7:12   ` Hannes Reinecke
2018-03-05 23:14 ` [PATCH v2 15/23] libmultipath: API for foreign multipath handling Martin Wilck
2018-03-06  7:12   ` Hannes Reinecke
2018-03-07 19:08   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 16/23] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
2018-03-06  7:13   ` Hannes Reinecke
2018-03-05 23:15 ` [PATCH v2 17/23] libmultipath/foreign: nvme foreign library Martin Wilck
2018-03-06  7:13   ` Hannes Reinecke
2018-03-07 19:09   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 18/23] libmultipath: pathinfo: call into " Martin Wilck
2018-03-06  7:14   ` Hannes Reinecke
2018-03-07 19:10   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 19/23] multipath: use foreign API Martin Wilck
2018-03-06  7:14   ` Hannes Reinecke
2018-03-07 19:11   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 20/23] multipathd: " Martin Wilck
2018-03-06  7:15   ` Hannes Reinecke
2018-03-07 19:25   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 21/23] libmultipath: foreign/nvme: implement path display Martin Wilck
2018-03-06  7:15   ` Hannes Reinecke
2018-03-07 19:27   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 22/23] multipathd: update path group prio in check_path Martin Wilck
2018-03-06  7:16   ` Hannes Reinecke
2018-03-07 20:01   ` Benjamin Marzinski
2018-03-05 23:15 ` [PATCH v2 23/23] multipathd: fix signal blocking logic Martin Wilck
2018-03-06  7:16   ` Hannes Reinecke
2018-03-06  8:55     ` Martin Wilck
2018-03-07 20:24   ` Benjamin Marzinski
     [not found] ` <20180305231507.10386-9-mwilck@suse.com>
2018-03-06  7:08   ` [PATCH v2 08/23] libmultipath: fix compiler warnings for -Wcast-qual Hannes Reinecke

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.