"Foreign" NVMe support for multipath-tools
Subsystems (2)
cover "Foreign" NVMe support for multipath-tools
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
Signature · 1 line
2.16.1
RFC PATCH 1/20 multipath(d)/Makefile: add explicit dependency on libraries
Otherwise the binaries won't be re-linked if the libraries change.
--- multipath/Makefile | 2 +- multipathd/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
multipath/Makefile +1 -1
@@ -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
multipathd/Makefile +1 -1
@@ -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
Signature · 1 line
2.16.1
Re: [RFC PATCH 01/20] multipath(d)/Makefile: add explicit dependency on libraries
Quoted 2 lines · Martin Wilck
Otherwise the binaries won't be re-linked if the libraries change.
Quoted 34 lines
Signed-off-by Martin Wilck <[email protected]>--- multipath/Makefile | 2 +- multipathd/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)multipath/Makefile +1
-1@@ -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.gzmultipathd/Makefile +1
-1@@ -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.gzSignature · 1 line
2.16.1
RFC PATCH 2/20 libmultipath: remove unused "stdout helpers"
In reply to Martin Wilck--- libmultipath/print.c | 26 -------------------------- libmultipath/print.h | 5 ----- 2 files changed, 31 deletions(-)
libmultipath/print.c +0 -26
@@ -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 );
libmultipath/print.h +0 -5
@@ -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);
Signature · 1 line
2.16.1
Re: [RFC PATCH 02/20] libmultipath: remove unused "stdout helpers"
Quoted 1 line · Martin Wilck
Signed-off-by Martin Wilck <[email protected]>
Quoted 59 lines
--- libmultipath/print.c | 26 -------------------------- libmultipath/print.h | 5 ----- 2 files changed, 31 deletions(-)libmultipath/print.c +0
-26@@ -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 );libmultipath/print.h +0
-5@@ -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);Signature · 1 line
2.16.1
RFC PATCH 3/20 libmultipath: get rid of selector "hack" in print.c
In reply to Martin WilckBy properly linking the path groups with their parent multipath, we don't need this "hack" any more.
--- 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(-)
libmultipath/dmparser.c +1 -1
@@ -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);
libmultipath/pgpolicies.c +6 -5
@@ -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; }
libmultipath/print.c +3 -3
@@ -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;
libmultipath/structs.c +10 -0
@@ -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) {
libmultipath/structs.h +2 -1
@@ -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);
Signature · 1 line
2.16.1
Re: [RFC PATCH 03/20] libmultipath: get rid of selector "hack" in print.c
Quoted 3 lines · Martin Wilck
By properly linking the path groups with their parent multipath, we don't need this "hack" any more.
Quoted 148 lines
Signed-off-by Martin Wilck <[email protected]>--- 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(-)libmultipath/dmparser.c +1
-1@@ -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);libmultipath/pgpolicies.c +6
-5@@ -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; }libmultipath/print.c +3
-3@@ -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;libmultipath/structs.c +10
-0@@ -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) {libmultipath/structs.h +2
-1@@ -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);Signature · 1 line
2.16.1
RFC PATCH 4/20 libmultipath: parser: use call-by-value for "snprint" methods
In reply to Martin WilckConvert 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.
--- libmultipath/dict.c | 206 ++++++++++++++++++++++++-------------------------- libmultipath/parser.c | 9 ++- libmultipath/parser.h | 12 ++- 3 files changed, 112 insertions(+), 115 deletions(-)
libmultipath/dict.c +98 -108
@@ -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 ; }
libmultipath/parser.c +6 -3
@@ -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 ;
libmultipath/parser.h +8 -4
@@ -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
Signature · 1 line
2.16.1
Re: [RFC PATCH 04/20] libmultipath: parser: use call-by-value for "snprint" methods
Quoted 6 lines · 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.
Quoted 552 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/dict.c | 206 ++++++++++++++++++++++++-------------------------- libmultipath/parser.c | 9 ++- libmultipath/parser.h | 12 ++- 3 files changed, 112 insertions(+), 115 deletions(-)libmultipath/dict.c +98
-108@@ -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 ; }libmultipath/parser.c +6
-3@@ -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 ;libmultipath/parser.h +8
-4@@ -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 Signature · 1 line
2.16.1
RFC PATCH 5/20 libmultipath: don't update path groups when printing
In reply to Martin WilckUpdating 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.
--- libmultipath/print.c | 7 ------- 1 file changed, 7 deletions(-)
libmultipath/print.c +0 -7
@@ -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); }
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
Quoted 11 lines · 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.ccode 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
Quoted 26 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/print.c | 7 ------- 1 file changed, 7 deletions(-)libmultipath/print.c +0
-7@@ -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); }Signature · 1 line
2.16.1
Re: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
Quoted 32 lines · Benjamin Marzinski
Quoted 13 lines · 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.Quoted 5 lines
Moreover, correctness forbids changing properties so deeply in a code path
that's supposed to print them only. Finally, this piece of code prevents theprint.ccode 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.[...]
Quoted 7 lines
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
Signature · 3 lines
Dr. Martin Wilck <[email protected]>, 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 <[email protected]>
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).
--- multipathd/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
multipathd/main.c +6 -2
@@ -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 ;
Signature · 1 line
2.16.1
Re: [RFC PATCH 05/20] libmultipath: don't update path groups when printing
Quoted 29 lines · Martin Wilck
Quoted 9 lines · Benjamin Marzinski
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
reinstatedNow it calls either
2a.
update_path_groups()(forgroup_by_prioand failback immediate)
(->reload_map()->setup_map()->select_path_group()->path_group_prio_update()), or2b.
need_switch_pathgroup()(otherwise)So all we need to make sure is that
need_switch_pathgroup()callsselect_path_group(). It does that already, except for the "failback manual" case.
Quoted 6 lines
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_udevis set, either when the event arrives or the wait times out, we'll callreconfigure()which makes sure all priorities are correct].
looks good.
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.
Quoted 54 lines
Best,
MartinSignature · 18 lines
Dr. Martin Wilck <[email protected]>, 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 <[email protected]> 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 <[email protected]> --- multipathd/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)multipathd/main.c +6
-2@@ -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 ;Signature · 1 line
2.16.1
RFC PATCH 6/20 libmultipath/print: use "const" where appropriate
In reply to Martin WilckConvert 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.
--- 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(-)
libmultipath/configure.h +0 -1
@@ -35,5 +35,4 @@ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int forcint 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);
libmultipath/discovery.c +3 -3
@@ -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 ];
libmultipath/discovery.h +4 -2
@@ -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,
libmultipath/print.c +67 -66
488 lines not on this page · raw message
libmultipath/print.h +21 -20
71 lines not on this page · raw message
Signature · 1 line
2.16.1
Re: [RFC PATCH 06/20] libmultipath/print: use "const" where appropriate
Quoted 4 lines · Martin Wilck
Convert the
print.h/print.ccode to use "const" qualifiers properly. This is generally considered good programming practice, and the printing code shouldn't change any objects anyway.
Quoted 678 lines
Signed-off-by Martin Wilck <[email protected]>--- 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(-)libmultipath/configure.h +0
-1@@ -35,5 +35,4 @@ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int forcint 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);libmultipath/discovery.c +3
-3@@ -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 ];libmultipath/discovery.h +4
-2@@ -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,libmultipath/print.c +67
-66@@ -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;libmultipath/print.h +21
-20@@ -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);Signature · 1 line
2.16.1
RFC PATCH 7/20 libmultipath: use "const" in devmapper code
In reply to Martin WilckImprove use of "const" qualifiers in libmultipath's devmapper code.
--- libmultipath/devmapper.c | 32 ++++++++++++++++---------------- libmultipath/devmapper.h | 16 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-)
libmultipath/devmapper.c +16 -16
@@ -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)
libmultipath/devmapper.h +8 -8
@@ -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);
Signature · 1 line
2.16.1
Re: [RFC PATCH 07/20] libmultipath: use "const" in devmapper code
Quoted 2 lines · Martin Wilck
Improve use of "const" qualifiers in libmultipath's devmapper code.
Quoted 174 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/devmapper.c | 32 ++++++++++++++++---------------- libmultipath/devmapper.h | 16 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-)libmultipath/devmapper.c +16
-16@@ -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)libmultipath/devmapper.h +8
-8@@ -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);Signature · 1 line
2.16.1
RFC PATCH 8/20 libmultipath: fix compiler warnings for -Wcast-qual
In reply to Martin WilckFix the warnings that were caused by adding the -Wcast-qual compiler flag in the previous patch.
--- 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(-)
kpartx/devmapper.c +2 -1
@@ -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; }
libmpathcmd/mpath_cmd.c +1 -1
@@ -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; }
libmultipath/checkers/rbd.c +2 -2
@@ -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;
libmultipath/devmapper.c +2 -1
@@ -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)
libmultipath/discovery.c +6 -6
@@ -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' ;
libmultipath/list.h +2 -2
@@ -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) );})/*
libmultipath/memory.h +7 -1
@@ -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))
libmultipath/structs.c +1 -1
@@ -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;
libmultipath/structs.h +1 -1
@@ -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 );
libmultipath/uevent.c +3 -3
@@ -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
libmultipath/util.c +3 -3
@@ -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 ; }
multipathd/main.c +5 -5
@@ -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 ; }
Signature · 1 line
2.16.1
Re: [RFC PATCH 08/20] libmultipath: fix compiler warnings for -Wcast-qual
Quoted 3 lines · Martin Wilck
Fix the warnings that were caused by adding the -Wcast-qual compiler flag in the previous patch.
Quoted 293 lines
Signed-off-by Martin Wilck <[email protected]>--- 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(-)kpartx/devmapper.c +2
-1@@ -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; }libmpathcmd/mpath_cmd.c +1
-1@@ -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; }libmultipath/checkers/rbd.c +2
-2@@ -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;libmultipath/devmapper.c +2
-1@@ -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)libmultipath/discovery.c +6
-6@@ -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' ;libmultipath/list.h +2
-2@@ -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) );})/* libmultipath/memory.h +7
-1@@ -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))libmultipath/structs.c +1
-1@@ -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;libmultipath/structs.h +1
-1@@ -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 );libmultipath/uevent.c +3
-3@@ -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 libmultipath/util.c +3
-3@@ -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 ; }multipathd/main.c +5
-5@@ -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 ; }Signature · 1 line
2.16.1
RFC PATCH 9/20 multipath-tools: Makefile.inc: use -Werror=cast-qual
In reply to Martin WilckCasting "const" away is often an indicator for wrong code. Add a compiler flag to warn about such possible breakage.
--- Makefile.inc | 1 + 1 file changed, 1 insertion(+)
Makefile.inc +1 -0
@@ -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
Signature · 1 line
2.16.1
Re: [RFC PATCH 09/20] multipath-tools: Makefile.inc: use -Werror=cast-qual
Quoted 3 lines · Martin Wilck
Casting "const" away is often an indicator for wrong code. Add a compiler flag to warn about such possible breakage.
Quoted 19 lines
Signed-off-by Martin Wilck <[email protected]>--- Makefile.inc | 1 + 1 file changed, 1 insertion(+)Makefile.inc +1
-0@@ -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=4Signature · 1 line
2.16.1
RFC PATCH 10/20 libmultipath: add vector_free_const()
In reply to Martin Wilck... to dispose of constant vectors (const struct _vector*).
--- libmultipath/vector.h | 1 + 1 file changed, 1 insertion(+)
libmultipath/vector.h +1 -0
@@ -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);
Signature · 1 line
2.16.1
Re: [RFC PATCH 10/20] libmultipath: add vector_free_const()
Quoted 2 lines · Martin Wilck
... to dispose of constant vectors (const struct _vector*).
Quoted 19 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/vector.h | 1 + 1 file changed, 1 insertion(+)libmultipath/vector.h +1
-0@@ -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);Signature · 1 line
2.16.1
RFC PATCH 11/20 libmultipath: add vector_convert()
In reply to Martin WilckThis 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.
--- libmultipath/vector.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
libmultipath/vector.h +29 -0
@@ -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);
Signature · 1 line
2.16.1
Re: [RFC PATCH 11/20] libmultipath: add vector_convert()
Quoted 6 lines · 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.
Quoted 47 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/vector.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)libmultipath/vector.h +29
-0@@ -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);Signature · 1 line
2.16.1
RFC PATCH 12/20 libmultipath: "generic multipath" interface
In reply to Martin WilckThis 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.
--- 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
libmultipath/Makefile +1 -1
@@ -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)
libmultipath/dm-generic.c new file +70 -0
70 lines not on this page · raw message
libmultipath/dm-generic.h new file +41 -0
41 lines not on this page · raw message
libmultipath/generic.c new file +39 -0
@@ -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 ); +}
libmultipath/generic.h new file +136 -0
136 lines not on this page · raw message
libmultipath/list.h +4 -0
@@ -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) );})
libmultipath/print.c +34 -0
@@ -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) {
libmultipath/print.h +7 -0
@@ -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);
libmultipath/structs.c +4 -0
@@ -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; }
libmultipath/structs.h +4 -0
@@ -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 {
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 12/20] libmultipath: "generic multipath" interface
Quoted 10 lines · 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.
Quoted 8 lines
The patch also implements the interface for the internal
dm_multipathdata structure.The
style()method looks a bit exotic, but it's necessary becauseprint_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
Quoted 511 lines
Signed-off-by Martin Wilck <[email protected]>--- 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.hlibmultipath/Makefile +1
-1@@ -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)libmultipath/dm-generic.c new file +70
-0@@ -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, +};libmultipath/dm-generic.h new file +41
-0@@ -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 */ libmultipath/generic.c new file +39
-0@@ -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 ); +}libmultipath/generic.h new file +136
-0@@ -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 */ libmultipath/list.h +4
-0@@ -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) );})libmultipath/print.c +34
-0@@ -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) {libmultipath/print.h +7
-0@@ -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);libmultipath/structs.c +4
-0@@ -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; }libmultipath/structs.h +4
-0@@ -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 {Signature · 1 line
2.16.1
Re: [RFC PATCH 12/20] libmultipath: "generic multipath" interface
Quoted 8 lines · Benjamin Marzinski
I have one nit here.
print.hnow relies ondm-generic.h, since it usesdm_multipath_to_gen()in its defines. So shouldn't it simply includedm-generic.h, which would allowconfigure.c,main.c, andcli_handlers.c
to not includedm-generic.h, since they only need it because they includeprint.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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
RFC PATCH 13/20 libmultipath: print: convert API to generic data type
In reply to Martin WilckConvert 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.
--- 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(-)
libmultipath/configure.c +1 -0
@@ -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"
libmultipath/dm-generic.c +1 -1
@@ -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 = {
libmultipath/print.c +74 -42
213 lines not on this page · raw message
libmultipath/print.h +22 -6
@@ -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 */
multipath/main.c +1 -0
@@ -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"
multipathd/cli_handlers.c +1 -0
@@ -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>
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 13/20] libmultipath: print: convert API to generic data type
Quoted 193 lines · 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 <[email protected]>--- 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(-)libmultipath/configure.c +1
-0@@ -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" libmultipath/dm-generic.c +1
-1@@ -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 = {libmultipath/print.c +38
-21@@ -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);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);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);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: " );
libmultipath/print.c int snprint_multipath_topology(char *buff, int len, const struct multipath *mpp, · line 1059
Quoted 10 lines
libmultipath/print.c +3
-7- - 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 insnprint_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
Quoted 154 lines
libmultipath/print.c +33
-14if (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; }libmultipath/print.h +22
-6@@ -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 */ multipath/main.c +1
-0@@ -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" multipathd/cli_handlers.c +1
-0@@ -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> Signature · 1 line
2.16.1
RFC PATCH 14/20 libmultipath: print: use generic API for get_x_layout()
In reply to Martin WilckIntroduce 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.
--- libmultipath/print.c | 73 ++++++++++++++++++++++++++++++++++++++++------------ libmultipath/print.h | 8 ++++++ 2 files changed, 65 insertions(+), 16 deletions(-)
libmultipath/print.c +57 -16
@@ -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); } }
libmultipath/print.h +8 -0
@@ -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 *);
Signature · 1 line
2.16.1
Re: [RFC PATCH 14/20] libmultipath: print: use generic API for get_x_layout()
Quoted 8 lines · Martin Wilck
Introduce new functions
_get_path_layoutand_get_multipath_layoutusing 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_NOTallows calling theget_x_layoutfunction several times and determine the overall field width.
Quoted 133 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/print.c | 73 ++++++++++++++++++++++++++++++++++++++++------------ libmultipath/print.h | 8 ++++++ 2 files changed, 65 insertions(+), 16 deletions(-)libmultipath/print.c +57
-16@@ -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); } }libmultipath/print.h +8
-0@@ -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 *);Signature · 1 line
2.16.1
RFC PATCH 15/20 libmultipath: API for foreign multipath handling
In reply to Martin WilckAdd 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.
--- 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
libmultipath/Makefile +1 -1
@@ -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)
libmultipath/foreign.c new file +471 -0
471 lines not on this page · raw message
libmultipath/foreign.h new file +322 -0
322 lines not on this page · raw message
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 15/20] libmultipath: API for foreign multipath handling
Quoted 11 lines · 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.
Quoted 8 lines
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
Quoted 9 lines
Signed-off-by Martin Wilck <[email protected]>--- 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>
Quoted 142 lines
libmultipath/foreign.h new file +142
-0+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) +*
libmultipath/foreign.h line 194
Quoted 10 lines
libmultipath/foreign.h new file +10
-0+* @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
Quoted 130 lines
libmultipath/foreign.h new file +128
-0+ +/** +* init_foreign(dir) +* load and initialize foreign multipath libraries in dir (libforeign-*.so). +* @param dir: directory to search +* @returns: 0 on success, negative value on failure. +*/ +int init_foreign (const char *multipath_dir); + +/** +* cleanup_foreign(dir) +* cleanup and free all data structures owned by foreign libraries +*/ +void cleanup_foreign (void ); + +/** +* add_foreign(udev) +* check if a device belongs to any foreign library. +* calls add() for all known foreign libs, in the order registered, +* until the first one returns FOREIGN_CLAIMED or FOREIGN_OK. +* @param udev: udev device to check +* @returns: status code +* @retval FOREIGN_CLAIMED: newly claimed by a foreign lib +* @retval FOREIGN_OK: already claimed by a foreign lib +* @retval FOREIGN_IGNORED: ignored by all foreign libs +* @retval FOREIGN_ERR: an error occured +*/ +int add_foreign (struct udev_device *); + +/** +* change_foreign(udev) +* Notify foreign libraries of an udev CHANGE event +* @param udev: udev device to check +* @returns: status code (see change() method above). +*/ +int change_foreign (struct udev_device *); + +/** +* delete_foreign(udev) +* @param udev: udev device being removed +* @returns: status code (see remove() above) +*/ +int delete_foreign (struct udev_device *); + +/** +* delete_all_foreign() +* call delete_all() for all foreign libraries +* @returns: status code (see delete_all() above) +*/ +int delete_all_foreign (void ); + +/** +* check_foreign() +* call check() (see above) for all foreign libraries +*/ +void check_foreign (void ); + +/** +* foreign_path_layout() +* call this before printing paths, after get_path_layout(), to determine +* output field width. +*/ +void foreign_path_layout (void ); + +/** +* foreign_multipath_layout() +* call this before printing maps, after get_multipath_layout(), to determine +* output field width. +*/ +void foreign_multipath_layout (void ); + +/** +* snprint_foreign_topology(buf, len, verbosity); +* prints topology information from foreign libraries into buffer, +* '\0' - terminated. +* @param buf: output buffer +* @param len: size of output buffer +* @param verbosity: verbosity level +* @returns: number of printed characters excluding trailing '\0'. +*/ +int snprint_foreign_topology (char *buf,int len,int verbosity); + +/** +* snprint_foreign_paths(buf, len, style, pad); +* prints formatted path information from foreign libraries into buffer, +* '\0' - terminated. +* @param buf: output buffer +* @param len: size of output buffer +* @param style: format string +* @param pad: whether to pad field width +* @returns: number of printed characters excluding trailing '\0'. +*/ +int snprint_foreign_paths (char *buf,int len,const char *style,int pad); + +/** +* snprint_foreign_multipaths(buf, len, style, pad); +* prints formatted map information from foreign libraries into buffer, +* '\0' - terminated. +* @param buf: output buffer +* @param len: size of output buffer +* @param style: format string +* @param pad: whether to pad field width +* @returns: number of printed characters excluding trailing '\0'. +*/ +int snprint_foreign_multipaths (char *buf,int len, +const char *style,int pretty); + +/** +* print_foreign_topology(v) +* print foreign topology to stdout +* @param verbosity: verbosity level +*/ +void print_foreign_topology (int verbosity); + +/** +* is_claimed_by_foreign(ud) +* @param udev: udev device +* @returns: true iff device is (newly or already) claimed by a foreign lib +*/ +static inline bool +is_claimed_by_foreign (struct udev_device *ud) +{ +int rc =add_foreign (ud); + +return (rc ==FOREIGN_CLAIMED || rc ==FOREIGN_OK ); +} + +#endif /* _FOREIGN_H */ Signature · 1 line
2.16.1
RFC PATCH 16/20 libmultipath/print: add "%G - foreign" wildcard
In reply to Martin WilckThis adds a format field to identify foreign maps as such, and uses it in default-formatted topology output (generic_style()).
--- libmultipath/generic.c | 4 +++- libmultipath/print.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
libmultipath/generic.c +3 -1
@@ -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 ); }
libmultipath/print.c +14 -0
@@ -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} };
Signature · 1 line
2.16.1
Re: [RFC PATCH 16/20] libmultipath/print: add "%G - foreign" wildcard
Quoted 3 lines · Martin Wilck
This adds a format field to identify foreign maps as such, and uses it in default-formatted topology output (
generic_style()).
Quoted 69 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/generic.c | 4 +++- libmultipath/print.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)libmultipath/generic.c +3
-1@@ -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 ); }libmultipath/print.c +14
-0@@ -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} };Signature · 1 line
2.16.1
RFC PATCH 17/20 libmultipath/foreign: nvme foreign library
In reply to Martin WilckThis still contains stubs for path handling and checking, but it's functional for printing already.
--- 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
Makefile +1 -0
@@ -7,6 +7,7 @@ BUILDDIRS = \ libmultipath \ libmultipath/prioritizers \ libmultipath/checkers \ + libmultipath/foreign \ libmpathpersist \ multipath \ multipathd \
libmultipath/foreign/Makefile new file +30 -0
@@ -0,0 +1,30 @@ +# +# Copyright (C) 2003 Christophe Varoqui, <[email protected]> +# +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)
libmultipath/foreign/nvme.c new file +444 -0
444 lines not on this page · raw message
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
Quoted 108 lines · Martin Wilck
This still contains stubs for path handling and checking, but it's functional for printing already.
Signed-off-by Martin Wilck <[email protected]>--- 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.cMakefile +1
-0@@ -7,6 +7,7 @@ BUILDDIRS = \ libmultipath \ libmultipath/prioritizers \ libmultipath/checkers \ + libmultipath/foreign \ libmpathpersist \ multipath \ multipathd \libmultipath/foreign/Makefile new file +30
-0@@ -0,0 +1,30 @@ +# +# Copyright (C) 2003 Christophe Varoqui, <[email protected]> +# +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)libmultipath/foreign/nvme.c new file +42
-0@@ -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 */
libmultipath/foreign/nvme.c line 52
Quoted 10 lines
libmultipath/foreign/nvme.c new file +10
-0+#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
Quoted 174 lines
libmultipath/foreign/nvme.c new file +174
-0+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 ; +
libmultipath/foreign/nvme.c line 236
Quoted 10 lines
libmultipath/foreign/nvme.c new file +10
-0+ (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.
Quoted 49 lines
libmultipath/foreign/nvme.c new file +49
-0+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; +
libmultipath/foreign/nvme.c line 296
Quoted 10 lines
libmultipath/foreign/nvme.c new file +10
-0+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
Quoted 150 lines
libmultipath/foreign/nvme.c new file +148
-0+ 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), +};Signature · 1 line
2.16.1
Re: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
Quoted 22 lines · Benjamin Marzinski
Quoted 21 lines · Martin Wilck
This still contains stubs for path handling and checking, but it's functional
for printing already.Signed-off-by Martin Wilck <[email protected]>--- 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.clibmultipath/foreign/nvme.c new file +0
-0
Quoted 10 lines
libmultipath/foreign/nvme.c line 52
Quoted 6 lines
libmultipath/foreign/nvme.c new file +6
-0+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_devtypeare 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.
Quoted 18 lines
+
Quoted 5 lines
libmultipath/foreign/nvme.c new file +5
-0+void cleanup (struct context *ctx) +{ +if (ctx ==NULL ) +return ; +libmultipath/foreign/nvme.c line 236
Quoted 10 lines
libmultipath/foreign/nvme.c new file +10
-0+ (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
Quoted 8 lines
explaining that it's not necessary here. If you really did need to lock
ctx in order guard against someone accessingctx->mpvecincleanup(), 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.
Quoted 11 lines
Quoted 11 lines
libmultipath/foreign/nvme.c new file +11
-0+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 )
Quoted 8 lines
libmultipath/foreign/nvme.c line 296
Quoted 5 lines
libmultipath/foreign/nvme.c new file +5
-0+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->udevwill keep this device around.
See above.
Regards,
Martin
Quoted 166 lines
-Ben
Quoted 161 lines
libmultipath/foreign/nvme.c new file +26
-0+ 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",
libmultipath/foreign/nvme.c new file +1
-0+NUL L);
libmultipath/foreign/nvme.c new file +14
-0+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));libmultipath/foreign/nvme.c new file +11
-0+ +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)
libmultipath/foreign/nvme.c new file +36
-0+{ +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,
libmultipath/foreign/nvme.c new file +3
-0+ udev_device_get_sysname(ud)); + else if (rc != FOREIGN_IGNORED) + condlog(1, "%s: %s: retcode %d deleting map %s",
__func__,libmultipath/foreign/nvme.c new file +13
-0+ 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.
+ */libmultipath/foreign/nvme.c new file +7
-0+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)libmultipath/foreign/nvme.c new file +7
-0+{ +condlog (5 ,"%s called for \"%s\"" , __func__,THIS ); +/* NOP */ +} + +/* +* It's safe to pass our internal pointer, this is only used under the lock.
+ */libmultipath/foreign/nvme.c new file +7
-0+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)
libmultipath/foreign/nvme.c new file +6
-0+{ +condlog (5 ,"%s called for \"%s\"" , __func__,THIS ); +/* NOP */ +} + +/* compile-time check whether all methods are present and correctly typed */
libmultipath/foreign/nvme.c new file +15
-0+#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), +};Signature · 1 line
2.16.1
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Benjamin Marzinski
maintainerRe: [RFC PATCH 17/20] libmultipath/foreign: nvme foreign library
Quoted 28 lines · Martin Wilck
Quoted 18 lines · Benjamin Marzinski
Quoted 5 lines · Martin Wilck
libmultipath/foreign/nvme.c new file +5
-0+void cleanup (struct context *ctx) +{ +if (ctx ==NULL ) +return ; +libmultipath/foreign/nvme.c line 236
Quoted 10 lines
libmultipath/foreign/nvme.c new file +10
-0+ (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
Quoted 8 lines
explaining that it's not necessary here. If you really did need to lock
ctx in order guard against someone accessingctx->mpvecincleanup(), 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.
Quoted 3 lines
I don't understand, sorry. I need to lock because some other entity may still be using
ctx->mpvecwhencleanup()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.
Quoted 4 lines
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.
Quoted 3 lines
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.cfile, didn't occur to me before.
-Ben
RFC PATCH 18/20 multipath: use foreign API
In reply to Martin WilckUse the "foreign" code to print information about multipath maps owned by foreign libraries in print mode (multipath -ll, -l).
--- multipath/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
multipath/main.c +13 -0
@@ -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 ();
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 18/20] multipath: use foreign API
Quoted 3 lines · Martin Wilck
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.
Quoted 59 lines
Signed-off-by Martin Wilck <[email protected]>--- multipath/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)multipath/main.c +13
-0@@ -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 ();Signature · 1 line
2.16.1
Re: [RFC PATCH 18/20] multipath: use foreign API
Quoted 11 lines · Benjamin Marzinski
Quoted 3 lines · Martin Wilck
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 inpathinfo()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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
RFC PATCH 19/20 multipathd: use foreign API
In reply to Martin WilckCall 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.
--- libmultipath/discovery.c | 4 +++- multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++----- multipathd/main.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-)
libmultipath/discovery.c +3 -1
@@ -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,
multipathd/cli_handlers.c +34 -5
@@ -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 ;
multipathd/main.c +40 -3
103 lines not on this page · raw message
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 19/20] multipathd: use foreign API
Quoted 182 lines · 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 <[email protected]>--- libmultipath/discovery.c | 4 +++- multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++----- multipathd/main.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-)libmultipath/discovery.c +3
-1@@ -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,multipathd/cli_handlers.c +34
-5@@ -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 ;multipathd/main.c +1
-0@@ -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
multipathd/main.c rescan: · line 703
Quoted 4 lines
multipathd/main.c +1
-0@@ -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.
multipathd/main.c rescan: · line 709
Quoted 6 lines
multipathd/main.c +6
-0+case FOREIGN_CLAIMED : +case FOREIGN_OK : +orphan_path (pp,"claimed by foreign library" ); +return 0 ; +default : +break ;
Is there a purpose to this break?
Quoted 45 lines
multipathd/main.c +20
-1+ } +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.
multipathd/main.c uev_trigger (struct uevent * uev, void * trigger_data) · line 1158
Quoted 10 lines
multipathd/main.c +6
-1*/ 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
Quoted 40 lines
multipathd/main.c +6
-1if (!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 ();Signature · 1 line
2.16.1
Re: [RFC PATCH 19/20] multipathd: use foreign API
Quoted 56 lines · Benjamin Marzinski
Quoted 35 lines · 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 <[email protected]>--- libmultipath/discovery.c | 4 +++- multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++- ---- multipathd/main.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-)multipathd/main.c +1
-0@@ -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 256multipathd/main.c rescan: · line 703
Quoted 4 lines
multipathd/main.c +1
-0@@ -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 callsglob(), 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 thestrict_timingoption.strict_timingcallssetitimer(), which sets an alarm in checkerloop, without any locking.strict_timingalso
messes with any call tolock_file().lock_file()and_find_slaves()will
Quoted 8 lines
never interfere with eachother, since both are only called with the vecs
lock held (I think. See below).strict_timingprobably needs to get reimplemented usingnanosleep()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.
Quoted 10 lines
multipathd/main.c rescan: · line 709
Quoted 8 lines
multipathd/main.c +6
-0+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.
Quoted 11 lines
Quoted 11 lines
multipathd/main.c +2
-1conf =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 ))
Quoted 8 lines
multipathd/main.c uev_trigger (struct uevent * uev, void * trigger_data) · line 1158
Quoted 6 lines
multipathd/main.c +4
-0+ (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->kernelset to "dm-"?
Although I don't see a likely candidate, I didn't want to exclude it in general.
Quoted 3 lines
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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Benjamin Marzinski
maintainerRe: [RFC PATCH 19/20] multipathd: use foreign API
Quoted 66 lines · Martin Wilck
Quoted 56 lines · Benjamin Marzinski
Quoted 35 lines · 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 <[email protected]>--- libmultipath/discovery.c | 4 +++- multipathd/cli_handlers.c | 39 ++++++++++++++++++++++++++++++++++- ---- multipathd/main.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-)multipathd/main.c +1
-0@@ -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 256multipathd/main.c rescan: · line 703
Quoted 4 lines
multipathd/main.c +1
-0@@ -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 callsglob(), 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 thestrict_timingoption.strict_timingcallssetitimer(), which sets an alarm in checkerloop, without any locking.strict_timingalso
messes with any call tolock_file().lock_file()and_find_slaves()willQuoted 8 lines
never interfere with eachother, since both are only called with the vecs
lock held (I think. See below).strict_timingprobably needs to get reimplemented usingnanosleep()or some other non-signal method, so that
there aren't two threads setting alarms and waiting for SIGARLM at the
same time.
Quoted 2 lines
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.
Quoted 11 lines
Quoted 10 lines
multipathd/main.c rescan: · line 709
Quoted 8 lines
multipathd/main.c +6
-0+case FOREIGN_CLAIMED : +case FOREIGN_OK : +orphan_path (pp,"claimed by foreign library"); +return 0 ; +default : +break ;Is there a purpose to this break?
Quoted 2 lines
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.
Quoted 23 lines
Quoted 11 lines
Quoted 11 lines
multipathd/main.c +2
-1conf =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 ))Quoted 8 lines
multipathd/main.c uev_trigger (struct uevent * uev, void * trigger_data) · line 1158
Quoted 6 lines
multipathd/main.c +4
-0+ (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->kernelset to "dm-"?Although I don't see a likely candidate, I didn't want to exclude it in general.
Quoted 8 lines
Quoted 3 lines
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
Quoted 7 lines
Regards,
MartinSignature · 3 lines
Dr. Martin Wilck <[email protected]>, Tel. +49 (0)911 74053 2107 SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)
Re: [RFC PATCH 19/20] multipathd: use foreign API
In reply to Benjamin MarzinskiQuoted 6 lines · Benjamin Marzinski
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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Benjamin Marzinski
maintainerRe: [RFC PATCH 19/20] multipathd: use foreign API
Quoted 10 lines · Martin Wilck
Quoted 6 lines · Benjamin Marzinski
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
Quoted 7 lines
Martin
Signature · 3 lines
Dr. Martin Wilck <[email protected]>, Tel. +49 (0)911 74053 2107 SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)
PATCH 1/1 multipathd: fix inverted signal blocking logic
Quoted 4 lines · Benjamin Marzinski
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.
are delivered to the uxsock thread"
--- multipathd/main.c | 7 +++++-- multipathd/uxlsnr.c | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-)
multipathd/main.c +5 -2
@@ -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);
multipathd/uxlsnr.c +5 -5
@@ -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;
Signature · 1 line
2.16.1
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 5 lines · Martin Wilck
multipathd/main.c +0
-0
multipathd/main.c signal_init(void) · line 2277
Quoted 10 lines
multipathd/main.c +4
-2@@ -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.
Quoted 11 lines
multipathd/uxlsnr.c +0
-3@@ -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 );
multipathd/uxlsnr.c void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data) · line 180
Quoted 10 lines
multipathd/uxlsnr.c +5
-2-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.
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 38 lines · Bart Van Assche
Quoted 5 lines · Martin Wilck
multipathd/main.c +0
-0multipathd/main.c signal_init(void) · line 2277
Quoted 10 lines
multipathd/main.c +4
-2@@ -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.Quoted 18 lines
multipathd/uxlsnr.c +4
-5@@ -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 );
Quoted 8 lines
Quoted 4 lines
multipathd/uxlsnr.c +1
-0+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 fourthppoll()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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 8 lines · Martin Wilck
Quoted 3 lines · Bart Van Assche
This change looks more complicated to me than necessary. Have you considered
to pass an empty signal set as the fourthppoll()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.
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 6 lines · Bart Van Assche
Quoted 5 lines · Martin Wilck
Quoted 3 lines · Bart Van Assche
This change looks more complicated to me than necessary. Have you considered
to pass an empty signal set as the fourthppoll()argument?
Quoted 6 lines
Quoted 3 lines
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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 11 lines · Martin Wilck
Quoted 10 lines · Bart Van Assche
Quoted 8 lines · Martin Wilck
Quoted 3 lines · Bart Van Assche
This change looks more complicated to me than necessary. Have you considered
to pass an empty signal set as the fourthppoll()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").
Quoted 5 lines
Quoted 2 lines
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.
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 23 lines · Bart Van Assche
Quoted 14 lines · Martin Wilck
Quoted 13 lines · Bart Van Assche
Quoted 11 lines · Martin Wilck
Quoted 4 lines · Bart Van Assche
This change looks more complicated to me than necessary. Have you
considered
to pass an empty signal set as the fourthppoll()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").Quoted 7 lines
Quoted 2 lines
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.
Quoted 10 lines
I see two reasons:
- All signals that are delivered to the multipathd process except SIGALRM
should interruptppoll(). 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
callsppoll().
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.
Quoted 3 lines
- 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
Quoted 2 lines
Bart.
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 5 lines · Martin Wilck
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.
Re: [PATCH] multipathd: fix inverted signal blocking logic
Hello Bart,
Quoted 9 lines · Bart Van Assche
Quoted 7 lines · Martin Wilck
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 interruptppoll()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?
Quoted 11 lines
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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Benjamin Marzinski
maintainerRe: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 35 lines · Martin Wilck
Hello Bart,
Quoted 9 lines · Bart Van Assche
Quoted 7 lines · Martin Wilck
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 interruptppoll()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?Quoted 11 lines
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 firstpthread_create()call.
* Unblock signals from the thread that should receive signals.
Quoted 7 lines
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
Quoted 7 lines
Martin
Signature · 3 lines
Dr. Martin Wilck <[email protected]>, Tel. +49 (0)911 74053 2107 SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)
Re: [PATCH] multipathd: fix inverted signal blocking logic
Quoted 11 lines · Benjamin Marzinski
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 inio_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
Signature · 8 lines
Dr. Martin Wilck <[email protected]>, 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 [email protected] https://www.redhat.com/mailman/listinfo/dm-devel
Re: [RFC PATCH 19/20] multipathd: use foreign API
In reply to Benjamin MarzinskiQuoted 3 lines · Benjamin Marzinski
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_timingoption.
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.
RFC PATCH 20/20 libmultipath: foreign/nvme: implement path display
In reply to Martin Wilckimplement 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).
--- libmultipath/foreign/nvme.c | 342 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 327 insertions(+), 15 deletions(-)
libmultipath/foreign/nvme.c +327 -15
@@ -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 */
Signature · 1 line
2.16.1
Benjamin Marzinski
maintainerRe: [RFC PATCH 20/20] libmultipath: foreign/nvme: implement path display
Quoted 14 lines · 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 hcildev_stserial multipath host WWNN
Quoted 7 lines
[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.
Quoted 228 lines
Signed-off-by Martin Wilck <[email protected]>--- libmultipath/foreign/nvme.c | 342 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 327 insertions(+), 15 deletions(-)libmultipath/foreign/nvme.c +129
-10@@ -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" ));
libmultipath/foreign/nvme.c static int snprint_nvme_map(const struct gen_multipath *gmp, · line 281
Quoted 10 lines
libmultipath/foreign/nvme.c +10
-0+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
Quoted 261 lines
libmultipath/foreign/nvme.c +188
-5default : +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 */ Signature · 1 line
2.16.1