[dm-devel] [PATCH][RESEND] multipath: check if a device belongs to multipath

Christophe Varoqui christophe.varoqui at gmail.com
Fri Aug 17 20:13:10 UTC 2012


On ven., 2012-07-27 at 15:55 -0500, Benjamin Marzinski wrote:
> This patch adds a new multipath option "-c", which checks if a device
> belongs to multipath.  This can be done during the add uevent for the
> device, before the multipath device has even been created.  This allows
> udev to be able to handle multipath path devices differently.  To do
> this multipath now keeps track of the wwids of all previously created
> multipath devices in /etc/multipath/wwids. The file creating and
> editting code from alias.[ch] has been split out into file.[ch]. When a
> device is checked to see if it's a multipath path, it's wwid is
> compared against the ones in the wwids file. Also, since the
> uid_attribute may not have been added to the udev database entry for
> the device if this is called in a udev rule, when using the "-c" option,
> get_uid will now also check the process' envirionment variables for the
> uid_attribute.
> 
I'd like other distribution maintainers' comments on this one, as it
impacts the multipath-tools intregration with udev.

Hannes ? Did you face the same issue with SuSE ? Did you solve it
differently ?

Ben, does this approach supersedes/extends the "complicated blacklisting
scheme" you proposed earlier ?

Thanks.

> Signed-off-by: Benjamin Marzinski <bmarzins at redhat.com>
> ---
>  libmultipath/Makefile    |    2 
>  libmultipath/alias.c     |  153 ---------------------------------------
>  libmultipath/alias.h     |    1 
>  libmultipath/configure.c |    3 
>  libmultipath/defaults.h  |    1 
>  libmultipath/discovery.c |    2 
>  libmultipath/file.c      |  180 +++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/file.h      |   11 ++
>  libmultipath/wwids.c     |  139 ++++++++++++++++++++++++++++++++++++
>  libmultipath/wwids.h     |   18 ++++
>  multipath/main.c         |   37 ++++++++-
>  11 files changed, 389 insertions(+), 158 deletions(-)
> 
> Index: multipath-tools-120518/libmultipath/alias.c
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/alias.c
> +++ multipath-tools-120518/libmultipath/alias.c
> @@ -3,19 +3,16 @@
>   * Copyright (c) 2005 Benjamin Marzinski, Redhat
>   */
>  #include <stdlib.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
> -#include <fcntl.h>
>  #include <errno.h>
>  #include <unistd.h>
>  #include <string.h>
>  #include <limits.h>
>  #include <stdio.h>
> -#include <signal.h>
>  
>  #include "debug.h"
>  #include "uxsock.h"
>  #include "alias.h"
> +#include "file.h"
>  
> 
>  /*
> @@ -36,150 +33,6 @@
>   * See the file COPYING included with this distribution for more details.
>   */
>  
> -static int
> -ensure_directories_exist(char *str, mode_t dir_mode)
> -{
> -	char *pathname;
> -	char *end;
> -	int err;
> -
> -	pathname = strdup(str);
> -	if (!pathname){
> -		condlog(0, "Cannot copy bindings file pathname : %s",
> -			strerror(errno));
> -		return -1;
> -	}
> -	end = pathname;
> -	/* skip leading slashes */
> -	while (end && *end && (*end == '/'))
> -		end++;
> -
> -	while ((end = strchr(end, '/'))) {
> -		/* if there is another slash, make the dir. */
> -		*end = '\0';
> -		err = mkdir(pathname, dir_mode);
> -		if (err && errno != EEXIST) {
> -			condlog(0, "Cannot make directory [%s] : %s",
> -				pathname, strerror(errno));
> -			free(pathname);
> -			return -1;
> -		}
> -		if (!err)
> -			condlog(3, "Created dir [%s]", pathname);
> -		*end = '/';
> -		end++;
> -	}
> -	free(pathname);
> -	return 0;
> -}
> -
> -static void
> -sigalrm(int sig)
> -{
> -	/* do nothing */
> -}
> -
> -static int
> -lock_bindings_file(int fd)
> -{
> -	struct sigaction act, oldact;
> -	sigset_t set, oldset;
> -	struct flock lock;
> -	int err;
> -
> -	memset(&lock, 0, sizeof(lock));
> -	lock.l_type = F_WRLCK;
> -	lock.l_whence = SEEK_SET;
> -
> -	act.sa_handler = sigalrm;
> -	sigemptyset(&act.sa_mask);
> -	act.sa_flags = 0;
> -	sigemptyset(&set);
> -	sigaddset(&set, SIGALRM);
> -
> -	sigaction(SIGALRM, &act, &oldact);
> -	sigprocmask(SIG_UNBLOCK, &set, &oldset);
> -
> -	alarm(BINDINGS_FILE_TIMEOUT);
> -	err = fcntl(fd, F_SETLKW, &lock);
> -	alarm(0);
> -
> -	if (err) {
> -		if (errno != EINTR)
> -			condlog(0, "Cannot lock bindings file : %s",
> -					strerror(errno));
> -		else
> -			condlog(0, "Bindings file is locked. Giving up.");
> -	}
> -
> -	sigprocmask(SIG_SETMASK, &oldset, NULL);
> -	sigaction(SIGALRM, &oldact, NULL);
> -	return err;
> -
> -}
> -
> -
> -static int
> -open_bindings_file(char *file, int *can_write)
> -{
> -	int fd;
> -	struct stat s;
> -
> -	if (ensure_directories_exist(file, 0700))
> -		return -1;
> -	*can_write = 1;
> -	fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
> -	if (fd < 0) {
> -		if (errno == EROFS) {
> -			*can_write = 0;
> -			condlog(3, "Cannot open bindings file [%s] read/write. "
> -				" trying readonly", file);
> -			fd = open(file, O_RDONLY);
> -			if (fd < 0) {
> -				condlog(0, "Cannot open bindings file [%s] "
> -					"readonly : %s", file, strerror(errno));
> -				return -1;
> -			}
> -		}
> -		else {
> -			condlog(0, "Cannot open bindings file [%s] : %s", file,
> -				strerror(errno));
> -			return -1;
> -		}
> -	}
> -	if (*can_write && lock_bindings_file(fd) < 0)
> -		goto fail;
> -
> -	memset(&s, 0, sizeof(s));
> -	if (fstat(fd, &s) < 0){
> -		condlog(0, "Cannot stat bindings file : %s", strerror(errno));
> -		goto fail;
> -	}
> -	if (s.st_size == 0) {
> -		if (*can_write == 0)
> -			goto fail;
> -		/* If bindings file is empty, write the header */
> -		size_t len = strlen(BINDINGS_FILE_HEADER);
> -		if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) {
> -			condlog(0,
> -				"Cannot write header to bindings file : %s",
> -				strerror(errno));
> -			/* cleanup partially written header */
> -			if (ftruncate(fd, 0))
> -				condlog(0, "Cannot truncate the header : %s",
> -					strerror(errno));
> -			goto fail;
> -		}
> -		fsync(fd);
> -		condlog(3, "Initialized new bindings file [%s]", file);
> -	}
> -
> -	return fd;
> -
> -fail:
> -	close(fd);
> -	return -1;
> -}
>  
>  static int
>  format_devname(char *name, int id, int len, char *prefix)
> @@ -370,7 +223,7 @@ get_user_friendly_alias(char *wwid, char
>  		return NULL;
>  	}
>  
> -	fd = open_bindings_file(file, &can_write);
> +	fd = open_file(file, &can_write, BINDINGS_FILE_HEADER);
>  	if (fd < 0)
>  		return NULL;
>  
> @@ -414,7 +267,7 @@ get_user_friendly_wwid(char *alias, char
>  		return NULL;
>  	}
>  
> -	fd = open_bindings_file(file, &unused);
> +	fd = open_file(file, &unused, BINDINGS_FILE_HEADER);
>  	if (fd < 0)
>  		return NULL;
>  
> Index: multipath-tools-120518/libmultipath/alias.h
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/alias.h
> +++ multipath-tools-120518/libmultipath/alias.h
> @@ -1,4 +1,3 @@
> -#define BINDINGS_FILE_TIMEOUT 30
>  #define BINDINGS_FILE_HEADER \
>  "# Multipath bindings, Version : 1.0\n" \
>  "# NOTE: this file is automatically maintained by the multipath program.\n" \
> Index: multipath-tools-120518/libmultipath/configure.c
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/configure.c
> +++ multipath-tools-120518/libmultipath/configure.c
> @@ -37,6 +37,7 @@
>  #include "prio.h"
>  #include "util.h"
>  #include "uxsock.h"
> +#include "wwids.h"
>  
>  extern int
>  setup_map (struct multipath * mpp, char * params, int params_size)
> @@ -407,6 +408,8 @@ domap (struct multipath * mpp, char * pa
>  		 * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
>  		 * succeeded
>  		 */
> +		if (mpp->action == ACT_CREATE)
> +			remember_wwid(mpp->wwid);
>  		if (!conf->daemon) {
>  			/* multipath client mode */
>  			dm_switchgroup(mpp->alias, mpp->bestpg);
> Index: multipath-tools-120518/libmultipath/defaults.h
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/defaults.h
> +++ multipath-tools-120518/libmultipath/defaults.h
> @@ -24,5 +24,6 @@
>  #define DEFAULT_SOCKET		"/var/run/multipathd.sock"
>  #define DEFAULT_CONFIGFILE	"/etc/multipath.conf"
>  #define DEFAULT_BINDINGS_FILE	"/etc/multipath/bindings"
> +#define DEFAULT_WWIDS_FILE	"/etc/multipath/wwids"
>  
>  char * set_default (char * str);
> Index: multipath-tools-120518/libmultipath/file.c
> ===================================================================
> --- /dev/null
> +++ multipath-tools-120518/libmultipath/file.c
> @@ -0,0 +1,180 @@
> +/*
> + * Copyright (c) 2005 Christophe Varoqui
> + * Copyright (c) 2005 Benjamin Marzinski, Redhat
> + */
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <signal.h>
> +
> +#include "file.h"
> +#include "debug.h"
> +#include "uxsock.h"
> +
> +
> +/*
> + * significant parts of this file were taken from iscsi-bindings.c of the
> + * linux-iscsi project.
> + * Copyright (C) 2002 Cisco Systems, Inc.
> + *
> + * 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.
> + *
> + * See the file COPYING included with this distribution for more details.
> + */
> +
> +static int
> +ensure_directories_exist(char *str, mode_t dir_mode)
> +{
> +	char *pathname;
> +	char *end;
> +	int err;
> +
> +	pathname = strdup(str);
> +	if (!pathname){
> +		condlog(0, "Cannot copy file pathname %s : %s",
> +			str, strerror(errno));
> +		return -1;
> +	}
> +	end = pathname;
> +	/* skip leading slashes */
> +	while (end && *end && (*end == '/'))
> +		end++;
> +
> +	while ((end = strchr(end, '/'))) {
> +		/* if there is another slash, make the dir. */
> +		*end = '\0';
> +		err = mkdir(pathname, dir_mode);
> +		if (err && errno != EEXIST) {
> +			condlog(0, "Cannot make directory [%s] : %s",
> +				pathname, strerror(errno));
> +			free(pathname);
> +			return -1;
> +		}
> +		if (!err)
> +			condlog(3, "Created dir [%s]", pathname);
> +		*end = '/';
> +		end++;
> +	}
> +	free(pathname);
> +	return 0;
> +}
> +
> +static void
> +sigalrm(int sig)
> +{
> +	/* do nothing */
> +}
> +
> +static int
> +lock_file(int fd, char *file_name)
> +{
> +	struct sigaction act, oldact;
> +	sigset_t set, oldset;
> +	struct flock lock;
> +	int err;
> +
> +	memset(&lock, 0, sizeof(lock));
> +	lock.l_type = F_WRLCK;
> +	lock.l_whence = SEEK_SET;
> +
> +	act.sa_handler = sigalrm;
> +	sigemptyset(&act.sa_mask);
> +	act.sa_flags = 0;
> +	sigemptyset(&set);
> +	sigaddset(&set, SIGALRM);
> +
> +	sigaction(SIGALRM, &act, &oldact);
> +	sigprocmask(SIG_UNBLOCK, &set, &oldset);
> +
> +	alarm(FILE_TIMEOUT);
> +	err = fcntl(fd, F_SETLKW, &lock);
> +	alarm(0);
> +
> +	if (err) {
> +		if (errno != EINTR)
> +			condlog(0, "Cannot lock %s : %s", file_name,
> +				strerror(errno));
> +		else
> +			condlog(0, "%s is locked. Giving up.", file_name);
> +	}
> +
> +	sigprocmask(SIG_SETMASK, &oldset, NULL);
> +	sigaction(SIGALRM, &oldact, NULL);
> +	return err;
> +}
> +
> +int
> +open_file(char *file, int *can_write, char *header)
> +{
> +	int fd;
> +	struct stat s;
> +
> +	if (ensure_directories_exist(file, 0700))
> +		return -1;
> +	*can_write = 1;
> +	fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
> +	if (fd < 0) {
> +		if (errno == EROFS) {
> +			*can_write = 0;
> +			condlog(3, "Cannot open file [%s] read/write. "
> +				" trying readonly", file);
> +			fd = open(file, O_RDONLY);
> +			if (fd < 0) {
> +				condlog(0, "Cannot open file [%s] "
> +					"readonly : %s", file, strerror(errno));
> +				return -1;
> +			}
> +		}
> +		else {
> +			condlog(0, "Cannot open file [%s] : %s", file,
> +				strerror(errno));
> +			return -1;
> +		}
> +	}
> +	if (*can_write && lock_file(fd, file) < 0)
> +		goto fail;
> +
> +	memset(&s, 0, sizeof(s));
> +	if (fstat(fd, &s) < 0){
> +		condlog(0, "Cannot stat file %s : %s", file, strerror(errno));
> +		goto fail;
> +	}
> +	if (s.st_size == 0) {
> +		if (*can_write == 0)
> +			goto fail;
> +		/* If file is empty, write the header */
> +		size_t len = strlen(header);
> +		if (write_all(fd, header, len) != len) {
> +			condlog(0,
> +				"Cannot write header to file %s : %s", file,
> +				strerror(errno));
> +			/* cleanup partially written header */
> +			if (ftruncate(fd, 0))
> +				condlog(0, "Cannot truncate header : %s",
> +					strerror(errno));
> +			goto fail;
> +		}
> +		fsync(fd);
> +		condlog(3, "Initialized new file [%s]", file);
> +	}
> +
> +	return fd;
> +
> +fail:
> +	close(fd);
> +	return -1;
> +}
> Index: multipath-tools-120518/libmultipath/file.h
> ===================================================================
> --- /dev/null
> +++ multipath-tools-120518/libmultipath/file.h
> @@ -0,0 +1,11 @@
> +/*
> + * Copyright (c) 2010 Benjamin Marzinski, Redhat
> + */
> +
> +#ifndef _FILE_H
> +#define _FILE_H
> +
> +#define FILE_TIMEOUT 30
> +int open_file(char *file, int *can_write, char *header);
> +
> +#endif /* _FILE_H */
> Index: multipath-tools-120518/multipath/main.c
> ===================================================================
> --- multipath-tools-120518.orig/multipath/main.c
> +++ multipath-tools-120518/multipath/main.c
> @@ -53,6 +53,7 @@
>  #include <errno.h>
>  #include <sys/time.h>
>  #include <sys/resource.h>
> +#include <wwids.h>
>  #include "dev_t.h"
>  
>  int logsink;
> @@ -82,7 +83,7 @@ usage (char * progname)
>  {
>  	fprintf (stderr, VERSION_STRING);
>  	fprintf (stderr, "Usage:\n");
> -	fprintf (stderr, "  %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
> +	fprintf (stderr, "  %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
>  	fprintf (stderr, "  %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
>  	fprintf (stderr, "  %s -F [-v lvl]\n", progname);
>  	fprintf (stderr, "  %s -t\n", progname);
> @@ -95,6 +96,7 @@ usage (char * progname)
>  		"  -ll     show multipath topology (maximum info)\n" \
>  		"  -f      flush a multipath device map\n" \
>  		"  -F      flush all multipath device maps\n" \
> +		"  -c      check if a device should be a path in a multipath device\n" \
>  		"  -q      allow queue_if_no_path when multipathd is not running\n"\
>  		"  -d      dry run, do not create or update devmaps\n" \
>  		"  -t      dump internal hardware table\n" \
> @@ -209,6 +211,7 @@ get_dm_mpvec (vector curmp, vector pathv
>  
>  		if (!conf->dry_run)
>  			reinstate_paths(mpp);
> +		remember_wwid(mpp->wwid);
>  	}
>  	return 0;
>  }
> @@ -259,9 +262,13 @@ configure (void)
>  	 * if we have a blacklisted device parameter, exit early
>  	 */
>  	if (dev &&
> -	    (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0))
> -			goto out;
> -
> +	    (filter_devnode(conf->blist_devnode,
> +			    conf->elist_devnode, dev) > 0)) {
> +		if (conf->dry_run == 2)
> +			printf("%s is not a valid multipath device path\n",
> +			       conf->dev);
> +		goto out;
> +	}
>  	/*
>  	 * scope limiting must be translated into a wwid
>  	 * failing the translation is fatal (by policy)
> @@ -277,6 +284,15 @@ configure (void)
>  		if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
>  				refwwid) > 0)
>  			goto out;
> +		if (conf->dry_run == 2) {
> +			if (check_wwids_file(refwwid, 0) == 0){
> +				printf("%s is a valid multipath device path\n", conf->dev);
> +				r = 0;
> +			}
> +			else
> +				printf("%s is not a valid multipath device path\n", conf->dev);
> +			goto out;
> +		}
>  	}
>  
>  	/*
> @@ -412,7 +428,7 @@ main (int argc, char *argv[])
>  	if (load_config(DEFAULT_CONFIGFILE))
>  		exit(1);
>  
> -	while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:Brtq")) != EOF ) {
> +	while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) {
>  		switch(arg) {
>  		case 1: printf("optarg : %s\n",optarg);
>  			break;
> @@ -434,8 +450,12 @@ main (int argc, char *argv[])
>  		case 'q':
>  			conf->allow_queueing = 1;
>  			break;
> +		case 'c':
> +			conf->dry_run = 2;
> +			break;
>  		case 'd':
> -			conf->dry_run = 1;
> +			if (!conf->dry_run)
> +				conf->dry_run = 1;
>  			break;
>  		case 'f':
>  			conf->remove = FLUSH_ONE;
> @@ -517,6 +537,11 @@ main (int argc, char *argv[])
>  	}
>  	dm_init();
>  
> +	if (conf->dry_run == 2 &&
> +	    (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
> +		condlog(0, "the -c option requires a path to check");
> +		goto out;
> +	}
>  	if (conf->remove == FLUSH_ONE) {
>  		if (conf->dev_type == DEV_DEVMAP)
>  			r = dm_flush_map(conf->dev);
> Index: multipath-tools-120518/libmultipath/Makefile
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/Makefile
> +++ multipath-tools-120518/libmultipath/Makefile
> @@ -15,7 +15,7 @@ OBJS = memory.o parser.o vector.o devmap
>         pgpolicies.o debug.o regex.o defaults.o uevent.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
> +       lock.o waiter.o file.o wwids.o
>  
>  LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h)
>  
> Index: multipath-tools-120518/libmultipath/wwids.c
> ===================================================================
> --- /dev/null
> +++ multipath-tools-120518/libmultipath/wwids.c
> @@ -0,0 +1,139 @@
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <stdio.h>
> +
> +#include "checkers.h"
> +#include "vector.h"
> +#include "structs.h"
> +#include "debug.h"
> +#include "uxsock.h"
> +#include "file.h"
> +#include "wwids.h"
> +#include "defaults.h"
> +
> +/*
> + * Copyright (c) 2010 Benjamin Marzinski, Redhat
> + */
> +
> +static int
> +lookup_wwid(FILE *f, char *wwid) {
> +	int c;
> +	char buf[LINE_MAX];
> +	int count;
> +
> +	while ((c = fgetc(f)) != EOF){
> +		if (c != '/') {
> +			if (fgets(buf, LINE_MAX, f) == NULL)
> +				return 0;
> +			else
> +				continue;
> +		}
> +		count = 0;
> +		while ((c = fgetc(f)) != '/') {
> +			if (c == EOF)
> +				return 0;
> +			if (count >= WWID_SIZE - 1)
> +				goto next;
> +			if (wwid[count] == '\0')
> +				goto next;
> +			if (c != wwid[count++])
> +				goto next;
> +		}
> +		if (wwid[count] == '\0')
> +			return 1;
> +next:
> +		if (fgets(buf, LINE_MAX, f) == NULL)
> +			return 0;
> +	}
> +	return 0;
> +}
> +
> +static int
> +write_out_wwid(int fd, char *wwid) {
> +	int ret;
> +	off_t offset;
> +	char buf[WWID_SIZE + 3];
> +
> +	ret = snprintf(buf, WWID_SIZE + 3, "/%s/\n", wwid);
> +	if (ret >= (WWID_SIZE + 3) || ret < 0){
> +		condlog(0, "can't format wwid for writing (%d) : %s",
> +			ret, strerror(errno));
> +		return -1;
> +	}
> +	offset = lseek(fd, 0, SEEK_END);
> +	if (offset < 0) {
> +		condlog(0, "can't seek to the end of wwids file : %s",
> +			strerror(errno));
> +		return -1;
> +	}
> +	if (write_all(fd, buf, strlen(buf)) != strlen(buf)) {
> +		condlog(0, "cannot write wwid to wwids file : %s",
> +			strerror(errno));
> +		if (ftruncate(fd, offset))
> +			condlog(0, "cannot truncate failed wwid write : %s",
> +				strerror(errno));
> +		return -1;
> +	}
> +	return 1;
> +}
> +
> +int
> +check_wwids_file(char *wwid, int write_wwid)
> +{
> +	int fd, can_write, found, ret;
> +	FILE *f;
> +	fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER);
> +	if (fd < 0)
> +		return -1;
> +
> +	f = fdopen(fd, "r");
> +	if (!f) {
> +		condlog(0,"can't fdopen wwids file : %s", strerror(errno));
> +		close(fd);
> +		return -1;
> +	}
> +	found = lookup_wwid(f, wwid);
> +	if (found) {
> +		ret = 0;
> +		goto out;
> +	}
> +	if (!write_wwid) {
> +		ret = -1;
> +		goto out;
> +	}
> +	if (!can_write) {
> +		condlog(0, "wwids file is read-only. Can't write wwid");
> +		ret = -1;
> +		goto out;
> +	}
> +
> +	if (fflush(f) != 0) {
> +		condlog(0, "cannot fflush wwids file stream : %s",
> +			strerror(errno));
> +		ret = -1;
> +		goto out;
> +	}
> +
> +	ret = write_out_wwid(fd, wwid);
> +out:
> +	fclose(f);
> +	return ret;
> +}
> +
> +int
> +remember_wwid(char *wwid)
> +{
> +	int ret = check_wwids_file(wwid, 1);
> +	if (ret < 0){
> +		condlog(3, "failed writing wwid %s to wwids file", wwid);
> +		return -1;
> +	}
> +	if (ret == 1)
> +		condlog(3, "wrote wwid %s to wwids file", wwid);
> +	else
> +		condlog(4, "wwid %s already in wwids file", wwid);
> +	return 0;
> +}
> Index: multipath-tools-120518/libmultipath/wwids.h
> ===================================================================
> --- /dev/null
> +++ multipath-tools-120518/libmultipath/wwids.h
> @@ -0,0 +1,18 @@
> +/*
> + * Copyright (c) 2010 Benjamin Marzinski, Redhat
> + */
> +
> +#ifndef _WWIDS_H
> +#define _WWIDS_H
> +
> +#define WWIDS_FILE_HEADER \
> +"# Multipath wwids, Version : 1.0\n" \
> +"# NOTE: This file is automatically maintained by multipath and multipathd.\n" \
> +"# You should not need to edit this file in normal circumstances.\n" \
> +"#\n" \
> +"# Valid WWIDs:\n"
> +
> +int remember_wwid(char *wwid);
> +int check_wwids_file(char *wwid, int write_wwid);
> +
> +#endif /* _WWIDS_H */
> Index: multipath-tools-120518/libmultipath/discovery.c
> ===================================================================
> --- multipath-tools-120518.orig/libmultipath/discovery.c
> +++ multipath-tools-120518/libmultipath/discovery.c
> @@ -810,6 +810,8 @@ get_uid (struct path * pp)
>  
>  	memset(pp->wwid, 0, WWID_SIZE);
>  	value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
> +	if ((!value || strlen(value) == 0) && conf->dry_run == 2)
> +		value = getenv(pp->uid_attribute);
>  	if (value && strlen(value)) {
>  		size_t len = WWID_SIZE;
>  






More information about the dm-devel mailing list