multipath: delegate dangerous commands to multipathd
authorMartin Wilck <mwilck@suse.com>
Sat, 13 Jan 2018 21:19:20 +0000 (22:19 +0100)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 7 Mar 2018 08:27:50 +0000 (09:27 +0100)
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.

Note that with delegation, "multipath -r" will not produce any
terminal output, so this may affect users who capture "multipath -r"
output for parsing it. It would be very hard to produce compatible output
to the normal multipath command for different verbosity levels. I
considered running "show topology" after "reconfigure", but the output
would have slightly different format and would only match -v2, anyway.

I plan to convert more multipath commands, but that needs some more
thought. Some additional multipathd client commands need to be
implemented first.

Changes wrt v2:
 - use libmpathcmd rather than exec'ing multipathd (Ben Marzinski)
 - pass more parameters from main program, preparing for other commands

Makefile.inc
multipath/main.c

index d953f5e..d82d3b5 100644 (file)
@@ -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) -DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
                   $(CFLAGS)
 BIN_CFLAGS     = -fPIE -DPIE
 LIB_CFLAGS     = -fPIC
index bffe065..25162a0 100644 (file)
@@ -578,6 +578,64 @@ 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 char *dev,
+                          enum devtypes dev_type, const struct config *conf)
+{
+       int fd;
+       char command[1024], *p, *reply;
+       int n, r = 0;
+
+       fd = mpath_connect();
+       if (fd == -1)
+               return 0;
+
+       p = command;
+       *p = '\0';
+       n = sizeof(command);
+
+       if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
+               p += snprintf(p, n, "reconfigure");
+       }
+       /* Add other translations here */
+
+       if (strlen(command) == 0)
+               /* No command found, no need to delegate */
+               return 0;
+       else if (p >= command + sizeof(command)) {
+               condlog(0, "internal error - command buffer overflow");
+               r = -1;
+               goto out;
+       }
+
+       condlog(3, "delegating command to multipathd");
+       r = mpath_process_cmd(fd, command, &reply, conf->uxsock_timeout);
+
+       if (r == -1) {
+               condlog(1, "error in multipath command %s: %s",
+                       command, strerror(errno));
+               goto out;
+       }
+
+       if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
+               printf("%s", reply);
+       r = 1;
+
+out:
+       FREE(reply);
+       close(fd);
+       if (r < 0)
+               exit(1);
+       return r;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -781,10 +839,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, dev, dev_type, conf))
+               exit(0);
+
        if (cmd == CMD_RESET_WWIDS) {
                struct multipath * mpp;
                int i;