All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools
@ 2018-02-20 13:26 Martin Wilck
  2018-02-20 13:26 ` [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
                   ` (19 more replies)
  0 siblings, 20 replies; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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/20-09/20) 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/20 and
11/20 are two minor helpers for the patches that follow.

Patch 12/20 and 15/20 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/20. 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/20 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/20 and 20/20 provide the implementation of NVMe native multipath
support using these APIs. Patch 18/20 and 19/20 contain the necessary changes
to multipath and multipathd to call into the new APIs.

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.

Best Regards,
Martin

Martin Wilck (20):
  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
  multipath: use foreign API
  multipathd: use foreign API
  libmultipath: foreign/nvme: implement path display

 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        | 471 ++++++++++++++++++++++++++
 libmultipath/foreign.h        | 322 ++++++++++++++++++
 libmultipath/foreign/Makefile |  30 ++
 libmultipath/foreign/nvme.c   | 756 ++++++++++++++++++++++++++++++++++++++++++
 libmultipath/generic.c        |  41 +++
 libmultipath/generic.h        | 136 ++++++++
 libmultipath/list.h           |   6 +-
 libmultipath/memory.h         |   8 +-
 libmultipath/parser.c         |   9 +-
 libmultipath/parser.h         |  12 +-
 libmultipath/pgpolicies.c     |  11 +-
 libmultipath/print.c          | 397 +++++++++++++---------
 libmultipath/print.h          |  81 +++--
 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             |  53 ++-
 39 files changed, 2500 insertions(+), 371 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] 63+ messages in thread

* [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:35   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers" Martin Wilck
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers"
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
  2018-02-20 13:26 ` [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:36   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c Martin Wilck
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +Cc: dm-devel, Martin Wilck

Signed-off-by: Martin Wilck <mwilck@suse.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] 63+ messages in thread

* [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
  2018-02-20 13:26 ` [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
  2018-02-20 13:26 ` [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers" Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:36   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (2 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:37   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 05/20] libmultipath: don't update path groups when printing Martin Wilck
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 05/20] libmultipath: don't update path groups when printing
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (3 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-02-28 23:40   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate Martin Wilck
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (4 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 05/20] libmultipath: don't update path groups when printing Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:37   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 07/20] libmultipath: use "const" in devmapper code Martin Wilck
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 07/20] libmultipath: use "const" in devmapper code
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (5 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:39   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual Martin Wilck
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +Cc: dm-devel, Martin Wilck

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

Signed-off-by: Martin Wilck <mwilck@suse.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] 63+ messages in thread

* [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (6 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 07/20] libmultipath: use "const" in devmapper code Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:39   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +Cc: dm-devel, Martin Wilck

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>
---
 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(-)

diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
index 4469fa848de8..eb9dac639175 100644
--- a/kpartx/devmapper.c
+++ b/kpartx/devmapper.c
@@ -11,6 +11,7 @@
 #include <sys/sysmacros.h>
 #include "devmapper.h"
 
+#define FREE_CONST(p) do { free((void*)(long)p); p = NULL; } while(0)
 #define _UUID_PREFIX "part"
 #define UUID_PREFIX _UUID_PREFIX "%d-"
 #define _UUID_PREFIX_LEN (sizeof(_UUID_PREFIX) - 1)
@@ -695,7 +696,7 @@ int dm_find_part(const char *parent, const char *delim, int part,
 	} else
 		*part_uuid = uuid;
 out:
-	free((void*)tmp);
+	FREE_CONST(tmp);
 	return r;
 }
 
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
index af618cff917c..29d148ce8aff 100644
--- a/libmpathcmd/mpath_cmd.c
+++ b/libmpathcmd/mpath_cmd.c
@@ -64,7 +64,7 @@ static size_t write_all(int fd, const void *buf, size_t len)
 		}
 		if (!n)
 			return total;
-		buf = n + (char *)buf;
+		buf = n + (const char *)buf;
 		len -= n;
 		total += n;
 	}
diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c
index 2c1800976e40..b1d99b4c81f6 100644
--- a/libmultipath/checkers/rbd.c
+++ b/libmultipath/checkers/rbd.c
@@ -288,7 +288,7 @@ void libcheck_free(struct checker * c)
 static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg)
 {
 	char *addr_tok, *start, *save;
-	char *cmd[2];
+	const char *cmd[2];
 	char *blklist, *stat;
 	size_t blklist_len, stat_len;
 	int ret;
@@ -436,7 +436,7 @@ static int sysfs_write_rbd_remove(const char *buf, int buf_len)
 
 static int rbd_rm_blacklist(struct rbd_checker_context *ct)
 {
-	char *cmd[2];
+	const char *cmd[2];
 	char *stat, *cmd_str;
 	size_t stat_len;
 	int ret;
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index f61838cbe369..607aea8dc1fc 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <time.h>
 
+#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
 #define MAX_WAIT 5
 #define LOOPS_PER_SEC 5
 
@@ -1426,7 +1427,7 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
 	n += strlen(newdep);
 	p += strlen(dep);
 	strcat(n, p);
-	free(newtable);
+	FREE_CONST(newtable);
 }
 
 int dm_reassign_table(const char *name, char *old, char *new)
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 98bddee52c8f..645224c1029c 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -121,7 +121,7 @@ path_discover (vector pathvec, struct config * conf,
 	if (!devname)
 		return PATHINFO_FAILED;
 
-	pp = find_path_by_dev(pathvec, (char *)devname);
+	pp = find_path_by_dev(pathvec, devname);
 	if (!pp) {
 		char devt[BLK_DEV_SIZE];
 		dev_t devnum = udev_device_get_devnum(udevice);
@@ -905,12 +905,12 @@ static int
 parse_vpd_pg83(const unsigned char *in, size_t in_len,
 	       char *out, size_t out_len)
 {
-	unsigned char *d;
-	unsigned char *vpd = NULL;
+	const unsigned char *d;
+	const unsigned char *vpd = NULL;
 	int len = -ENODATA, vpd_type, vpd_len, prio = -1, i, naa_prio;
 
-	d = (unsigned char *)in + 4;
-	while (d < (unsigned char *)in + in_len) {
+	d = in + 4;
+	while (d < in + in_len) {
 		/* Select 'association: LUN' */
 		if ((d[1] & 0x30) != 0) {
 			d += d[3] + 4;
@@ -1027,7 +1027,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
 				out[len] = '\0';
 			}
 		} else if (vpd_type == 0x1) {
-			unsigned char *p;
+			const unsigned char *p;
 			int p_len;
 
 			out[0] = '1';
diff --git a/libmultipath/list.h b/libmultipath/list.h
index 2b1dcf396695..c9110ac9de7e 100644
--- a/libmultipath/list.h
+++ b/libmultipath/list.h
@@ -18,8 +18,8 @@
  * @member:	the name of the member within the struct.
  *
  */
-#define container_of(ptr, type, member) ({			\
-	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+#define container_of(ptr, type, member) ({		\
+	typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})
 
 /*
diff --git a/libmultipath/memory.h b/libmultipath/memory.h
index 927619b58a62..63f59d80584c 100644
--- a/libmultipath/memory.h
+++ b/libmultipath/memory.h
@@ -43,6 +43,7 @@ int debug;
 		      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
 #define STRDUP(n)    ( dbg_strdup((n), \
 		      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+#define FREE_CONST(p) do { FREE((void*)(unsigned long)p); } while(0)
 
 /* Memory debug prototypes defs */
 extern void *dbg_malloc(unsigned long, char *, char *, int);
@@ -54,7 +55,12 @@ extern void dbg_free_final(char *);
 #else
 
 #define MALLOC(n)    (calloc(1,(n)))
-#define FREE(p)      do { free((void*)p); p = NULL; } while(0)
+#define FREE(p)      do { free(p); p = NULL; } while(0)
+/*
+ * Double cast to avoid warnings with -Wcast-qual
+ * use this for valid free() operations on const pointers
+ */
+#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
 #define REALLOC(p,n) (realloc((p),(n)))
 #define STRDUP(n)    (strdup(n))
 
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 1ade1a6705ad..4db08451824d 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -418,7 +418,7 @@ find_mp_by_str (vector mpvec, char * str)
 }
 
 struct path *
-find_path_by_dev (vector pathvec, char * dev)
+find_path_by_dev (vector pathvec, const char * dev)
 {
 	int i;
 	struct path * pp;
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 71b37cc20674..bccc845a1222 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -387,7 +387,7 @@ struct multipath * find_mp_by_str (vector mp, char * wwid);
 struct multipath * find_mp_by_minor (vector mp, int minor);
 
 struct path * find_path_by_devt (vector pathvec, const char * devt);
-struct path * find_path_by_dev (vector pathvec, char * dev);
+struct path * find_path_by_dev (vector pathvec, const char * dev);
 struct path * first_path (struct multipath * mpp);
 
 int pathcountgr (struct pathgroup *, int);
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 8f4129ca7fd0..685ef3362c6d 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -157,7 +157,7 @@ static int uevent_get_env_positive_int(const struct uevent *uev,
 void
 uevent_get_wwid(struct uevent *uev)
 {
-	char *uid_attribute;
+	const char *uid_attribute;
 	const char *val;
 	struct config * conf;
 
@@ -167,8 +167,8 @@ uevent_get_wwid(struct uevent *uev)
 
 	val = uevent_get_env_var(uev, uid_attribute);
 	if (val)
-		uev->wwid = (char*)val;
-	free(uid_attribute);
+		uev->wwid = val;
+	FREE_CONST(uid_attribute);
 }
 
 bool
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 0b43d29d1236..d3dd3eb524d0 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -32,7 +32,7 @@ strchop(char *str)
 int
 basenamecpy (const char * str1, char * str2, int str2len)
 {
-	char *p;
+	const char *p;
 
 	if (!str1 || !strlen(str1))
 		return 0;
@@ -43,7 +43,7 @@ basenamecpy (const char * str1, char * str2, int str2len)
 	if (!str2)
 		return 0;
 
-	p = (char *)str1 + (strlen(str1) - 1);
+	p = str1 + (strlen(str1) - 1);
 
 	while (*--p != '/' && p != str1)
 		continue;
@@ -454,7 +454,7 @@ int safe_write(int fd, const void *buf, size_t count)
 			return -errno;
 		}
 		count -= r;
-		buf = (char *)buf + r;
+		buf = (const char *)buf + r;
 	}
 	return 0;
 }
diff --git a/multipathd/main.c b/multipathd/main.c
index a8a0c302e8fe..b900bb3ec2e3 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -408,7 +408,7 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
 	pthread_testcancel();
 	rc = ev_add_map(uev->kernel, alias, vecs);
 	lock_cleanup_pop(vecs->lock);
-	FREE(alias);
+	FREE_CONST(alias);
 	return rc;
 }
 
@@ -532,7 +532,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
 	remove_map_and_stop_waiter(mpp, vecs, 1);
 out:
 	lock_cleanup_pop(vecs->lock);
-	FREE(alias);
+	FREE_CONST(alias);
 	return 0;
 }
 
@@ -1028,11 +1028,11 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
 				pp->dev);
 out_lock:
 	lock_cleanup_pop(vecs->lock);
-	FREE(devt);
-	FREE(action);
+	FREE_CONST(devt);
+	FREE_CONST(action);
 	return r;
 out:
-	FREE(action);
+	FREE_CONST(action);
 	return 1;
 }
 
-- 
2.16.1

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

* [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (7 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:59   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 10/20] libmultipath: add vector_free_const() Martin Wilck
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 10/20] libmultipath: add vector_free_const()
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (8 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  6:00   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 11/20] libmultipath: add vector_convert() Martin Wilck
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +Cc: dm-devel, Martin Wilck

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

Signed-off-by: Martin Wilck <mwilck@suse.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] 63+ messages in thread

* [RFC PATCH 11/20] libmultipath: add vector_convert()
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (9 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 10/20] libmultipath: add vector_free_const() Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  6:02   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 12/20] libmultipath: "generic multipath" interface Martin Wilck
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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] 63+ messages in thread

* [RFC PATCH 12/20] libmultipath: "generic multipath" interface
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (10 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 11/20] libmultipath: add vector_convert() Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-02-28 23:47   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 13/20] libmultipath: print: convert API to generic data type Martin Wilck
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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      |  34 ++++++++++++
 libmultipath/print.h      |   7 +++
 libmultipath/structs.c    |   4 ++
 libmultipath/structs.h    |   4 ++
 10 files changed, 340 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..61cbffb708b6
--- /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');
+
+	if (strcmp(alias_buf, wwid_buf))
+		n = snprintf(buf, len, " (%%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..e6f56381791f 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -29,6 +29,7 @@
 #include "uevent.h"
 #include "debug.h"
 #include "discovery.h"
+#include "dm-generic.h"
 
 #define MAX(x,y) (x > y) ? x : y
 #define TAIL     (line + len - 1 - c)
@@ -756,6 +757,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 +780,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 +803,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..c624d2bfe8d4 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -122,3 +122,10 @@ 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);
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] 63+ messages in thread

* [RFC PATCH 13/20] libmultipath: print: convert API to generic data type
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (11 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 12/20] libmultipath: "generic multipath" interface Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-02-28 23:55   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout() Martin Wilck
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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      | 116 +++++++++++++++++++++++++++++-----------------
 libmultipath/print.h      |  28 ++++++++---
 multipath/main.c          |   1 +
 multipathd/cli_handlers.c |   1 +
 6 files changed, 100 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 e6f56381791f..8846765066ef 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -31,7 +31,8 @@
 #include "discovery.h"
 #include "dm-generic.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) \
@@ -846,8 +847,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 */
@@ -870,7 +871,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);
@@ -913,8 +914,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 */
@@ -937,7 +938,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);
@@ -948,8 +949,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 */
@@ -972,7 +973,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++);
@@ -980,8 +981,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;
@@ -998,7 +1001,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) {
@@ -1011,12 +1014,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];
@@ -1028,60 +1049,71 @@ 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);
+	c += snprintf(c, sizeof(style) - (c - style), " %%d %%s");
 	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 c624d2bfe8d4..e71f87722315 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -1,3 +1,6 @@
+#ifndef _PRINT_H
+#define _PRINT_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"
@@ -94,11 +97,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,
@@ -119,7 +128,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);
 
@@ -129,3 +142,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] 63+ messages in thread

* [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout()
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (12 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 13/20] libmultipath: print: convert API to generic data type Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  6:03   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 15/20] libmultipath: API for foreign multipath handling Martin Wilck
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 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 8846765066ef..9a5a6a2f4ad6 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -698,20 +698,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));
 		}
 	}
@@ -727,22 +755,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 e71f87722315..1ba364ac19ac 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -93,7 +93,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] 63+ messages in thread

* [RFC PATCH 15/20] libmultipath: API for foreign multipath handling
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (13 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout() Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  3:01   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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 | 471 +++++++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/foreign.h | 322 +++++++++++++++++++++++++++++++++
 3 files changed, 794 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..f429e2759df3
--- /dev/null
+++ b/libmultipath/foreign.c
@@ -0,0 +1,471 @@
+/*
+  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 <glob.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;
+
+#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)
+{
+	if (fgn == NULL || *fgn == NULL)
+		return;
+	if ((*fgn)->context != NULL)
+		(*fgn)->cleanup((*fgn)->context);
+	if ((*fgn)->handle != NULL)
+		dlclose((*fgn)->handle);
+	free(*fgn);
+}
+
+void cleanup_foreign(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	vector_foreach_slot(foreigns, fgn, i)
+		free_foreign(&fgn);
+	vector_free(foreigns);
+	foreigns = NULL;
+}
+
+int init_foreign(const char *multipath_dir)
+{
+	char pathbuf[PATH_MAX];
+	static const char base[] = "libforeign-";
+	static const char suffix[] = ".so";
+	glob_t globbuf;
+	int ret = -EINVAL, r, i;
+
+	if (foreigns != NULL) {
+		condlog(0, "%s: already initialized", __func__);
+		return -EEXIST;
+	}
+	foreigns = vector_alloc();
+
+	if (snprintf(pathbuf, sizeof(pathbuf), "%s/%s*%s",
+		     multipath_dir, base, suffix) >= sizeof(pathbuf)) {
+		condlog(1, "%s: path length overflow", __func__);
+		goto err;
+	}
+
+	condlog(4, "%s: looking for %s\n", __func__, pathbuf);
+	memset(&globbuf, 0, sizeof(globbuf));
+	r = glob(pathbuf, 0, NULL, &globbuf);
+
+	if (r == GLOB_NOMATCH) {
+		condlog(3, "%s: no foreign multipath libraries found",
+			__func__);
+		globfree(&globbuf);
+		return 0;
+	} else if (r != 0) {
+		char *msg;
+
+		if (errno != 0) {
+			ret = -errno;
+			msg = strerror(errno);
+		} else {
+			ret = -1;
+			msg = (r == GLOB_ABORTED ? "read error" :
+			       "out of memory");
+		}
+		condlog(0, "%s: search for foreign libraries failed: %d (%s)",
+			__func__, r, msg);
+		globfree(&globbuf);
+		goto err;
+	}
+
+	for (i = 0; i < globbuf.gl_pathc; i++) {
+		char *msg, *fn;
+		struct foreign *fgn;
+		int len, namesz;
+
+		fn = strrchr(globbuf.gl_pathv[i], '/');
+		if (fn == NULL)
+			fn = globbuf.gl_pathv[i];
+		else
+			fn++;
+
+		len = strlen(fn);
+		if (len <= sizeof(base) + sizeof(suffix) - 2) {
+			condlog(0, "%s: internal error: filename too short: %s",
+				__func__, globbuf.gl_pathv[i]);
+			continue;
+		}
+
+		condlog(4, "%s: found %s", __func__, fn);
+
+		namesz = len + 3 - sizeof(base) - sizeof(suffix);
+		fgn = malloc(sizeof(*fgn) + namesz);
+		if (fgn == NULL)
+			continue;
+		memset(fgn, 0, sizeof(*fgn));
+
+		strlcpy((char*)fgn + sizeof(*fgn), fn + sizeof(base) - 1,
+			namesz);
+		fgn->name = (const char*)fgn + sizeof(*fgn);
+
+		fgn->handle = dlopen(globbuf.gl_pathv[i], RTLD_NOW|RTLD_LOCAL);
+		msg = dlerror();
+		if (fgn->handle == NULL) {
+			condlog(1, "%s: failed to open %s: %s", __func__,
+				fn, msg);
+			free_foreign(&fgn);
+			continue;
+		}
+
+		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);
+			free_foreign(&fgn);
+			continue;
+		}
+
+		if (vector_alloc_slot(foreigns) == NULL) {
+			free_foreign(&fgn);
+			continue;
+		}
+		vector_set_slot(foreigns, fgn);
+		condlog(3, "foreign library \"%s\" loaded successfully", fgn->name);
+
+		continue;
+
+	dl_err:
+		free_foreign(&fgn);
+	}
+	globfree(&globbuf);
+
+	return 0;
+err:
+	cleanup_foreign();
+	return ret;
+}
+
+int add_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	dev_t dt;
+	int j;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		int 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));
+			return r;
+		} else if (r == FOREIGN_OK) {
+			condlog(4, "%s: foreign \"%s\" owns device %d:%d",
+				__func__, fgn->name, major(dt), minor(dt));
+			return r;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+	return FOREIGN_IGNORED;
+}
+
+int change_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	int j;
+	dev_t dt;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		int 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));
+			return r;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+	return FOREIGN_IGNORED;
+}
+
+int delete_foreign(struct udev_device *udev)
+{
+	struct foreign *fgn;
+	int j;
+	dev_t dt;
+
+	if (udev == NULL) {
+		condlog(1, "%s called with NULL udev", __func__);
+		return FOREIGN_ERR;
+	}
+	dt = udev_device_get_devnum(udev);
+	vector_foreach_slot(foreigns, fgn, j) {
+		int 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));
+			return r;
+		} else if (r != FOREIGN_IGNORED) {
+			condlog(1, "%s: unexpected return value %d from \"%s\"",
+				__func__, r, fgn->name);
+		}
+	}
+	return FOREIGN_IGNORED;
+}
+
+int delete_all_foreign(void)
+{
+	struct foreign *fgn;
+	int j;
+
+	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);
+		}
+	}
+	return FOREIGN_OK;
+}
+
+void check_foreign(void)
+{
+	struct foreign *fgn;
+	int j;
+
+	vector_foreach_slot(foreigns, fgn, j) {
+		fgn->check(fgn->context);
+	}
+}
+
+/* Call this after get_path_layout */
+void foreign_path_layout(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	vector_foreach_slot(foreigns, fgn, i) {
+		const struct _vector *vec;
+
+		fgn->lock(fgn->context);
+		vec = fgn->get_paths(fgn->context);
+		if (vec != NULL) {
+			_get_path_layout(vec, LAYOUT_RESET_NOT);
+		}
+		fgn->release_paths(fgn->context, vec);
+		fgn->unlock(fgn->context);
+	}
+}
+
+/* Call this after get_multipath_layout */
+void foreign_multipath_layout(void)
+{
+	struct foreign *fgn;
+	int i;
+
+	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);
+	}
+}
+
+int snprint_foreign_topology(char *buf, int len, int verbosity)
+{
+	struct foreign *fgn;
+	int i;
+	char *c = buf;
+
+	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);
+	}
+
+	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;
+
+	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);
+	}
+
+	return c - buf;
+}
+
+int snprint_foreign_multipaths(char *buf, int len,
+			       const char *style, int pretty)
+{
+	struct foreign *fgn;
+	int i;
+	char *c = buf;
+
+	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);
+	}
+
+	return c - buf;
+}
diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h
new file mode 100644
index 000000000000..4e96ff812ebf
--- /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);
+
+	const char *name;
+	void *handle;
+	struct context *context;
+};
+
+/**
+ * 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] 63+ messages in thread

* [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (14 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 15/20] libmultipath: API for foreign multipath handling Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  6:04   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library Martin Wilck
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 libmultipath/generic.c |  4 +++-
 libmultipath/print.c   | 14 ++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/libmultipath/generic.c b/libmultipath/generic.c
index 61cbffb708b6..5f74427cb5b1 100644
--- a/libmultipath/generic.c
+++ b/libmultipath/generic.c
@@ -33,7 +33,9 @@ int generic_style(const struct gen_multipath* gm,
 	gm->ops->snprint(gm, wwid_buf, sizeof(wwid_buf), 'w');
 
 	if (strcmp(alias_buf, wwid_buf))
-		n = snprintf(buf, len, " (%%w)");
+		n += snprintf(buf, len, "%%n (%%w) [%%G]");
+	else
+		n += snprintf(buf, len, "%%n [%%G]");
 
 	return (n < len ? n : len - 1);
 }
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 9a5a6a2f4ad6..a6ff6b297b3f 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -342,6 +342,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)
 {
@@ -621,6 +627,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},
@@ -644,6 +656,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}
 };
 
@@ -667,6 +680,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] 63+ messages in thread

* [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (15 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  3:14   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 18/20] multipath: use foreign API Martin Wilck
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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   | 444 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 475 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..4e9c3a52d03c
--- /dev/null
+++ b/libmultipath/foreign/nvme.c
@@ -0,0 +1,444 @@
+/*
+  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)
+{
+	if (ctx == NULL)
+		return;
+
+	(void)delete_all(ctx);
+
+	lock(ctx);
+	pthread_cleanup_push(unlock, ctx);
+	vector_free(ctx->mpvec);
+	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);
+	map->subsys = udev_device_ref(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] 63+ messages in thread

* [RFC PATCH 18/20] multipath: use foreign API
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (16 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  3:55   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 19/20] multipathd: " Martin Wilck
  2018-02-20 13:26 ` [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display Martin Wilck
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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] 63+ messages in thread

* [RFC PATCH 19/20] multipathd: use foreign API
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (17 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 18/20] multipath: use foreign API Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:13   ` Benjamin Marzinski
  2018-02-20 13:26 ` [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display Martin Wilck
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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>
---
 libmultipath/discovery.c  |  4 +++-
 multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-----
 multipathd/main.c         | 43 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 77 insertions(+), 9 deletions(-)

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,
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 b900bb3ec2e3..e1d98861a841 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
@@ -699,6 +700,15 @@ rescan:
 		mpp->action = ACT_RELOAD;
 		extract_hwe_from_path(mpp);
 	} else {
+		switch (add_foreign(pp->udev)) {
+		case FOREIGN_CLAIMED:
+		case FOREIGN_OK:
+			orphan_path(pp, "claimed by foreign library");
+			return 0;
+		default:
+			break;
+		}
+
 		if (!should_multipath(pp, vecs->pathvec)) {
 			orphan_path(pp, "only one path");
 			return 0;
@@ -798,6 +808,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 +929,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 +1149,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 +1964,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 +2153,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 +2405,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 +2565,7 @@ child (void * param)
 	FREE(vecs);
 	vecs = NULL;
 
+	cleanup_foreign();
 	cleanup_checkers();
 	cleanup_prio();
 
-- 
2.16.1

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

* [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display
  2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
                   ` (18 preceding siblings ...)
  2018-02-20 13:26 ` [RFC PATCH 19/20] multipathd: " Martin Wilck
@ 2018-02-20 13:26 ` Martin Wilck
  2018-03-01  5:19   ` Benjamin Marzinski
  19 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-02-20 13:26 UTC (permalink / raw)
  To: Christophe Varoqui, Hannes Reinecke; +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:

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

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 | 342 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 327 insertions(+), 15 deletions(-)

diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
index 4e9c3a52d03c..5546a8eb178a 100644
--- a/libmultipath/foreign/nvme.c
+++ b/libmultipath/foreign/nvme.c
@@ -25,42 +25,97 @@
 #include <stdbool.h>
 #include <libudev.h>
 #include <pthread.h>
+#include <limits.h>
+#include <glob.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 +130,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 +146,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 +178,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 +186,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));
+		__attribute__ ((fallthrough));
 	default:
+		return snprintf(buff, len, "%s", N_A);
 		break;
 	}
 	return 0;
@@ -176,6 +306,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)
@@ -228,7 +359,10 @@ void cleanup(struct context *ctx)
 
 	lock(ctx);
 	pthread_cleanup_push(unlock, ctx);
-	vector_free(ctx->mpvec);
+	if (ctx->udev)
+		udev_unref(ctx->udev);
+	if (ctx->mpvec)
+		vector_free(ctx->mpvec);
 	pthread_cleanup_pop(1);
 	pthread_mutex_destroy(&ctx->mutex);
 
@@ -250,6 +384,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;
@@ -278,6 +416,142 @@ 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 void _find_slaves(struct context *ctx, struct nvme_map *map)
+{
+	char pathbuf[PATH_MAX];
+	glob_t globbuf;
+	struct nvme_path *path;
+	int r, i;
+
+	if (map == NULL || map->udev == NULL)
+		return;
+
+	vector_foreach_slot(map->pathvec, path, i)
+		path->seen = false;
+
+	memset(&globbuf, 0, sizeof(globbuf));
+	snprintf(pathbuf, sizeof(pathbuf),
+		"%s/slaves/*",
+		udev_device_get_syspath(map->udev));
+
+	r = glob(pathbuf, 0, NULL, &globbuf);
+
+	if (r == GLOB_NOMATCH) {
+		condlog(3, "%s: %s: no paths for %s", __func__, THIS,
+			udev_device_get_sysname(map->udev));
+		globfree(&globbuf);
+		return;
+	} else if (r != 0) {
+		condlog(1, "%s: %s: error %d searching paths for %d:%d", __func__,
+			THIS, r, major(map->devt), minor(map->devt));
+		globfree(&globbuf);
+		return;
+	}
+	for (i = 0; i < globbuf.gl_pathc; i++) {
+		char *fn;
+		struct udev_device *udev;
+
+		fn = strrchr(globbuf.gl_pathv[i], '/');
+		if (fn == NULL)
+			fn = globbuf.gl_pathv[i];
+		else
+			fn++;
+
+		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);
+	}
+	globfree(&globbuf);
+
+	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)
 {
@@ -296,12 +570,25 @@ static int _add_map(struct context *ctx, struct udev_device *ud,
 	map->subsys = udev_device_ref(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;
 }
@@ -390,9 +677,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;
 }
 
@@ -416,14 +719,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] 63+ messages in thread

* Re: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
  2018-02-20 13:26 ` [RFC PATCH 05/20] libmultipath: don't update path groups when printing Martin Wilck
@ 2018-02-28 23:40   ` Benjamin Marzinski
  2018-03-02 13:59     ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-02-28 23:40 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:43PM +0100, 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.

Well, it is true that we've only been updating the path group priority
when we've needed it, and we've only need it to be uptodate when we are
picking a new pathgroup, or are printing it out. When failback is set to
"manual", we rarely are picking a new pathgroup, so we rarely update the
pathgroup prio. 

If we really want to be honest with the user, we probably want to reload
the multipath device whenever a path group's priority changes enough to
make their order change.  Otherwise, the kernel will still failover to
the wrong path group.  We currently only do this for FAILBACK_IMMEDIATE,
and we don't even do that very well. For instance, we will currently
reorder pathgroups when their priority has gone to 0 because they have
no valid paths. In this case, we should expect that when the paths
return, they will most likely have the same priority as they previously
had. Thus, we shouldn't lower that path group's priority while they are
down, since it will just cause two pointless table reloads (one when the
last path in the group goes down, and another when the first path comes
back). But I digress.

I'd be fine with simply updating the path group priority whever we change a
path's priority, if we aren't updating it when printing it. The bigger
work of actually making sure that the path group order it the table
is always uptodate needs to happen, but it doesn't need to happen in
this patchset.

-Ben
> 
> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 12/20] libmultipath: "generic multipath" interface
  2018-02-20 13:26 ` [RFC PATCH 12/20] libmultipath: "generic multipath" interface Martin Wilck
@ 2018-02-28 23:47   ` Benjamin Marzinski
  2018-03-01  8:51     ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-02-28 23:47 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:50PM +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.
>

I have one nit here. print.h now relies on dm-generic.h, since it uses
dm_multipath_to_gen() in its defines.  So shouldn't it simply include
dm-generic.h, which would allow configure.c, main.c, and cli_handlers.c
to not include dm-generic.h, since they only need it because they
include print.h?

-Ben
 
> 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      |  34 ++++++++++++
>  libmultipath/print.h      |   7 +++
>  libmultipath/structs.c    |   4 ++
>  libmultipath/structs.h    |   4 ++
>  10 files changed, 340 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..61cbffb708b6
> --- /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');
> +
> +	if (strcmp(alias_buf, wwid_buf))
> +		n = snprintf(buf, len, " (%%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..e6f56381791f 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -29,6 +29,7 @@
>  #include "uevent.h"
>  #include "debug.h"
>  #include "discovery.h"
> +#include "dm-generic.h"
>  
>  #define MAX(x,y) (x > y) ? x : y
>  #define TAIL     (line + len - 1 - c)
> @@ -756,6 +757,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 +780,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 +803,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..c624d2bfe8d4 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -122,3 +122,10 @@ 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);
> 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] 63+ messages in thread

* Re: [RFC PATCH 13/20] libmultipath: print: convert API to generic data type
  2018-02-20 13:26 ` [RFC PATCH 13/20] libmultipath: print: convert API to generic data type Martin Wilck
@ 2018-02-28 23:55   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-02-28 23:55 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:51PM +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>
> ---
>  libmultipath/configure.c  |   1 +
>  libmultipath/dm-generic.c |   2 +-
>  libmultipath/print.c      | 116 +++++++++++++++++++++++++++++-----------------
>  libmultipath/print.h      |  28 ++++++++---
>  multipath/main.c          |   1 +
>  multipathd/cli_handlers.c |   1 +
>  6 files changed, 100 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 e6f56381791f..8846765066ef 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -31,7 +31,8 @@
>  #include "discovery.h"
>  #include "dm-generic.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) \
> @@ -846,8 +847,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 */
> @@ -870,7 +871,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);
> @@ -913,8 +914,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 */
> @@ -937,7 +938,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);
> @@ -948,8 +949,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 */
> @@ -972,7 +973,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++);
> @@ -980,8 +981,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;
> @@ -998,7 +1001,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) {
> @@ -1011,12 +1014,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];
> @@ -1028,60 +1049,71 @@ 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);
> +	c += snprintf(c, sizeof(style) - (c - style), " %%d %%s");

You already added %d and %s to the style line in
snprint_multipath_style()

It causes multipath to dublicate the dev and vend/prod/rev as shown
below.

# multipath -l mpathc
mpathc (333333330000007d0) dm-5 Linux,scsi_debug dm-5 Linux,scsi_debug
size=100M features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
|-+- policy='service-time 0' prio=0 status=active
| `- 9:0:0:0 sde 8:64 active undef unknown
`-+- policy='service-time 0' prio=0 status=enabled
  `- 8:0:0:0 sdd 8:48 active undef unknown


>  	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 c624d2bfe8d4..e71f87722315 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -1,3 +1,6 @@
> +#ifndef _PRINT_H
> +#define _PRINT_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"
> @@ -94,11 +97,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,
> @@ -119,7 +128,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);
>  
> @@ -129,3 +142,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] 63+ messages in thread

* Re: [RFC PATCH 15/20] libmultipath: API for foreign multipath handling
  2018-02-20 13:26 ` [RFC PATCH 15/20] libmultipath: API for foreign multipath handling Martin Wilck
@ 2018-03-01  3:01   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  3:01 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:53PM +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.

ACK, with one minor nit

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

<snip>

> +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);
> +
> +	const char *name;
> +	void *handle;
> +	struct context *context;
> +};

Instead of having a separate pointer "name", would you mind using
const char name[0];

at the end of the structure, like struct logmsg does? I believe this
should work with const.

-Ben

> +
> +/**
> + * 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] 63+ messages in thread

* Re: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
  2018-02-20 13:26 ` [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library Martin Wilck
@ 2018-03-01  3:14   ` Benjamin Marzinski
  2018-03-02 16:04     ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  3:14 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:55PM +0100, 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   | 444 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 475 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..4e9c3a52d03c
> --- /dev/null
> +++ b/libmultipath/foreign/nvme.c
> @@ -0,0 +1,444 @@
> +/*
> +  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);

According to the libudev reference manual, udev devices returned by
udev_device_get_parent_with_subsystem_devtype are attached to their
child and free along with them, so this unref shouldn't be necessary

> +	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)
> +{
> +	if (ctx == NULL)
> +		return;
> +
> +	(void)delete_all(ctx);
> +
> +	lock(ctx);
> +	pthread_cleanup_push(unlock, ctx);
> +	vector_free(ctx->mpvec);
> +	pthread_cleanup_pop(1);
> +	pthread_mutex_destroy(&ctx->mutex);
> +
> +	free(ctx);
> +}

Would you mind either removing the locking, or adding a comment
explaining that it's not necessary here.  If you really did need to lock
ctx in order guard against someone accessing ctx->mpvec in cleanup(),
then not setting it to NULL after its freed, and immediately freeing ctx
afterwards would clearly be broken, so seeing the locking makes it look
like this function is wrong.

> +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);
> +	map->subsys = udev_device_ref(subsys);

You shouldn't need to get a reference here, since map->udev will keep
this device around.

-Ben

> +	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] 63+ messages in thread

* Re: [RFC PATCH 18/20] multipath: use foreign API
  2018-02-20 13:26 ` [RFC PATCH 18/20] multipath: use foreign API Martin Wilck
@ 2018-03-01  3:55   ` Benjamin Marzinski
  2018-03-02 16:36     ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  3:55 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:56PM +0100, Martin Wilck wrote:
> Use the "foreign" code to print information about multipath maps
> owned by foreign libraries in print mode (multipath -ll, -l).
> 

It's not a big deal, but I assume your is_claimed_by_foreign() call in
pathinfo() from your next patch was supposed to be in this one.  Until I
saw that, I couldn't figure out how foreign maps could ever get added
during a call to multipath.

> 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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-02-20 13:26 ` [RFC PATCH 19/20] multipathd: " Martin Wilck
@ 2018-03-01  5:13   ` Benjamin Marzinski
  2018-03-02 17:04     ` Martin Wilck
                       ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:13 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:57PM +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.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/discovery.c  |  4 +++-
>  multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-----
>  multipathd/main.c         | 43 ++++++++++++++++++++++++++++++++++++++++---
>  3 files changed, 77 insertions(+), 9 deletions(-)
> 
> 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,
> 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 b900bb3ec2e3..e1d98861a841 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
> @@ -699,6 +700,15 @@ rescan:
>  		mpp->action = ACT_RELOAD;
>  		extract_hwe_from_path(mpp);
>  	} else {
> +		switch (add_foreign(pp->udev)) {

There's a rather convoluted issue here. This function will eventually
call _find_slaves() in the nvme code, which calls glob(), which isn't
strictly multithreading safe for a number of reasons. The only one that
effects multipathd is its use of SIGALRM. Now assuming signal processing
worked correctly in multipathd (it doesn't. commit 534ec4c broke it. I'm
planning on fixing that shortly) there would still be a problem, because
of the strict_timing option.  strict_timing calls setitimer(), which
sets an alarm in checkerloop, without any locking.  strict_timing also
messes with any call to lock_file(). lock_file() and _find_slaves() will
never interfere with eachother, since both are only called with the vecs
lock held (I think. See below). strict_timing probably needs to get
reimplemented using nanosleep() or some other non-signal method, so that
there aren't two threads setting alarms and waiting for SIGARLM at the
same time.

> +		case FOREIGN_CLAIMED:
> +		case FOREIGN_OK:
> +			orphan_path(pp, "claimed by foreign library");
> +			return 0;
> +		default:
> +			break;

Is there a purpose to this break?


> +		}
> +
>  		if (!should_multipath(pp, vecs->pathvec)) {
>  			orphan_path(pp, "only one path");
>  			return 0;
> @@ -798,6 +808,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 +929,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 +1149,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;
> +		}

I'm confused. Should foreign maps ever have uev->kernel set to "dm-"?
If this is correct, these calls probably need to get called with the
vecs lock held, otherwise they can interfere with calls to lock_file().

-Ben

>  		if (!strncmp(uev->action, "change", 6)) {
>  			r = uev_add_map(uev, vecs);
>  
> @@ -1932,7 +1964,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 +2153,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 +2405,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 +2565,7 @@ child (void * param)
>  	FREE(vecs);
>  	vecs = NULL;
>  
> +	cleanup_foreign();
>  	cleanup_checkers();
>  	cleanup_prio();
>  
> -- 
> 2.16.1

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

* Re: [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display
  2018-02-20 13:26 ` [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display Martin Wilck
@ 2018-03-01  5:19   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:19 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:58PM +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:
> 
> 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
> 
> 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).

ACK with one small nit.
 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/foreign/nvme.c | 342 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 327 insertions(+), 15 deletions(-)
> 
> diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c
> index 4e9c3a52d03c..5546a8eb178a 100644
> --- a/libmultipath/foreign/nvme.c
> +++ b/libmultipath/foreign/nvme.c
> @@ -25,42 +25,97 @@
>  #include <stdbool.h>
>  #include <libudev.h>
>  #include <pthread.h>
> +#include <limits.h>
> +#include <glob.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 +130,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 +146,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 +178,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 +186,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));
> +		__attribute__ ((fallthrough));

This attribute only exists in gcc 7.x. Both gcc and clang also accept
the marker comment

/* fall through */

to stop fall through warnings, and it doesn't cause issues with earlier
versions of gcc. Would you mind switching to this?

-Ben

>  	default:
> +		return snprintf(buff, len, "%s", N_A);
>  		break;
>  	}
>  	return 0;
> @@ -176,6 +306,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)
> @@ -228,7 +359,10 @@ void cleanup(struct context *ctx)
>  
>  	lock(ctx);
>  	pthread_cleanup_push(unlock, ctx);
> -	vector_free(ctx->mpvec);
> +	if (ctx->udev)
> +		udev_unref(ctx->udev);
> +	if (ctx->mpvec)
> +		vector_free(ctx->mpvec);
>  	pthread_cleanup_pop(1);
>  	pthread_mutex_destroy(&ctx->mutex);
>  
> @@ -250,6 +384,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;
> @@ -278,6 +416,142 @@ 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 void _find_slaves(struct context *ctx, struct nvme_map *map)
> +{
> +	char pathbuf[PATH_MAX];
> +	glob_t globbuf;
> +	struct nvme_path *path;
> +	int r, i;
> +
> +	if (map == NULL || map->udev == NULL)
> +		return;
> +
> +	vector_foreach_slot(map->pathvec, path, i)
> +		path->seen = false;
> +
> +	memset(&globbuf, 0, sizeof(globbuf));
> +	snprintf(pathbuf, sizeof(pathbuf),
> +		"%s/slaves/*",
> +		udev_device_get_syspath(map->udev));
> +
> +	r = glob(pathbuf, 0, NULL, &globbuf);
> +
> +	if (r == GLOB_NOMATCH) {
> +		condlog(3, "%s: %s: no paths for %s", __func__, THIS,
> +			udev_device_get_sysname(map->udev));
> +		globfree(&globbuf);
> +		return;
> +	} else if (r != 0) {
> +		condlog(1, "%s: %s: error %d searching paths for %d:%d", __func__,
> +			THIS, r, major(map->devt), minor(map->devt));
> +		globfree(&globbuf);
> +		return;
> +	}
> +	for (i = 0; i < globbuf.gl_pathc; i++) {
> +		char *fn;
> +		struct udev_device *udev;
> +
> +		fn = strrchr(globbuf.gl_pathv[i], '/');
> +		if (fn == NULL)
> +			fn = globbuf.gl_pathv[i];
> +		else
> +			fn++;
> +
> +		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);
> +	}
> +	globfree(&globbuf);
> +
> +	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)
>  {
> @@ -296,12 +570,25 @@ static int _add_map(struct context *ctx, struct udev_device *ud,
>  	map->subsys = udev_device_ref(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;
>  }
> @@ -390,9 +677,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;
>  }
>  
> @@ -416,14 +719,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] 63+ messages in thread

* Re: [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries
  2018-02-20 13:26 ` [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
@ 2018-03-01  5:35   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:35 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:39PM +0100, Martin Wilck wrote:
> Otherwise the binaries won't be re-linked if the libraries change.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers"
  2018-02-20 13:26 ` [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers" Martin Wilck
@ 2018-03-01  5:36   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:36 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:40PM +0100, 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(-)
> 
> 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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c
  2018-02-20 13:26 ` [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c Martin Wilck
@ 2018-03-01  5:36   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:36 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:41PM +0100, Martin Wilck wrote:
> By properly linking the path groups with their parent multipath,
> we don't need this "hack" any more.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods
  2018-02-20 13:26 ` [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
@ 2018-03-01  5:37   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:37 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:42PM +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.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate
  2018-02-20 13:26 ` [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate Martin Wilck
@ 2018-03-01  5:37   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:37 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:44PM +0100, 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.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 07/20] libmultipath: use "const" in devmapper code
  2018-02-20 13:26 ` [RFC PATCH 07/20] libmultipath: use "const" in devmapper code Martin Wilck
@ 2018-03-01  5:39   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:39 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:45PM +0100, Martin Wilck wrote:
> Improve use of "const" qualifiers in libmultipath's devmapper code.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual
  2018-02-20 13:26 ` [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual Martin Wilck
@ 2018-03-01  5:39   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:39 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:46PM +0100, Martin Wilck wrote:
> Fix the warnings that were caused by adding the -Wcast-qual compiler
> flag in the previous patch.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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(-)
> 
> diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
> index 4469fa848de8..eb9dac639175 100644
> --- a/kpartx/devmapper.c
> +++ b/kpartx/devmapper.c
> @@ -11,6 +11,7 @@
>  #include <sys/sysmacros.h>
>  #include "devmapper.h"
>  
> +#define FREE_CONST(p) do { free((void*)(long)p); p = NULL; } while(0)
>  #define _UUID_PREFIX "part"
>  #define UUID_PREFIX _UUID_PREFIX "%d-"
>  #define _UUID_PREFIX_LEN (sizeof(_UUID_PREFIX) - 1)
> @@ -695,7 +696,7 @@ int dm_find_part(const char *parent, const char *delim, int part,
>  	} else
>  		*part_uuid = uuid;
>  out:
> -	free((void*)tmp);
> +	FREE_CONST(tmp);
>  	return r;
>  }
>  
> diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
> index af618cff917c..29d148ce8aff 100644
> --- a/libmpathcmd/mpath_cmd.c
> +++ b/libmpathcmd/mpath_cmd.c
> @@ -64,7 +64,7 @@ static size_t write_all(int fd, const void *buf, size_t len)
>  		}
>  		if (!n)
>  			return total;
> -		buf = n + (char *)buf;
> +		buf = n + (const char *)buf;
>  		len -= n;
>  		total += n;
>  	}
> diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c
> index 2c1800976e40..b1d99b4c81f6 100644
> --- a/libmultipath/checkers/rbd.c
> +++ b/libmultipath/checkers/rbd.c
> @@ -288,7 +288,7 @@ void libcheck_free(struct checker * c)
>  static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg)
>  {
>  	char *addr_tok, *start, *save;
> -	char *cmd[2];
> +	const char *cmd[2];
>  	char *blklist, *stat;
>  	size_t blklist_len, stat_len;
>  	int ret;
> @@ -436,7 +436,7 @@ static int sysfs_write_rbd_remove(const char *buf, int buf_len)
>  
>  static int rbd_rm_blacklist(struct rbd_checker_context *ct)
>  {
> -	char *cmd[2];
> +	const char *cmd[2];
>  	char *stat, *cmd_str;
>  	size_t stat_len;
>  	int ret;
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index f61838cbe369..607aea8dc1fc 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -27,6 +27,7 @@
>  #include <sys/types.h>
>  #include <time.h>
>  
> +#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
>  #define MAX_WAIT 5
>  #define LOOPS_PER_SEC 5
>  
> @@ -1426,7 +1427,7 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
>  	n += strlen(newdep);
>  	p += strlen(dep);
>  	strcat(n, p);
> -	free(newtable);
> +	FREE_CONST(newtable);
>  }
>  
>  int dm_reassign_table(const char *name, char *old, char *new)
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index 98bddee52c8f..645224c1029c 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -121,7 +121,7 @@ path_discover (vector pathvec, struct config * conf,
>  	if (!devname)
>  		return PATHINFO_FAILED;
>  
> -	pp = find_path_by_dev(pathvec, (char *)devname);
> +	pp = find_path_by_dev(pathvec, devname);
>  	if (!pp) {
>  		char devt[BLK_DEV_SIZE];
>  		dev_t devnum = udev_device_get_devnum(udevice);
> @@ -905,12 +905,12 @@ static int
>  parse_vpd_pg83(const unsigned char *in, size_t in_len,
>  	       char *out, size_t out_len)
>  {
> -	unsigned char *d;
> -	unsigned char *vpd = NULL;
> +	const unsigned char *d;
> +	const unsigned char *vpd = NULL;
>  	int len = -ENODATA, vpd_type, vpd_len, prio = -1, i, naa_prio;
>  
> -	d = (unsigned char *)in + 4;
> -	while (d < (unsigned char *)in + in_len) {
> +	d = in + 4;
> +	while (d < in + in_len) {
>  		/* Select 'association: LUN' */
>  		if ((d[1] & 0x30) != 0) {
>  			d += d[3] + 4;
> @@ -1027,7 +1027,7 @@ parse_vpd_pg83(const unsigned char *in, size_t in_len,
>  				out[len] = '\0';
>  			}
>  		} else if (vpd_type == 0x1) {
> -			unsigned char *p;
> +			const unsigned char *p;
>  			int p_len;
>  
>  			out[0] = '1';
> diff --git a/libmultipath/list.h b/libmultipath/list.h
> index 2b1dcf396695..c9110ac9de7e 100644
> --- a/libmultipath/list.h
> +++ b/libmultipath/list.h
> @@ -18,8 +18,8 @@
>   * @member:	the name of the member within the struct.
>   *
>   */
> -#define container_of(ptr, type, member) ({			\
> -	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> +#define container_of(ptr, type, member) ({		\
> +	typeof( ((type *)0)->member ) *__mptr = (ptr);	\
>  	(type *)( (char *)__mptr - offsetof(type,member) );})
>  
>  /*
> diff --git a/libmultipath/memory.h b/libmultipath/memory.h
> index 927619b58a62..63f59d80584c 100644
> --- a/libmultipath/memory.h
> +++ b/libmultipath/memory.h
> @@ -43,6 +43,7 @@ int debug;
>  		      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
>  #define STRDUP(n)    ( dbg_strdup((n), \
>  		      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
> +#define FREE_CONST(p) do { FREE((void*)(unsigned long)p); } while(0)
>  
>  /* Memory debug prototypes defs */
>  extern void *dbg_malloc(unsigned long, char *, char *, int);
> @@ -54,7 +55,12 @@ extern void dbg_free_final(char *);
>  #else
>  
>  #define MALLOC(n)    (calloc(1,(n)))
> -#define FREE(p)      do { free((void*)p); p = NULL; } while(0)
> +#define FREE(p)      do { free(p); p = NULL; } while(0)
> +/*
> + * Double cast to avoid warnings with -Wcast-qual
> + * use this for valid free() operations on const pointers
> + */
> +#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
>  #define REALLOC(p,n) (realloc((p),(n)))
>  #define STRDUP(n)    (strdup(n))
>  
> diff --git a/libmultipath/structs.c b/libmultipath/structs.c
> index 1ade1a6705ad..4db08451824d 100644
> --- a/libmultipath/structs.c
> +++ b/libmultipath/structs.c
> @@ -418,7 +418,7 @@ find_mp_by_str (vector mpvec, char * str)
>  }
>  
>  struct path *
> -find_path_by_dev (vector pathvec, char * dev)
> +find_path_by_dev (vector pathvec, const char * dev)
>  {
>  	int i;
>  	struct path * pp;
> diff --git a/libmultipath/structs.h b/libmultipath/structs.h
> index 71b37cc20674..bccc845a1222 100644
> --- a/libmultipath/structs.h
> +++ b/libmultipath/structs.h
> @@ -387,7 +387,7 @@ struct multipath * find_mp_by_str (vector mp, char * wwid);
>  struct multipath * find_mp_by_minor (vector mp, int minor);
>  
>  struct path * find_path_by_devt (vector pathvec, const char * devt);
> -struct path * find_path_by_dev (vector pathvec, char * dev);
> +struct path * find_path_by_dev (vector pathvec, const char * dev);
>  struct path * first_path (struct multipath * mpp);
>  
>  int pathcountgr (struct pathgroup *, int);
> diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
> index 8f4129ca7fd0..685ef3362c6d 100644
> --- a/libmultipath/uevent.c
> +++ b/libmultipath/uevent.c
> @@ -157,7 +157,7 @@ static int uevent_get_env_positive_int(const struct uevent *uev,
>  void
>  uevent_get_wwid(struct uevent *uev)
>  {
> -	char *uid_attribute;
> +	const char *uid_attribute;
>  	const char *val;
>  	struct config * conf;
>  
> @@ -167,8 +167,8 @@ uevent_get_wwid(struct uevent *uev)
>  
>  	val = uevent_get_env_var(uev, uid_attribute);
>  	if (val)
> -		uev->wwid = (char*)val;
> -	free(uid_attribute);
> +		uev->wwid = val;
> +	FREE_CONST(uid_attribute);
>  }
>  
>  bool
> diff --git a/libmultipath/util.c b/libmultipath/util.c
> index 0b43d29d1236..d3dd3eb524d0 100644
> --- a/libmultipath/util.c
> +++ b/libmultipath/util.c
> @@ -32,7 +32,7 @@ strchop(char *str)
>  int
>  basenamecpy (const char * str1, char * str2, int str2len)
>  {
> -	char *p;
> +	const char *p;
>  
>  	if (!str1 || !strlen(str1))
>  		return 0;
> @@ -43,7 +43,7 @@ basenamecpy (const char * str1, char * str2, int str2len)
>  	if (!str2)
>  		return 0;
>  
> -	p = (char *)str1 + (strlen(str1) - 1);
> +	p = str1 + (strlen(str1) - 1);
>  
>  	while (*--p != '/' && p != str1)
>  		continue;
> @@ -454,7 +454,7 @@ int safe_write(int fd, const void *buf, size_t count)
>  			return -errno;
>  		}
>  		count -= r;
> -		buf = (char *)buf + r;
> +		buf = (const char *)buf + r;
>  	}
>  	return 0;
>  }
> diff --git a/multipathd/main.c b/multipathd/main.c
> index a8a0c302e8fe..b900bb3ec2e3 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -408,7 +408,7 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
>  	pthread_testcancel();
>  	rc = ev_add_map(uev->kernel, alias, vecs);
>  	lock_cleanup_pop(vecs->lock);
> -	FREE(alias);
> +	FREE_CONST(alias);
>  	return rc;
>  }
>  
> @@ -532,7 +532,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
>  	remove_map_and_stop_waiter(mpp, vecs, 1);
>  out:
>  	lock_cleanup_pop(vecs->lock);
> -	FREE(alias);
> +	FREE_CONST(alias);
>  	return 0;
>  }
>  
> @@ -1028,11 +1028,11 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
>  				pp->dev);
>  out_lock:
>  	lock_cleanup_pop(vecs->lock);
> -	FREE(devt);
> -	FREE(action);
> +	FREE_CONST(devt);
> +	FREE_CONST(action);
>  	return r;
>  out:
> -	FREE(action);
> +	FREE_CONST(action);
>  	return 1;
>  }
>  
> -- 
> 2.16.1

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

* Re: [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual
  2018-02-20 13:26 ` [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
@ 2018-03-01  5:59   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  5:59 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:47PM +0100, Martin Wilck wrote:
> Casting "const" away is often an indicator for wrong code.
> Add a compiler flag to warn about such possible breakage.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 10/20] libmultipath: add vector_free_const()
  2018-02-20 13:26 ` [RFC PATCH 10/20] libmultipath: add vector_free_const() Martin Wilck
@ 2018-03-01  6:00   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  6:00 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:48PM +0100, Martin Wilck wrote:
> ... to dispose of constant vectors (const struct _vector*).
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 11/20] libmultipath: add vector_convert()
  2018-02-20 13:26 ` [RFC PATCH 11/20] libmultipath: add vector_convert() Martin Wilck
@ 2018-03-01  6:02   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  6:02 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:49PM +0100, 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.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout()
  2018-02-20 13:26 ` [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout() Martin Wilck
@ 2018-03-01  6:03   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  6:03 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:52PM +0100, 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.
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.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 8846765066ef..9a5a6a2f4ad6 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -698,20 +698,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));
>  		}
>  	}
> @@ -727,22 +755,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 e71f87722315..1ba364ac19ac 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -93,7 +93,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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard
  2018-02-20 13:26 ` [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
@ 2018-03-01  6:04   ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-01  6:04 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Feb 20, 2018 at 02:26:54PM +0100, Martin Wilck wrote:
> This adds a format field to identify foreign maps as such, and
> uses it in default-formatted topology output (generic_style()).
> 

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

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/generic.c |  4 +++-
>  libmultipath/print.c   | 14 ++++++++++++++
>  2 files changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/libmultipath/generic.c b/libmultipath/generic.c
> index 61cbffb708b6..5f74427cb5b1 100644
> --- a/libmultipath/generic.c
> +++ b/libmultipath/generic.c
> @@ -33,7 +33,9 @@ int generic_style(const struct gen_multipath* gm,
>  	gm->ops->snprint(gm, wwid_buf, sizeof(wwid_buf), 'w');
>  
>  	if (strcmp(alias_buf, wwid_buf))
> -		n = snprintf(buf, len, " (%%w)");
> +		n += snprintf(buf, len, "%%n (%%w) [%%G]");
> +	else
> +		n += snprintf(buf, len, "%%n [%%G]");
>  
>  	return (n < len ? n : len - 1);
>  }
> diff --git a/libmultipath/print.c b/libmultipath/print.c
> index 9a5a6a2f4ad6..a6ff6b297b3f 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -342,6 +342,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)
>  {
> @@ -621,6 +627,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},
> @@ -644,6 +656,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}
>  };
>  
> @@ -667,6 +680,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	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH 12/20] libmultipath: "generic multipath" interface
  2018-02-28 23:47   ` Benjamin Marzinski
@ 2018-03-01  8:51     ` Martin Wilck
  0 siblings, 0 replies; 63+ messages in thread
From: Martin Wilck @ 2018-03-01  8:51 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Wed, 2018-02-28 at 17:47 -0600, Benjamin Marzinski wrote:
> 
> I have one nit here. print.h now relies on dm-generic.h, since it
> uses
> dm_multipath_to_gen() in its defines.  So shouldn't it simply include
> dm-generic.h, which would allow configure.c, main.c, and
> cli_handlers.c
> to not include dm-generic.h, since they only need it because they
> include print.h?

Sure, I can do that. 

This is a basic style question - should .h files (a) contain #includes
for all other header files they depend on, or should (b) the .c code
be required to #include everything in correct order? AFAICS we don't
have a policy about that in multipath-tools, it's sometimes this way
and sometimes the other way. Personally I'm slightly inclined towards
(b) because it makes the dependencies of .c files more explicit, but I
don't care much. (a) makes the life of the programmer a bit easier.

Regards,
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] 63+ messages in thread

* Re: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
  2018-02-28 23:40   ` Benjamin Marzinski
@ 2018-03-02 13:59     ` Martin Wilck
  2018-03-02 15:31       ` Benjamin Marzinski
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 13:59 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

[-- Attachment #1: Type: text/plain, Size: 2526 bytes --]

On Wed, 2018-02-28 at 17:40 -0600, Benjamin Marzinski wrote:
> On Tue, Feb 20, 2018 at 02:26:43PM +0100, 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.
> 
> Well, it is true that we've only been updating the path group
> priority
> when we've needed it, and we've only need it to be uptodate when we
> are
> picking a new pathgroup, or are printing it out. When failback is set
> to
> "manual", we rarely are picking a new pathgroup, so we rarely update
> the
> pathgroup prio. 
> 
> [...]
>
> I'd be fine with simply updating the path group priority whever we
> change a
> path's priority, if we aren't updating it when printing it. The
> bigger
> work of actually making sure that the path group order it the table
> is always uptodate needs to happen, but it doesn't need to happen in
> this patchset.

I just reviewed the code flow in check_path(), and here's what I see:

1. calls update_prio(pp, new_path_up)
   -> updates path's prio, or all paths' prios if the path was
      reinstated

Now it calls either

2a. update_path_groups() (for group_by_prio and failback immediate)
  (-> reload_map() -> setup_map() -> select_path_group()
  -> path_group_prio_update()), or
  
2b. need_switch_pathgroup() (otherwise)
  
So all we need to make sure is that need_switch_pathgroup() calls 
select_path_group(). It does that already, except for the "failback
manual" case.

So all we need is IMO the attached patch. Tell me what you think.

[All of the above is only called if (!mpp->wait_for_udev), but if
wait_for_udev is set, either when the event arrives or the wait times
out, we'll call reconfigure() which makes sure all priorities are
correct].

Best,
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)

[-- Attachment #2: 0001-multipathd-update-path-group-prio-in-check_path.patch --]
[-- Type: text/x-patch, Size: 1361 bytes --]

From 149f4458d138d504ee5947aaa6e38d134b21368a Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Fri, 2 Mar 2018 14:51:52 +0100
Subject: [PATCH] multipathd: update path group prio in check_path

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 e1d98861a841..61739ac6ea59 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


[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



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

* Re: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
  2018-03-02 13:59     ` Martin Wilck
@ 2018-03-02 15:31       ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-02 15:31 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Fri, Mar 02, 2018 at 02:59:40PM +0100, Martin Wilck wrote:
> On Wed, 2018-02-28 at 17:40 -0600, Benjamin Marzinski wrote:
> > On Tue, Feb 20, 2018 at 02:26:43PM +0100, Martin Wilck wrote:
> >
> > I'd be fine with simply updating the path group priority whever we
> > change a
> > path's priority, if we aren't updating it when printing it. The
> > bigger
> > work of actually making sure that the path group order it the table
> > is always uptodate needs to happen, but it doesn't need to happen in
> > this patchset.
> 
> I just reviewed the code flow in check_path(), and here's what I see:
> 
> 1. calls update_prio(pp, new_path_up)
>    -> updates path's prio, or all paths' prios if the path was
>       reinstated
> 
> Now it calls either
> 
> 2a. update_path_groups() (for group_by_prio and failback immediate)
>   (-> reload_map() -> setup_map() -> select_path_group()
>   -> path_group_prio_update()), or
>   
> 2b. need_switch_pathgroup() (otherwise)
>   
> So all we need to make sure is that need_switch_pathgroup() calls 
> select_path_group(). It does that already, except for the "failback
> manual" case.
> 
> So all we need is IMO the attached patch. Tell me what you think.
> 
> [All of the above is only called if (!mpp->wait_for_udev), but if
> wait_for_udev is set, either when the event arrives or the wait times
> out, we'll call reconfigure() which makes sure all priorities are
> correct].

looks good.

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

I haven't looked through the code for them, but I think there are case
where we zero out a path's or pathgroup's priority, simply because it is
down.  It looks weird when all the failed paths get lumped together in
one path group, or when the high priority path group suddenly stops
being listed as high priority.  Obviously, this gets fixed as soon as
the paths come back online, so no harm is done, but it seems like
multipathd is doing a bunch of busy-work, just to make the output less
clear.

I realize there isn't an obvious and simple answer here, because
sometimes when all the paths in a pathgroup fail, and you switch
pathgroups, you really do change the priority of paths, which gets
updated in the still-working ones.  This means that if you leave the
priorities of the failed paths as they were, you can still get incorrect
groupings. But, like I said, all this has nothing to do with your
current patchset.
 
> Best,
> 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)

> From 149f4458d138d504ee5947aaa6e38d134b21368a Mon Sep 17 00:00:00 2001
> From: Martin Wilck <mwilck@suse.com>
> Date: Fri, 2 Mar 2018 14:51:52 +0100
> Subject: [PATCH] multipathd: update path group prio in check_path
> 
> 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 e1d98861a841..61739ac6ea59 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] 63+ messages in thread

* Re: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
  2018-03-01  3:14   ` Benjamin Marzinski
@ 2018-03-02 16:04     ` Martin Wilck
  2018-03-02 18:30       ` Benjamin Marzinski
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 16:04 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Wed, 2018-02-28 at 21:14 -0600, Benjamin Marzinski wrote:
> On Tue, Feb 20, 2018 at 02:26:55PM +0100, 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   | 444
> > ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 475 insertions(+)
> >  create mode 100644 libmultipath/foreign/Makefile
> >  create mode 100644 libmultipath/foreign/nvme.c
> > 
> > diff --git a/libmultipath/foreign/nvme.c
> > b/libmultipath/foreign/nvme.c
> > new file mode 100644
> > index 000000000000..4e9c3a52d03c
> > --- /dev/null
> > +++ b/libmultipath/foreign/nvme.c
> > 
> > +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);
> 
> According to the libudev reference manual, udev devices returned by
> udev_device_get_parent_with_subsystem_devtype are attached to their
> child and free along with them, so this unref shouldn't be necessary

I'd figured that myself and fixed it in patch 20/20. It must have
excaped my attention when I cleaned up. I'll fix the sequence.

> +
> > +void cleanup(struct context *ctx)
> > +{
> > +	if (ctx == NULL)
> > +		return;
> > +
> > +	(void)delete_all(ctx);
> > +
> > +	lock(ctx);
> > +	pthread_cleanup_push(unlock, ctx);
> > +	vector_free(ctx->mpvec);
> > +	pthread_cleanup_pop(1);
> > +	pthread_mutex_destroy(&ctx->mutex);
> > +
> > +	free(ctx);
> > +}
> 
> Would you mind either removing the locking, or adding a comment
> explaining that it's not necessary here.  If you really did need to
> lock
> ctx in order guard against someone accessing ctx->mpvec in cleanup(),
> then not setting it to NULL after its freed, and immediately freeing
> ctx
> afterwards would clearly be broken, so seeing the locking makes it
> look
> like this function is wrong.

I don't understand, sorry. I need to lock because some other entity may
still be using ctx->mpvec when cleanup() is called, and I should wait
until that other entity has released the lock before I free it. I'm
also pretty sure that checkers such as coverity would complain if I
free a structure here without locking which I access only under the
lock in other places.

I agree, though, that I should nullify the data and add checks in the
other functions. I'll also add some locking in the foreign.c file,
didn't occur to me before.

> > +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);
> > +	map->subsys = udev_device_ref(subsys);
> 
> You shouldn't need to get a reference here, since map->udev will keep
> this device around.

See above.

Regards,
Martin

> 
> -Ben
> 
> > +	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,
> > +							       "nv
> > me-subsystem",
> > +							       NUL
> > L);
> > +	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
> 
> 

-- 
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] 63+ messages in thread

* Re: [RFC PATCH 18/20] multipath: use foreign API
  2018-03-01  3:55   ` Benjamin Marzinski
@ 2018-03-02 16:36     ` Martin Wilck
  0 siblings, 0 replies; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 16:36 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Wed, 2018-02-28 at 21:55 -0600, Benjamin Marzinski wrote:
> On Tue, Feb 20, 2018 at 02:26:56PM +0100, Martin Wilck wrote:
> > Use the "foreign" code to print information about multipath maps
> > owned by foreign libraries in print mode (multipath -ll, -l).
> > 
> 
> It's not a big deal, but I assume your is_claimed_by_foreign() call
> in
> pathinfo() from your next patch was supposed to be in this
> one.  Until I
> saw that, I couldn't figure out how foreign maps could ever get added
> during a call to multipath.

Yeah. Thanks for looking closely. I'll revert the order of the two
patches.

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] 63+ messages in thread

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-03-01  5:13   ` Benjamin Marzinski
@ 2018-03-02 17:04     ` Martin Wilck
  2018-03-02 18:42       ` Benjamin Marzinski
  2018-03-02 19:19     ` Martin Wilck
  2018-03-02 21:00     ` [RFC PATCH 19/20] multipathd: use foreign API Bart Van Assche
  2 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 17:04 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Wed, 2018-02-28 at 23:13 -0600, Benjamin Marzinski wrote:
> On Tue, Feb 20, 2018 at 02:26:57PM +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.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/discovery.c  |  4 +++-
> >  multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-
> > ----
> >  multipathd/main.c         | 43
> > ++++++++++++++++++++++++++++++++++++++++---
> >  3 files changed, 77 insertions(+), 9 deletions(-)
> > 
> > diff --git a/multipathd/main.c b/multipathd/main.c
> > index b900bb3ec2e3..e1d98861a841 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
> > @@ -699,6 +700,15 @@ rescan:
> >  		mpp->action = ACT_RELOAD;
> >  		extract_hwe_from_path(mpp);
> >  	} else {
> > +		switch (add_foreign(pp->udev)) {
> 
> There's a rather convoluted issue here. This function will eventually
> call _find_slaves() in the nvme code, which calls glob(), which isn't
> strictly multithreading safe for a number of reasons. The only one
> that
> effects multipathd is its use of SIGALRM. Now assuming signal
> processing
> worked correctly in multipathd (it doesn't. commit 534ec4c broke it.
> I'm
> planning on fixing that shortly) there would still be a problem,
> because
> of the strict_timing option.  strict_timing calls setitimer(), which
> sets an alarm in checkerloop, without any locking.  strict_timing
> also
> messes with any call to lock_file(). lock_file() and _find_slaves()
> will
> never interfere with eachother, since both are only called with the
> vecs
> lock held (I think. See below). strict_timing probably needs to get
> reimplemented using nanosleep() or some other non-signal method, so
> that
> there aren't two threads setting alarms and waiting for SIGARLM at
> the
> same time.

Thanks for spotting this. It was lazyness on my side to use glob(). I
will reimplement this using safer, more elementary functions. 

> 
> > +		case FOREIGN_CLAIMED:
> > +		case FOREIGN_OK:
> > +			orphan_path(pp, "claimed by foreign
> > library");
> > +			return 0;
> > +		default:
> > +			break;
> 
> Is there a purpose to this break?

I thought this was common style. You find it the kernel's CodingStyle
document, too. I have no issues with removing it if you insist.

> > 	conf = get_multipath_config();
> >  	disable_changed_wwids = conf->disable_changed_wwids;
> >  	put_multipath_config(conf);
> > @@ -1122,8 +1149,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;
> > +		}
> 
> I'm confused. Should foreign maps ever have uev->kernel set to "dm-"?

Although I don't see a likely candidate, I didn't want to exclude it in
general.

> If this is correct, these calls probably need to get called with the
> vecs lock held, otherwise they can interfere with calls to
> lock_file().

Please explain. These devices are ignored by multipath-tools, because
!uevent_is_mpath(uev), so they won't be part of any of their data
structures. And lock_file() is only about fcntl, what does it have to
do with this code? 

Regards,
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] 63+ messages in thread

* Re: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
  2018-03-02 16:04     ` Martin Wilck
@ 2018-03-02 18:30       ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-02 18:30 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Fri, Mar 02, 2018 at 05:04:28PM +0100, Martin Wilck wrote:
> On Wed, 2018-02-28 at 21:14 -0600, Benjamin Marzinski wrote:
> > On Tue, Feb 20, 2018 at 02:26:55PM +0100, Martin Wilck wrote:
> > > +void cleanup(struct context *ctx)
> > > +{
> > > +	if (ctx == NULL)
> > > +		return;
> > > +
> > > +	(void)delete_all(ctx);
> > > +
> > > +	lock(ctx);
> > > +	pthread_cleanup_push(unlock, ctx);
> > > +	vector_free(ctx->mpvec);
> > > +	pthread_cleanup_pop(1);
> > > +	pthread_mutex_destroy(&ctx->mutex);
> > > +
> > > +	free(ctx);
> > > +}
> > 
> > Would you mind either removing the locking, or adding a comment
> > explaining that it's not necessary here.  If you really did need to
> > lock
> > ctx in order guard against someone accessing ctx->mpvec in cleanup(),
> > then not setting it to NULL after its freed, and immediately freeing
> > ctx
> > afterwards would clearly be broken, so seeing the locking makes it
> > look
> > like this function is wrong.
> 
> I don't understand, sorry. I need to lock because some other entity may
> still be using ctx->mpvec when cleanup() is called, and I should wait
> until that other entity has released the lock before I free it.

Who else could be using ctx->mpvec?  You only call cleanup on code paths
through init_foreign and cleanup_foreign.  There are no seperate threads
running in parallel in multipath, and in multipathd, you call
init_foreign before any other threads except the log writer thread is
created, and call cleanup_foreign after all the main threads except for
the log writer thread have been waited for? I admit, there could be a
rogue checker or prio thread that has been cancelled, but still not
returned, but those don't touch the foreign ctx code. If I'm missing
something, or you want to make sure that this code is future-proofed,
against possible future threads, you need some ref counting. Otherwise,
you could get into a situation where the thread doing the cleanup locks
the ctx->mutex and then another thread blocks on it. When the cleanup
thread drops the mutex and frees ctx, the other thread will grab a lock
to freed memory.

> I'm
> also pretty sure that checkers such as coverity would complain if I
> free a structure here without locking which I access only under the
> lock in other places.

Yeah. That's why I said you could just add a comment.
 
> I agree, though, that I should nullify the data and add checks in the
> other functions. I'll also add some locking in the foreign.c file,
> didn't occur to me before.

-Ben

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

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-03-02 17:04     ` Martin Wilck
@ 2018-03-02 18:42       ` Benjamin Marzinski
  0 siblings, 0 replies; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-02 18:42 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Fri, Mar 02, 2018 at 06:04:29PM +0100, Martin Wilck wrote:
> On Wed, 2018-02-28 at 23:13 -0600, Benjamin Marzinski wrote:
> > On Tue, Feb 20, 2018 at 02:26:57PM +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.
> > > 
> > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > ---
> > >  libmultipath/discovery.c  |  4 +++-
> > >  multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++-
> > > ----
> > >  multipathd/main.c         | 43
> > > ++++++++++++++++++++++++++++++++++++++++---
> > >  3 files changed, 77 insertions(+), 9 deletions(-)
> > > 
> > > diff --git a/multipathd/main.c b/multipathd/main.c
> > > index b900bb3ec2e3..e1d98861a841 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
> > > @@ -699,6 +700,15 @@ rescan:
> > >  		mpp->action = ACT_RELOAD;
> > >  		extract_hwe_from_path(mpp);
> > >  	} else {
> > > +		switch (add_foreign(pp->udev)) {
> > 
> > There's a rather convoluted issue here. This function will eventually
> > call _find_slaves() in the nvme code, which calls glob(), which isn't
> > strictly multithreading safe for a number of reasons. The only one
> > that
> > effects multipathd is its use of SIGALRM. Now assuming signal
> > processing
> > worked correctly in multipathd (it doesn't. commit 534ec4c broke it.
> > I'm
> > planning on fixing that shortly) there would still be a problem,
> > because
> > of the strict_timing option.  strict_timing calls setitimer(), which
> > sets an alarm in checkerloop, without any locking.  strict_timing
> > also
> > messes with any call to lock_file(). lock_file() and _find_slaves()
> > will
> > never interfere with eachother, since both are only called with the
> > vecs
> > lock held (I think. See below). strict_timing probably needs to get
> > reimplemented using nanosleep() or some other non-signal method, so
> > that
> > there aren't two threads setting alarms and waiting for SIGARLM at
> > the
> > same time.
> 
> Thanks for spotting this. It was lazyness on my side to use glob(). I
> will reimplement this using safer, more elementary functions. 

Sure. But lock_file() already needs this fixed to work correctly, and
once it is, I don't see a problem calling glob() here.
 
> > 
> > > +		case FOREIGN_CLAIMED:
> > > +		case FOREIGN_OK:
> > > +			orphan_path(pp, "claimed by foreign
> > > library");
> > > +			return 0;
> > > +		default:
> > > +			break;
> > 
> > Is there a purpose to this break?
> 
> I thought this was common style. You find it the kernel's CodingStyle
> document, too. I have no issues with removing it if you insist.

I didn't realize that. I'm fine with keeping it. It's not confusing. I
just thought it was an accident.

> > > 	conf = get_multipath_config();
> > >  	disable_changed_wwids = conf->disable_changed_wwids;
> > >  	put_multipath_config(conf);
> > > @@ -1122,8 +1149,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;
> > > +		}
> > 
> > I'm confused. Should foreign maps ever have uev->kernel set to "dm-"?
> 
> Although I don't see a likely candidate, I didn't want to exclude it in
> general.
> 
> > If this is correct, these calls probably need to get called with the
> > vecs lock held, otherwise they can interfere with calls to
> > lock_file().
> 
> Please explain. These devices are ignored by multipath-tools, because
> !uevent_is_mpath(uev), so they won't be part of any of their data
> structures. And lock_file() is only about fcntl, what does it have to
> do with this code? 

add_foreign will eventually call glob().  Like I said above, as long as
all the functions that use SIGALRM are restricted from being called at
the same time, they can't mess with each other's timeout, and everything
is fine. But if you call add_foreign here without holding the vecs lock,
then there would be nothing to keep it and lock_file() from being called
at the same time. This is yet another example of the headache involved
in removing the vecs lock.  It is protecting a lot of stuff that's
really easy to overlook (I'm not saying that's a good thing.. Just that
it's a thing).

-Ben

> Regards,
> 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)

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

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-03-01  5:13   ` Benjamin Marzinski
  2018-03-02 17:04     ` Martin Wilck
@ 2018-03-02 19:19     ` Martin Wilck
  2018-03-02 20:00       ` Benjamin Marzinski
  2018-03-02 21:00     ` [RFC PATCH 19/20] multipathd: use foreign API Bart Van Assche
  2 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 19:19 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Wed, 2018-02-28 at 23:13 -0600, Benjamin Marzinski wrote:
> 
> effects multipathd is its use of SIGALRM. Now assuming signal
> processing
> worked correctly in multipathd (it doesn't. commit 534ec4c broke it.
> I'm
> planning on fixing that shortly)

Details about this breakage, and your idea how to fix it, would be
highly appreciated.

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] 63+ messages in thread

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-03-02 19:19     ` Martin Wilck
@ 2018-03-02 20:00       ` Benjamin Marzinski
  2018-03-02 21:18         ` [PATCH] multipathd: fix inverted signal blocking logic Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-02 20:00 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Bart Van Assche, dm-devel

On Fri, Mar 02, 2018 at 08:19:39PM +0100, Martin Wilck wrote:
> On Wed, 2018-02-28 at 23:13 -0600, Benjamin Marzinski wrote:
> > 
> > effects multipathd is its use of SIGALRM. Now assuming signal
> > processing
> > worked correctly in multipathd (it doesn't. commit 534ec4c broke it.
> > I'm
> > planning on fixing that shortly)
> 
> Details about this breakage, and your idea how to fix it, would be
> highly appreciated.

I plan on fixing the issue using exactly the method that commit 534ec4c
says it is using. :) I cleaned up the signal handling years ago with
commit 5ee9f71, which blocked all the then-used signals for all threads
except uxlsnr, which is who calls handle_signals. Other threads
unblocked signals only as necessary. I'm not sure what issue caused Bart
to write 534ec4c. Perhaps an earlier commit actually broke the signal
handling, and this was just the commit that git blame pointed to.  But
in any case, after commit 534ec4c, we are only blocking SIGUSR2 on all
threads, which is the only signal we don't need to block.  This means
that, for instance, we have no idea which thread a SIGALRM is going to,
because any of them could receive it.  It is safe to unblock SIGUSR2 on
multiple threads at once, since (I hope) the only things that send it
are stop_io_err_stat_thread() and stop_waiter_thread(), and both of
those send it via pthread_kill, which will make sure it goes to the
proper thread.

-Ben

> 
> 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)

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

* Re: [RFC PATCH 19/20] multipathd: use foreign API
  2018-03-01  5:13   ` Benjamin Marzinski
  2018-03-02 17:04     ` Martin Wilck
  2018-03-02 19:19     ` Martin Wilck
@ 2018-03-02 21:00     ` Bart Van Assche
  2 siblings, 0 replies; 63+ messages in thread
From: Bart Van Assche @ 2018-03-02 21:00 UTC (permalink / raw)
  To: bmarzins, mwilck; +Cc: dm-devel

On Wed, 2018-02-28 at 23:13 -0600, Benjamin Marzinski wrote:
> Now assuming signal processing worked correctly in multipathd (it doesn't.
> commit 534ec4c broke it. I'm planning on fixing that shortly) there would
> still be a problem, because of the strict_timing option.

Although I'm not convinced that there is anything wrong with commit 534ec4c:
if you want to change signal handling in multipathd please retest multipathd
with Valgrind. Although Valgrind's signal handling is POSIX compliant it
handles signal delivery different than the Linux kernel.

Bart.

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

* [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 20:00       ` Benjamin Marzinski
@ 2018-03-02 21:18         ` Martin Wilck
  2018-03-02 21:35           ` Bart Van Assche
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 21:18 UTC (permalink / raw)
  To: Benjamin Marzinski, Bart Van Assche; +Cc: dm-devel

On Fri, 2018-03-02 at 14:00 -0600, Benjamin Marzinski wrote:

> But
> in any case, after commit 534ec4c, we are only blocking SIGUSR2 on
> all
> threads, which is the only signal we don't need to block.  This means

I can see what you mean. Better like this, maybe?

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
occasional SIGALRM. The current logic does exactly the opposite, it blocks
termination signals in SIGPOLL and allows multipathd to be killed e.g.
by SIGALRM.

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

Fixes: 534ec4c "multipathd: Ensure that SIGINT, SIGTERM, SIGHUP and SIGUSR1
are delivered to the uxsock thread"

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

diff --git a/multipathd/main.c b/multipathd/main.c
index 61739ac6ea59..85ee9b713d75 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2270,10 +2270,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] 63+ messages in thread

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 21:18         ` [PATCH] multipathd: fix inverted signal blocking logic Martin Wilck
@ 2018-03-02 21:35           ` Bart Van Assche
  2018-03-02 22:15             ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Bart Van Assche @ 2018-03-02 21:35 UTC (permalink / raw)
  To: bmarzins, mwilck; +Cc: dm-devel

On Fri, 2018-03-02 at 22:18 +0100, Martin Wilck wrote:
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 61739ac6ea59..85ee9b713d75 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -2270,10 +2270,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);

The modified code was introduced by commit 90dd424afa65 ("multipathd:
fix SIGUSR2 handling"). This change looks fine to me.

> 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;

This change looks more complicated to me than necessary. Have you considered
to pass an empty signal set as the fourth ppoll() argument?

Thanks,

Bart.

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

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 21:35           ` Bart Van Assche
@ 2018-03-02 22:15             ` Martin Wilck
  2018-03-02 22:23               ` Bart Van Assche
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 22:15 UTC (permalink / raw)
  To: Bart Van Assche, bmarzins; +Cc: dm-devel

On Fri, 2018-03-02 at 21:35 +0000, Bart Van Assche wrote:
> On Fri, 2018-03-02 at 22:18 +0100, Martin Wilck wrote:
> > diff --git a/multipathd/main.c b/multipathd/main.c
> > index 61739ac6ea59..85ee9b713d75 100644
> > --- a/multipathd/main.c
> > +++ b/multipathd/main.c
> > @@ -2270,10 +2270,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);
> 
> The modified code was introduced by commit 90dd424afa65 ("multipathd:
> fix SIGUSR2 handling"). This change looks fine to me.
> 
> > 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;
> 
> This change looks more complicated to me than necessary. Have you
> considered
> to pass an empty signal set as the fourth ppoll() argument?

An empty set would mean that no signal is blocked during ppoll().
Therefore e.g. SIGALRM would terminate multipathd if it arrives
during the ppoll (no handler set, and default action is "Term").

Regards,
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] 63+ messages in thread

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 22:15             ` Martin Wilck
@ 2018-03-02 22:23               ` Bart Van Assche
  2018-03-02 23:16                 ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Bart Van Assche @ 2018-03-02 22:23 UTC (permalink / raw)
  To: bmarzins, mwilck; +Cc: dm-devel

On Fri, 2018-03-02 at 23:15 +0100, Martin Wilck wrote:
> On Fri, 2018-03-02 at 21:35 +0000, Bart Van Assche wrote:
> > This change looks more complicated to me than necessary. Have you
> > considered
> > to pass an empty signal set as the fourth ppoll() argument?
> 
> An empty set would mean that no signal is blocked during ppoll().
> Therefore e.g. SIGALRM would terminate multipathd if it arrives
> during the ppoll (no handler set, and default action is "Term").

Have you considered to only block SIGALRM while ppoll() is in progress?

Thanks,

Bart.

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

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 22:23               ` Bart Van Assche
@ 2018-03-02 23:16                 ` Martin Wilck
  2018-03-02 23:27                   ` Bart Van Assche
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-02 23:16 UTC (permalink / raw)
  To: Bart Van Assche, bmarzins; +Cc: dm-devel

On Fri, 2018-03-02 at 22:23 +0000, Bart Van Assche wrote:
> On Fri, 2018-03-02 at 23:15 +0100, Martin Wilck wrote:
> > On Fri, 2018-03-02 at 21:35 +0000, Bart Van Assche wrote:
> > > This change looks more complicated to me than necessary. Have you
> > > considered
> > > to pass an empty signal set as the fourth ppoll() argument?
> > 
> > An empty set would mean that no signal is blocked during ppoll().
> > Therefore e.g. SIGALRM would terminate multipathd if it arrives
> > during the ppoll (no handler set, and default action is "Term").
> 
> Have you considered to only block SIGALRM while ppoll() is in
> progress?

Why should we? The same reasoning applies to other signals such as e.g.
SIGUSR2. We need to block all signals except those that we can handle.

Regards,
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] 63+ messages in thread

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 23:16                 ` Martin Wilck
@ 2018-03-02 23:27                   ` Bart Van Assche
  2018-03-03  0:31                     ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Bart Van Assche @ 2018-03-02 23:27 UTC (permalink / raw)
  To: bmarzins, mwilck; +Cc: dm-devel

On Sat, 2018-03-03 at 00:16 +0100, Martin Wilck wrote:
> On Fri, 2018-03-02 at 22:23 +0000, Bart Van Assche wrote:
> > On Fri, 2018-03-02 at 23:15 +0100, Martin Wilck wrote:
> > > On Fri, 2018-03-02 at 21:35 +0000, Bart Van Assche wrote:
> > > > This change looks more complicated to me than necessary. Have you
> > > > considered
> > > > to pass an empty signal set as the fourth ppoll() argument?
> > > 
> > > An empty set would mean that no signal is blocked during ppoll().
> > > Therefore e.g. SIGALRM would terminate multipathd if it arrives
> > > during the ppoll (no handler set, and default action is "Term").
> > 
> > Have you considered to only block SIGALRM while ppoll() is in
> > progress?
> 
> Why should we? The same reasoning applies to other signals such as e.g.
> SIGUSR2. We need to block all signals except those that we can handle.

I see two reasons:
- All signals that are delivered to the multipathd process except SIGALRM
  should interrupt ppoll(). SIGPIPE is delivered to the thread that caused
  that signal to be raised. SIGUSR2 is sent to a specific thread. Hence
  neither SIGPIPE nor SIGUSR2 will ever be delivered to the thread that
  calls ppoll().
- Asking ppoll() to block all signals is weird because some signals, e.g.
  SIGKILL and SIGSTOP, cannot be blocked.

Bart.

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

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-02 23:27                   ` Bart Van Assche
@ 2018-03-03  0:31                     ` Martin Wilck
  2018-03-05 16:27                       ` Bart Van Assche
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-03  0:31 UTC (permalink / raw)
  To: Bart Van Assche, bmarzins; +Cc: dm-devel

On Fri, 2018-03-02 at 23:27 +0000, Bart Van Assche wrote:
> On Sat, 2018-03-03 at 00:16 +0100, Martin Wilck wrote:
> > On Fri, 2018-03-02 at 22:23 +0000, Bart Van Assche wrote:
> > > On Fri, 2018-03-02 at 23:15 +0100, Martin Wilck wrote:
> > > > On Fri, 2018-03-02 at 21:35 +0000, Bart Van Assche wrote:
> > > > > This change looks more complicated to me than necessary. Have
> > > > > you
> > > > > considered
> > > > > to pass an empty signal set as the fourth ppoll() argument?
> > > > 
> > > > An empty set would mean that no signal is blocked during
> > > > ppoll().
> > > > Therefore e.g. SIGALRM would terminate multipathd if it arrives
> > > > during the ppoll (no handler set, and default action is
> > > > "Term").
> > > 
> > > Have you considered to only block SIGALRM while ppoll() is in
> > > progress?
> > 
> > Why should we? The same reasoning applies to other signals such as
> > e.g.
> > SIGUSR2. We need to block all signals except those that we can
> > handle.
> 
> I see two reasons:
> - All signals that are delivered to the multipathd process except
> SIGALRM
>   should interrupt ppoll(). SIGPIPE is delivered to the thread that
> caused
>   that signal to be raised. SIGUSR2 is sent to a specific thread.
> Hence
>   neither SIGPIPE nor SIGUSR2 will ever be delivered to the thread
> that
>   calls ppoll().

So, there's no reason not to block them, right? Is it expected behavior
that a user running 'kill -USR2 $(pidof multipathd)' terminates the
process? Why do you think these signals should interrupt ppoll()
although the uxlsnr can't can't handle them? Isn't it sufficient that
they're handled by the threads that are meant to do that?

IMO the idea of ppoll() is to specify a set of signals the calling
thread is interested in, and that's precisely the set of signals
handle_signals() can deal with.

I'm rather neutral about SIGPIPE, we can add a sigdelset(&set, SIGPIPE)
if you insist (multipathd will die anyway), but clearing SIGUSR2 in the
uxlsnr would be wrong IMO, as it's dedicated to the waiter thread.

> - Asking ppoll() to block all signals is weird because some signals,
> e.g.
>   SIGKILL and SIGSTOP, cannot be blocked.

And the kernel makes sure that doesn't happen. So I can add
sigdelset(&set, SIGKILL) bit it's kind of pointless.

Martin

> 
> Bart.

-- 
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] 63+ messages in thread

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-03  0:31                     ` Martin Wilck
@ 2018-03-05 16:27                       ` Bart Van Assche
  2018-03-05 17:28                         ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Bart Van Assche @ 2018-03-05 16:27 UTC (permalink / raw)
  To: bmarzins, mwilck; +Cc: dm-devel

On Sat, 2018-03-03 at 01:31 +0100, Martin Wilck wrote:
> So, there's no reason not to block them, right? Is it expected behavior
> that a user running 'kill -USR2 $(pidof multipathd)' terminates the
> process? Why do you think these signals should interrupt ppoll()
> although the uxlsnr can't can't handle them? Isn't it sufficient that
> they're handled by the threads that are meant to do that?

Blocking all signals except the ones for which we installed a handler sounds
weird to me. I think users expect daemons to process signals instead of
blocking all but a specific set of signals. This is a rather philosophical
argument and not an argument of which I think that it is strong enough to
prevent this patch of being integrated in the upstream multipath-tools
repository.

Bart.

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

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-05 16:27                       ` Bart Van Assche
@ 2018-03-05 17:28                         ` Martin Wilck
  2018-03-06  0:46                           ` Benjamin Marzinski
  0 siblings, 1 reply; 63+ messages in thread
From: Martin Wilck @ 2018-03-05 17:28 UTC (permalink / raw)
  To: Bart Van Assche, bmarzins; +Cc: dm-devel

Hello Bart,

On Mon, 2018-03-05 at 16:27 +0000, Bart Van Assche wrote:
> On Sat, 2018-03-03 at 01:31 +0100, Martin Wilck wrote:
> > So, there's no reason not to block them, right? Is it expected
> > behavior
> > that a user running 'kill -USR2 $(pidof multipathd)' terminates the
> > process? Why do you think these signals should interrupt ppoll()
> > although the uxlsnr can't can't handle them? Isn't it sufficient
> > that
> > they're handled by the threads that are meant to do that?
> 
> Blocking all signals except the ones for which we installed a handler
> sounds
> weird to me. I think users expect daemons to process signals instead
> of
> blocking all but a specific set of signals. This is a rather
> philosophical
> argument and not an argument of which I think that it is strong
> enough to
> prevent this patch of being integrated in the upstream multipath-
> tools
> repository.

Thank you. Meanwhile, I found that this patch requires a change in the
"marginal paths" code. I'll post an official patch as update.

Regarding the philosophical discussion, may I remind you of your own
words from 534ec4c?

    The POSIX standard mentions that the only way to guarantee that
    signals are delivered to a specific thread is:
     * Block all signals before the first pthread_create() call.
     * Unblock signals from the thread that should receive signals.

If we unblock signals with a default disposition of "Term" for which we
have no handler, stray signals caught would terminate multipathd. I
don't think that's what we want. Of course we must react on
SIGINT/SIGTERM/SIGHUP in the way the user expects us to, but
terminating on other signals would be wrong.

Let's see if others have to say anything about this.

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] 63+ messages in thread

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-05 17:28                         ` Martin Wilck
@ 2018-03-06  0:46                           ` Benjamin Marzinski
  2018-03-06  8:48                             ` Martin Wilck
  0 siblings, 1 reply; 63+ messages in thread
From: Benjamin Marzinski @ 2018-03-06  0:46 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Bart Van Assche, dm-devel

On Mon, Mar 05, 2018 at 06:28:05PM +0100, Martin Wilck wrote:
> Hello Bart,
> 
> On Mon, 2018-03-05 at 16:27 +0000, Bart Van Assche wrote:
> > On Sat, 2018-03-03 at 01:31 +0100, Martin Wilck wrote:
> > > So, there's no reason not to block them, right? Is it expected
> > > behavior
> > > that a user running 'kill -USR2 $(pidof multipathd)' terminates the
> > > process? Why do you think these signals should interrupt ppoll()
> > > although the uxlsnr can't can't handle them? Isn't it sufficient
> > > that
> > > they're handled by the threads that are meant to do that?
> > 
> > Blocking all signals except the ones for which we installed a handler
> > sounds
> > weird to me. I think users expect daemons to process signals instead
> > of
> > blocking all but a specific set of signals. This is a rather
> > philosophical
> > argument and not an argument of which I think that it is strong
> > enough to
> > prevent this patch of being integrated in the upstream multipath-
> > tools
> > repository.
> 
> Thank you. Meanwhile, I found that this patch requires a change in the
> "marginal paths" code. I'll post an official patch as update.
> 
> Regarding the philosophical discussion, may I remind you of your own
> words from 534ec4c?
> 
>     The POSIX standard mentions that the only way to guarantee that
>     signals are delivered to a specific thread is:
>      * Block all signals before the first pthread_create() call.
>      * Unblock signals from the thread that should receive signals.
> 
> If we unblock signals with a default disposition of "Term" for which we
> have no handler, stray signals caught would terminate multipathd. I
> don't think that's what we want. Of course we must react on
> SIGINT/SIGTERM/SIGHUP in the way the user expects us to, but
> terminating on other signals would be wrong.
> 
> Let's see if others have to say anything about this.

This is prety close to what I had in mind. The only things missing, that
I noticed when I was looking at multipathd's signal handling, is dealing
with SIGUSR2 in io_err_stat.c, which it sounds like you have already
spotted, and changing the calls to setitimer and usleep outside of the
vecs lock to use nanosleep, so they don't interact with SIGALRM.

I'll send a patch based on yours, to fix these.

-Ben

> 
> 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)

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

* Re: [PATCH] multipathd: fix inverted signal blocking logic
  2018-03-06  0:46                           ` Benjamin Marzinski
@ 2018-03-06  8:48                             ` Martin Wilck
  0 siblings, 0 replies; 63+ messages in thread
From: Martin Wilck @ 2018-03-06  8:48 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Bart Van Assche, dm-devel

On Mon, 2018-03-05 at 18:46 -0600, Benjamin Marzinski wrote:
> 
> This is prety close to what I had in mind. The only things missing,
> that
> I noticed when I was looking at multipathd's signal handling, is
> dealing
> with SIGUSR2 in io_err_stat.c, which it sounds like you have already
> spotted, and changing the calls to setitimer and usleep outside of
> the
> vecs lock to use nanosleep, so they don't interact with SIGALRM.
> 
> I'll send a patch based on yours, to fix these.

I'm curious to see what you come up with. I've something on my
workbench which seems to work well but needs some cleanup. The idea is
to have a dedicated "alarm dispatcher" thread that deals with kernel
timers exclusively, and forwards expiry events to the threads that have
asked for it. The dispatcher maintains a list of active alarms and sets
a kernel timer to the expiry time of the first alarm in the list.

Cheers,
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] 63+ messages in thread

end of thread, other threads:[~2018-03-06  8:48 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-20 13:26 [RFC PATCH 00/20] "Foreign" NVMe support for multipath-tools Martin Wilck
2018-02-20 13:26 ` [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries Martin Wilck
2018-03-01  5:35   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers" Martin Wilck
2018-03-01  5:36   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c Martin Wilck
2018-03-01  5:36   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods Martin Wilck
2018-03-01  5:37   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 05/20] libmultipath: don't update path groups when printing Martin Wilck
2018-02-28 23:40   ` Benjamin Marzinski
2018-03-02 13:59     ` Martin Wilck
2018-03-02 15:31       ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate Martin Wilck
2018-03-01  5:37   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 07/20] libmultipath: use "const" in devmapper code Martin Wilck
2018-03-01  5:39   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual Martin Wilck
2018-03-01  5:39   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual Martin Wilck
2018-03-01  5:59   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 10/20] libmultipath: add vector_free_const() Martin Wilck
2018-03-01  6:00   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 11/20] libmultipath: add vector_convert() Martin Wilck
2018-03-01  6:02   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 12/20] libmultipath: "generic multipath" interface Martin Wilck
2018-02-28 23:47   ` Benjamin Marzinski
2018-03-01  8:51     ` Martin Wilck
2018-02-20 13:26 ` [RFC PATCH 13/20] libmultipath: print: convert API to generic data type Martin Wilck
2018-02-28 23:55   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout() Martin Wilck
2018-03-01  6:03   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 15/20] libmultipath: API for foreign multipath handling Martin Wilck
2018-03-01  3:01   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard Martin Wilck
2018-03-01  6:04   ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library Martin Wilck
2018-03-01  3:14   ` Benjamin Marzinski
2018-03-02 16:04     ` Martin Wilck
2018-03-02 18:30       ` Benjamin Marzinski
2018-02-20 13:26 ` [RFC PATCH 18/20] multipath: use foreign API Martin Wilck
2018-03-01  3:55   ` Benjamin Marzinski
2018-03-02 16:36     ` Martin Wilck
2018-02-20 13:26 ` [RFC PATCH 19/20] multipathd: " Martin Wilck
2018-03-01  5:13   ` Benjamin Marzinski
2018-03-02 17:04     ` Martin Wilck
2018-03-02 18:42       ` Benjamin Marzinski
2018-03-02 19:19     ` Martin Wilck
2018-03-02 20:00       ` Benjamin Marzinski
2018-03-02 21:18         ` [PATCH] multipathd: fix inverted signal blocking logic Martin Wilck
2018-03-02 21:35           ` Bart Van Assche
2018-03-02 22:15             ` Martin Wilck
2018-03-02 22:23               ` Bart Van Assche
2018-03-02 23:16                 ` Martin Wilck
2018-03-02 23:27                   ` Bart Van Assche
2018-03-03  0:31                     ` Martin Wilck
2018-03-05 16:27                       ` Bart Van Assche
2018-03-05 17:28                         ` Martin Wilck
2018-03-06  0:46                           ` Benjamin Marzinski
2018-03-06  8:48                             ` Martin Wilck
2018-03-02 21:00     ` [RFC PATCH 19/20] multipathd: use foreign API Bart Van Assche
2018-02-20 13:26 ` [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display Martin Wilck
2018-03-01  5:19   ` Benjamin Marzinski

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.