dm-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
* [PATCH][RESEND] multipath: check if a device belongs to multipath
@ 2012-07-27 20:55 Benjamin Marzinski
  2012-08-17 20:13 ` Christophe Varoqui
  2012-08-21 17:40 ` Christophe Varoqui
  0 siblings, 2 replies; 7+ messages in thread
From: Benjamin Marzinski @ 2012-07-27 20:55 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

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.

Signed-off-by: Benjamin Marzinski <bmarzins@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;
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-07-27 20:55 [PATCH][RESEND] multipath: check if a device belongs to multipath Benjamin Marzinski
@ 2012-08-17 20:13 ` Christophe Varoqui
  2012-08-20 12:15   ` Hannes Reinecke
  2012-08-21 17:40 ` Christophe Varoqui
  1 sibling, 1 reply; 7+ messages in thread
From: Christophe Varoqui @ 2012-08-17 20:13 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development

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@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;
>  

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-08-17 20:13 ` Christophe Varoqui
@ 2012-08-20 12:15   ` Hannes Reinecke
  2012-08-20 17:43     ` Benjamin Marzinski
  0 siblings, 1 reply; 7+ messages in thread
From: Hannes Reinecke @ 2012-08-20 12:15 UTC (permalink / raw)
  To: christophe.varoqui, device-mapper development; +Cc: Christophe Varoqui

On 08/17/2012 10:13 PM, Christophe Varoqui wrote:
> 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 ?
> 
No; currently I didn't solve it at all, what with me being tied up
with customer issues :-(

But this is basically the approach I've discussed with Harald Hoyer
and Kay Sievers on how we should facilitate proper systemd integration.

The idea here is to have a udev rule calling 'multipath -c' via
PROGRAM, so that udev can detect if a device should've been handled
via multipath.
Which would allow any rules following that one to evaluate this
status and possibly skip the device.

So from that perspective the patch should be okay.

However, the one thing to note is this patch _again_ is using
hard-coded filenames under /etc, which really shouldn't happen.
We should be introducing a configuration file variable to set it.

> Ben, does this approach supersedes/extends the "complicated blacklisting
> scheme" you proposed earlier ?
> 
I sincerely hope so ...

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-08-20 12:15   ` Hannes Reinecke
@ 2012-08-20 17:43     ` Benjamin Marzinski
  2012-08-20 17:50       ` Christophe Varoqui
  0 siblings, 1 reply; 7+ messages in thread
From: Benjamin Marzinski @ 2012-08-20 17:43 UTC (permalink / raw)
  To: Hannes Reinecke; +Cc: device-mapper development, Christophe Varoqui

On Mon, Aug 20, 2012 at 02:15:21PM +0200, Hannes Reinecke wrote:
> On 08/17/2012 10:13 PM, Christophe Varoqui wrote:
> > 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 ?
> > 
> No; currently I didn't solve it at all, what with me being tied up
> with customer issues :-(
> 
> But this is basically the approach I've discussed with Harald Hoyer
> and Kay Sievers on how we should facilitate proper systemd integration.
> 
> The idea here is to have a udev rule calling 'multipath -c' via
> PROGRAM, so that udev can detect if a device should've been handled
> via multipath.
> Which would allow any rules following that one to evaluate this
> status and possibly skip the device.
> 
> So from that perspective the patch should be okay.
> 
> However, the one thing to note is this patch _again_ is using
> hard-coded filenames under /etc, which really shouldn't happen.
> We should be introducing a configuration file variable to set it.

I'll post a patch that adds a configuration parameter soon.

> 
> > Ben, does this approach supersedes/extends the "complicated blacklisting
> > scheme" you proposed earlier ?
> > 
> I sincerely hope so ...

actually, this is patch is what I though were the non-objectional parts
to that patch.  I still think it's useful to be able to setup multipath
so that instead of defaulting to use all the non-blacklisted LUNs, it
just defaults to using the LUNs which actually have multiple paths. That
patch didn't effect how the blacklisting code worked. Nor did it keep you
from setting up multipath on single pathed LUNs. It just didn't default
to setting up multipath devices on single pathed LUNs, if you had never
set up a multipath device on that LUN before. 

-Ben

> Cheers,
> 
> Hannes
> -- 
> Dr. Hannes Reinecke		      zSeries & Storage
> hare@suse.de			      +49 911 74053 688
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
> GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-08-20 17:43     ` Benjamin Marzinski
@ 2012-08-20 17:50       ` Christophe Varoqui
  2012-08-20 21:57         ` Benjamin Marzinski
  0 siblings, 1 reply; 7+ messages in thread
From: Christophe Varoqui @ 2012-08-20 17:50 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development, Christophe Varoqui

On lun., 2012-08-20 at 12:43 -0500, Benjamin Marzinski wrote:
> On Mon, Aug 20, 2012 at 02:15:21PM +0200, Hannes Reinecke wrote:
> > On 08/17/2012 10:13 PM, Christophe Varoqui wrote:
> > > 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 ?
> > > 
> > No; currently I didn't solve it at all, what with me being tied up
> > with customer issues :-(
> > 
> > But this is basically the approach I've discussed with Harald Hoyer
> > and Kay Sievers on how we should facilitate proper systemd integration.
> > 
> > The idea here is to have a udev rule calling 'multipath -c' via
> > PROGRAM, so that udev can detect if a device should've been handled
> > via multipath.
> > Which would allow any rules following that one to evaluate this
> > status and possibly skip the device.
> > 
> > So from that perspective the patch should be okay.
> > 
> > However, the one thing to note is this patch _again_ is using
> > hard-coded filenames under /etc, which really shouldn't happen.
> > We should be introducing a configuration file variable to set it.
> 
> I'll post a patch that adds a configuration parameter soon.
> 
> > 
> > > Ben, does this approach supersedes/extends the "complicated blacklisting
> > > scheme" you proposed earlier ?
> > > 
> > I sincerely hope so ...
> 
> actually, this is patch is what I though were the non-objectional parts
> to that patch.  I still think it's useful to be able to setup multipath
> so that instead of defaulting to use all the non-blacklisted LUNs, it
> just defaults to using the LUNs which actually have multiple paths. That
> patch didn't effect how the blacklisting code worked. Nor did it keep you
> from setting up multipath on single pathed LUNs. It just didn't default
> to setting up multipath devices on single pathed LUNs, if you had never
> set up a multipath device on that LUN before. 
> 
Ok fine. Do you prefer I merge the already submitted patch so that you
can submit an incremental patch for the cache file location or I wait
for your submitting a feature-complete patch ?

Thanks for the clarification.

cvaroqui,
OpenSVC

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-08-20 17:50       ` Christophe Varoqui
@ 2012-08-20 21:57         ` Benjamin Marzinski
  0 siblings, 0 replies; 7+ messages in thread
From: Benjamin Marzinski @ 2012-08-20 21:57 UTC (permalink / raw)
  To: christophe.varoqui; +Cc: device-mapper development, Christophe Varoqui

On Mon, Aug 20, 2012 at 07:50:31PM +0200, Christophe Varoqui wrote:
> On lun., 2012-08-20 at 12:43 -0500, Benjamin Marzinski wrote:
> > On Mon, Aug 20, 2012 at 02:15:21PM +0200, Hannes Reinecke wrote:
> > > On 08/17/2012 10:13 PM, Christophe Varoqui wrote:
> > > > 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 ?
> > > > 
> > > No; currently I didn't solve it at all, what with me being tied up
> > > with customer issues :-(
> > > 
> > > But this is basically the approach I've discussed with Harald Hoyer
> > > and Kay Sievers on how we should facilitate proper systemd integration.
> > > 
> > > The idea here is to have a udev rule calling 'multipath -c' via
> > > PROGRAM, so that udev can detect if a device should've been handled
> > > via multipath.
> > > Which would allow any rules following that one to evaluate this
> > > status and possibly skip the device.
> > > 
> > > So from that perspective the patch should be okay.
> > > 
> > > However, the one thing to note is this patch _again_ is using
> > > hard-coded filenames under /etc, which really shouldn't happen.
> > > We should be introducing a configuration file variable to set it.
> > 
> > I'll post a patch that adds a configuration parameter soon.
> > 
> > > 
> > > > Ben, does this approach supersedes/extends the "complicated blacklisting
> > > > scheme" you proposed earlier ?
> > > > 
> > > I sincerely hope so ...
> > 
> > actually, this is patch is what I though were the non-objectional parts
> > to that patch.  I still think it's useful to be able to setup multipath
> > so that instead of defaulting to use all the non-blacklisted LUNs, it
> > just defaults to using the LUNs which actually have multiple paths. That
> > patch didn't effect how the blacklisting code worked. Nor did it keep you
> > from setting up multipath on single pathed LUNs. It just didn't default
> > to setting up multipath devices on single pathed LUNs, if you had never
> > set up a multipath device on that LUN before. 
> > 
> Ok fine. Do you prefer I merge the already submitted patch so that you
> can submit an incremental patch for the cache file location or I wait
> for your submitting a feature-complete patch ?
> 
> Thanks for the clarification.

The existing patch could have stood to be broken up in the interest of
easy reading. I don't want to make it any larger. I'll just send a
second patch that adds the multipath.conf option.

Thanks.

-Ben 

> 
> cvaroqui,
> OpenSVC

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH][RESEND] multipath: check if a device belongs to multipath
  2012-07-27 20:55 [PATCH][RESEND] multipath: check if a device belongs to multipath Benjamin Marzinski
  2012-08-17 20:13 ` Christophe Varoqui
@ 2012-08-21 17:40 ` Christophe Varoqui
  1 sibling, 0 replies; 7+ messages in thread
From: Christophe Varoqui @ 2012-08-21 17:40 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development, Christophe Varoqui

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.
> 
Applied.

Thanks.

> Signed-off-by: Benjamin Marzinski <bmarzins@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;
>  

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-08-21 17:40 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-27 20:55 [PATCH][RESEND] multipath: check if a device belongs to multipath Benjamin Marzinski
2012-08-17 20:13 ` Christophe Varoqui
2012-08-20 12:15   ` Hannes Reinecke
2012-08-20 17:43     ` Benjamin Marzinski
2012-08-20 17:50       ` Christophe Varoqui
2012-08-20 21:57         ` Benjamin Marzinski
2012-08-21 17:40 ` Christophe Varoqui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).