Some multipath commands are dangerous to run while multipathd is running. For example, "multipath -r" may apply a modified configuration to the kernel, while multipathd is still using the old configuration, leading to inconsistent state between multipathd and the kernel. It is safer to use equivalent multipathd client commands instead. For now, do this only for "multipath -r", but other invocations may be added in the future. Perhaps some day, all "multipath" commands will be mapped to multipathd actions. Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> --- Makefile.inc | 2 +- multipath/main.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index 29c290a2..d012b3d7 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -90,7 +90,7 @@ OPTFLAGS = -O2 -g -pipe -Wall -Wextra -Wformat=2 -Werror=implicit-int \ -Wp,-D_FORTIFY_SOURCE=2 $(STACKPROT) \ --param=ssp-buffer-size=4 -CFLAGS = $(OPTFLAGS) -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" +CFLAGS = $(OPTFLAGS) -D BIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" BIN_CFLAGS = -fPIE -DPIE LIB_CFLAGS = -fPIC SHARED_FLAGS = -shared diff --git a/multipath/main.c b/multipath/main.c index dede017e..b54aa9bb 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -502,6 +502,74 @@ get_dev_type(char *dev) { return DEV_NONE; } +/* + * Some multipath commands are dangerous to run while multipathd is running. + * For example, "multipath -r" may apply a modified configuration to the kernel, + * while multipathd is still using the old configuration, leading to + * inconsistent state. + * + * It is safer to use equivalent multipathd client commands instead. + */ +int delegate_to_multipathd(enum mpath_cmds cmd, const struct config *conf) +{ +#define DELEGATE_MAX_ARGS 5 + int fd = mpath_connect(); + char mpd_path[PATH_MAX]; + char *argv[DELEGATE_MAX_ARGS]; + char log[4096], *p; + char verbosity[2] = { '0', '\0' }; + int idx = 1, cmd_idx, sz, n, i; + + if (fd == -1) + return 0; + close(fd); + + if (conf->verbosity > 0 && conf->verbosity < 8) + verbosity[0] = '0' + conf->verbosity; + argv[idx++] = "-v"; + argv[idx++] = verbosity; + + cmd_idx = idx; + if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) { + argv[idx++] = "reconfigure"; + } /* Add other translations here */ + + if (idx == cmd_idx) + /* No command found, no need to delegate */ + return 0; + else if (idx >= DELEGATE_MAX_ARGS) { + condlog(0, "internal error - argv overflow"); + exit(1); + } + + argv[idx] = NULL; + snprintf(mpd_path, sizeof(mpd_path), "%s/%s", BIN_DIR, "multipathd"); + argv[0] = mpd_path; + + condlog(1, "delegating command to multipathd"); + + sz = sizeof(log); + p = log; + i = 0; + n = snprintf(p, sz, "command: %s", argv[i++]); + while (i < idx && n < sz) { + sz -= n; + p += n; + n = snprintf(p, sz, " %s", argv[i++]); + } + condlog(2, "%s", log); + if (n >= sz) + condlog(2, "(command on previous line was truncated)"); + + if (execv(mpd_path, argv) == -1) { + condlog(0, "failed to execute multipathd: %s", strerror(errno)); + exit(1); + } + + /* not reached */ + return 1; +} + int main (int argc, char *argv[]) { @@ -695,10 +763,15 @@ main (int argc, char *argv[]) } else mpath_disconnect(fd); } + if (cmd == CMD_REMOVE_WWID && !dev) { condlog(0, "the -w option requires a device"); goto out; } + + if (delegate_to_multipathd(cmd, conf)) + exit(0); /* not reached */ + if (cmd == CMD_RESET_WWIDS) { struct multipath * mpp; int i; -- 2.14.0 -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel