* [PATCH v3 00/87] multipath-tools series part VII: addional patches
@ 2020-08-19 13:18 mwilck
2020-08-19 13:18 ` [PATCH v3 84/87] libmultipath: add consistency check for alias settings mwilck
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: mwilck @ 2020-08-19 13:18 UTC (permalink / raw)
To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck
From: Martin Wilck <mwilck@suse.com>
This is v3 of part VII of a larger patch series for multipath-tools I've
been preparing. It's based on the previously submitted part VI.
The full series will also be available here:
https://github.com/mwilck/multipath-tools/tree/ups/submit-200819
This part is tagged "submit-200819-7".
This part contains patches added since the v1 and v2 submissions of the series.
One is Liu's fix for disassemble_map(), rebased on top of my previous changes
to that function.
84/87, related to inconsistent alias settings, belongs logically to part III.
I couldn't add it there because it would have changed the numbering in the
series wrt v1, which I wanted to avoid.
Changes v2 -> v3, as suggested by Ben Marzinski:
84/87 "libmultipath: add consistency check for alias settings"
- fixed possible freeing of NULL pointer
- search vector backwards in add_binding()
- avoid fd leak in check_alias_settings()
85/87 "libmultipath: alias.c: use strtok_r() instead of strtok()"
- new, provide thread safety in alias.c
86/87 "libmultipath: adopt_paths(): set pp->mpp only on success"
- new, implement Ben's suggestion in his review of patch 54 in the
v2 series ("[PATCH v2 44/54] libmultipath: adopt_paths(): don't
bail out on single path failure")
Besides, a trivial warning fix was added (87/87).
Martin Wilck (6):
multipath: check_path_valid(): eliminate some failure modes
libmultipath: alias: static const variable for BINDINGS_FILE_HEADER
libmultipath: add consistency check for alias settings
libmultipath: alias.c: use strtok_r() instead of strtok()
libmultipath: adopt_paths(): set pp->mpp only on success
libmultipath: fix a -Wformat-truncation warning from gcc 10
Zhiqiang Liu (1):
libmultipath: free pp if store_path fails in disassemble_map
libmultipath/alias.c | 294 +++++++++++++++++++++++++++++++++++--
libmultipath/alias.h | 15 +-
libmultipath/dmparser.c | 12 +-
libmultipath/structs_vec.c | 15 +-
libmultipath/util.c | 6 +-
multipath/main.c | 21 +--
multipathd/main.c | 3 +
7 files changed, 327 insertions(+), 39 deletions(-)
--
2.28.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 84/87] libmultipath: add consistency check for alias settings
2020-08-19 13:18 [PATCH v3 00/87] multipath-tools series part VII: addional patches mwilck
@ 2020-08-19 13:18 ` mwilck
2020-08-19 22:13 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok() mwilck
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: mwilck @ 2020-08-19 13:18 UTC (permalink / raw)
To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck
From: Martin Wilck <mwilck@suse.com>
A typo in a config file, assigning the same alias to multiple WWIDs,
can cause massive confusion and even data corruption. Check and
if possible fix the bindings file in such cases.
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/alias.c | 265 +++++++++++++++++++++++++++++++++++++++++++
libmultipath/alias.h | 3 +
multipath/main.c | 3 +
multipathd/main.c | 3 +
4 files changed, 274 insertions(+)
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 0759c4e..df44bdc 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -4,6 +4,7 @@
*/
#include <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
@@ -17,6 +18,9 @@
#include "vector.h"
#include "checkers.h"
#include "structs.h"
+#include "config.h"
+#include "util.h"
+#include "errno.h"
/*
@@ -438,3 +442,264 @@ get_user_friendly_wwid(const char *alias, char *buff, const char *file)
fclose(f);
return 0;
}
+
+struct binding {
+ char *alias;
+ char *wwid;
+};
+
+static void _free_binding(struct binding *bdg)
+{
+ free(bdg->wwid);
+ free(bdg->alias);
+ free(bdg);
+}
+
+/*
+ * Perhaps one day we'll implement this more efficiently, thus use
+ * an abstract type.
+ */
+typedef struct _vector Bindings;
+
+static void free_bindings(Bindings *bindings)
+{
+ struct binding *bdg;
+ int i;
+
+ vector_foreach_slot(bindings, bdg, i)
+ _free_binding(bdg);
+ vector_reset(bindings);
+}
+
+enum {
+ BINDING_EXISTS,
+ BINDING_CONFLICT,
+ BINDING_ADDED,
+ BINDING_DELETED,
+ BINDING_NOTFOUND,
+ BINDING_ERROR,
+};
+
+static int add_binding(Bindings *bindings, const char *alias, const char *wwid)
+{
+ struct binding *bdg;
+ int i, cmp = 0;
+
+ /*
+ * Keep the bindings array sorted by alias.
+ * Optimization: Search backwards, assuming that the bindings file is
+ * sorted already.
+ */
+ vector_foreach_slot_backwards(bindings, bdg, i) {
+ if ((cmp = strcmp(bdg->alias, alias)) <= 0)
+ break;
+ }
+
+ /* Check for exact match */
+ if (i >= 0 && cmp == 0)
+ return strcmp(bdg->wwid, wwid) ?
+ BINDING_CONFLICT : BINDING_EXISTS;
+
+ i++;
+ bdg = calloc(1, sizeof(*bdg));
+ if (bdg) {
+ bdg->wwid = strdup(wwid);
+ bdg->alias = strdup(alias);
+ if (bdg->wwid && bdg->alias &&
+ vector_insert_slot(bindings, i, bdg))
+ return BINDING_ADDED;
+ else
+ _free_binding(bdg);
+ }
+
+ return BINDING_ERROR;
+}
+
+static int write_bindings_file(const Bindings *bindings, int fd)
+{
+ struct binding *bnd;
+ char line[LINE_MAX];
+ int i;
+
+ if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1)
+ != sizeof(BINDINGS_FILE_HEADER) - 1)
+ return -1;
+
+ vector_foreach_slot(bindings, bnd, i) {
+ int len;
+
+ len = snprintf(line, sizeof(line), "%s %s\n",
+ bnd->alias, bnd->wwid);
+
+ if (len < 0 || (size_t)len >= sizeof(line)) {
+ condlog(1, "%s: line overflow", __func__);
+ return -1;
+ }
+
+ if (write(fd, line, len) != len)
+ return -1;
+ }
+ return 0;
+}
+
+static int fix_bindings_file(const struct config *conf,
+ const Bindings *bindings)
+{
+ int rc;
+ long fd;
+ char tempname[PATH_MAX];
+
+ if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file))
+ return -1;
+ if ((fd = mkstemp(tempname)) == -1) {
+ condlog(1, "%s: mkstemp: %m", __func__);
+ return -1;
+ }
+ pthread_cleanup_push(close_fd, (void*)fd);
+ rc = write_bindings_file(bindings, fd);
+ pthread_cleanup_pop(1);
+ if (rc == -1) {
+ condlog(1, "failed to write new bindings file %s",
+ tempname);
+ unlink(tempname);
+ return rc;
+ }
+ if ((rc = rename(tempname, conf->bindings_file)) == -1)
+ condlog(0, "%s: rename: %m", __func__);
+ else
+ condlog(1, "updated bindings file %s", conf->bindings_file);
+ return rc;
+}
+
+static int _check_bindings_file(const struct config *conf, FILE *file,
+ Bindings *bindings)
+{
+ int rc = 0;
+ unsigned int linenr = 0;
+ char *line = NULL;
+ size_t line_len = 0;
+ ssize_t n;
+
+ pthread_cleanup_push(free, line);
+ while ((n = getline(&line, &line_len, file)) >= 0) {
+ char *c, *alias, *wwid;
+ const char *mpe_wwid;
+
+ linenr++;
+ c = strpbrk(line, "#\n\r");
+ if (c)
+ *c = '\0';
+ alias = strtok(line, " \t");
+ if (!alias) /* blank line */
+ continue;
+ wwid = strtok(NULL, " \t");
+ if (!wwid) {
+ condlog(1, "invalid line %d in bindings file, missing WWID",
+ linenr);
+ continue;
+ }
+ c = strtok(NULL, " \t");
+ if (c)
+ /* This is non-fatal */
+ condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
+ linenr, c);
+
+ mpe_wwid = get_mpe_wwid(conf->mptable, alias);
+ if (mpe_wwid && strcmp(mpe_wwid, wwid)) {
+ condlog(0, "ERROR: alias \"%s\" for WWID %s in bindings file "
+ "on line %u conflicts with multipath.conf entry for %s",
+ alias, wwid, linenr, mpe_wwid);
+ rc = -1;
+ continue;
+ }
+
+ switch (add_binding(bindings, alias, wwid)) {
+ case BINDING_CONFLICT:
+ condlog(0, "ERROR: multiple bindings for alias \"%s\" in "
+ "bindings file on line %u, discarding binding to WWID %s",
+ alias, linenr, wwid);
+ rc = -1;
+ break;
+ case BINDING_EXISTS:
+ condlog(2, "duplicate line for alias %s in bindings file on line %u",
+ alias, linenr);
+ break;
+ case BINDING_ERROR:
+ condlog(2, "error adding binding %s -> %s",
+ alias, wwid);
+ break;
+ default:
+ break;
+ }
+ }
+ pthread_cleanup_pop(1);
+ return rc;
+}
+
+static void cleanup_fclose(void *p)
+{
+ fclose(p);
+}
+
+/*
+ * check_alias_settings(): test for inconsistent alias configuration
+ *
+ * It's a fatal configuration error if the same alias is assigned to
+ * multiple WWIDs. In the worst case, it can cause data corruption
+ * by mangling devices with different WWIDs into the same multipath map.
+ * This function tests the configuration from multipath.conf and the
+ * bindings file for consistency, drops inconsistent multipath.conf
+ * alias settings, and rewrites the bindings file if necessary, dropping
+ * conflicting lines (if user_friendly_names is on, multipathd will
+ * fill in the deleted lines with a newly generated alias later).
+ * Note that multipath.conf is not rewritten. Use "multipath -T" for that.
+ *
+ * Returns: 0 in case of success, -1 if the configuration was bad
+ * and couldn't be fixed.
+ */
+int check_alias_settings(const struct config *conf)
+{
+ int can_write;
+ int rc = 0, i, fd;
+ Bindings bindings = {.allocated = 0, };
+ struct mpentry *mpe;
+
+ pthread_cleanup_push_cast(free_bindings, &bindings);
+ vector_foreach_slot(conf->mptable, mpe, i) {
+ if (!mpe->wwid || !mpe->alias)
+ continue;
+ if (add_binding(&bindings, mpe->alias, mpe->wwid) ==
+ BINDING_CONFLICT) {
+ condlog(0, "ERROR: alias \"%s\" bound to multiple wwids in multipath.conf, "
+ "discarding binding to %s",
+ mpe->alias, mpe->wwid);
+ free(mpe->alias);
+ mpe->alias = NULL;
+ }
+ }
+ /* This clears the bindings */
+ pthread_cleanup_pop(1);
+
+ pthread_cleanup_push_cast(free_bindings, &bindings);
+ fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER);
+ if (fd != -1) {
+ FILE *file = fdopen(fd, "r");
+
+ if (file != NULL) {
+ pthread_cleanup_push(cleanup_fclose, file);
+ rc = _check_bindings_file(conf, file, &bindings);
+ pthread_cleanup_pop(1);
+ if (rc == -1 && can_write && !conf->bindings_read_only)
+ rc = fix_bindings_file(conf, &bindings);
+ else if (rc == -1)
+ condlog(0, "ERROR: bad settings in read-only bindings file %s",
+ conf->bindings_file);
+ } else {
+ condlog(1, "failed to fdopen %s: %m",
+ conf->bindings_file);
+ close(fd);
+ }
+ }
+ pthread_cleanup_pop(1);
+ return rc;
+}
diff --git a/libmultipath/alias.h b/libmultipath/alias.h
index 236b3ba..dbc950c 100644
--- a/libmultipath/alias.h
+++ b/libmultipath/alias.h
@@ -10,4 +10,7 @@ char *use_existing_alias (const char *wwid, const char *file,
const char *alias_old,
const char *prefix, int bindings_read_only);
+struct config;
+int check_alias_settings(const struct config *);
+
#endif /* _ALIAS_H */
diff --git a/multipath/main.c b/multipath/main.c
index 9e65070..80bc4b5 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -64,6 +64,7 @@
#include "time-util.h"
#include "file.h"
#include "valid.h"
+#include "alias.h"
int logsink;
struct udev *udev;
@@ -958,6 +959,8 @@ main (int argc, char *argv[])
exit(RTVL_FAIL);
}
+ check_alias_settings(conf);
+
if (optind < argc) {
dev = MALLOC(FILE_NAME_SIZE);
diff --git a/multipathd/main.c b/multipathd/main.c
index 343ee95..9f12a57 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -63,6 +63,7 @@
#include "uevent.h"
#include "log.h"
#include "uxsock.h"
+#include "alias.h"
#include "mpath_cmd.h"
#include "mpath_persist.h"
@@ -2717,6 +2718,8 @@ reconfigure (struct vectors * vecs)
conf->verbosity = verbosity;
if (bindings_read_only)
conf->bindings_read_only = bindings_read_only;
+ check_alias_settings(conf);
+
uxsock_timeout = conf->uxsock_timeout;
old = rcu_dereference(multipath_conf);
--
2.28.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok()
2020-08-19 13:18 [PATCH v3 00/87] multipath-tools series part VII: addional patches mwilck
2020-08-19 13:18 ` [PATCH v3 84/87] libmultipath: add consistency check for alias settings mwilck
@ 2020-08-19 13:18 ` mwilck
2020-08-19 22:16 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success mwilck
2020-08-19 13:18 ` [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10 mwilck
3 siblings, 1 reply; 10+ messages in thread
From: mwilck @ 2020-08-19 13:18 UTC (permalink / raw)
To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck
From: Martin Wilck <mwilck@suse.com>
... for thread-safety.
Suggested-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/alias.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index df44bdc..de28f25 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -141,14 +141,14 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
rewind(f);
while (fgets(buf, LINE_MAX, f)) {
const char *alias, *wwid;
- char *c;
+ char *c, *saveptr;
int curr_id;
line_nr++;
c = strpbrk(buf, "#\n\r");
if (c)
*c = '\0';
- alias = strtok(buf, " \t");
+ alias = strtok_r(buf, " \t", &saveptr);
if (!alias) /* blank line */
continue;
curr_id = scan_devname(alias, prefix);
@@ -164,7 +164,7 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
biggest_id = curr_id;
if (curr_id > id && curr_id < smallest_bigger_id)
smallest_bigger_id = curr_id;
- wwid = strtok(NULL, " \t");
+ wwid = strtok_r(NULL, " \t", &saveptr);
if (!wwid){
condlog(3,
"Ignoring malformed line %u in bindings file",
@@ -206,17 +206,17 @@ rlookup_binding(FILE *f, char *buff, const char *map_alias)
buff[0] = '\0';
while (fgets(line, LINE_MAX, f)) {
- char *c;
+ char *c, *saveptr;
const char *alias, *wwid;
line_nr++;
c = strpbrk(line, "#\n\r");
if (c)
*c = '\0';
- alias = strtok(line, " \t");
+ alias = strtok_r(line, " \t", &saveptr);
if (!alias) /* blank line */
continue;
- wwid = strtok(NULL, " \t");
+ wwid = strtok_r(NULL, " \t", &saveptr);
if (!wwid){
condlog(3,
"Ignoring malformed line %u in bindings file",
@@ -582,23 +582,23 @@ static int _check_bindings_file(const struct config *conf, FILE *file,
pthread_cleanup_push(free, line);
while ((n = getline(&line, &line_len, file)) >= 0) {
- char *c, *alias, *wwid;
+ char *c, *alias, *wwid, *saveptr;
const char *mpe_wwid;
linenr++;
c = strpbrk(line, "#\n\r");
if (c)
*c = '\0';
- alias = strtok(line, " \t");
+ alias = strtok_r(line, " \t", &saveptr);
if (!alias) /* blank line */
continue;
- wwid = strtok(NULL, " \t");
+ wwid = strtok_r(NULL, " \t", &saveptr);
if (!wwid) {
condlog(1, "invalid line %d in bindings file, missing WWID",
linenr);
continue;
}
- c = strtok(NULL, " \t");
+ c = strtok_r(NULL, " \t", &saveptr);
if (c)
/* This is non-fatal */
condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
--
2.28.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success
2020-08-19 13:18 [PATCH v3 00/87] multipath-tools series part VII: addional patches mwilck
2020-08-19 13:18 ` [PATCH v3 84/87] libmultipath: add consistency check for alias settings mwilck
2020-08-19 13:18 ` [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok() mwilck
@ 2020-08-19 13:18 ` mwilck
2020-08-19 22:15 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10 mwilck
3 siblings, 1 reply; 10+ messages in thread
From: mwilck @ 2020-08-19 13:18 UTC (permalink / raw)
To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck
From: Martin Wilck <mwilck@suse.com>
Make sure that pp->mpp is only set for paths that have been
successfully added to mpp->paths.
Suggested-by: Benjamin Marzinki <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/structs_vec.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 2d85df9..cc2dafa 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -248,14 +248,10 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
pp->dev, mpp->alias);
continue;
}
- pp->mpp = mpp;
if (pp->initialized == INIT_REMOVED)
continue;
- condlog(3, "%s: ownership set to %s",
- pp->dev, mpp->alias);
-
if (!mpp->paths && !(mpp->paths = vector_alloc()))
- return 1;
+ goto err;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
@@ -270,10 +266,17 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
store_path(mpp->paths, pp))
- return 1;
+ goto err;
+
+ pp->mpp = mpp;
+ condlog(3, "%s: ownership set to %s",
+ pp->dev, mpp->alias);
}
}
return 0;
+err:
+ condlog(1, "error setting ownership of %s to %s", pp->dev, mpp->alias);
+ return 1;
}
void orphan_path(struct path *pp, const char *reason)
--
2.28.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10
2020-08-19 13:18 [PATCH v3 00/87] multipath-tools series part VII: addional patches mwilck
` (2 preceding siblings ...)
2020-08-19 13:18 ` [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success mwilck
@ 2020-08-19 13:18 ` mwilck
2020-08-19 22:40 ` Benjamin Marzinski
3 siblings, 1 reply; 10+ messages in thread
From: mwilck @ 2020-08-19 13:18 UTC (permalink / raw)
To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck
From: Martin Wilck <mwilck@suse.com>
This fixes a warning seen with gcc 10 on x86 (32 bit).
Fix it by checking the snprintf() return value.
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 207e63c..1512424 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -250,9 +250,9 @@ int systemd_service_enabled_in(const char *dev, const char *prefix)
p = d->d_name + strlen(d->d_name) - 6;
if (strcmp(p, ".wants"))
continue;
- snprintf(file, sizeof(file), "%s/%s/%s",
- path, d->d_name, service);
- if (stat(file, &stbuf) == 0) {
+ if (!safe_sprintf(file, "%s/%s/%s",
+ path, d->d_name, service)
+ && stat(file, &stbuf) == 0) {
condlog(3, "%s: found %s", dev, file);
found++;
break;
--
2.28.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 84/87] libmultipath: add consistency check for alias settings
2020-08-19 13:18 ` [PATCH v3 84/87] libmultipath: add consistency check for alias settings mwilck
@ 2020-08-19 22:13 ` Benjamin Marzinski
0 siblings, 0 replies; 10+ messages in thread
From: Benjamin Marzinski @ 2020-08-19 22:13 UTC (permalink / raw)
To: mwilck; +Cc: dm-devel
On Wed, Aug 19, 2020 at 03:18:16PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> A typo in a config file, assigning the same alias to multiple WWIDs,
> can cause massive confusion and even data corruption. Check and
> if possible fix the bindings file in such cases.
>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/alias.c | 265 +++++++++++++++++++++++++++++++++++++++++++
> libmultipath/alias.h | 3 +
> multipath/main.c | 3 +
> multipathd/main.c | 3 +
> 4 files changed, 274 insertions(+)
>
> diff --git a/libmultipath/alias.c b/libmultipath/alias.c
> index 0759c4e..df44bdc 100644
> --- a/libmultipath/alias.c
> +++ b/libmultipath/alias.c
> @@ -4,6 +4,7 @@
> */
> #include <stdlib.h>
> #include <errno.h>
> +#include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #include <limits.h>
> @@ -17,6 +18,9 @@
> #include "vector.h"
> #include "checkers.h"
> #include "structs.h"
> +#include "config.h"
> +#include "util.h"
> +#include "errno.h"
>
>
> /*
> @@ -438,3 +442,264 @@ get_user_friendly_wwid(const char *alias, char *buff, const char *file)
> fclose(f);
> return 0;
> }
> +
> +struct binding {
> + char *alias;
> + char *wwid;
> +};
> +
> +static void _free_binding(struct binding *bdg)
> +{
> + free(bdg->wwid);
> + free(bdg->alias);
> + free(bdg);
> +}
> +
> +/*
> + * Perhaps one day we'll implement this more efficiently, thus use
> + * an abstract type.
> + */
> +typedef struct _vector Bindings;
> +
> +static void free_bindings(Bindings *bindings)
> +{
> + struct binding *bdg;
> + int i;
> +
> + vector_foreach_slot(bindings, bdg, i)
> + _free_binding(bdg);
> + vector_reset(bindings);
> +}
> +
> +enum {
> + BINDING_EXISTS,
> + BINDING_CONFLICT,
> + BINDING_ADDED,
> + BINDING_DELETED,
> + BINDING_NOTFOUND,
> + BINDING_ERROR,
> +};
> +
> +static int add_binding(Bindings *bindings, const char *alias, const char *wwid)
> +{
> + struct binding *bdg;
> + int i, cmp = 0;
> +
> + /*
> + * Keep the bindings array sorted by alias.
> + * Optimization: Search backwards, assuming that the bindings file is
> + * sorted already.
> + */
> + vector_foreach_slot_backwards(bindings, bdg, i) {
> + if ((cmp = strcmp(bdg->alias, alias)) <= 0)
> + break;
> + }
> +
> + /* Check for exact match */
> + if (i >= 0 && cmp == 0)
> + return strcmp(bdg->wwid, wwid) ?
> + BINDING_CONFLICT : BINDING_EXISTS;
> +
> + i++;
> + bdg = calloc(1, sizeof(*bdg));
> + if (bdg) {
> + bdg->wwid = strdup(wwid);
> + bdg->alias = strdup(alias);
> + if (bdg->wwid && bdg->alias &&
> + vector_insert_slot(bindings, i, bdg))
> + return BINDING_ADDED;
> + else
> + _free_binding(bdg);
> + }
> +
> + return BINDING_ERROR;
> +}
> +
> +static int write_bindings_file(const Bindings *bindings, int fd)
> +{
> + struct binding *bnd;
> + char line[LINE_MAX];
> + int i;
> +
> + if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1)
> + != sizeof(BINDINGS_FILE_HEADER) - 1)
> + return -1;
> +
> + vector_foreach_slot(bindings, bnd, i) {
> + int len;
> +
> + len = snprintf(line, sizeof(line), "%s %s\n",
> + bnd->alias, bnd->wwid);
> +
> + if (len < 0 || (size_t)len >= sizeof(line)) {
> + condlog(1, "%s: line overflow", __func__);
> + return -1;
> + }
> +
> + if (write(fd, line, len) != len)
> + return -1;
> + }
> + return 0;
> +}
> +
> +static int fix_bindings_file(const struct config *conf,
> + const Bindings *bindings)
> +{
> + int rc;
> + long fd;
> + char tempname[PATH_MAX];
> +
> + if (safe_sprintf(tempname, "%s.XXXXXX", conf->bindings_file))
> + return -1;
> + if ((fd = mkstemp(tempname)) == -1) {
> + condlog(1, "%s: mkstemp: %m", __func__);
> + return -1;
> + }
> + pthread_cleanup_push(close_fd, (void*)fd);
> + rc = write_bindings_file(bindings, fd);
> + pthread_cleanup_pop(1);
> + if (rc == -1) {
> + condlog(1, "failed to write new bindings file %s",
> + tempname);
> + unlink(tempname);
> + return rc;
> + }
> + if ((rc = rename(tempname, conf->bindings_file)) == -1)
> + condlog(0, "%s: rename: %m", __func__);
> + else
> + condlog(1, "updated bindings file %s", conf->bindings_file);
> + return rc;
> +}
> +
> +static int _check_bindings_file(const struct config *conf, FILE *file,
> + Bindings *bindings)
> +{
> + int rc = 0;
> + unsigned int linenr = 0;
> + char *line = NULL;
> + size_t line_len = 0;
> + ssize_t n;
> +
> + pthread_cleanup_push(free, line);
> + while ((n = getline(&line, &line_len, file)) >= 0) {
> + char *c, *alias, *wwid;
> + const char *mpe_wwid;
> +
> + linenr++;
> + c = strpbrk(line, "#\n\r");
> + if (c)
> + *c = '\0';
> + alias = strtok(line, " \t");
> + if (!alias) /* blank line */
> + continue;
> + wwid = strtok(NULL, " \t");
> + if (!wwid) {
> + condlog(1, "invalid line %d in bindings file, missing WWID",
> + linenr);
> + continue;
> + }
> + c = strtok(NULL, " \t");
> + if (c)
> + /* This is non-fatal */
> + condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
> + linenr, c);
> +
> + mpe_wwid = get_mpe_wwid(conf->mptable, alias);
> + if (mpe_wwid && strcmp(mpe_wwid, wwid)) {
> + condlog(0, "ERROR: alias \"%s\" for WWID %s in bindings file "
> + "on line %u conflicts with multipath.conf entry for %s",
> + alias, wwid, linenr, mpe_wwid);
> + rc = -1;
> + continue;
> + }
> +
> + switch (add_binding(bindings, alias, wwid)) {
> + case BINDING_CONFLICT:
> + condlog(0, "ERROR: multiple bindings for alias \"%s\" in "
> + "bindings file on line %u, discarding binding to WWID %s",
> + alias, linenr, wwid);
> + rc = -1;
> + break;
> + case BINDING_EXISTS:
> + condlog(2, "duplicate line for alias %s in bindings file on line %u",
> + alias, linenr);
> + break;
> + case BINDING_ERROR:
> + condlog(2, "error adding binding %s -> %s",
> + alias, wwid);
> + break;
> + default:
> + break;
> + }
> + }
> + pthread_cleanup_pop(1);
> + return rc;
> +}
> +
> +static void cleanup_fclose(void *p)
> +{
> + fclose(p);
> +}
> +
> +/*
> + * check_alias_settings(): test for inconsistent alias configuration
> + *
> + * It's a fatal configuration error if the same alias is assigned to
> + * multiple WWIDs. In the worst case, it can cause data corruption
> + * by mangling devices with different WWIDs into the same multipath map.
> + * This function tests the configuration from multipath.conf and the
> + * bindings file for consistency, drops inconsistent multipath.conf
> + * alias settings, and rewrites the bindings file if necessary, dropping
> + * conflicting lines (if user_friendly_names is on, multipathd will
> + * fill in the deleted lines with a newly generated alias later).
> + * Note that multipath.conf is not rewritten. Use "multipath -T" for that.
> + *
> + * Returns: 0 in case of success, -1 if the configuration was bad
> + * and couldn't be fixed.
> + */
> +int check_alias_settings(const struct config *conf)
> +{
> + int can_write;
> + int rc = 0, i, fd;
> + Bindings bindings = {.allocated = 0, };
> + struct mpentry *mpe;
> +
> + pthread_cleanup_push_cast(free_bindings, &bindings);
> + vector_foreach_slot(conf->mptable, mpe, i) {
> + if (!mpe->wwid || !mpe->alias)
> + continue;
> + if (add_binding(&bindings, mpe->alias, mpe->wwid) ==
> + BINDING_CONFLICT) {
> + condlog(0, "ERROR: alias \"%s\" bound to multiple wwids in multipath.conf, "
> + "discarding binding to %s",
> + mpe->alias, mpe->wwid);
> + free(mpe->alias);
> + mpe->alias = NULL;
> + }
> + }
> + /* This clears the bindings */
> + pthread_cleanup_pop(1);
> +
> + pthread_cleanup_push_cast(free_bindings, &bindings);
> + fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER);
> + if (fd != -1) {
> + FILE *file = fdopen(fd, "r");
> +
> + if (file != NULL) {
> + pthread_cleanup_push(cleanup_fclose, file);
> + rc = _check_bindings_file(conf, file, &bindings);
> + pthread_cleanup_pop(1);
> + if (rc == -1 && can_write && !conf->bindings_read_only)
> + rc = fix_bindings_file(conf, &bindings);
> + else if (rc == -1)
> + condlog(0, "ERROR: bad settings in read-only bindings file %s",
> + conf->bindings_file);
> + } else {
> + condlog(1, "failed to fdopen %s: %m",
> + conf->bindings_file);
> + close(fd);
> + }
> + }
> + pthread_cleanup_pop(1);
> + return rc;
> +}
> diff --git a/libmultipath/alias.h b/libmultipath/alias.h
> index 236b3ba..dbc950c 100644
> --- a/libmultipath/alias.h
> +++ b/libmultipath/alias.h
> @@ -10,4 +10,7 @@ char *use_existing_alias (const char *wwid, const char *file,
> const char *alias_old,
> const char *prefix, int bindings_read_only);
>
> +struct config;
> +int check_alias_settings(const struct config *);
> +
> #endif /* _ALIAS_H */
> diff --git a/multipath/main.c b/multipath/main.c
> index 9e65070..80bc4b5 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -64,6 +64,7 @@
> #include "time-util.h"
> #include "file.h"
> #include "valid.h"
> +#include "alias.h"
>
> int logsink;
> struct udev *udev;
> @@ -958,6 +959,8 @@ main (int argc, char *argv[])
> exit(RTVL_FAIL);
> }
>
> + check_alias_settings(conf);
> +
> if (optind < argc) {
> dev = MALLOC(FILE_NAME_SIZE);
>
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 343ee95..9f12a57 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -63,6 +63,7 @@
> #include "uevent.h"
> #include "log.h"
> #include "uxsock.h"
> +#include "alias.h"
>
> #include "mpath_cmd.h"
> #include "mpath_persist.h"
> @@ -2717,6 +2718,8 @@ reconfigure (struct vectors * vecs)
> conf->verbosity = verbosity;
> if (bindings_read_only)
> conf->bindings_read_only = bindings_read_only;
> + check_alias_settings(conf);
> +
> uxsock_timeout = conf->uxsock_timeout;
>
> old = rcu_dereference(multipath_conf);
> --
> 2.28.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success
2020-08-19 13:18 ` [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success mwilck
@ 2020-08-19 22:15 ` Benjamin Marzinski
0 siblings, 0 replies; 10+ messages in thread
From: Benjamin Marzinski @ 2020-08-19 22:15 UTC (permalink / raw)
To: mwilck; +Cc: dm-devel
On Wed, Aug 19, 2020 at 03:18:18PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> Make sure that pp->mpp is only set for paths that have been
> successfully added to mpp->paths.
>
> Suggested-by: Benjamin Marzinki <bmarzins@redhat.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/structs_vec.c | 15 +++++++++------
> 1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
> index 2d85df9..cc2dafa 100644
> --- a/libmultipath/structs_vec.c
> +++ b/libmultipath/structs_vec.c
> @@ -248,14 +248,10 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
> pp->dev, mpp->alias);
> continue;
> }
> - pp->mpp = mpp;
> if (pp->initialized == INIT_REMOVED)
> continue;
> - condlog(3, "%s: ownership set to %s",
> - pp->dev, mpp->alias);
> -
> if (!mpp->paths && !(mpp->paths = vector_alloc()))
> - return 1;
> + goto err;
>
> conf = get_multipath_config();
> pthread_cleanup_push(put_multipath_config, conf);
> @@ -270,10 +266,17 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
>
> if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
> store_path(mpp->paths, pp))
> - return 1;
> + goto err;
> +
> + pp->mpp = mpp;
> + condlog(3, "%s: ownership set to %s",
> + pp->dev, mpp->alias);
> }
> }
> return 0;
> +err:
> + condlog(1, "error setting ownership of %s to %s", pp->dev, mpp->alias);
> + return 1;
> }
>
> void orphan_path(struct path *pp, const char *reason)
> --
> 2.28.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok()
2020-08-19 13:18 ` [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok() mwilck
@ 2020-08-19 22:16 ` Benjamin Marzinski
0 siblings, 0 replies; 10+ messages in thread
From: Benjamin Marzinski @ 2020-08-19 22:16 UTC (permalink / raw)
To: mwilck; +Cc: dm-devel
On Wed, Aug 19, 2020 at 03:18:17PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> ... for thread-safety.
>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> Suggested-by: Benjamin Marzinski <bmarzins@redhat.com>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/alias.c | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/libmultipath/alias.c b/libmultipath/alias.c
> index df44bdc..de28f25 100644
> --- a/libmultipath/alias.c
> +++ b/libmultipath/alias.c
> @@ -141,14 +141,14 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
> rewind(f);
> while (fgets(buf, LINE_MAX, f)) {
> const char *alias, *wwid;
> - char *c;
> + char *c, *saveptr;
> int curr_id;
>
> line_nr++;
> c = strpbrk(buf, "#\n\r");
> if (c)
> *c = '\0';
> - alias = strtok(buf, " \t");
> + alias = strtok_r(buf, " \t", &saveptr);
> if (!alias) /* blank line */
> continue;
> curr_id = scan_devname(alias, prefix);
> @@ -164,7 +164,7 @@ lookup_binding(FILE *f, const char *map_wwid, char **map_alias,
> biggest_id = curr_id;
> if (curr_id > id && curr_id < smallest_bigger_id)
> smallest_bigger_id = curr_id;
> - wwid = strtok(NULL, " \t");
> + wwid = strtok_r(NULL, " \t", &saveptr);
> if (!wwid){
> condlog(3,
> "Ignoring malformed line %u in bindings file",
> @@ -206,17 +206,17 @@ rlookup_binding(FILE *f, char *buff, const char *map_alias)
> buff[0] = '\0';
>
> while (fgets(line, LINE_MAX, f)) {
> - char *c;
> + char *c, *saveptr;
> const char *alias, *wwid;
>
> line_nr++;
> c = strpbrk(line, "#\n\r");
> if (c)
> *c = '\0';
> - alias = strtok(line, " \t");
> + alias = strtok_r(line, " \t", &saveptr);
> if (!alias) /* blank line */
> continue;
> - wwid = strtok(NULL, " \t");
> + wwid = strtok_r(NULL, " \t", &saveptr);
> if (!wwid){
> condlog(3,
> "Ignoring malformed line %u in bindings file",
> @@ -582,23 +582,23 @@ static int _check_bindings_file(const struct config *conf, FILE *file,
>
> pthread_cleanup_push(free, line);
> while ((n = getline(&line, &line_len, file)) >= 0) {
> - char *c, *alias, *wwid;
> + char *c, *alias, *wwid, *saveptr;
> const char *mpe_wwid;
>
> linenr++;
> c = strpbrk(line, "#\n\r");
> if (c)
> *c = '\0';
> - alias = strtok(line, " \t");
> + alias = strtok_r(line, " \t", &saveptr);
> if (!alias) /* blank line */
> continue;
> - wwid = strtok(NULL, " \t");
> + wwid = strtok_r(NULL, " \t", &saveptr);
> if (!wwid) {
> condlog(1, "invalid line %d in bindings file, missing WWID",
> linenr);
> continue;
> }
> - c = strtok(NULL, " \t");
> + c = strtok_r(NULL, " \t", &saveptr);
> if (c)
> /* This is non-fatal */
> condlog(1, "invalid line %d in bindings file, extra args \"%s\"",
> --
> 2.28.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10
2020-08-19 13:18 ` [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10 mwilck
@ 2020-08-19 22:40 ` Benjamin Marzinski
2020-08-20 19:09 ` Martin Wilck
0 siblings, 1 reply; 10+ messages in thread
From: Benjamin Marzinski @ 2020-08-19 22:40 UTC (permalink / raw)
To: mwilck; +Cc: dm-devel
On Wed, Aug 19, 2020 at 03:18:19PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> This fixes a warning seen with gcc 10 on x86 (32 bit).
> Fix it by checking the snprintf() return value.
>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/util.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/libmultipath/util.c b/libmultipath/util.c
> index 207e63c..1512424 100644
> --- a/libmultipath/util.c
> +++ b/libmultipath/util.c
> @@ -250,9 +250,9 @@ int systemd_service_enabled_in(const char *dev, const char *prefix)
> p = d->d_name + strlen(d->d_name) - 6;
> if (strcmp(p, ".wants"))
> continue;
> - snprintf(file, sizeof(file), "%s/%s/%s",
> - path, d->d_name, service);
> - if (stat(file, &stbuf) == 0) {
> + if (!safe_sprintf(file, "%s/%s/%s",
> + path, d->d_name, service)
> + && stat(file, &stbuf) == 0) {
> condlog(3, "%s: found %s", dev, file);
> found++;
> break;
> --
> 2.28.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10
2020-08-19 22:40 ` Benjamin Marzinski
@ 2020-08-20 19:09 ` Martin Wilck
0 siblings, 0 replies; 10+ messages in thread
From: Martin Wilck @ 2020-08-20 19:09 UTC (permalink / raw)
To: Benjamin Marzinski; +Cc: dm-devel
On Wed, 2020-08-19 at 17:40 -0500, Benjamin Marzinski wrote:
> On Wed, Aug 19, 2020 at 03:18:19PM +0200, mwilck@suse.com wrote:
> > From: Martin Wilck <mwilck@suse.com>
> >
> > This fixes a warning seen with gcc 10 on x86 (32 bit).
> > Fix it by checking the snprintf() return value.
> >
> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
Thanks a lot, Ben!
This was the last Reviewed-by: tag missing on this series.
I've pushed it to github.com/openSUSE/multipath-tools (upstream-queue)
now.
Regards
Martin
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2020-08-20 19:09 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-19 13:18 [PATCH v3 00/87] multipath-tools series part VII: addional patches mwilck
2020-08-19 13:18 ` [PATCH v3 84/87] libmultipath: add consistency check for alias settings mwilck
2020-08-19 22:13 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 85/87] libmultipath: alias.c: use strtok_r() instead of strtok() mwilck
2020-08-19 22:16 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 86/87] libmultipath: adopt_paths(): set pp->mpp only on success mwilck
2020-08-19 22:15 ` Benjamin Marzinski
2020-08-19 13:18 ` [PATCH v3 87/87] libmultipath: fix a -Wformat-truncation warning from gcc 10 mwilck
2020-08-19 22:40 ` Benjamin Marzinski
2020-08-20 19:09 ` Martin Wilck
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.