[dm-devel] [PATCH 4/4] multipath: delegate dangerous commands to multipathd

Benjamin Marzinski bmarzins at redhat.com
Thu Sep 7 21:57:58 UTC 2017


On Tue, Aug 29, 2017 at 12:05:36AM +0200, Martin Wilck wrote:
> 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.

Thanks. I've been meaning to do something like this forever.

> 
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>  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);
> +	}

Why not just return 0 here, so that we can try the failing back to the
multipath code. In the longer term, it's definitely worth asking if that
code needs to exist at all, of if a large chunk of multipath code can
just turn into wrapped calls to multipathd.

> +
> +	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);
> +	}

Why exec multipathd, instead of using the libmpathcmd api, like
mpathpersist, libdmmp, and the multipathd client do?

-Ben

> +
> +	/* 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




More information about the dm-devel mailing list