r250 - in multipath-tools/upstream/current: . devmap_name kpartx libmultipath multipath multipathd path_priority/pp_alua path_priority/pp_balance_units path_priority/pp_emc path_priority/pp_random

Bastian Blank waldi at costa.debian.org
Wed Feb 1 23:48:35 UTC 2006


Author: waldi
Date: Wed Feb  1 23:48:32 2006
New Revision: 250

Added:
   multipath-tools/upstream/current/libmultipath/alias.c
   multipath-tools/upstream/current/libmultipath/alias.h
   multipath-tools/upstream/current/libmultipath/log.c
   multipath-tools/upstream/current/libmultipath/log.h
   multipath-tools/upstream/current/libmultipath/log_pthread.c
   multipath-tools/upstream/current/libmultipath/log_pthread.h
   multipath-tools/upstream/current/path_priority/pp_random/   (props changed)
   multipath-tools/upstream/current/path_priority/pp_random/Makefile
   multipath-tools/upstream/current/path_priority/pp_random/pp_random.c
Removed:
   multipath-tools/upstream/current/kpartx/gpt.c.orig
   multipath-tools/upstream/current/multipath/multipath.dev
   multipath-tools/upstream/current/multipathd/log.c
   multipath-tools/upstream/current/multipathd/log.h
   multipath-tools/upstream/current/multipathd/log_pthread.c
   multipath-tools/upstream/current/multipathd/log_pthread.h
Modified:
   multipath-tools/upstream/current/ChangeLog
   multipath-tools/upstream/current/Makefile
   multipath-tools/upstream/current/Makefile.inc
   multipath-tools/upstream/current/devmap_name/Makefile
   multipath-tools/upstream/current/kpartx/Makefile
   multipath-tools/upstream/current/kpartx/byteorder.h
   multipath-tools/upstream/current/kpartx/dos.c
   multipath-tools/upstream/current/kpartx/kpartx.c
   multipath-tools/upstream/current/libmultipath/Makefile
   multipath-tools/upstream/current/libmultipath/blacklist.c
   multipath-tools/upstream/current/libmultipath/cache.c
   multipath-tools/upstream/current/libmultipath/config.c
   multipath-tools/upstream/current/libmultipath/config.h
   multipath-tools/upstream/current/libmultipath/debug.c
   multipath-tools/upstream/current/libmultipath/debug.h
   multipath-tools/upstream/current/libmultipath/defaults.h
   multipath-tools/upstream/current/libmultipath/devmapper.c
   multipath-tools/upstream/current/libmultipath/devmapper.h
   multipath-tools/upstream/current/libmultipath/dict.c
   multipath-tools/upstream/current/libmultipath/discovery.c
   multipath-tools/upstream/current/libmultipath/discovery.h
   multipath-tools/upstream/current/libmultipath/dmparser.c
   multipath-tools/upstream/current/libmultipath/hwtable.c
   multipath-tools/upstream/current/libmultipath/pgpolicies.c
   multipath-tools/upstream/current/libmultipath/pgpolicies.h
   multipath-tools/upstream/current/libmultipath/print.c
   multipath-tools/upstream/current/libmultipath/print.h
   multipath-tools/upstream/current/libmultipath/propsel.c
   multipath-tools/upstream/current/libmultipath/propsel.h
   multipath-tools/upstream/current/libmultipath/structs.c
   multipath-tools/upstream/current/libmultipath/structs.h
   multipath-tools/upstream/current/libmultipath/switchgroup.c
   multipath-tools/upstream/current/libmultipath/switchgroup.h
   multipath-tools/upstream/current/libmultipath/uevent.c
   multipath-tools/upstream/current/libmultipath/uxsock.c
   multipath-tools/upstream/current/libmultipath/uxsock.h
   multipath-tools/upstream/current/libmultipath/vector.c
   multipath-tools/upstream/current/multipath.conf.annotated
   multipath-tools/upstream/current/multipath.conf.synthetic
   multipath-tools/upstream/current/multipath/Makefile
   multipath-tools/upstream/current/multipath/main.c
   multipath-tools/upstream/current/multipath/main.h
   multipath-tools/upstream/current/multipath/multipath.rules
   multipath-tools/upstream/current/multipathd/Makefile
   multipath-tools/upstream/current/multipathd/cli.c
   multipath-tools/upstream/current/multipathd/cli.h
   multipath-tools/upstream/current/multipathd/cli_handlers.c
   multipath-tools/upstream/current/multipathd/cli_handlers.h
   multipath-tools/upstream/current/multipathd/main.c
   multipath-tools/upstream/current/multipathd/main.h
   multipath-tools/upstream/current/multipathd/uxclnt.c
   multipath-tools/upstream/current/path_priority/pp_alua/Makefile
   multipath-tools/upstream/current/path_priority/pp_alua/mpath_prio_alua.8
   multipath-tools/upstream/current/path_priority/pp_balance_units/Makefile
   multipath-tools/upstream/current/path_priority/pp_emc/Makefile
Log:
Load multipath-tools-0.4.6 into /multipath-tools/upstream/current.


Modified: multipath-tools/upstream/current/ChangeLog
==============================================================================
--- multipath-tools/upstream/current/ChangeLog	(original)
+++ multipath-tools/upstream/current/ChangeLog	Wed Feb  1 23:48:32 2006
@@ -662,7 +662,7 @@
 
 	* [multipathd] setsched prio to RT
 	* [multipath] massive include cleanup
-	* [multipath] add a "default_prio_callout" keyword
+	* [multipath] add a "prio_callout" keyword
 	  first user will be SPC-3 ALUA priority field fetcher
 	  from IBM
 	* [multipath] reenable stdout on some error paths
@@ -700,9 +700,9 @@
 	  pathvecs
 	* [multipath] push WWID_SIZE to 64 char (scsi_id w/ JBODs)
 	* [multipath] add a exit_tool() wrapper fn for runfile unlink
-	* [multipath] add a "default_path_grouping_policy" keyword in the
+	* [multipath] add a "path_grouping_policy" keyword in the
 	  "defaults" block.
-	* [multipath] add a "default_getuid_callout" keyword in the
+	* [multipath] add a "getuid_callout" keyword in the
 	  "defaults" block. Now multipath is going to work with JBODs
 	* [multipath] fix segfault when pathvec is empty after
 	  get_pathvec()

Modified: multipath-tools/upstream/current/Makefile
==============================================================================
--- multipath-tools/upstream/current/Makefile	(original)
+++ multipath-tools/upstream/current/Makefile	Wed Feb  1 23:48:32 2006
@@ -20,7 +20,7 @@
 export KRNLSRC
 export KRNLOBJ
 
-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \;)
+BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib)
 
 VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
 

Modified: multipath-tools/upstream/current/Makefile.inc
==============================================================================
--- multipath-tools/upstream/current/Makefile.inc	(original)
+++ multipath-tools/upstream/current/Makefile.inc	Wed Feb  1 23:48:32 2006
@@ -28,7 +28,6 @@
 mandir      = /usr/share/man/man8
 
 GZIP        = /bin/gzip -9 -c
-STRIP       = strip --strip-all -R .comment -R .note
 
 CHECKERSLIB = $(checkersdir)/libcheckers
 MULTIPATHLIB = $(multipathdir)/libmultipath

Modified: multipath-tools/upstream/current/devmap_name/Makefile
==============================================================================
--- multipath-tools/upstream/current/devmap_name/Makefile	(original)
+++ multipath-tools/upstream/current/devmap_name/Makefile	Wed Feb  1 23:48:32 2006
@@ -23,17 +23,15 @@
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 

Modified: multipath-tools/upstream/current/kpartx/Makefile
==============================================================================
--- multipath-tools/upstream/current/kpartx/Makefile	(original)
+++ multipath-tools/upstream/current/kpartx/Makefile	Wed Feb  1 23:48:32 2006
@@ -27,12 +27,10 @@
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 $(MULTIPATHLIB)-$(BUILD).a:
@@ -40,7 +38,7 @@
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 

Modified: multipath-tools/upstream/current/kpartx/byteorder.h
==============================================================================
--- multipath-tools/upstream/current/kpartx/byteorder.h	(original)
+++ multipath-tools/upstream/current/kpartx/byteorder.h	Wed Feb  1 23:48:32 2006
@@ -1,15 +1,19 @@
 #ifndef BYTEORDER_H_INCLUDED
 #define BYTEORDER_H_INCLUDED
 
-#if defined (__s390__) || defined (__s390x__)
-#define le32_to_cpu(x)	( \
-		(*(((unsigned char *) &(x)))) + \
-		(*(((unsigned char *) &(x))+1) << 8) + \
-		(*(((unsigned char *) &(x))+2) << 16) + \
-		(*(((unsigned char *) &(x))+3) << 24) \
-	)
+#ifdef __linux__
+#  include <endian.h>
+#  include <byteswap.h>
 #else
-#define le32_to_cpu(x)	(x)
+#  error unsupported
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#  define le32_to_cpu(x) (x)
+#elif BYTE_ORDER == BIG_ENDIAN
+#  define le32_to_cpu(x) bswap_32(x)
+#else
+#  error unsupported
 #endif
 
 #endif				/* BYTEORDER_H_INCLUDED */

Modified: multipath-tools/upstream/current/kpartx/dos.c
==============================================================================
--- multipath-tools/upstream/current/kpartx/dos.c	(original)
+++ multipath-tools/upstream/current/kpartx/dos.c	Wed Feb  1 23:48:32 2006
@@ -1,6 +1,7 @@
 #include "kpartx.h"
 #include "byteorder.h"
 #include <stdio.h>
+#include <string.h>
 #include "dos.h"
 
 static int
@@ -12,7 +13,7 @@
 read_extended_partition(int fd, struct partition *ep,
 			struct slice *sp, int ns)
 {
-	struct partition *p;
+	struct partition p;
 	unsigned long start, here;
 	unsigned char *bp;
 	int loopct = 0;
@@ -33,14 +34,19 @@
 		if (bp[510] != 0x55 || bp[511] != 0xaa)
 			return n;
 
-		p = (struct partition *) (bp + 0x1be);
-
-		for (i=0; i<2; i++, p++) {
-			if (p->nr_sects == 0 || is_extended(p->sys_type))
-				continue;
+		for (i=0; i<2; i++) {
+			memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
+			if (is_extended(p.sys_type)) {
+				if (p.nr_sects) {
+					here = start + le32_to_cpu(p.start_sect);
+					moretodo = 1;
+				}
+				else
+					continue;
+			}
 			if (n < ns) {
-				sp[n].start = here + le32_to_cpu(p->start_sect);
-				sp[n].size = le32_to_cpu(p->nr_sects);
+				sp[n].start = here + le32_to_cpu(p.start_sect);
+				sp[n].size = le32_to_cpu(p.nr_sects);
 				n++;
 			} else {
 				fprintf(stderr,
@@ -49,15 +55,6 @@
 			}
 			loopct = 0;
 		}
-
-		p -= 2;
-		for (i=0; i<2; i++, p++) {
-			if(p->nr_sects != 0 && is_extended(p->sys_type)) {
-				here = start + le32_to_cpu(p->start_sect);
-				moretodo = 1;
-				break;
-			}
-		}
 	}
 	return n;
 }
@@ -69,9 +66,9 @@
 
 int
 read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
-	struct partition *p;
+	struct partition p;
 	unsigned long offset = all.start;
-	int i, n=0;
+	int i, n=4;
 	unsigned char *bp;
 
 	bp = (unsigned char *)getblock(fd, offset);
@@ -81,32 +78,23 @@
 	if (bp[510] != 0x55 || bp[511] != 0xaa)
 		return -1;
 
-	p = (struct partition *) (bp + 0x1be);
 	for (i=0; i<4; i++) {
-		if (is_gpt(p->sys_type)) {
-			return 0;
-		}
-		p++;
+		memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
 	}
-	p = (struct partition *) (bp + 0x1be);
 	for (i=0; i<4; i++) {
-		/* always add, even if zero length */
-		if (n < ns) {
-			sp[n].start =  le32_to_cpu(p->start_sect);
-			sp[n].size = le32_to_cpu(p->nr_sects);
-			n++;
+		memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
+		if (is_gpt(p.sys_type))
+			return 0;
+		if (i < ns) {
+			sp[i].start =  le32_to_cpu(p.start_sect);
+			sp[i].size = le32_to_cpu(p.nr_sects);
 		} else {
 			fprintf(stderr,
 				"dos_partition: too many slices\n");
 			break;
 		}
-		p++;
-	}
-	p = (struct partition *) (bp + 0x1be);
-	for (i=0; i<4; i++) {
-		if (is_extended(p->sys_type))
-			n += read_extended_partition(fd, p, sp+n, ns-n);
-		p++;
+		if (is_extended(p.sys_type))
+			n += read_extended_partition(fd, &p, sp+n, ns-n);
 	}
 	return n;
 }

Modified: multipath-tools/upstream/current/kpartx/kpartx.c
==============================================================================
--- multipath-tools/upstream/current/kpartx/kpartx.c	(original)
+++ multipath-tools/upstream/current/kpartx/kpartx.c	Wed Feb  1 23:48:32 2006
@@ -315,7 +315,7 @@
 	for (i = 0; i < ptct; i++) {
 		ptp = &pts[i];
 
-		if (type && strcmp(type, ptp->type) > 0)
+		if (type && strcmp(type, ptp->type))
 			continue;
 		
 		/* here we get partitions */

Modified: multipath-tools/upstream/current/libmultipath/Makefile
==============================================================================
--- multipath-tools/upstream/current/libmultipath/Makefile	(original)
+++ multipath-tools/upstream/current/libmultipath/Makefile	Wed Feb  1 23:48:32 2006
@@ -10,18 +10,23 @@
        hwtable.o blacklist.o util.o dmparser.o config.o \
        structs.o cache.o discovery.o propsel.o dict.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
-       switchgroup.o uxsock.o print.o
+       switchgroup.o uxsock.o print.o alias.o log_pthread.o \
+       log.o
 
 CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
 
+PREVBUILD = $(shell nm debug.o|grep log_safe)
+
 ifeq ($(strip $(DAEMON)),1)
 	CFLAGS += -DDAEMON
+	CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
+else
+	CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
 endif
 
 all: $(BUILD)
 
-prepare:
-	@rm -f debug.o
+prepare: $(CLEAN)
 	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
 	@rm -f *-$(BUILD).a
 

Added: multipath-tools/upstream/current/libmultipath/alias.c
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/alias.c	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,369 @@
+#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"
+
+
+/*
+ * 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 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");
+		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 fd;
+	struct stat s;
+
+	if (ensure_directories_exist(file, 0700))
+		return -1;
+	fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+	if (fd < 0) {
+		condlog(0, "Cannot open bindings file [%s] : %s", file,
+			strerror(errno));
+		return -1;
+	}
+
+	if (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 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 */
+			ftruncate(fd, 0);
+			goto fail;
+		}
+		fsync(fd);
+		condlog(3, "Initialized new bindings file [%s]", file);
+	}
+	
+	return fd;
+
+fail:
+	close(fd);
+	return -1;
+}
+
+
+static int
+lookup_binding(int fd, char *map_wwid, char **map_alias)
+{
+	char buf[LINE_MAX];
+	FILE *f;
+	unsigned int line_nr = 0;
+	int scan_fd;
+	int id = 0;
+
+	*map_alias = NULL;
+	scan_fd = dup(fd);
+	if (scan_fd < 0) {
+		condlog(0, "Cannot dup bindings file descriptor : %s",
+			strerror(errno));
+		return -1;
+	}
+	f = fdopen(scan_fd, "r");
+	if (!f) {
+		condlog(0, "cannot fdopen on bindings file descriptor : %s",
+			strerror(errno));
+		close(scan_fd);
+		return -1;
+	}
+	while (fgets(buf, LINE_MAX, f)) {
+		char *c, *alias, *wwid;
+		int curr_id;
+
+		line_nr++;
+		c = strpbrk(buf, "#\n\r");
+		if (c)
+			*c = '\0';
+		alias = strtok(buf, " \t");
+		if (!alias) /* blank line */
+			continue;
+		if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+			id = curr_id + 1;
+		wwid = strtok(NULL, " \t");
+		if (!wwid){
+			condlog(3,
+				"Ignoring malformed line %u in bindings file",
+				line_nr);
+			continue;
+		}
+		if (strcmp(wwid, map_wwid) == 0){
+			condlog(3, "Found matching wwid [%s] in bindings file."
+				"\nSetting alias to %s", wwid, alias);
+			*map_alias = strdup(alias);
+			if (*map_alias == NULL)
+				condlog(0, "Cannot copy alias from bindings "
+					"file : %s", strerror(errno));
+			fclose(f);
+			return id;
+		}
+	}
+	condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
+	fclose(f);
+	return id;
+}	
+
+static int
+rlookup_binding(int fd, char **map_wwid, char *map_alias)
+{
+	char buf[LINE_MAX];
+	FILE *f;
+	unsigned int line_nr = 0;
+	int scan_fd;
+	int id = 0;
+
+	*map_wwid = NULL;
+	scan_fd = dup(fd);
+	if (scan_fd < 0) {
+		condlog(0, "Cannot dup bindings file descriptor : %s",
+			strerror(errno));
+		return -1;
+	}
+	f = fdopen(scan_fd, "r");
+	if (!f) {
+		condlog(0, "cannot fdopen on bindings file descriptor : %s",
+			strerror(errno));
+		close(scan_fd);
+		return -1;
+	}
+	while (fgets(buf, LINE_MAX, f)) {
+		char *c, *alias, *wwid;
+		int curr_id;
+
+		line_nr++;
+		c = strpbrk(buf, "#\n\r");
+		if (c)
+			*c = '\0';
+		alias = strtok(buf, " \t");
+		if (!alias) /* blank line */
+			continue;
+		if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+			id = curr_id + 1;
+		wwid = strtok(NULL, " \t");
+		if (!wwid){
+			condlog(3,
+				"Ignoring malformed line %u in bindings file",
+				line_nr);
+			continue;
+		}
+		if (strcmp(alias, map_alias) == 0){
+			condlog(3, "Found matching alias [%s] in bindings file."
+				"\nSetting wwid to %s", alias, wwid);
+			*map_wwid = strdup(wwid);
+			if (*map_wwid == NULL)
+				condlog(0, "Cannot copy alias from bindings "
+					"file : %s", strerror(errno));
+			fclose(f);
+			return id;
+		}
+	}
+	condlog(3, "No matching alias [%s] in bindings file.", map_alias);
+	fclose(f);
+	return id;
+}	
+
+static char *
+allocate_binding(int fd, char *wwid, int id)
+{
+	char buf[LINE_MAX];
+	off_t offset;
+	char *alias, *c;
+	
+	if (id < 0) {
+		condlog(0, "Bindings file full. Cannot allocate new binding");
+		return NULL;
+	}
+	
+	snprintf(buf, LINE_MAX, "mpath%d %s\n", id, wwid);
+	buf[LINE_MAX - 1] = '\0';
+
+	offset = lseek(fd, 0, SEEK_END);
+	if (offset < 0){
+		condlog(0, "Cannot seek to end of bindings file : %s",
+			strerror(errno));
+		return NULL;
+	}
+	if (write_all(fd, buf, strlen(buf)) != strlen(buf)){
+		condlog(0, "Cannot write binding to bindings file : %s",
+			strerror(errno));
+		/* clear partial write */
+		ftruncate(fd, offset);
+		return NULL;
+	}
+	c = strchr(buf, ' ');
+	*c = '\0';
+	alias = strdup(buf);
+	if (alias == NULL)
+		condlog(0, "cannot copy new alias from bindings file : %s",
+			strerror(errno));
+	else
+		condlog(3, "Created new binding [%s] for WWID [%s]", alias,
+			wwid);
+	return alias;
+}		
+
+char *
+get_user_friendly_alias(char *wwid, char *file)
+{
+	char *alias;
+	int fd, id;
+
+	if (!wwid || *wwid == '\0') {
+		condlog(3, "Cannot find binding for empty WWID");
+		return NULL;
+	}
+
+	fd = open_bindings_file(file);
+	if (fd < 0)
+		return NULL;
+	id = lookup_binding(fd, wwid, &alias);
+	if (id < 0) {
+		close(fd);
+		return NULL;
+	}
+	if (!alias)
+		alias = allocate_binding(fd, wwid, id);
+
+	close(fd);
+	return alias;
+}
+
+char *
+get_user_friendly_wwid(char *alias, char *file)
+{
+	char *wwid;
+	int fd, id;
+
+	if (!alias || *alias == '\0') {
+		condlog(3, "Cannot find binding for empty alias");
+		return NULL;
+	}
+
+	fd = open_bindings_file(file);
+	if (fd < 0)
+		return NULL;
+	id = rlookup_binding(fd, &wwid, alias);
+	if (id < 0) {
+		close(fd);
+		return NULL;
+	}
+
+	close(fd);
+	return wwid;
+}

Added: multipath-tools/upstream/current/libmultipath/alias.h
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/alias.h	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,12 @@
+#define BINDINGS_FILE_TIMEOUT 3
+#define BINDINGS_FILE_HEADER \
+"# Multipath bindings, Version : 1.0\n" \
+"# NOTE: this file is automatically maintained by the multipath program.\n" \
+"# You should not need to edit this file in normal circumstances.\n" \
+"#\n" \
+"# Format:\n" \
+"# alias wwid\n" \
+"#\n"
+
+char *get_user_friendly_alias(char *wwid, char *file);
+char *get_user_friendly_wwid(char *alias, char *file);

Modified: multipath-tools/upstream/current/libmultipath/blacklist.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/blacklist.c	(original)
+++ multipath-tools/upstream/current/libmultipath/blacklist.c	Wed Feb  1 23:48:32 2006
@@ -82,9 +82,12 @@
 	if (!blist)
 		return;
 
-	vector_foreach_slot (blist, ble, i)
-		if (ble)
+	vector_foreach_slot (blist, ble, i) {
+		if (ble) {
+			regfree(ble);
 			FREE(ble);
+		}
+	}
 
 	vector_free(blist);
 }

Modified: multipath-tools/upstream/current/libmultipath/cache.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/cache.c	(original)
+++ multipath-tools/upstream/current/libmultipath/cache.c	Wed Feb  1 23:48:32 2006
@@ -12,7 +12,7 @@
 revoke_cache_info(struct path * pp)
 {
 	pp->checker_context = NULL;
-	pp->fd = 0;
+	pp->fd = -1;
 	pp->mpp = NULL;
 	pp->getuid = NULL;
 	pp->getprio = NULL;

Modified: multipath-tools/upstream/current/libmultipath/config.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/config.c	(original)
+++ multipath-tools/upstream/current/libmultipath/config.c	Wed Feb  1 23:48:32 2006
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "regex.h"
 #include "memory.h"
 #include "util.h"
 #include "debug.h"
@@ -18,15 +19,27 @@
 find_hwe (vector hwtable, char * vendor, char * product)
 {
 	int i;
-	struct hwentry * hwe;
+	struct hwentry *hwe, *ret = NULL;
+	regex_t vre, pre;
 
 	vector_foreach_slot (hwtable, hwe, i) {
-		if (strcmp_chomp(hwe->vendor, vendor) == 0 &&
-		    (hwe->product[0] == '*' ||
-		    strcmp_chomp(hwe->product, product) == 0))
-			return hwe;
+		if (regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
+			break;
+		if (regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
+			regfree(&vre);
+			break;
+		}
+		if (!regexec(&vre, vendor, 0, NULL, 0) &&
+		    !regexec(&pre, product, 0, NULL, 0))
+			ret = hwe;
+		
+		regfree(&pre);
+		regfree(&vre);
+
+		if (ret)
+			break;
 	}
-	return NULL;
+	return ret;
 }
 
 extern struct mpentry *
@@ -183,12 +196,26 @@
 	return dst;
 }
 
+static int
+dup_hwe (vector hwtable, char * vendor, char * product)
+{
+	struct hwentry * hwe = find_hwe(hwtable, vendor, product);
+
+	if (hwe)
+		return 1;
+
+	return 0;
+}
+
 int
 store_hwe (vector hwtable, char * vendor, char * product, int pgp,
 	   char * getuid)
 {
 	struct hwentry * hwe;
 
+	if (dup_hwe(hwtable, vendor, product))
+		return 0;
+
 	hwe = alloc_hwe();
 
 	if (!hwe)
@@ -228,10 +255,13 @@
 int
 store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
 	   char * getuid, char * getprio, char * hwhandler,
-	   char * features, char * checker)
+	   char * features, char * checker, int pgfailback)
 {
 	struct hwentry * hwe;
 
+	if (dup_hwe(hwtable, vendor, product))
+		return 0;
+	
 	hwe = alloc_hwe();
 
 	if (!hwe)
@@ -284,6 +314,8 @@
 	else
 		hwe->checker_index = get_checker_id(DEFAULT_CHECKER);
 
+	hwe->pgfailback = pgfailback;
+
 	if (!vector_alloc_slot(hwtable))
 		goto out;
 
@@ -309,14 +341,11 @@
 	if (conf->dev)
 		FREE(conf->dev);
 
-	if (conf->multipath)
-		FREE(conf->multipath);
-
 	if (conf->udev_dir)
 		FREE(conf->udev_dir);
 
-	if (conf->default_selector)
-		FREE(conf->default_selector);
+	if (conf->selector)
+		FREE(conf->selector);
 
 	if (conf->default_getuid)
 		FREE(conf->default_getuid);
@@ -324,8 +353,8 @@
 	if (conf->default_getprio)
 		FREE(conf->default_getprio);
 
-	if (conf->default_features)
-		FREE(conf->default_features);
+	if (conf->features)
+		FREE(conf->features);
 
 	if (conf->default_hwhandler)
 		FREE(conf->default_hwhandler);
@@ -354,6 +383,7 @@
 
 	conf->dev_type = DEV_NONE;
 	conf->minio = 1000;
+	conf->bindings_file = DEFAULT_BINDINGS_FILE;
 
 	/*
 	 * read the config file
@@ -374,9 +404,10 @@
 		if (!conf->hwtable)
 			goto out;
 		
-		if (setup_default_hwtable(conf->hwtable))
-			goto out;
 	}
+	if (setup_default_hwtable(conf->hwtable))
+		goto out;
+
 	if (conf->blist == NULL) {
 		conf->blist = vector_alloc();
 		
@@ -392,8 +423,8 @@
 		if (!conf->mptable)
 			goto out;
 	}
-	if (conf->default_selector == NULL)
-		conf->default_selector = set_default(DEFAULT_SELECTOR);
+	if (conf->selector == NULL)
+		conf->selector = set_default(DEFAULT_SELECTOR);
 
 	if (conf->udev_dir == NULL)
 		conf->udev_dir = set_default(DEFAULT_UDEVDIR);
@@ -401,17 +432,20 @@
 	if (conf->default_getuid == NULL)
 		conf->default_getuid = set_default(DEFAULT_GETUID);
 
-	if (conf->default_features == NULL)
-		conf->default_features = set_default(DEFAULT_FEATURES);
+	if (conf->features == NULL)
+		conf->features = set_default(DEFAULT_FEATURES);
 
 	if (conf->default_hwhandler == NULL)
 		conf->default_hwhandler = set_default(DEFAULT_HWHANDLER);
 
-	if (!conf->default_selector  || !conf->udev_dir         ||
-	    !conf->default_getuid    || !conf->default_features ||
+	if (!conf->selector  || !conf->udev_dir         ||
+	    !conf->default_getuid    || !conf->features ||
 	    !conf->default_hwhandler)
 		goto out;
 
+	if (!conf->default_checker_index)
+		conf->default_checker_index = READSECTOR0;
+
 	return 0;
 out:
 	free_config(conf);

Modified: multipath-tools/upstream/current/libmultipath/config.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/config.h	(original)
+++ multipath-tools/upstream/current/libmultipath/config.h	Wed Feb  1 23:48:32 2006
@@ -18,6 +18,7 @@
 	int checker_index;
 	int pgfailback;
 	int rr_weight;
+	int no_path_retry;
 
 	char * vendor;
 	char * product;
@@ -33,6 +34,7 @@
 	int pgpolicy;
 	int pgfailback;
 	int rr_weight;
+	int no_path_retry;
 
 	char * wwid;
 	char * selector;
@@ -46,8 +48,9 @@
 	int list;
 	int pgpolicy_flag;
 	int with_sysfs;
-	int default_selector_args;
+	int selector_args;
 	int default_pgpolicy;
+	int default_checker_index;
 	int dev_type;
 	int minio;
 	int checkint;
@@ -55,15 +58,17 @@
 	int pgfailback;
 	int remove;
 	int rr_weight;
+	int no_path_retry;
+	int user_friendly_names;
 
 	char * dev;
-	char * multipath;
 	char * udev_dir;
-	char * default_selector;
+	char * selector;
 	char * default_getuid;
 	char * default_getprio;
-	char * default_features;
+	char * features;
 	char * default_hwhandler;
+	char * bindings_file;
 
 	vector mptable;
 	vector hwtable;
@@ -87,7 +92,7 @@
 		char * getuid);
 int store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
 		char * getuid, char * getprio, char * hwhandler,
-		char * features, char * checker);
+		char * features, char * checker, int pgfailback);
 
 int load_config (char * file);
 struct config * alloc_config (void);

Modified: multipath-tools/upstream/current/libmultipath/debug.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/debug.c	(original)
+++ multipath-tools/upstream/current/libmultipath/debug.c	Wed Feb  1 23:48:32 2006
@@ -3,7 +3,7 @@
 #include <stdarg.h>
 
 #if DAEMON
-#include "../multipathd/log_pthread.h"
+#include "log_pthread.h"
 #endif
 
 #include "config.h"

Modified: multipath-tools/upstream/current/libmultipath/debug.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/debug.h	(original)
+++ multipath-tools/upstream/current/libmultipath/debug.h	Wed Feb  1 23:48:32 2006
@@ -4,7 +4,8 @@
 
 #include <pthread.h>
 #include <stdarg.h>
-#include "../multipathd/log_pthread.h"
+
+#include "log_pthread.h"
 
 int logsink;
 

Modified: multipath-tools/upstream/current/libmultipath/defaults.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/defaults.h	(original)
+++ multipath-tools/upstream/current/libmultipath/defaults.h	Wed Feb  1 23:48:32 2006
@@ -9,5 +9,6 @@
 #define DEFAULT_PIDFILE		"/var/run/multipathd.pid"
 #define DEFAULT_SOCKET		"/var/run/multipathd.sock"
 #define DEFAULT_CONFIGFILE	"/etc/multipath.conf"
+#define DEFAULT_BINDINGS_FILE  "/var/lib/multipath/bindings"
 
 char * set_default (char * str);

Modified: multipath-tools/upstream/current/libmultipath/devmapper.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/devmapper.c	(original)
+++ multipath-tools/upstream/current/libmultipath/devmapper.c	Wed Feb  1 23:48:32 2006
@@ -15,6 +15,24 @@
 #define MAX_WAIT 5
 #define LOOPS_PER_SEC 5
 
+static void
+dm_dummy_log (int level, const char *file, int line, const char *f, ...)
+{
+	return;
+}
+
+void
+dm_restore_log (void)
+{
+	dm_log_init(NULL);
+}
+
+void
+dm_shut_log (void)
+{
+	dm_log_init(&dm_dummy_log);
+}
+
 extern int
 dm_prereq (char * str, int x, int y, int z)
 {
@@ -84,7 +102,7 @@
 
 extern int
 dm_addmap (int task, const char *name, const char *target,
-	   const char *params, unsigned long long size) {
+	   const char *params, unsigned long long size, const char *uuid) {
 	int r = 0;
 	struct dm_task *dmt;
 
@@ -97,6 +115,9 @@
 	if (!dm_task_add_target (dmt, 0, size, target, params))
 		goto addout;
 
+	if (uuid && !dm_task_set_uuid(dmt, uuid))
+		goto addout;
+
 	dm_task_no_open_count(dmt);
 
 	r = dm_task_run (dmt);
@@ -170,6 +191,34 @@
 }
 
 extern int
+dm_get_uuid(char *name, char *uuid)
+{
+	struct dm_task *dmt;
+	const char *uuidtmp;
+
+	dmt = dm_task_create(DM_DEVICE_INFO);
+	if (!dmt)
+		return 1;
+
+        if (!dm_task_set_name (dmt, name))
+                goto uuidout;
+
+	if (!dm_task_run(dmt))
+                goto uuidout;
+
+	uuidtmp = dm_task_get_uuid(dmt);
+	if (uuidtmp)
+		strcpy(uuid, uuidtmp);
+	else
+		uuid[0] = '\0';
+
+uuidout:
+	dm_task_destroy(dmt);
+
+	return 0;
+}
+
+extern int
 dm_get_status(char * name, char * outstatus)
 {
 	int r = 1;
@@ -204,6 +253,12 @@
 	return r;
 }
 
+/*
+ * returns:
+ *    1 : match
+ *    0 : no match
+ *   -1 : empty map
+ */
 extern int
 dm_type(char * name, char * type)
 {
@@ -229,7 +284,9 @@
 	next = dm_get_next_target(dmt, next, &start, &length,
 				  &target_type, &params);
 
-	if (0 == strcmp(target_type, type))
+	if (!target_type)
+		r = -1;
+	else if (!strcmp(target_type, type))
 		r = 1;
 
 out:
@@ -330,8 +387,10 @@
 	if (dm_remove_partmaps(mapname))
 		return 1;
 
-	if (dm_get_opencount(mapname))
+	if (dm_get_opencount(mapname)) {
+		condlog(2, "%s: map in use", mapname);
 		return 1;
+	}	
 
 	r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
 
@@ -376,11 +435,10 @@
 }
 
 int
-dm_fail_path(char * mapname, char * path)
+dm_message(char * mapname, char * message)
 {
 	int r = 1;
 	struct dm_task *dmt;
-	char str[32];
 
 	if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
 		return 1;
@@ -391,10 +449,7 @@
 	if (!dm_task_set_sector(dmt, 0))
 		goto out;
 
-	if (snprintf(str, 32, "fail_path %s\n", path) > 32)
-		goto out;
-
-	if (!dm_task_set_message(dmt, str))
+	if (!dm_task_set_message(dmt, message))
 		goto out;
 
 	dm_task_no_open_count(dmt);
@@ -404,97 +459,75 @@
 
 	r = 0;
 out:
+	if (r)
+		condlog(0, "DM message failed [%s]", message);
+
 	dm_task_destroy(dmt);
 	return r;
 }
 
 int
-dm_reinstate(char * mapname, char * path)
+dm_fail_path(char * mapname, char * path)
 {
-	int r = 1;
-	struct dm_task *dmt;
-	char str[32];
+	char message[32];
 
-	if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
+	if (snprintf(message, 32, "fail_path %s\n", path) > 32)
 		return 1;
 
-	if (!dm_task_set_name(dmt, mapname))
-		goto out;
+	return dm_message(mapname, message);
+}
 
-	if (!dm_task_set_sector(dmt, 0))
-		goto out;
+int
+dm_reinstate_path(char * mapname, char * path)
+{
+	char message[32];
 
-	if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
-		goto out;
+	if (snprintf(message, 32, "reinstate_path %s\n", path) > 32)
+		return 1;
 
-	if (!dm_task_set_message(dmt, str))
-		goto out;
+	return dm_message(mapname, message);
+}
 
-	dm_task_no_open_count(dmt);
+int
+dm_queue_if_no_path(char *mapname, int enable)
+{
+	char *message;
 
-	if (!dm_task_run(dmt))
-		goto out;
+	if (enable)
+		message = "queue_if_no_path\n";
+	else
+		message = "fail_if_no_path\n";
 
-	r = 0;
-out:
-	dm_task_destroy(dmt);
-	return r;
+	return dm_message(mapname, message);
 }
 
 static int
 dm_groupmsg (char * msg, char * mapname, int index)
 {
-	int r = 0;
-	struct dm_task *dmt;
-	char str[24];
-
-	if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
-		return 0;
-
-	if (!dm_task_set_name(dmt, mapname))
-		goto out;
-
-	if (!dm_task_set_sector(dmt, 0))
-		goto out;
-
-	snprintf(str, 24, "%s_group %i\n", msg, index);
-
-	if (!dm_task_set_message(dmt, str))
-		goto out;
-
-	dm_task_no_open_count(dmt);
-
-	if (!dm_task_run(dmt))
-		goto out;
+	char message[32];
 
-	condlog(3, "message %s 0 %s", mapname, str);
-	r = 1;
-
-	out:
-	if (!r)
-		condlog(3, "message %s 0 %s failed", mapname, str);
-
-	dm_task_destroy(dmt);
+	if (snprintf(message, 32, "%s_group %i\n", msg, index) > 32)
+		return 1;
 
-	return r;
+	return dm_message(mapname, message);
 }
 
 int
 dm_switchgroup(char * mapname, int index)
 {
-	return dm_groupmsg("switch", mapname,index);
+	return dm_groupmsg("switch", mapname, index);
 }
 
 int
 dm_enablegroup(char * mapname, int index)
 {
-	return dm_groupmsg("enable", mapname,index);
+	return dm_groupmsg("enable", mapname, index);
 }
 
 int
 dm_disablegroup(char * mapname, int index)
 {
-	return dm_groupmsg("disable", mapname,index);
+	return dm_groupmsg("disable", mapname, index);
 }
 
 int
@@ -502,6 +535,7 @@
 {
 	struct multipath * mpp;
 	int r = 1;
+	int info;
 	struct dm_task *dmt;
 	struct dm_names *names;
 	unsigned next = 0;
@@ -526,31 +560,37 @@
 	}
 
 	do {
-		if (dm_type(names->name, type)) {
-			mpp = alloc_multipath();
+		info = dm_type(names->name, type);
+
+		if (!info)
+			goto next;
+
+		mpp = alloc_multipath();
 
-			if (!mpp)
-				goto out;
+		if (!mpp)
+			goto out;
 
+		mpp->alias = STRDUP(names->name);
+
+		if (!mpp->alias)
+			goto out1;
+
+		if (info > 0) {
 			if (dm_get_map(names->name, &mpp->size, mpp->params))
 				goto out1;
 
 			if (dm_get_status(names->name, mpp->status))
 				goto out1;
 
-			mpp->alias = MALLOC(strlen(names->name) + 1);
-
-			if (!mpp->alias)
-				goto out1;
+			dm_get_uuid(names->name, mpp->wwid);
+		}
 
-			strncat(mpp->alias, names->name, strlen(names->name));
+		if (!vector_alloc_slot(mp))
+			goto out1;
 
-			if (!vector_alloc_slot(mp))
-				goto out1;
-			
-			vector_set_slot(mp, mpp);
-			mpp = NULL;
-		}
+		vector_set_slot(mp, mpp);
+		mpp = NULL;
+next:
                 next = names->next;
                 names = (void *) names + next;
 	} while (next);
@@ -616,10 +656,12 @@
 
 	/*
 	 * device map might not be ready when we get here from
-	 * uevent trigger
+	 * daemon uev_trigger -> uev_add_map
 	 */
 	while (--loop) {
+		dm_shut_log();
 		r = dm_task_run(dmt);
+		dm_restore_log();
 
 		if (r)
 			break;
@@ -718,6 +760,52 @@
 	return r;
 }
 
+static struct dm_info *
+alloc_dminfo (void)
+{
+	return MALLOC(sizeof(struct dm_info));
+}
+
+int
+dm_get_info (char * mapname, struct dm_info ** dmi)
+{
+	int r = 1;
+	struct dm_task *dmt = NULL;
+	
+	if (!mapname)
+		return 1;
+
+	if (!*dmi)
+		*dmi = alloc_dminfo();
+
+	if (!*dmi)
+		return 1;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+		goto out;
+
+	if (!dm_task_set_name(dmt, mapname))
+		goto out;
+
+	dm_task_no_open_count(dmt);
+
+	if (!dm_task_run(dmt))
+		goto out;
+
+	if (!dm_task_get_info(dmt, *dmi))
+		goto out;
+
+	r = 0;
+out:
+	if (r)
+		memset(*dmi, 0, sizeof(struct dm_info));
+
+	if (dmt)
+		dm_task_destroy(dmt);
+
+	return r;
+}
+
 #if 0
 int
 dm_rename (char * old, char * new)

Modified: multipath-tools/upstream/current/libmultipath/devmapper.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/devmapper.h	(original)
+++ multipath-tools/upstream/current/libmultipath/devmapper.h	Wed Feb  1 23:48:32 2006
@@ -1,7 +1,9 @@
+void dm_shut_log(void);
+void dm_restore_log(void);
 int dm_prereq (char *, int, int, int);
 int dm_simplecmd (int, const char *);
 int dm_addmap (int, const char *, const char *, const char *,
-	       unsigned long long);
+	       unsigned long long, const char *uuid);
 int dm_map_present (char *);
 int dm_get_map(char *, unsigned long long *, char *);
 int dm_get_status(char *, char *);
@@ -9,7 +11,8 @@
 int dm_flush_map (char *, char *);
 int dm_flush_maps (char *);
 int dm_fail_path(char * mapname, char * path);
-int dm_reinstate(char * mapname, char * path);
+int dm_reinstate_path(char * mapname, char * path);
+int dm_queue_if_no_path(char *mapname, int enable);
 int dm_switchgroup(char * mapname, int index);
 int dm_enablegroup(char * mapname, int index);
 int dm_disablegroup(char * mapname, int index);
@@ -18,6 +21,8 @@
 int dm_get_minor (char *name);
 char * dm_mapname(int major, int minor);
 int dm_remove_partmaps (char * mapname);
+int dm_get_uuid(char *name, char *uuid);
+int dm_get_info (char * mapname, struct dm_info ** dmi);
 
 #if 0
 int dm_rename (char * old, char * new);

Modified: multipath-tools/upstream/current/libmultipath/dict.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/dict.c	(original)
+++ multipath-tools/upstream/current/libmultipath/dict.c	Wed Feb  1 23:48:32 2006
@@ -14,17 +14,6 @@
  * default block handlers
  */
 static int
-multipath_tool_handler(vector strvec)
-{
-	conf->multipath = set_value(strvec);
-
-	if (!conf->multipath)
-		return 1;
-
-	return 0;
-}
-
-static int
 polling_interval_handler(vector strvec)
 {
 	char * buff;
@@ -50,9 +39,9 @@
 static int
 def_selector_handler(vector strvec)
 {
-	conf->default_selector = set_value(strvec);
+	conf->selector = set_value(strvec);
 
-	if (!conf->default_selector)
+	if (!conf->selector)
 		return 1;
 
 	return 0;
@@ -104,10 +93,26 @@
 static int
 def_features_handler(vector strvec)
 {
-	conf->default_features = set_value(strvec);
+	conf->features = set_value(strvec);
+
+	if (!conf->features)
+		return 1;
+
+	return 0;
+}
+
+static int
+def_path_checker_handler(vector strvec)
+{
+	char * buff;
 
-	if (!conf->default_features)
+	buff = set_value(strvec);
+
+	if (!buff)
 		return 1;
+	
+	conf->default_checker_index = get_checker_id(buff);
+	FREE(buff);
 
 	return 0;
 }
@@ -166,6 +171,45 @@
 	return 0;
 }
 
+static int
+def_no_path_retry_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+	if (!buff)
+		return 1;
+
+	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+		conf->no_path_retry = NO_PATH_RETRY_FAIL;
+	else if (!strncmp(buff, "queue", 5))
+		conf->no_path_retry = NO_PATH_RETRY_QUEUE;
+	else if ((conf->no_path_retry = atoi(buff)) < 1)
+		conf->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+	FREE(buff);
+	return 0;
+}
+
+static int
+names_handler(vector strvec)
+{
+	char * buff;
+
+	buff = set_value(strvec);
+
+	if (!buff)
+		return 1;
+
+	if (!strncmp(buff, "no", 2) || !strncmp(buff, "0", 1))
+		conf->user_friendly_names = 0;
+	else if (!strncmp(buff, "yes", 2) || !strncmp(buff, "1", 1))
+		conf->user_friendly_names = 1;
+
+	FREE(buff);
+	return 0;
+}
+
 /*
  * blacklist block handlers
  */
@@ -427,6 +471,30 @@
 	return 0;
 }
 
+static int
+hw_no_path_retry_handler(vector strvec)
+{
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+	char *buff;
+
+	if (!hwe)
+		return 1;
+
+	buff = set_value(strvec);
+	if (!buff)
+		return 1;
+
+	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+		hwe->no_path_retry = NO_PATH_RETRY_FAIL;
+	else if (!strncmp(buff, "queue", 5))
+		hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
+	else if ((hwe->no_path_retry = atoi(buff)) < 1)
+		hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+	FREE(buff);
+	return 0;
+}
+
 /*
  * multipaths block handlers
  */
@@ -574,6 +642,30 @@
 	return 0;
 }
 
+static int
+mp_no_path_retry_handler(vector strvec)
+{
+	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+	char *buff;
+
+	if (!mpe)
+		return 1;
+
+	buff = set_value(strvec);
+	if (!buff)
+		return 1;
+
+	if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+		mpe->no_path_retry = NO_PATH_RETRY_FAIL;
+	else if (!strncmp(buff, "queue", 5))
+		mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
+	else if ((mpe->no_path_retry = atoi(buff)) < 1)
+		mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+	FREE(buff);
+	return 0;
+}
+
 vector
 init_keywords(void)
 {
@@ -581,17 +673,29 @@
 
 	install_keyword_root("defaults", NULL);
 	install_keyword("polling_interval", &polling_interval_handler);
-	install_keyword("multipath_tool", &multipath_tool_handler);
 	install_keyword("udev_dir", &udev_dir_handler);
+	install_keyword("selector", &def_selector_handler);
+	install_keyword("path_grouping_policy", &def_pgpolicy_handler);
+	install_keyword("getuid_callout", &def_getuid_callout_handler);
+	install_keyword("prio_callout", &def_prio_callout_handler);
+	install_keyword("features", &def_features_handler);
+	install_keyword("path_checker", &def_path_checker_handler);
+	install_keyword("failback", &default_failback_handler);
+	install_keyword("rr_min_io", &def_minio_handler);
+	install_keyword("rr_weight", &def_weight_handler);
+	install_keyword("no_path_retry", &def_no_path_retry_handler);
+	install_keyword("user_friendly_names", &names_handler);
+
+	/*
+	 * deprecated synonyms
+	 */
 	install_keyword("default_selector", &def_selector_handler);
 	install_keyword("default_path_grouping_policy", &def_pgpolicy_handler);
 	install_keyword("default_getuid_callout", &def_getuid_callout_handler);
 	install_keyword("default_prio_callout", &def_prio_callout_handler);
 	install_keyword("default_features", &def_features_handler);
-	install_keyword("failback", &default_failback_handler);
-	install_keyword("rr_min_io", &def_minio_handler);
-	install_keyword("rr_weight", &def_weight_handler);
-	
+	install_keyword("default_path_checker", &def_path_checker_handler);
+
 	install_keyword_root("devnode_blacklist", &blacklist_handler);
 	install_keyword("devnode", &ble_handler);
 	install_keyword("wwid", &ble_handler);
@@ -610,6 +714,7 @@
 	install_keyword("prio_callout", &prio_callout_handler);
 	install_keyword("failback", &hw_failback_handler);
 	install_keyword("rr_weight", &hw_weight_handler);
+	install_keyword("no_path_retry", &hw_no_path_retry_handler);
 	install_sublevel_end();
 
 	install_keyword_root("multipaths", &multipaths_handler);
@@ -621,6 +726,7 @@
 	install_keyword("path_selector", &mp_selector_handler);
 	install_keyword("failback", &mp_failback_handler);
 	install_keyword("rr_weight", &mp_weight_handler);
+	install_keyword("no_path_retry", &mp_no_path_retry_handler);
 	install_sublevel_end();
 
 	return keywords;

Modified: multipath-tools/upstream/current/libmultipath/discovery.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/discovery.c	(original)
+++ multipath-tools/upstream/current/libmultipath/discovery.c	Wed Feb  1 23:48:32 2006
@@ -20,6 +20,8 @@
 #include "sg_include.h"
 #include "discovery.h"
 
+#include "../libcheckers/path_state.h"
+
 #define readattr(a,b) \
 	sysfs_read_attribute_value(a, b, sizeof(b))
 
@@ -56,23 +58,31 @@
 	struct sysfs_directory * devp;
 	char path[FILE_NAME_SIZE];
 	struct path * pp;
-	int r = 1;
+	int r = 0;
 
 	if(safe_sprintf(path, "%s/block", sysfs_path)) {
 		condlog(0, "path too small");
-		exit(1);
+		return 1;
 	}
 	sdir = sysfs_open_directory(path);
+
+	if (!sdir)
+		return 1;
+
 	sysfs_read_directory(sdir);
 
 	dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
+		if (!devp)
+			continue;
+
 		if (blacklist(conf->blist, devp->name))
 			continue;
 
 		if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
 				devp->name)) {
 			condlog(0, "path too small");
-			exit(1);
+			sysfs_close_directory(sdir);
+			return 1;
 		}
 				
 		if (!filepresent(path))
@@ -86,28 +96,35 @@
 			 * the caller wants
 			 */
 			if (!store_pathinfo(pathvec, conf->hwtable,
-					   devp->name, flag))
-				goto out;
+					   devp->name, flag)) {
+				r++;
+				continue;
+			}
 		} else {
 			/*
 			 * path already known :
 			 * refresh only what the caller wants
 			 */
-			if (pathinfo(pp, conf->hwtable, flag))
-				goto out;
+			if (pathinfo(pp, conf->hwtable, flag)) {
+				r++;
+				continue;
+			}
 		}
 	}
-	r = 0;
-out:
 	sysfs_close_directory(sdir);
 	return r;
 }
 
+/*
+ * the daemon can race udev upon path add,
+ * not multipath(8), ran by udev
+ */
+#if DAEMON
 #define WAIT_MAX_SECONDS 5
 #define WAIT_LOOP_PER_SECOND 5
 
 static int
-wait_sysfs_attr (char * filename)
+wait_for_file (char * filename)
 {
 	int loop;
 	struct stat stats;
@@ -118,10 +135,20 @@
 		if (stat(filename, &stats) == 0)
 			return 0;
 
+		if (errno != ENOENT)
+			return 1;
+
 		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
 	}
 	return 1;
-}	
+}
+#else
+static int
+wait_for_file (char * filename)
+{
+	return 0;
+}
+#endif
 			
 #define declare_sysfs_get_str(fname, fmt) \
 extern int \
@@ -134,7 +161,7 @@
 	if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
 		return 1; \
 \
-	if (wait_sysfs_attr(attr_path)) \
+	if (wait_for_file(attr_path)) \
 		return 1; \
 \
 	if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
@@ -166,7 +193,7 @@
 	if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
 		return 0; \
 \
-	if (wait_sysfs_attr(attr_path)) \
+	if (wait_for_file(attr_path)) \
 		return 0; \
 \
 	if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
@@ -189,43 +216,19 @@
 opennode (char * dev, int mode)
 {
 	char devpath[FILE_NAME_SIZE];
-	int fd;
-	int loop;
 
 	if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
 		condlog(0, "devpath too small");
 		return -1;
 	}
 
-	loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
-	
-	while (--loop) {
-		fd = open(devpath, mode);
-
-		if (fd <= 0 && errno != ENOENT) {
-			condlog(3, "open error (%s)\n", strerror(errno));
-			return fd;
-		}
-		if (fd > 0)
-			return fd;
-
-		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+	if (wait_for_file(devpath)) {
+		condlog(3, "failed to open %s", devpath);
+		return -1;
 	}
-	condlog(0, "failed to open %s", devpath);
-	return -1;
-}
-
-int
-get_claimed(char * devname)
-{
-	int fd = opennode(devname, O_EXCL);
-
-	if (fd < 0)
-		return 1;
 
-	close(fd);
-	return 0;
-}	
+	return open(devpath, mode);
+}
 
 extern int
 devt2devname (char *devname, char *devt)
@@ -239,7 +242,7 @@
 
 	if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
 		condlog(0, "block_path too small");
-		exit(1);
+		return 1;
 	}
 	sdir = sysfs_open_directory(block_path);
 	sysfs_read_directory(sdir);
@@ -248,7 +251,7 @@
 		if(safe_sprintf(attr_path, "%s/%s/dev",
 				block_path, devp->name)) {
 			condlog(0, "attr_path too small");
-			exit(1);
+			goto err;
 		}
 		sysfs_read_attribute_value(attr_path, attr_value,
 					   sizeof(attr_value));
@@ -263,7 +266,7 @@
 			if(safe_sprintf(attr_path, "%s/%s",
 					block_path, devp->name)) {
 				condlog(0, "attr_path too small");
-				exit(1);
+				goto err;
 			}
 			sysfs_get_name_from_path(attr_path, devname,
 						 FILE_NAME_SIZE);
@@ -271,6 +274,7 @@
 			return 0;
 		}
 	}
+err:
 	sysfs_close_directory(sdir);
 	return 1;
 }
@@ -377,6 +381,8 @@
 	else if (!strncmp(sdev->bus, "ide", 3))
 		curpath->bus = SYSFS_BUS_IDE;
 
+	sysfs_close_device(sdev);
+
 	return;
 }
 
@@ -451,7 +457,6 @@
 static int
 common_sysfs_pathinfo (struct path * curpath)
 {
-
 	sysfs_get_bus(sysfs_path, curpath);
 	condlog(3, "bus = %i", curpath->bus);
 
@@ -502,10 +507,6 @@
 		return 1;
 
 	dst = cmd;
-
-	if (!dst)
-		return 1;
-
 	p = dst;
 	pos = strchr(string, '%');
 	myfree = CALLOUT_MAX_SIZE;
@@ -582,7 +583,7 @@
 	char buff[CALLOUT_MAX_SIZE];
 	char prio[16];
 
-	condlog(3, "===== path %s =====", pp->dev);
+	condlog(3, "===== path info %s (mask 0x%x) =====", pp->dev, mask);
 
 	/*
 	 * fetch info available in sysfs
@@ -591,21 +592,17 @@
 		return 1;
 
 	/*
-	 * then those not available through sysfs
+	 * fetch info not available through sysfs
 	 */
-	if (mask & DI_CLAIMED) {
-		pp->claimed = get_claimed(pp->dev);
-		condlog(3, "claimed = %i", pp->claimed);
-	}
-	if (pp->fd <= 0)
+	if (pp->fd < 0)
 		pp->fd = opennode(pp->dev, O_RDONLY);
 
-	if (pp->fd <= 0)
-		return 1;
+	if (pp->fd < 0)
+		goto out;
 
-	if (pp->bus == SYSFS_BUS_SCSI)
-		if (scsi_ioctl_pathinfo(pp, mask))
-			return 1;
+	if (pp->bus == SYSFS_BUS_SCSI &&
+	    scsi_ioctl_pathinfo(pp, mask))
+		goto out;
 
 	/* get and store hwe pointer */
 	pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id);
@@ -662,4 +659,13 @@
 		condlog(3, "uid = %s (cache)", pp->wwid);
 
 	return 0;
+
+out:
+	/*
+	 * Recoverable error, for example faulty or offline path
+	 * Set up safe defaults, don't trust the cache
+	 */
+	memset(pp->wwid, 0, WWID_SIZE);
+	pp->state = PATH_DOWN;
+	return 0;
 }

Modified: multipath-tools/upstream/current/libmultipath/discovery.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/discovery.h	(original)
+++ multipath-tools/upstream/current/libmultipath/discovery.h	Wed Feb  1 23:48:32 2006
@@ -40,14 +40,21 @@
 /*
  * discovery bitmask
  */
-#define DI_SYSFS	1
-#define DI_SERIAL	2
-#define DI_CLAIMED	4
-#define DI_CHECKER	8
-#define DI_PRIO		16
-#define DI_WWID		32
+enum discovery_mode {
+	__DI_SYSFS,
+	__DI_SERIAL,
+	__DI_CHECKER,
+	__DI_PRIO,
+	__DI_WWID
+};
 
-#define DI_ALL		(DI_SYSFS  | DI_SERIAL | DI_CLAIMED | DI_CHECKER | \
-			 DI_PRIO   | DI_WWID)
+#define DI_SYSFS	(1 << __DI_SYSFS)
+#define DI_SERIAL	(1 << __DI_SERIAL)
+#define DI_CHECKER	(1 << __DI_CHECKER)
+#define DI_PRIO		(1 << __DI_PRIO)
+#define DI_WWID 	(1 << __DI_WWID)
+
+#define DI_ALL		(DI_SYSFS  | DI_SERIAL | DI_CHECKER | DI_PRIO | \
+			 DI_WWID)
 
 #endif /* DISCOVERY_H */

Modified: multipath-tools/upstream/current/libmultipath/dmparser.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/dmparser.c	(original)
+++ multipath-tools/upstream/current/libmultipath/dmparser.c	Wed Feb  1 23:48:32 2006
@@ -250,7 +250,7 @@
 {
 	char * word;
 	char * p;
-	int i, j;
+	int i, j, k;
 	int num_feature_args;
 	int num_hwhandler_args;
 	int num_pg;
@@ -405,12 +405,13 @@
 
 			pp->failcount = atoi(word);
 			FREE(word);
+
+			/*
+			 * selector args
+			 */
+			for (k = 0; k < num_pg_args; k++)
+				p += get_word(p, NULL);
 		}
-		/*
-		 * selector args
-		 */
-		for (j = 0; j < num_pg_args; j++)
-			p += get_word(p, NULL);
 	}
 	return 0;
 }

Modified: multipath-tools/upstream/current/libmultipath/hwtable.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/hwtable.c	(original)
+++ multipath-tools/upstream/current/libmultipath/hwtable.c	Wed Feb  1 23:48:32 2006
@@ -17,7 +17,8 @@
 	r += store_hwe(hw, "COMPAQ", "MSA1000 VOLUME", GROUP_BY_SERIAL, DEFAULT_GETUID);
 	r += store_hwe(hw, "DDN", "SAN DataDirector", MULTIBUS, DEFAULT_GETUID);
 	r += store_hwe(hw, "DEC", "HSG80", GROUP_BY_SERIAL, DEFAULT_GETUID);
-	r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS, DEFAULT_GETUID);
+	r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS,
+		       "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n");
 	r += store_hwe(hw, "FSC", "CentricStor", GROUP_BY_SERIAL, DEFAULT_GETUID);
 	r += store_hwe(hw, "HITACHI", "DF400", MULTIBUS, DEFAULT_GETUID);
 	r += store_hwe(hw, "HITACHI", "DF500", MULTIBUS, DEFAULT_GETUID);
@@ -36,13 +37,13 @@
 
 	r += store_hwe_ext(hw, "DGC", "*", GROUP_BY_PRIO, DEFAULT_GETUID,
 		   "/sbin/mpath_prio_emc /dev/%n", "1 emc",
-		   "1 queue_if_no_path", "emc_clariion");
+		   "1 queue_if_no_path", "emc_clariion", FAILBACK_IMMEDIATE);
 	r += store_hwe_ext(hw, "IBM", "3542", GROUP_BY_SERIAL, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur");
+		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
 	r += store_hwe_ext(hw, "SGI", "TP9400", MULTIBUS, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur");
+		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
 	r += store_hwe_ext(hw, "SGI", "TP9500", FAILOVER, DEFAULT_GETUID,
-		   NULL, "0", "0", "tur");
+		   NULL, "0", "0", "tur", FAILBACK_UNDEF);
 
 	return r;
 }

Added: multipath-tools/upstream/current/libmultipath/log.c
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/log.c	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "memory.h"
+#include "log.h"
+
+#define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
+
+#if LOGDBG
+static void dump_logarea (void)
+{
+	struct logmsg * msg;
+	
+	logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
+		la->start, la->end);
+	logdbg(stderr, "|addr     |next     |prio|msg\n");
+
+	for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
+	     msg = msg->next)
+		logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+				msg->prio, (char *)&msg->str);
+
+	logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
+			msg->prio, (char *)&msg->str);
+
+	logdbg(stderr, "\n\n");
+}
+#endif
+		
+static int logarea_init (int size)
+{
+	logdbg(stderr,"enter logarea_init\n");
+	la = (struct logarea *)MALLOC(sizeof(struct logarea));
+	
+	if (!la)
+		return 1;
+
+	if (size < MAX_MSG_SIZE)
+		size = DEFAULT_AREA_SIZE;
+
+	la->start = MALLOC(size);
+	memset(la->start, 0, size);
+
+	if (!la->start) {
+		FREE(la);
+		return 1;
+	}
+
+	la->empty = 1;
+	la->end = la->start + size;
+	la->head = la->start;
+	la->tail = la->start;
+
+	la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
+
+	if (!la->buff) {
+		FREE(la->start);
+		FREE(la);
+		return 1;
+	}
+	return 0;
+
+}
+
+int log_init(char *program_name, int size)
+{
+	logdbg(stderr,"enter log_init\n");
+	openlog(program_name, 0, LOG_DAEMON);
+
+	if (logarea_init(size))
+		return 1;
+
+	return 0;
+}
+
+void free_logarea (void)
+{
+	FREE(la->start);
+	FREE(la->buff);
+	FREE(la);
+	return;
+}
+
+void log_close (void)
+{
+	free_logarea();
+	closelog();
+
+	return;
+}
+
+int log_enqueue (int prio, const char * fmt, va_list ap)
+{
+	int len, fwd;
+	char buff[MAX_MSG_SIZE];
+	struct logmsg * msg;
+	struct logmsg * lastmsg;
+
+	lastmsg = (struct logmsg *)la->tail;
+
+	if (!la->empty) {
+		fwd = sizeof(struct logmsg) + 
+		      strlen((char *)&lastmsg->str) * sizeof(char) + 1;
+		la->tail += ALIGN(fwd, sizeof(void *));
+	}
+	vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
+	len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
+		    sizeof(void *));
+
+	/* not enough space on tail : rewind */
+	if (la->head <= la->tail && len > (la->end - la->tail)) {
+		logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
+		la->tail = la->start;
+
+		if (la->empty)
+			la->head = la->start;
+	}
+
+	/* not enough space on head : drop msg */
+	if (la->head > la->tail && len >= (la->head - la->tail)) {
+		logdbg(stderr, "enqueue: log area overrun, drop msg\n");
+
+		if (!la->empty)
+			la->tail = lastmsg;
+
+		return 1;
+	}
+
+	/* ok, we can stage the msg in the area */
+	la->empty = 0;
+	msg = (struct logmsg *)la->tail;
+	msg->prio = prio;
+	memcpy((void *)&msg->str, buff, strlen(buff));
+	lastmsg->next = la->tail;
+	msg->next = la->head;
+
+	logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
+		msg->prio, (char *)&msg->str);
+
+#if LOGDBG
+	dump_logarea();
+#endif
+	return 0;
+}
+
+int log_dequeue (void * buff)
+{
+	struct logmsg * src = (struct logmsg *)la->head;
+	struct logmsg * dst = (struct logmsg *)buff;
+	struct logmsg * lst = (struct logmsg *)la->tail;
+
+	if (la->empty)
+		return 1;
+
+	int len = strlen((char *)&src->str) * sizeof(char) +
+		  sizeof(struct logmsg) + 1;
+
+	dst->prio = src->prio;
+	memcpy(dst, src,  len);
+
+	if (la->tail == la->head)
+		la->empty = 1; /* we purge the last logmsg */
+	else {
+		la->head = src->next;
+		lst->next = la->head;
+	}
+	logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
+		(void *)src, src->next, src->prio, (char *)&src->str);
+
+	memset((void *)src, 0,  len);
+
+	return la->empty;
+}
+
+/*
+ * this one can block under memory pressure
+ */
+void log_syslog (void * buff)
+{
+	struct logmsg * msg = (struct logmsg *)buff;
+
+	syslog(msg->prio, "%s", (char *)&msg->str);
+}

Added: multipath-tools/upstream/current/libmultipath/log.h
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/log.h	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,42 @@
+#ifndef LOG_H
+#define LOG_H
+
+#define DEFAULT_AREA_SIZE 8192
+#define MAX_MSG_SIZE 128
+
+#ifndef LOGLEVEL
+#define LOGLEVEL 5
+#endif
+
+#if LOGDBG
+#define logdbg(file, fmt, args...) fprintf(file, fmt, ##args)
+#else
+#define logdbg(file, fmt, args...) do {} while (0)
+#endif
+
+struct logmsg {
+	short int prio;
+	void * next;
+	char * str;
+};
+
+struct logarea {
+	int empty;
+	void * head;
+	void * tail;
+	void * start;
+	void * end;
+	char * buff;
+};
+
+struct logarea * la;
+
+int log_init (char * progname, int size);
+void log_close (void);
+int log_enqueue (int prio, const char * fmt, va_list ap);
+int log_dequeue (void *);
+void log_syslog (void *);
+void dump_logmsg (void *);
+void free_logarea (void);
+
+#endif /* LOG_H */

Added: multipath-tools/upstream/current/libmultipath/log_pthread.c
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/log_pthread.c	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <sys/mman.h>
+
+#include <memory.h>
+
+#include "log_pthread.h"
+#include "log.h"
+
+void log_safe (int prio, char * fmt, va_list ap)
+{
+	pthread_mutex_lock(logq_lock);
+	//va_start(ap, fmt);
+	log_enqueue(prio, fmt, ap);
+	va_end(ap);
+	pthread_mutex_unlock(logq_lock);
+
+	pthread_mutex_lock(logev_lock);
+	pthread_cond_signal(logev_cond);
+	pthread_mutex_unlock(logev_lock);
+}
+
+static void flush_logqueue (void)
+{
+	int empty;
+
+	do {
+		pthread_mutex_lock(logq_lock);
+		empty = log_dequeue(la->buff);
+		pthread_mutex_unlock(logq_lock);
+		log_syslog(la->buff);
+	} while (empty == 0);
+}
+
+static void * log_thread (void * et)
+{
+	mlockall(MCL_CURRENT | MCL_FUTURE);
+	logdbg(stderr,"enter log_thread\n");
+
+	while (1) {
+		pthread_mutex_lock(logev_lock);
+		pthread_cond_wait(logev_cond, logev_lock);
+		pthread_mutex_unlock(logev_lock);
+
+		flush_logqueue();
+	}
+}
+
+void log_thread_start (void)
+{
+	pthread_attr_t attr;
+	
+	logdbg(stderr,"enter log_thread_start\n");
+
+	logq_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+	logev_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+	logev_cond = (pthread_cond_t *) malloc(sizeof(pthread_cond_t));
+	
+	pthread_mutex_init(logq_lock, NULL);
+	pthread_mutex_init(logev_lock, NULL);
+	pthread_cond_init(logev_cond, NULL);
+	
+	pthread_attr_init(&attr);
+	pthread_attr_setstacksize(&attr, 64 * 1024);
+
+	if (log_init("multipathd", 0)) {
+		fprintf(stderr,"can't initialize log buffer\n");
+		exit(1);
+	}
+	pthread_create(&log_thr, &attr, log_thread, NULL);
+
+	return;
+}
+
+void log_thread_stop (void)
+{
+	logdbg(stderr,"enter log_thread_stop\n");
+
+	pthread_mutex_lock(logq_lock);
+	pthread_cancel(log_thr);
+	pthread_mutex_unlock(logq_lock);
+
+	flush_logqueue();
+
+	pthread_mutex_destroy(logq_lock);
+	pthread_mutex_destroy(logev_lock);
+	pthread_cond_destroy(logev_cond);
+
+	free_logarea();
+}	

Added: multipath-tools/upstream/current/libmultipath/log_pthread.h
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/libmultipath/log_pthread.h	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,14 @@
+#ifndef _LOG_PTHREAD_H
+#define _LOG_PTHREAD_H
+
+pthread_t log_thr;
+
+pthread_mutex_t *logq_lock;
+pthread_mutex_t *logev_lock;
+pthread_cond_t *logev_cond;
+
+void log_safe(int prio, char * fmt, va_list ap);
+void log_thread_start(void);
+void log_thread_stop(void);
+
+#endif /* _LOG_PTHREAD_H */

Modified: multipath-tools/upstream/current/libmultipath/pgpolicies.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/pgpolicies.c	(original)
+++ multipath-tools/upstream/current/libmultipath/pgpolicies.c	Wed Feb  1 23:48:32 2006
@@ -30,7 +30,7 @@
 	return -1;
 }
 
-extern void
+extern int
 get_pgpolicy_name (char * buff, int id)
 {
 	char * s;
@@ -57,8 +57,9 @@
 	}
 	if(safe_snprintf(buff, POLICY_NAME_SIZE, "%s", s)) {
 		fprintf(stderr, "get_pgpolicy_name: buff too small\n");
-		exit(1);
+		return 1;
 	}
+	return 0;
 }
 
 /*

Modified: multipath-tools/upstream/current/libmultipath/pgpolicies.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/pgpolicies.h	(original)
+++ multipath-tools/upstream/current/libmultipath/pgpolicies.h	Wed Feb  1 23:48:32 2006
@@ -20,7 +20,7 @@
 };
 
 int get_pgpolicy_id(char *);
-void get_pgpolicy_name (char *, int);
+int get_pgpolicy_name (char *, int);
 
 /*
  * policies

Modified: multipath-tools/upstream/current/libmultipath/print.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/print.c	(original)
+++ multipath-tools/upstream/current/libmultipath/print.c	Wed Feb  1 23:48:32 2006
@@ -1,5 +1,7 @@
 #include <stdio.h>
 #include <string.h>
+#include <math.h>
+#include <libdevmapper.h>
 
 #include "vector.h"
 #include "structs.h"
@@ -10,22 +12,30 @@
 
 #define MAX_FIELD_LEN 64
 
-#define MAX(x,y) (x > y) ? x : y;
+#define MAX(x,y) (x > y) ? x : y
 
 void
 get_path_layout (struct path_layout * pl, vector pathvec)
 {
 	int i;
-	int hbtl_len, dev_len, dev_t_len;
 	char buff[MAX_FIELD_LEN];
 	struct path * pp;
 
+	int uuid_len;
+	int hbtl_len;
+	int dev_len;
+	int dev_t_len;
+	int prio_len;
+
 	/* reset max col lengths */
+	pl->uuid_len = 0;
 	pl->hbtl_len = 0;
 	pl->dev_len = 0;
 	pl->dev_t_len = 0;
+	pl->prio_len = 0;
 
 	vector_foreach_slot (pathvec, pp, i) {
+		uuid_len = strlen(pp->wwid);
 		hbtl_len = snprintf(buff, MAX_FIELD_LEN, "%i:%i:%i:%i",
 					pp->sg_id.host_no,
 					pp->sg_id.channel,
@@ -33,10 +43,13 @@
 					pp->sg_id.lun);
 		dev_len = strlen(pp->dev);
 		dev_t_len = strlen(pp->dev_t);
+		prio_len = 1 + (int)log10(pp->priority);
 
+		pl->uuid_len = MAX(uuid_len, pl->uuid_len);
 		pl->hbtl_len = MAX(hbtl_len, pl->hbtl_len);
 		pl->dev_len = MAX(dev_len, pl->dev_len);
 		pl->dev_t_len = MAX(dev_t_len, pl->dev_t_len);
+		pl->prio_len = MAX(prio_len, pl->prio_len);
 	}
 	return;
 }
@@ -46,32 +59,126 @@
 {
 	int i;
 	char buff[MAX_FIELD_LEN];
-	int mapname_len, mapdev_len;
 	struct multipath * mpp;
 
+	int mapname_len;
+	int mapdev_len;
+	int failback_progress_len;
+	int queueing_progress_len;
+	int nr_active_len;
+
 	/* reset max col lengths */
 	ml->mapname_len = 0;
 	ml->mapdev_len = 0;
+	ml->failback_progress_len = 0;
+	ml->queueing_progress_len = 0;
+	ml->nr_active_len = 0;
 
 	vector_foreach_slot (mpvec, mpp, i) {
 		mapname_len = (mpp->alias) ?
 				strlen(mpp->alias) : strlen(mpp->wwid);
-		ml->mapname_len = MAX(mapname_len, ml->mapname_len);
+		if (mpp->dmi) mapdev_len = snprintf(buff, MAX_FIELD_LEN,
+			       	      "dm-%i", mpp->dmi->minor);
+		failback_progress_len = 4 + PROGRESS_LEN +
+					(int)log10(mpp->failback_tick) +
+					(int)log10(mpp->pgfailback);
+		queueing_progress_len = 5 + (int)log10(mpp->retry_tick);
+		nr_active_len = (int)log10(mpp->nr_active);
 
-		mapdev_len = snprintf(buff, MAX_FIELD_LEN,
-			       	      "dm-%i", mpp->minor);
+		ml->mapname_len = MAX(mapname_len, ml->mapname_len);
 		ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len);
+		ml->failback_progress_len = MAX(failback_progress_len,
+						ml->failback_progress_len);
+		ml->queueing_progress_len = MAX(queueing_progress_len,
+						ml->queueing_progress_len);
+		ml->nr_active_len = MAX(nr_active_len, ml->nr_active_len);
 	}
 	return;
 }
 
 #define TAIL   (line + len - 1 - c)
-#define PAD(x) while ((int)(c - s) < (x)) *c++ = ' '; s = c
+#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
+			*c++ = ' '; s = c
 #define NOPAD  s = c
+
 #define PRINT(var, size, format, args...)      \
 	        fwd = snprintf(var, size, format, ##args); \
 		c += (fwd >= size) ? size : fwd;
 
+#define PRINT_PROGRESS(cur, total)			\
+		int i = PROGRESS_LEN * cur / total;	\
+		int j = PROGRESS_LEN - i;		\
+							\
+		while (i-- > 0) {			\
+			PRINT(c, TAIL, "X");		\
+		}					\
+		while (j-- > 0) {			\
+			PRINT(c, TAIL, ".");		\
+		}					\
+		PRINT(c, TAIL, " %i/%i", cur, total)
+
+int
+snprint_map_header (char * line, int len, char * format,
+	            struct map_layout * ml)
+{
+	char * c = line;   /* line cursor */
+	char * s = line;   /* for padding */
+	char * f = format; /* format string cursor */
+	int fwd;
+
+	do {
+		if (!TAIL)
+			break;
+
+		if (*f != '%') {
+			*c++ = *f;
+			NOPAD;
+			continue;
+		}
+		f++;
+		switch (*f) {
+		case 'w':	
+			PRINT(c, TAIL, "name");
+			ml->mapname_len = MAX(ml->mapname_len, 4);
+			PAD(ml->mapname_len);
+			break;
+		case 'd':
+			PRINT(c, TAIL, "sysfs");
+			ml->mapdev_len = MAX(ml->mapdev_len, 5);
+			PAD(ml->mapdev_len);
+			break;
+		case 'F':
+			PRINT(c, TAIL, "failback");
+			ml->failback_progress_len =
+				MAX(ml->failback_progress_len, 8);
+			PAD(ml->failback_progress_len);
+			break;
+		case 'Q':
+			PRINT(c, TAIL, "queueing");
+			ml->queueing_progress_len =
+				MAX(ml->queueing_progress_len, 8);
+			PAD(ml->queueing_progress_len);
+			break;
+		case 'n':
+			PRINT(c, TAIL, "paths");
+			ml->nr_active_len = MAX(ml->nr_active_len, 5);
+			PAD(ml->nr_active_len);
+			break;
+		case 't':
+			PRINT(c, TAIL, "dm-st");
+			PAD(7);
+			break;
+		default:
+			break;
+		}
+	} while (*f++);
+
+	line[c - line - 1] = '\n';
+	line[c - line] = '\0';
+
+	return (c - line);
+}
+
 int
 snprint_map (char * line, int len, char * format,
 	     struct multipath * mpp, struct map_layout * ml)
@@ -79,7 +186,6 @@
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
-	int i, j;
 	int fwd;
 
 	do {
@@ -102,27 +208,119 @@
 			PAD(ml->mapname_len);
 			break;
 		case 'd':
-			PRINT(c, TAIL, "dm-%i", mpp->minor);
+			if (mpp->dmi) {
+				PRINT(c, TAIL, "dm-%i", mpp->dmi->minor);
+			}
 			PAD(ml->mapdev_len);
 			break;
 		case 'F':
 			if (!mpp->failback_tick) {
-				PRINT(c, TAIL, "[no scheduled failback]");
-				NOPAD;
-				break;
-			}
-			i = mpp->failback_tick;
-			j = mpp->pgfailback - mpp->failback_tick;
-
-			while (i-- > 0) {
-				PRINT(c, TAIL, "X");
+				PRINT(c, TAIL, "-");
+			} else {
+				PRINT_PROGRESS(mpp->failback_tick,
+					       mpp->pgfailback);
 			}
-			while (j-- > 0) {
-				PRINT(c, TAIL, ".");
+			PAD(ml->failback_progress_len);
+			break;
+		case 'Q':
+			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) {
+				PRINT(c, TAIL, "off");
+			} else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
+				PRINT(c, TAIL, "on");
+			} else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF) {
+				PRINT(c, TAIL, "-");
+			} else if (mpp->no_path_retry > 0) {
+				if (mpp->retry_tick) {
+					PRINT(c, TAIL, "%i sec",
+					      mpp->retry_tick);
+				} else {
+					PRINT(c, TAIL, "%i chk",
+					      mpp->no_path_retry);
+				}
+			}
+			PAD(ml->queueing_progress_len);
+			break;
+		case 'n':
+			PRINT(c, TAIL, "%i", mpp->nr_active);
+			PAD(ml->nr_active_len);
+			break;
+		case 't':
+			if (mpp->dmi && mpp->dmi->suspended) {
+				PRINT(c, TAIL, "suspend");
+			} else {
+				PRINT(c, TAIL, "active");
 			}
-			PRINT(c, TAIL, " %i/%i",
-				     mpp->failback_tick, mpp->pgfailback);
+			PAD(7);
+			break;
+		default:
+			break;
+		}
+	} while (*f++);
+
+	line[c - line - 1] = '\n';
+	line[c - line] = '\0';
+
+	return (c - line);
+}
+
+int
+snprint_path_header (char * line, int len, char * format,
+		     struct path_layout * pl)
+{
+	char * c = line;   /* line cursor */
+	char * s = line;   /* for padding */
+	char * f = format; /* format string cursor */
+	int fwd;
+
+	do {
+		if (!TAIL)
+			break;
+
+		if (*f != '%') {
+			*c++ = *f;
 			NOPAD;
+			continue;
+		}
+		f++;
+		switch (*f) {
+		case 'w':
+			PRINT(c, TAIL, "uuid");
+			PAD(pl->uuid_len);
+			break;
+		case 'i':
+			PRINT(c, TAIL, "hcil");
+			PAD(pl->hbtl_len);
+			break;
+		case 'd':
+			PRINT(c, TAIL, "dev");
+			pl->dev_len = MAX(pl->dev_len, 3);
+			PAD(pl->dev_len);
+			break;
+		case 'D':
+			PRINT(c, TAIL, "dev_t");
+			pl->dev_t_len = MAX(pl->dev_t_len, 5);
+			PAD(pl->dev_t_len);
+			break;
+		case 'T':
+			PRINT(c, TAIL, "chk-st");
+			PAD(8);
+			break;
+		case 't':
+			PRINT(c, TAIL, "dm-st");
+			PAD(8);
+			break;
+		case 's':
+			PRINT(c, TAIL, "vendor/product/rev");
+			NOPAD;
+			break;
+		case 'C':
+			PRINT(c, TAIL, "next-check");
+			NOPAD;
+			break;
+		case 'p':
+			PRINT(c, TAIL, "pri");
+			pl->prio_len = MAX(pl->prio_len, 3);
+			PAD(pl->prio_len);
 			break;
 		default:
 			break;
@@ -142,7 +340,6 @@
 	char * c = line;   /* line cursor */
 	char * s = line;   /* for padding */
 	char * f = format; /* format string cursor */
-	int i, j;
 	int fwd;
 
 	do {
@@ -157,12 +354,12 @@
 		f++;
 		switch (*f) {
 		case 'w':	
-			PRINT(c, TAIL, "%s ", pp->wwid);
-			NOPAD;
+			PRINT(c, TAIL, "%s", pp->wwid);
+			PAD(pl->uuid_len);
 			break;
 		case 'i':
 			if (pp->sg_id.host_no < 0) {
-				PRINT(c, TAIL, "#:#:#:# ");
+				PRINT(c, TAIL, "#:#:#:#");
 			} else {
 				PRINT(c, TAIL, "%i:%i:%i:%i",
 					pp->sg_id.host_no,
@@ -173,7 +370,11 @@
 			PAD(pl->hbtl_len);
 			break;
 		case 'd':
-			PRINT(c, TAIL, "%s", pp->dev);
+			if (!strlen(pp->dev)) {
+				PRINT(c, TAIL, "-");
+			} else {
+				PRINT(c, TAIL, "%s", pp->dev);
+			}
 			PAD(pl->dev_len);
 			break;
 		case 'D':
@@ -195,9 +396,10 @@
 				PRINT(c, TAIL, "[ghost]");
 				break;
 			default:
+				PRINT(c, TAIL, "[undef]");
 				break;
 			}
-			NOPAD;
+			PAD(8);
 			break;
 		case 't':
 			switch (pp->dmstate) {
@@ -208,15 +410,10 @@
 				PRINT(c, TAIL, "[failed]");
 				break;
 			default:
+				PRINT(c, TAIL, "[undef]");
 				break;
 			}
-			NOPAD;
-			break;
-		case 'c':
-			if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
-				PRINT(c, TAIL, "[claimed]");
-			}
-			NOPAD;
+			PAD(8);
 			break;
 		case 's':
 			PRINT(c, TAIL, "%s/%s/%s",
@@ -226,27 +423,18 @@
 		case 'C':
 			if (!pp->mpp) {
 				PRINT(c, TAIL, "[orphan]");
-				NOPAD;
-				break;
-			}
-			i = pp->tick;
-			j = pp->checkint - pp->tick;
-
-			while (i-- > 0) {
-				PRINT(c, TAIL, "X");
-			}
-			while (j-- > 0) {
-				PRINT(c, TAIL, ".");
+			} else {
+				PRINT_PROGRESS(pp->tick, pp->checkint);
 			}
-			PRINT(c, TAIL, " %i/%i",
-				      pp->tick, pp->checkint);
 			NOPAD;
 			break;
 		case 'p':
 			if (pp->priority) {
 				PRINT(c, TAIL, "%i", pp->priority);
+			} else {
+				PRINT(c, TAIL, "#");
 			}
-			NOPAD;
+			PAD(pl->prio_len);
 			break;
 		default:
 			break;

Modified: multipath-tools/upstream/current/libmultipath/print.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/print.h	(original)
+++ multipath-tools/upstream/current/libmultipath/print.h	Wed Feb  1 23:48:32 2006
@@ -8,7 +8,6 @@
  * %t : device mapper path status
  * %T : checker path status
  * %s : scsi strings
- * %c : claimed
  * %p : priority
  * 
  * map format magics :
@@ -17,27 +16,38 @@
  * %d : DM device name
  * %F : failback countdown
  * %C : checker countdown
+ * %Q : queueing policy changer countdown (no_path_retry)
+ * %n : number of active paths
+ * %t : device mapper map status
  */
-#define PRINT_PATH_LONG      "%w %i %d %D %p %t%T%c %s"
-#define PRINT_PATH_INDENT    " \\_ %i %d %D %t%T%c"
+#define PRINT_PATH_LONG      "%w %i %d %D %p %t%T %s"
+#define PRINT_PATH_INDENT    " \\_ %i %d %D %t%T"
 #define PRINT_PATH_CHECKER   "%i %d %D %p %t%T %C"
-#define PRINT_MAP_FAILBACK   "%w %d %F"
+#define PRINT_MAP_FAILBACK   "%w %d %F %Q %n %t"
 
 #define MAX_LINE_LEN 80
+#define PROGRESS_LEN 10
 
 struct path_layout {
+	int uuid_len;
 	int hbtl_len;
 	int dev_len;
 	int dev_t_len;
+	int prio_len;
 };
 
 struct map_layout {
 	int mapname_len;
 	int mapdev_len;
+	int failback_progress_len;
+	int queueing_progress_len;
+	int nr_active_len;
 };
 
 
 void get_path_layout (struct path_layout * pl, vector pathvec);
 void get_map_layout (struct map_layout * pl, vector mpvec);
+int snprint_path_header (char *, int, char *, struct path_layout *);
+int snprint_map_header (char *, int, char *, struct map_layout *);
 int snprint_path (char *, int, char *, struct path *, struct path_layout *);
 int snprint_map (char *, int, char *,struct multipath *, struct map_layout *);

Modified: multipath-tools/upstream/current/libmultipath/propsel.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/propsel.c	(original)
+++ multipath-tools/upstream/current/libmultipath/propsel.c	Wed Feb  1 23:48:32 2006
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "debug.h"
 #include "pgpolicies.h"
+#include "alias.h"
 
 #include "../libcheckers/checkers.h"
 
@@ -75,30 +76,35 @@
 
 	if (conf->pgpolicy_flag > 0) {
 		mp->pgpolicy = conf->pgpolicy_flag;
-		get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+			return 1;
 		condlog(3, "pgpolicy = %s (cmd line flag)", pgpolicy_name);
 		return 0;
 	}
 	if (mp->mpe && mp->mpe->pgpolicy > 0) {
 		mp->pgpolicy = mp->mpe->pgpolicy;
-		get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+			return 1;
 		condlog(3, "pgpolicy = %s (LUN setting)", pgpolicy_name);
 		return 0;
 	}
 	if (mp->hwe && mp->hwe->pgpolicy > 0) {
 		mp->pgpolicy = mp->hwe->pgpolicy;
-		get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+			return 1;
 		condlog(3, "pgpolicy = %s (controler setting)", pgpolicy_name);
 		return 0;
 	}
 	if (conf->default_pgpolicy > 0) {
 		mp->pgpolicy = conf->default_pgpolicy;
-		get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+		if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+			return 1;
 		condlog(3, "pgpolicy = %s (config file default)", pgpolicy_name);
 		return 0;
 	}
 	mp->pgpolicy = FAILOVER;
-	get_pgpolicy_name(pgpolicy_name, FAILOVER);
+	if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+		return 1;
 	condlog(3, "pgpolicy = %s (internal default)", pgpolicy_name);
 	return 0;
 }
@@ -116,7 +122,7 @@
 		condlog(3, "selector = %s (controler setting)", mp->selector);
 		return 0;
 	}
-	mp->selector = conf->default_selector;
+	mp->selector = conf->selector;
 	condlog(3, "selector = %s (internal default)", mp->selector);
 	return 0;
 }
@@ -126,8 +132,14 @@
 {
 	if (mp->mpe && mp->mpe->alias)
 		mp->alias = mp->mpe->alias;
-	else
-		mp->alias = mp->wwid;
+	else {
+		mp->alias = NULL;
+		if (conf->user_friendly_names)
+			mp->alias = get_user_friendly_alias(mp->wwid,
+					conf->bindings_file);
+		if (mp->alias == NULL)
+			mp->alias = mp->wwid;
+	}
 
 	return 0;
 }
@@ -140,7 +152,7 @@
 		condlog(3, "features = %s (controler setting)", mp->features);
 		return 0;
 	}
-	mp->features = conf->default_features;
+	mp->features = conf->features;
 	condlog(3, "features = %s (internal default)", mp->features);
 	return 0;
 }
@@ -169,8 +181,8 @@
 		pp->checkfn = get_checker_addr(pp->hwe->checker_index);
 		return 0;
 	}
-	pp->checkfn = &readsector0;
-	get_checker_name(checker_name, READSECTOR0);
+	pp->checkfn = get_checker_addr(conf->default_checker_index);
+	get_checker_name(checker_name, conf->default_checker_index);
 	condlog(3, "path checker = %s (internal default)", checker_name);
 	return 0;
 }
@@ -201,3 +213,28 @@
 	return 0;
 }
 
+extern int
+select_no_path_retry(struct multipath *mp)
+{
+	if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
+		mp->no_path_retry = mp->mpe->no_path_retry;
+		condlog(3, "no_path_retry = %i (multipath setting)",
+			mp->no_path_retry);
+		return 0;
+	}
+	if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
+		mp->no_path_retry = mp->hwe->no_path_retry;
+		condlog(3, "no_path_retry = %i (controler setting)",
+			mp->no_path_retry);
+		return 0;
+	}
+	if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
+		mp->no_path_retry = conf->no_path_retry;
+		condlog(3, "no_path_retry = %i (config file default)",
+			mp->no_path_retry);
+		return 0;
+	}
+	mp->no_path_retry = NO_PATH_RETRY_UNDEF;
+	condlog(3, "no_path_retry = NONE (internal default)");
+	return 0;
+}

Modified: multipath-tools/upstream/current/libmultipath/propsel.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/propsel.h	(original)
+++ multipath-tools/upstream/current/libmultipath/propsel.h	Wed Feb  1 23:48:32 2006
@@ -8,4 +8,4 @@
 int select_checkfn(struct path *pp);
 int select_getuid (struct path * pp);
 int select_getprio (struct path * pp);
-
+int select_no_path_retry(struct multipath *mp);

Modified: multipath-tools/upstream/current/libmultipath/structs.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/structs.c	(original)
+++ multipath-tools/upstream/current/libmultipath/structs.c	Wed Feb  1 23:48:32 2006
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <unistd.h>
+#include <libdevmapper.h>
 
 #include "memory.h"
 #include "vector.h"
@@ -20,6 +21,7 @@
 		pp->sg_id.channel = -1;
 		pp->sg_id.scsi_id = -1;
 		pp->sg_id.lun = -1;
+		pp->fd = -1;
 	}
 	return pp;
 }
@@ -33,7 +35,7 @@
 	if (pp->checker_context)
 		free(pp->checker_context);
 
-	if (pp->fd > 0)
+	if (pp->fd >= 0)
 		close(pp->fd);
 
 	FREE(pp);
@@ -106,7 +108,7 @@
 	mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
 
 	if (mpp)
-		mpp->nextpg = 1;
+		mpp->bestpg = 1;
 
 	return mpp;
 }
@@ -118,7 +120,7 @@
 		return;
 
 	if (mpp->selector &&
-	    mpp->selector != conf->default_selector &&
+	    mpp->selector != conf->selector &&
 	    (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
 	    (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector)))
 		FREE(mpp->selector);
@@ -129,7 +131,7 @@
 		FREE(mpp->alias);
 
 	if (mpp->features &&
-	    mpp->features != conf->default_features &&
+	    mpp->features != conf->features &&
 	    (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features)))
 		FREE(mpp->features);
 
@@ -138,12 +140,33 @@
 	    (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler)))
 		FREE(mpp->hwhandler);
 
+	if (mpp->dmi)
+		FREE(mpp->dmi);
+	
 	free_pathvec(mpp->paths, free_paths);
 	free_pgvec(mpp->pg, free_paths);
 	FREE(mpp);
 }
 
 void
+drop_multipath (vector mpvec, char * wwid, int free_paths)
+{
+	int i;
+	struct multipath * mpp;
+
+	if (!mpvec)
+		return;
+
+	vector_foreach_slot (mpvec, mpp, i) {
+		if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
+			free_multipath(mpp, free_paths);
+			vector_del_slot(mpvec, i);
+			return;
+		}
+	}
+}
+
+void
 free_multipathvec (vector mpvec, int free_paths)
 {
 	int i;
@@ -186,8 +209,11 @@
 	int i;
 	struct multipath * mpp;
 	
+	if (!mpp->dmi)
+		return NULL;
+
 	vector_foreach_slot (mp, mpp, i)
-		if (mpp->minor == minor)
+		if (mpp->dmi->minor == minor)
 			return mpp;
 
 	return NULL;
@@ -207,7 +233,7 @@
 }
 
 struct multipath *
-find_mp (vector mp, char * alias)
+find_mp_by_alias (vector mp, char * alias)
 {
 	int i;
 	int len;

Modified: multipath-tools/upstream/current/libmultipath/structs.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/structs.h	(original)
+++ multipath-tools/upstream/current/libmultipath/structs.h	Wed Feb  1 23:48:32 2006
@@ -14,6 +14,10 @@
 #define SCSI_PRODUCT_SIZE	17
 #define SCSI_REV_SIZE		5
 
+#define NO_PATH_RETRY_UNDEF	0
+#define NO_PATH_RETRY_FAIL	-1
+#define NO_PATH_RETRY_QUEUE	-2
+
 enum free_path_switch {
 	KEEP_PATHS,
 	FREE_PATHS
@@ -87,12 +91,11 @@
 	unsigned long long size;
 	unsigned int checkint;
 	unsigned int tick;
-	int state;
 	int bus;
+	int state;
 	int dmstate;
 	int failcount;
 	int priority;
-	int claimed;
 	int pgindex;
 	char * getuid;
 	char * getprio;
@@ -107,19 +110,23 @@
 
 struct multipath {
 	char wwid[WWID_SIZE];
-	int minor;
 	int pgpolicy;
 	int nextpg;
+	int bestpg;
 	int queuedio;
 	int action;
 	int pgfailback;
 	int failback_tick;
 	int rr_weight;
+	int nr_active;     /* current available(= not known as failed) paths */
+	int no_path_retry; /* number of retries after all paths are down */
+	int retry_tick;    /* remaining times for retries */
 	unsigned long long size;
 	vector paths;
 	vector pg;
 	char params[PARAMS_SIZE];
 	char status[PARAMS_SIZE];
+	struct dm_info * dmi;
 
 	/* configlet pointers */
 	char * alias;
@@ -148,12 +155,13 @@
 void free_pathgroup (struct pathgroup * pgp, int free_paths);
 void free_pgvec (vector pgvec, int free_paths);
 void free_multipath (struct multipath *, int free_paths);
+void drop_multipath (vector mpvec, char * wwid, int free_paths);
 void free_multipathvec (vector mpvec, int free_paths);
 
 int store_path (vector pathvec, struct path * pp);
 int store_pathgroup (vector pgvec, struct pathgroup * pgp);
 
-struct multipath * find_mp (vector mp, char * alias);
+struct multipath * find_mp_by_alias (vector mp, char * alias);
 struct multipath * find_mp_by_wwid (vector mp, char * wwid);
 struct multipath * find_mp_by_minor (vector mp, int minor);
 	

Modified: multipath-tools/upstream/current/libmultipath/switchgroup.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/switchgroup.c	(original)
+++ multipath-tools/upstream/current/libmultipath/switchgroup.c	Wed Feb  1 23:48:32 2006
@@ -3,22 +3,31 @@
 #include "switchgroup.h"
 #include "../libcheckers/path_state.h"
 
-extern void
+extern int
 select_path_group (struct multipath * mpp)
 {
 	int i, j;
 	int highest = 0;
+	int bestpg = 1;
 	struct pathgroup * pgp;
 	struct path * pp;
+
+	if (!mpp->pg)
+		return 1;
 	
 	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+		
 		vector_foreach_slot (pgp->paths, pp, j) {
 			if (pp->state != PATH_DOWN)
 				pgp->priority += pp->priority;
 		}
+
 		if (pgp->priority > highest) {
 			highest = pgp->priority;
-			mpp->nextpg = i + 1;
+			bestpg = i + 1;
 		}
 	}
+	return bestpg;
 }

Modified: multipath-tools/upstream/current/libmultipath/switchgroup.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/switchgroup.h	(original)
+++ multipath-tools/upstream/current/libmultipath/switchgroup.h	Wed Feb  1 23:48:32 2006
@@ -1 +1 @@
-void select_path_group (struct multipath * mpp);
+int select_path_group (struct multipath * mpp);

Modified: multipath-tools/upstream/current/libmultipath/uevent.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/uevent.c	(original)
+++ multipath-tools/upstream/current/libmultipath/uevent.c	Wed Feb  1 23:48:32 2006
@@ -58,7 +58,7 @@
 	sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
 	if (sock == -1) {
 		condlog(0, "error getting socket, exit\n");
-		exit(1);
+		return 1;
 	}
 
 	retval = bind(sock, (struct sockaddr *) &snl,
@@ -126,6 +126,8 @@
 
 		if (uev_trigger && uev_trigger(uev, trigger_data))
 			condlog(0, "uevent trigger error");
+
+		FREE(uev);
 	}
 
 exit:

Modified: multipath-tools/upstream/current/libmultipath/uxsock.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/uxsock.c	(original)
+++ multipath-tools/upstream/current/libmultipath/uxsock.c	Wed Feb  1 23:48:32 2006
@@ -8,6 +8,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/poll.h>
+#include <errno.h>
 
 #include "memory.h"
 #include "uxsock.h"
@@ -70,14 +71,21 @@
 }
 
 /*
- * keep writing until its all sent
+ * keep writing until it's all sent
  */
-int write_all(int fd, const void *buf, size_t len)
+size_t write_all(int fd, const void *buf, size_t len)
 {
 	size_t total = 0;
+
 	while (len) {
-		int n = write(fd, buf, len);
-		if (n <= 0) return total;
+		ssize_t n = write(fd, buf, len);
+		if (n < 0) {
+			if ((errno == EINTR) || (errno == EAGAIN))
+				continue;
+			return total;
+		}
+		if (!n)
+			return total;
 		buf = n + (char *)buf;
 		len -= n;
 		total += n;
@@ -88,12 +96,19 @@
 /*
  * keep reading until its all read
  */
-int read_all(int fd, void *buf, size_t len)
+size_t read_all(int fd, void *buf, size_t len)
 {
 	size_t total = 0;
+
 	while (len) {
-		int n = read(fd, buf, len);
-		if (n <= 0) return total;
+		ssize_t n = read(fd, buf, len);
+		if (n < 0) {
+			if ((errno == EINTR) || (errno == EAGAIN))
+				continue;
+			return total;
+		}
+		if (!n)
+			return total;
 		buf = n + (char *)buf;
 		len -= n;
 		total += n;

Modified: multipath-tools/upstream/current/libmultipath/uxsock.h
==============================================================================
--- multipath-tools/upstream/current/libmultipath/uxsock.h	(original)
+++ multipath-tools/upstream/current/libmultipath/uxsock.h	Wed Feb  1 23:48:32 2006
@@ -3,4 +3,5 @@
 int ux_socket_listen(const char *name);
 int send_packet(int fd, const char *buf, size_t len);
 int recv_packet(int fd, char **buf, size_t *len);
-
+size_t write_all(int fd, const void *buf, size_t len);
+size_t read_all(int fd, void *buf, size_t len);

Modified: multipath-tools/upstream/current/libmultipath/vector.c
==============================================================================
--- multipath-tools/upstream/current/libmultipath/vector.c	(original)
+++ multipath-tools/upstream/current/libmultipath/vector.c	Wed Feb  1 23:48:32 2006
@@ -80,7 +80,7 @@
 {
 	int i;
 
-	if (!v->allocated)
+	if (!v->allocated || slot < 0 || slot > VECTOR_SIZE(v))
 		return;
 
 	for (i = slot + 1; i < (v->allocated / VECTOR_DEFAULT_SIZE); i++)

Modified: multipath-tools/upstream/current/multipath.conf.annotated
==============================================================================
--- multipath-tools/upstream/current/multipath.conf.annotated	(original)
+++ multipath-tools/upstream/current/multipath.conf.annotated	Wed Feb  1 23:48:32 2006
@@ -9,14 +9,6 @@
 ##
 #defaults {
 #	#
-#	# name    : multipath_tool
-#	# scope   : multipathd
-#	# desc    : the tool in charge of configuring the multipath device maps
-#	# default : "/sbin/multipath -v0"
-#	#
-#	multipath_tool	"/sbin/multipath -v0"
-#
-#	#
 #	# name    : udev_dir
 #	# desc    : directory where udev creates its device nodes
 #	# default : /udev
@@ -32,42 +24,51 @@
 #	polling_interval 10
 #
 #	#
-#	# name    : default_selector
+#	# name    : selector
 #	# scope   : multipath
 #	# desc    : the default path selector algorithm to use
 #	#           these algorithms are offered by the kernel multipath target
 #	# values  : "round-robin 0"
 #	# default : "round-robin 0"
 #	#
-#	default_selector	"round-robin 0"
+#	selector	"round-robin 0"
 #
 #	#
-#	# name    : default_path_grouping_policy
+#	# name    : path_grouping_policy
 #	# scope   : multipath
 #	# desc    : the default path grouping policy to apply to unspecified
 #	#           multipaths
 #	# default : multibus
 #	#
-#	default_path_grouping_policy	multibus
+#	path_grouping_policy	multibus
 #
 #	#
-#	# name    : default_getuid_callout
+#	# name    : getuid_callout
 #	# scope   : multipath
 #	# desc    : the default program and args to callout to obtain a unique 
 #	#           path identifier. Absolute path required
 #	# default : /sbin/scsi_id -g -u -s
 #	#
-#	default_getuid_callout	"/sbin/scsi_id -g -u -s /block/%n"
+#	getuid_callout	"/sbin/scsi_id -g -u -s /block/%n"
 #
 #	#
-#	# name    : default_prio_callout
+#	# name    : prio_callout
 #	# scope   : multipath
 #	# desc    : the default program and args to callout to obtain a path 
 #	#           priority value. The ALUA bits in SPC-3 provide an
 #	#           exploitable prio value for example. "none" is a valid value
 #	# default : (null)
 #	#
-#	#default_prio_callout	"/bin/true"
+#	#prio_callout	"/bin/true"
+#
+#	#
+#	# name    : path_checker
+#	# scope   : multipath & multipathd
+#	# desc    : the default method used to determine the paths' state
+#	# values  : readsector0|tur|emc_clariion|hp_sw|directio
+#	# default : readsector0
+#	#
+#	#path_checker	readsector0
 #
 #	#
 #	# name    : rr_min_io
@@ -76,7 +77,7 @@
 #	#           to the next in the same path group
 #	# default : 1000
 #	#
-#	r_min_io	100
+#	rr_min_io	100
 #
 #	#
 #	# name    : rr_weight
@@ -86,7 +87,7 @@
 #	# values  : priorities|uniform
 #	# default : uniform
 #	#
-#	rr_weight		priorities
+#	rr_weight	priorities
 #
 #	#
 #	# name    : failback
@@ -98,6 +99,31 @@
 #	# default : immediate
 #	#
 #	failback	manual
+#
+#	#
+#	# name    : no_path_retry
+#	# scope   : multipath & multipathd
+#	# desc    : tell the number of retries until disable queueing, or
+#	#           "fail" means immediate failure (no queueing),
+#	#           "queue" means never stop queueing
+#	# values  : queue|fail|n (>0)
+#	# default : (null)
+#	#
+#	#no_path_retry  queue
+#
+#	#
+#	# name    : user_friendly_names
+#	# scope   : multipath
+#	# desc    : If set to "yes", using the bindings file
+#	#           /var/lib/multipath/bindings to assign a persistent and
+#	#           unique alias to the multipath, in the form of mpath<n>.
+#	#           If set to "no" use the WWID as the alias. In either case
+#	#           this be will be overriden by any specific aliases in this
+#	#           file.
+#	# values  : yes|no
+#	# default : no
+#	user_friendly_names no
+#
 #}
 #	
 ##
@@ -107,7 +133,7 @@
 ## default : cciss, fd, hd, md, dm, sr, scd, st, ram, raw, loop
 ##
 #blacklist {
-#        wwid 26353900f02796769
+#       wwid 26353900f02796769
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
 #	devnode "^hd[a-z][[0-9]*]"
 #	devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
@@ -176,6 +202,17 @@
 #		# default : immediate
 #		#
 #		failback		manual
+#
+#		#
+#		# name    : no_path_retry
+#		# scope   : multipath & multipathd
+#		# desc    : tell the number of retries until disable queueing, or
+#		#           "fail" means immediate failure (no queueing),
+#		#           "queue" means never stop queueing
+#		# values  : queue|fail|n (>0)
+#		# default : (null)
+#		#
+#		#no_path_retry  queue
 #	}
 #	multipath {
 #		wwid	1DEC_____321816758474

Modified: multipath-tools/upstream/current/multipath.conf.synthetic
==============================================================================
--- multipath-tools/upstream/current/multipath.conf.synthetic	(original)
+++ multipath-tools/upstream/current/multipath.conf.synthetic	Wed Feb  1 23:48:32 2006
@@ -3,20 +3,21 @@
 ## Uncomment the lines relevent to your environment
 ##
 #defaults {
-#	multipath_tool	"/sbin/multipath -v0"
-#	udev_dir	/dev
-#	polling_interval 10
-#	default_selector	"round-robin 0"
-#	default_path_grouping_policy	multibus
-#	default_getuid_callout	"/sbin/scsi_id -g -u -s /block/%n"
-#	default_prio_callout	"/bin/true"
-#	default_features	"0"
+#	udev_dir		/dev
+#	polling_interval 	10
+#	selector		"round-robin 0"
+#	path_grouping_policy	multibus
+#	getuid_callout		"/sbin/scsi_id -g -u -s /block/%n"
+#	prio_callout		/bin/true
+#	path_checker		readsector0
 #	rr_min_io		100
 #	rr_weight		priorities
 #	failback		immediate
+#	no_path_retry		fail
+#	user_friendly_name	no
 #}
 #devnode_blacklist {
-#        wwid 26353900f02796769
+#       wwid 26353900f02796769
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
 #	devnode "^hd[a-z][[0-9]*]"
 #	devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
@@ -30,10 +31,11 @@
 #		path_selector		"round-robin 0"
 #		failback		manual
 #		rr_weight		priorities
+#		no_path_retry		5
 #	}
 #	multipath {
-#		wwid	1DEC_____321816758474
-#		alias	red
+#		wwid			1DEC_____321816758474
+#		alias			red
 #	}
 #}
 #devices {
@@ -44,10 +46,10 @@
 #		getuid_callout          "/sbin/scsi_id -g -u -s /block/%n"
 #		path_checker		readsector0
 #		path_selector		"round-robin 0"
-#		features		"1 queue_if_no_path"
 #		hardware_handler	"0"
 #		failback		15
 #		rr_weight		priorities
+#		no_path_retry		queue
 #	}
 #	device {
 #		vendor			"COMPAQ  "

Modified: multipath-tools/upstream/current/multipath/Makefile
==============================================================================
--- multipath-tools/upstream/current/multipath/Makefile	(original)
+++ multipath-tools/upstream/current/multipath/Makefile	Wed Feb  1 23:48:32 2006
@@ -13,7 +13,7 @@
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS += $(libdm) $(libsysfs)
 else
-	LDFLAGS += -ldevmapper -lsysfs
+	LDFLAGS += -ldevmapper -lsysfs -lm
 endif
 
 EXEC = multipath
@@ -26,12 +26,10 @@
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 $(CHECKERSLIB)-$(BUILD).a:
@@ -42,16 +40,13 @@
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
-	install -d $(DESTDIR)/etc/dev.d/block/
-	install -m 755 multipath.dev $(DESTDIR)/etc/dev.d/block/
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
 	install -d $(DESTDIR)/etc/udev/rules.d
-	install -m 755 multipath.rules $(DESTDIR)/etc/udev/rules.d/
+	install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 
 uninstall:
-	rm $(DESTDIR)/etc/dev.d/block/multipath.dev
 	rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
 	rm $(DESTDIR)$(bindir)/$(EXEC)
 	rm $(DESTDIR)$(mandir)/$(EXEC).8.gz

Modified: multipath-tools/upstream/current/multipath/main.c
==============================================================================
--- multipath-tools/upstream/current/multipath/main.c	(original)
+++ multipath-tools/upstream/current/multipath/main.c	Wed Feb  1 23:48:32 2006
@@ -20,6 +20,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <sys/file.h>
+#include <errno.h>
 
 #include <parser.h>
 #include <vector.h>
@@ -42,6 +44,7 @@
 #include <switchgroup.h>
 #include <sysfs/libsysfs.h>
 #include <print.h>
+#include <alias.h>
 
 #include "main.h"
 #include "pgpolicies.h"
@@ -61,7 +64,6 @@
 		return NULL;
 
 	if (conf->dev_type == DEV_DEVNODE) {
-		condlog(3, "limited scope = %s", conf->dev);
 		basename(conf->dev, buff);
 		pp = find_path_by_dev(pathvec, buff);
 		
@@ -81,32 +83,24 @@
 				return NULL;
 			}
 		}
-
-		refwwid = MALLOC(WWID_SIZE);
-
-		if (!refwwid)
-			return NULL;
-
-		memcpy(refwwid, pp->wwid, WWID_SIZE);
-		return refwwid;
+		refwwid = pp->wwid;
+		goto out;
 	}
 
 	if (conf->dev_type == DEV_DEVT) {
-		condlog(3, "limited scope = %s", conf->dev);
 		pp = find_path_by_devt(pathvec, conf->dev);
 		
 		if (!pp) {
+			if (devt2devname(buff, conf->dev))
+				return NULL;
+
 			pp = alloc_path();
 
 			if (!pp)
 				return NULL;
 
-			devt2devname(conf->dev, buff);
+			strncpy(pp->dev, buff, FILE_NAME_SIZE);
 
-			if(safe_sprintf(pp->dev, "%s", buff)) {
-				fprintf(stderr, "pp->dev too small\n");
-				exit(1);
-			}
 			if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
 				return NULL;
 			
@@ -115,46 +109,44 @@
 				return NULL;
 			}
 		}
-
-		refwwid = MALLOC(WWID_SIZE);
-
-		if (!refwwid)
-			return NULL;
-		
-		memcpy(refwwid, pp->wwid, WWID_SIZE);
-		return refwwid;
+		refwwid = pp->wwid;
+		goto out;
 	}
 	if (conf->dev_type == DEV_DEVMAP) {
-		condlog(3, "limited scope = %s", conf->dev);
 		/*
-		 * may be an alias
+		 * may be a binding
 		 */
-		refwwid = get_mpe_wwid(conf->dev);
+		refwwid = get_user_friendly_wwid(conf->dev,
+						 conf->bindings_file);
 
 		if (refwwid)
 			return refwwid;
-		
+
 		/*
-		 * or directly a wwid
+		 * or may be an alias
 		 */
-		refwwid = MALLOC(WWID_SIZE);
+		refwwid = get_mpe_wwid(conf->dev);
 
+		/*
+		 * or directly a wwid
+		 */
 		if (!refwwid)
-			return NULL;
-
-		strncpy(refwwid, conf->dev, WWID_SIZE);
-		return refwwid;
+			refwwid = conf->dev;
 	}
+out:
+	if (refwwid && strlen(refwwid))
+		return STRDUP(refwwid);
+
 	return NULL;
 }
 
 static void
 print_path (struct path * pp, char * style)
 {
-	char buff[MAX_LINE_LEN];
+	char line[MAX_LINE_LEN];
 
-	snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
-	printf("%s", buff);
+	snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl);
+	printf("%s", line);
 }
 
 static void
@@ -167,10 +159,24 @@
 }
 
 static void
-print_all_paths (vector pathvec)
+print_all_paths (vector pathvec, int banner)
 {
 	int i;
 	struct path * pp;
+	char line[MAX_LINE_LEN];
+
+	if (!VECTOR_SIZE(pathvec)) {
+		if (banner)
+			fprintf(stdout, "===== no paths =====\n");
+		return;
+	}
+	
+	if (banner)
+		fprintf(stdout, "===== paths list =====\n");
+
+	get_path_layout(&pl, pathvec);
+	snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl);
+	fprintf(stdout, "%s", line);
 
 	vector_foreach_slot (pathvec, pp, i)
 		print_path(pp, PRINT_PATH_LONG);
@@ -183,7 +189,7 @@
 	struct path * pp = NULL;
 	struct pathgroup * pgp = NULL;
 
-	if (mpp->action == ACT_NOTHING || conf->verbosity == 0)
+	if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
 		return;
 
 	if (conf->verbosity > 1) {
@@ -283,7 +289,7 @@
 		return 0;
 
 	vector_foreach_slot (pathvec, pp, i) {
-		if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
+		if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
 			condlog(3, "skip path %s : out of scope", pp->dev);
 			free_path(pp);
 			vector_del_slot(pathvec, i);
@@ -311,7 +317,7 @@
 	
 	shift = snprintf(p, freechar, "%s %s %i %i",
 			 mp->features, mp->hwhandler,
-			 VECTOR_SIZE(mp->pg), mp->nextpg);
+			 VECTOR_SIZE(mp->pg), mp->bestpg);
 
 	if (shift >= freechar) {
 		fprintf(stderr, "mp->params too small\n");
@@ -362,9 +368,6 @@
 static int
 setup_map (struct multipath * mpp)
 {
-	struct path * pp;
-	int i;
-
 	/*
 	 * don't bother if devmap size is unknown
 	 */
@@ -374,17 +377,6 @@
 	}
 
 	/*
-	 * don't bother if a constituant path is claimed
-	 * (not by the device mapper driver)
-	 */
-	vector_foreach_slot (mpp->paths, pp, i) {
-		if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
-			condlog(3, "%s claimed", pp->dev);
-			return 1;
-		}
-	}
-
-	/*
 	 * properties selectors
 	 */
 	select_pgpolicy(mpp);
@@ -392,6 +384,7 @@
 	select_features(mpp);
 	select_hwhandler(mpp);
 	select_rr_weight(mpp);
+	select_no_path_retry(mpp);
 
 	/*
 	 * apply selected grouping policy to valid paths
@@ -425,7 +418,7 @@
 	 * ponders each path group and determine highest prio pg
 	 * to switch over (default to first)
 	 */
-	select_path_group(mpp);
+	mpp->bestpg = select_path_group(mpp);
 
 	/*
 	 * transform the mp->pg vector of vectors of paths
@@ -492,7 +485,7 @@
 {
 	struct multipath * cmpp;
 
-	cmpp = find_mp(curmp, mpp->alias);
+	cmpp = find_mp_by_alias(curmp, mpp->alias);
 
 	if (!cmpp) {
 		cmpp = find_mp_by_wwid(curmp, mpp->wwid);
@@ -503,52 +496,65 @@
 			dm_flush_map(cmpp->alias, DEFAULT_TARGET);
 		}
 		mpp->action = ACT_CREATE;
+		condlog(3, "set ACT_CREATE: map does not exists");
 		return;
 	}
+
+	if (!find_mp_by_wwid(curmp, mpp->wwid)) {
+		condlog(2, "remove: %s (wwid changed)", cmpp->alias);
+		dm_flush_map(mpp->alias, NULL);
+		strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
+		drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
+		mpp->action = ACT_CREATE;
+		condlog(3, "set ACT_CREATE: map wwid change");
+		return;
+	}
+		
 	if (pathcount(mpp, PATH_UP) == 0) {
-		condlog(3, "no good path");
 		mpp->action = ACT_NOTHING;
+		condlog(3, "set ACT_NOTHING: no usable path");
 		return;
 	}
 	if (cmpp->size != mpp->size) {
-		condlog(3, "size different than current");
 		mpp->action = ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: size change");
 		return;
 	}
-	if (strncmp(cmpp->features, mpp->features,
-		    strlen(mpp->features))) {
-		condlog(3, "features different than current");
+	if (!mpp->no_path_retry && /* let features be handled by the daemon */
+	    strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
 		mpp->action =  ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: features change");
 		return;
 	}
 	if (strncmp(cmpp->hwhandler, mpp->hwhandler,
 		    strlen(mpp->hwhandler))) {
-		condlog(3, "hwhandler different than current");
 		mpp->action = ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: hwhandler change");
 		return;
 	}
 	if (strncmp(cmpp->selector, mpp->selector,
 		    strlen(mpp->selector))) {
-		condlog(3, "selector different than current");
 		mpp->action = ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: selector change");
 		return;
 	}
 	if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
-		condlog(3, "different number of PG");
 		mpp->action = ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: number of path group change");
 		return;
 	}
 	if (pgcmp(mpp, cmpp)) {
-		condlog(3, "different path group topology");
 		mpp->action = ACT_RELOAD;
+		condlog(3, "set ACT_RELOAD: path group topology change");
 		return;
 	}
-	if (cmpp->nextpg != mpp->nextpg) {
-		condlog(3, "nextpg different than current");
+	if (cmpp->nextpg != mpp->bestpg) {
 		mpp->action = ACT_SWITCHPG;
+		condlog(3, "set ACT_SWITCHPG: next path group change");
 		return;
 	}
 	mpp->action = ACT_NOTHING;
+	condlog(3, "set ACT_NOTHING: map unchanged");
 	return;
 }
 
@@ -559,7 +565,13 @@
 	struct pathgroup * pgp;
 	struct path * pp;
 
+	if (!mpp->pg)
+		return 0;
+
 	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+
 		vector_foreach_slot (pgp->paths, pp, j) {
 			if (pp->state != PATH_UP &&
 			    (pgp->status == PGSTATE_DISABLED ||
@@ -567,7 +579,7 @@
 				continue;
 
 			if (pp->dmstate == PSTATE_FAILED) {
-				if (dm_reinstate(mpp->alias, pp->dev_t))
+				if (dm_reinstate_path(mpp->alias, pp->dev_t))
 					condlog(0, "error reinstating %s",
 						pp->dev);
 			}
@@ -576,75 +588,139 @@
 	return 0;
 }
 
+int lock_multipath (struct multipath * mpp, int lock)
+{
+	struct pathgroup * pgp;
+	struct path * pp;
+	int i, j;
+
+	if (!mpp || !mpp->pg)
+		return 0;
+	
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+		vector_foreach_slot(pgp->paths, pp, j) {
+			if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
+			    errno == EWOULDBLOCK)
+				return 1;
+			else if (!lock)
+				flock(pp->fd, LOCK_UN);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Return value:
+ *  -1: Retry
+ *   0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
+ *   1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
+ *   2: Map is already existing.
+ */
 static int
 domap (struct multipath * mpp)
 {
-	int op = ACT_NOTHING;
 	int r = 0;
 
-	print_mp(mpp);
-
 	/*
 	 * last chance to quit before touching the devmaps
 	 */
-	if (conf->dry_run)
+	if (conf->dry_run) {
+		print_mp(mpp);
 		return 0;
+	}
 
 	switch (mpp->action) {
 	case ACT_NOTHING:
-		return 0;
+		return 2;
 
 	case ACT_SWITCHPG:
-		dm_switchgroup(mpp->alias, mpp->nextpg);
+		dm_switchgroup(mpp->alias, mpp->bestpg);
 		/*
 		 * we may have avoided reinstating paths because there where in
 		 * active or disabled PG. Now that the topology has changed,
 		 * retry.
 		 */
 		reinstate_paths(mpp);
-		return 0;
+		return 2;
 
 	case ACT_CREATE:
-		op = DM_DEVICE_CREATE;
+		if (lock_multipath(mpp, 1)) {
+			condlog(3, "%s: in use", mpp->alias);
+			return -1;
+		}
+		dm_shut_log();
+
+		if (dm_map_present(mpp->alias))
+			break;
+
+		r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
+			      mpp->params, mpp->size, mpp->wwid);
+
+		/*
+		 * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
+		 * DM_TABLE_LOAD. Failing the second part leaves an
+		 * empty map. Clean it up.
+		 */
+		if (!r && dm_map_present(mpp->alias)) {
+			condlog(3, "%s: failed to load map "
+				   "(a path might be in use)",
+				   mpp->alias);
+			dm_flush_map(mpp->alias, NULL);
+		}
+
+		lock_multipath(mpp, 0);
+		dm_restore_log();
 		break;
 
 	case ACT_RELOAD:
-		op = DM_DEVICE_RELOAD;
+		r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
+			      mpp->params, mpp->size, NULL) &&
+		     dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
 		break;
 
 	default:
 		break;
 	}
 
-		
-	/*
-	 * device mapper creation or updating
-	 * here we know we'll have garbage on stderr from
-	 * libdevmapper. so shut it down temporarily.
-	 */
-	dm_log_init_verbose(0);
+	if (r) {
+		/*
+		 * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
+		 */
+		dm_switchgroup(mpp->alias, mpp->bestpg);
+		print_mp(mpp);
+	}
 
-	r = dm_addmap(op, mpp->alias, DEFAULT_TARGET, mpp->params, mpp->size);
+	return r;
+}
 
-	if (r == 0)
-		dm_simplecmd(DM_DEVICE_REMOVE, mpp->alias);
-	else if (op == DM_DEVICE_RELOAD)
-		dm_simplecmd(DM_DEVICE_RESUME, mpp->alias);
+static int
+deadmap (struct multipath * mpp)
+{
+	int i, j;
+	struct pathgroup * pgp;
+	struct path * pp;
 
-	/*
-	 * PG order is random, so we need to set the primary one
-	 * upon create or reload
-	 */
-	dm_switchgroup(mpp->alias, mpp->nextpg);
+	if (!mpp->pg)
+		return 1;
 
-	dm_log_init_verbose(1);
+	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
 
-	return r;
+		vector_foreach_slot (pgp->paths, pp, j)
+			if (strlen(pp->dev))
+				return 0; /* alive */
+	}
+	
+	return 1; /* dead */
 }
 
 static int
 coalesce_paths (vector curmp, vector pathvec)
 {
+	int r = 1;
 	int k, i;
 	char empty_buff[WWID_SIZE];
 	struct multipath * mpp;
@@ -675,10 +751,10 @@
 
 		mpp->mpe = find_mpe(pp1->wwid);
 		mpp->hwe = pp1->hwe;
+		strcpy(mpp->wwid, pp1->wwid);
 		select_alias(mpp);
 
 		pp1->mpp = mpp;
-		strcpy(mpp->wwid, pp1->wwid);
 		mpp->size = pp1->size;
 		mpp->paths = vector_alloc();
 
@@ -713,20 +789,42 @@
 			if (store_path(mpp->paths, pp2))
 				return 1;
 		}
-		if (setup_map(mpp)) {
-			free_multipath(mpp, KEEP_PATHS);
-			continue;
-		}
-		condlog(3, "action preset to %i", mpp->action);
+		if (setup_map(mpp))
+			goto next;
 
 		if (mpp->action == ACT_UNDEF)
 			select_action(mpp, curmp);
 
-		condlog(3, "action set to %i", mpp->action);
+		r = domap(mpp);
 
-		domap(mpp);
+		if (r < 0)
+			return r;
+
+		if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+				dm_queue_if_no_path(mpp->alias, 0);
+			else
+				dm_queue_if_no_path(mpp->alias, 1);
+		}
+
+next:
+		drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
 		free_multipath(mpp, KEEP_PATHS);
 	}
+	/*
+	 * Flush maps with only dead paths (ie not in sysfs)
+	 * Keep maps with only failed paths
+	 */
+	vector_foreach_slot (curmp, mpp, i) {
+		if (!deadmap(mpp))
+			continue;
+
+		if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
+			condlog(2, "remove: %s (dead) failed!",
+				mpp->alias);
+		else
+			condlog(2, "remove: %s (dead)", mpp->alias);
+	}
 	return 0;
 }
 
@@ -740,15 +838,16 @@
 		"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
 		"\t\t\t[device]\n" \
 		"\n" \
-		"\t-v level\tverbosty level\n" \
+		"\t-v level\tverbosity level\n" \
 		"\t   0\t\t\tno output\n" \
 		"\t   1\t\t\tprint created devmap names only\n" \
 		"\t   2\t\t\tdefault verbosity\n" \
 		"\t   3\t\t\tprint debug information\n" \
+		"\t-b file\t\tbindings file location\n" \
 		"\t-d\t\tdry run, do not create or update devmaps\n" \
 		"\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
 		"\t-ll\t\tshow multipath topology (maximum info)\n" \
-		"\t-F\t\tflush a multipath device map\n" \
+		"\t-f\t\tflush a multipath device map\n" \
 		"\t-F\t\tflush all multipath device maps\n" \
 		"\t-p policy\tforce all maps to specified policy :\n" \
 		"\t   failover\t\t1 path per priority group\n" \
@@ -772,10 +871,22 @@
 	struct pathgroup * pgp;
 	struct path * pp;
 
+	if (!mpp->pg)
+		return 0;
+
 	vector_foreach_slot (mpp->pg, pgp, i) {
+		if (!pgp->paths)
+			continue;
+
 		vector_foreach_slot (pgp->paths, pp, j) {
 			if (!strlen(pp->dev)) {
-				devt2devname(pp->dev, pp->dev_t);
+				if (devt2devname(pp->dev, pp->dev_t)) {
+					/*
+					 * path is not in sysfs anymore
+					 */
+					pp->state = PATH_DOWN;
+					continue;
+				}
 				pathinfo(pp, conf->hwtable,
 					 DI_SYSFS | DI_CHECKER | \
 					 DI_SERIAL | DI_PRIO);
@@ -796,29 +907,30 @@
 {
 	int i;
 	struct multipath * mpp;
-	char * wwid;
 
 	if (dm_get_maps(curmp, DEFAULT_TARGET))
 		return 1;
 
 	vector_foreach_slot (curmp, mpp, i) {
-		wwid = get_mpe_wwid(mpp->alias);
-
-		if (wwid) {
-			/* out of specified scope */
-			if (refwwid && strncmp(wwid, refwwid, WWID_SIZE))
-				continue;
-			wwid = NULL;
+		/*
+		 * discard out of scope maps
+		 */
+		if (mpp->wwid && refwwid &&
+		    strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
+			condlog(3, "skip map %s: out of scope", mpp->alias);
+			free_multipath(mpp, KEEP_PATHS);
+			vector_del_slot(curmp, i);
+			i--;
+			continue;
 		}
 
 		condlog(3, "params = %s", mpp->params);
 		condlog(3, "status = %s", mpp->status);
 
-		/* will set mpp->wwid */
 		disassemble_map(pathvec, mpp->params, mpp);
 
 		/*
-		 * disassemble_map may have added new paths to pathvec.
+		 * disassemble_map() can add new paths to pathvec.
 		 * If not in "fast list mode", we need to fetch information
 		 * about them
 		 */
@@ -826,7 +938,7 @@
 			update_paths(mpp);
 
 		if (conf->list > 1)
-			select_path_group(mpp);
+			mpp->bestpg = select_path_group(mpp);
 
 		disassemble_status(mpp->status, mpp);
 
@@ -839,17 +951,122 @@
 	return 0;
 }
 
-int
-main (int argc, char *argv[])
+
+/*
+ * Return value:
+ *  -1: Retry
+ *   0: Success
+ *   1: Failure
+ */
+static int
+configure (void)
 {
 	vector curmp = NULL;
 	vector pathvec = NULL;
-	int i;
+	int r = 1;
 	int di_flag = 0;
+	char * refwwid = NULL;
+	char * dev = NULL;
+
+	/*
+	 * allocate core vectors to store paths and multipaths
+	 */
+	curmp = vector_alloc();
+	pathvec = vector_alloc();
+
+	if (!curmp || !pathvec) {
+		condlog(0, "can not allocate memory");
+		goto out;
+	}
+
+	/*
+	 * if we have a blacklisted device parameter, exit early
+	 */
+	if (conf->dev) {
+		if (!strncmp(conf->dev, "/dev/", 5) &&
+		    strlen(conf->dev) > 5)
+			dev = conf->dev + 5;
+		else
+			dev = conf->dev;
+	}
+	
+	if (dev && blacklist(conf->blist, dev))
+		goto out;
+	
+	condlog(3, "load path identifiers cache");
+	cache_load(pathvec);
+
+	if (conf->verbosity > 2)
+		print_all_paths(pathvec, 1);
+
+	/*
+	 * scope limiting must be translated into a wwid
+	 * failing the translation is fatal (by policy)
+	 */
+	if (conf->dev) {
+		refwwid = get_refwwid(pathvec);
+
+		if (!refwwid) {
+			condlog(3, "scope is nul");
+			goto out;
+		}
+		condlog(3, "scope limited to %s", refwwid);
+	}
+
+	/*
+	 * get a path list
+	 */
+	if (conf->dev)
+		di_flag = DI_WWID;
+
+	if (conf->list > 1)
+		/* extended path info '-ll' */
+		di_flag |= DI_SYSFS | DI_CHECKER;
+	else if (conf->list)
+		/* minimum path info '-l' */
+		di_flag |= DI_SYSFS;
+	else
+		/* maximum info */
+		di_flag = DI_ALL;
+
+	if (path_discovery(pathvec, conf, di_flag))
+		goto out;
+
+	if (conf->verbosity > 2)
+		print_all_paths(pathvec, 1);
+
+	get_path_layout(&pl, pathvec);
+
+	if (get_dm_mpvec(curmp, pathvec, refwwid))
+		goto out;
+
+	filter_pathvec(pathvec, refwwid);
+
+	if (conf->list)
+		goto out;
+
+	/*
+	 * core logic entry point
+	 */
+	r = coalesce_paths(curmp, pathvec);
+
+out:
+	if (refwwid)
+		FREE(refwwid);
+
+	free_multipathvec(curmp, KEEP_PATHS);
+	free_pathvec(pathvec, FREE_PATHS);
+
+	return r;
+}
+
+int
+main (int argc, char *argv[])
+{
 	int arg;
 	extern char *optarg;
 	extern int optind;
-	char * refwwid = NULL;
+	int i, r;
 
 	if (getuid() != 0) {
 		fprintf(stderr, "need to be root\n");
@@ -866,7 +1083,7 @@
 	if (load_config(DEFAULT_CONFIGFILE))
 		exit(1);
 
-	while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
+	while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
 		switch(arg) {
 		case 1: printf("optarg : %s\n",optarg);
 			break;
@@ -877,14 +1094,17 @@
 
 			conf->verbosity = atoi(optarg);
 			break;
+		case 'b':
+			conf->bindings_file = optarg;
+			break;
 		case 'd':
 			conf->dry_run = 1;
 			break;
 		case 'f':
-			conf->remove = 1;
+			conf->remove = FLUSH_ONE;
 			break;
 		case 'F':
-			conf->remove = 2;
+			conf->remove = FLUSH_ALL;
 			break;
 		case 'l':
 			conf->list = 1;
@@ -945,83 +1165,15 @@
 		dm_flush_maps(DEFAULT_TARGET);
 		goto out;
 	}
-
-	/*
-	 * allocate core vectors to store paths and multipaths
-	 */
-	curmp = vector_alloc();
-	pathvec = vector_alloc();
-
-	if (!curmp || !pathvec) {
-		condlog(0, "can not allocate memory");
-		goto out;
-	}
-
-	/*
-	 * if we have a blacklisted device parameter, exit early
-	 */
-	if (conf->dev && blacklist(conf->blist, conf->dev))
-		goto out;
+	while ((r = configure()) < 0)
+		condlog(3, "restart multipath configuration process");
 	
-	condlog(3, "load path identifiers cache");
-	cache_load(pathvec);
-
-	if (conf->verbosity > 2) {
-		fprintf(stdout, "#\n# all paths in cache :\n#\n");
-		print_all_paths(pathvec);
-	}
-
-	/*
-	 * get a path list
-	 */
-	if (conf->dev)
-		di_flag = DI_WWID;
-
-	if (conf->list > 1)
-		/* extended path info '-ll' */
-		di_flag |= DI_SYSFS | DI_CHECKER;
-	else if (conf->list)
-		/* minimum path info '-l' */
-		di_flag |= DI_SYSFS;
-	else
-		/* maximum info */
-		di_flag = DI_ALL;
-
-	if (path_discovery(pathvec, conf, di_flag) || VECTOR_SIZE(pathvec) == 0)
-		goto out;
-
-	if (conf->verbosity > 2) {
-		fprintf(stdout, "#\n# all paths :\n#\n");
-		print_all_paths(pathvec);
-	}
-
-	refwwid = get_refwwid(pathvec);
-	get_path_layout(&pl, pathvec);
-
-	if (get_dm_mpvec(curmp, pathvec, refwwid))
-		goto out;
-
-	filter_pathvec(pathvec, refwwid);
-
-	if (conf->list)
-		goto out;
-
-	/*
-	 * core logic entry point
-	 */
-	coalesce_paths(curmp, pathvec);
-
 out:
-	if (refwwid)
-		FREE(refwwid);
-
-	free_multipathvec(curmp, KEEP_PATHS);
-	free_pathvec(pathvec, FREE_PATHS);
 	free_config(conf);
 	dm_lib_release();
 	dm_lib_exit();
 #ifdef _DEBUG_
 	dbg_free_final(NULL);
 #endif
-	exit(0);
+	return r;
 }

Modified: multipath-tools/upstream/current/multipath/main.h
==============================================================================
--- multipath-tools/upstream/current/multipath/main.h	(original)
+++ multipath-tools/upstream/current/multipath/main.h	Wed Feb  1 23:48:32 2006
@@ -43,8 +43,8 @@
  */
 #define PROG    "multipath"
 
-#define VERSION_CODE 0x000405
-#define DATE_CODE    0x100605
+#define VERSION_CODE 0x000406
+#define DATE_CODE    0x0b0a05
 
 #define MULTIPATH_VERSION(version)	\
 	(version >> 16) & 0xFF,		\

Modified: multipath-tools/upstream/current/multipath/multipath.rules
==============================================================================
--- multipath-tools/upstream/current/multipath/multipath.rules	(original)
+++ multipath-tools/upstream/current/multipath/multipath.rules	Wed Feb  1 23:48:32 2006
@@ -1,3 +1,22 @@
-# multipath wants the devmaps presented as meaninglful device names
-# so name them after their devmap name
-KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", NAME="%k", SYMLINK="%c"
+#
+# multipath and multipath partitions nodes are created in /dev/mapper/
+# this file should be installed in /etc/udev/rules.d
+#
+# !! udev must not discard DM events !!
+# !! check the other installed rules !!
+#
+
+# lookup the devmap name
+#ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
+#	PROGRAM="/sbin/devmap_name %M %m"
+ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
+	PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info"
+
+# take care of devmap partitioning
+ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
+	RUN+="/sbin/kpartx -a /dev/mapper/%c"
+
+# insert new paths in multipath topology
+ACTION=="add", SUBSYSTEM=="block", KERNEL!="dm-*", \
+	RUN+="/sbin/multipath -v0 %r/%k"
+

Modified: multipath-tools/upstream/current/multipathd/Makefile
==============================================================================
--- multipath-tools/upstream/current/multipathd/Makefile	(original)
+++ multipath-tools/upstream/current/multipathd/Makefile	Wed Feb  1 23:48:32 2006
@@ -15,7 +15,7 @@
 #
 CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
 	 -DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lcurses
+LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses -lm
 
 #
 # debuging stuff
@@ -27,7 +27,7 @@
 #
 # object files
 #
-OBJS = main.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
        $(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
 
 
@@ -43,7 +43,6 @@
 
 $(EXEC): clean $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
 $(CHECKERSLIB)-glibc.a:
@@ -54,7 +53,7 @@
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
 	install -d $(DESTDIR)$(rcdir)
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
@@ -65,6 +64,6 @@
 	rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
 
 clean:
-	$(MAKE) -C $(multipathdir) prepare
+	$(MAKE) -C $(multipathdir) prepare DAEMON=1
 	rm -f core *.o $(EXEC) *.gz
 

Modified: multipath-tools/upstream/current/multipathd/cli.c
==============================================================================
--- multipath-tools/upstream/current/multipathd/cli.c	(original)
+++ multipath-tools/upstream/current/multipathd/cli.c	Wed Feb  1 23:48:32 2006
@@ -121,6 +121,10 @@
 	r += add_key(keys, "del", DEL, 0);
 	r += add_key(keys, "switch", SWITCH, 0);
 	r += add_key(keys, "switchgroup", SWITCH, 0);
+	r += add_key(keys, "suspend", SUSPEND, 0);
+	r += add_key(keys, "resume", RESUME, 0);
+	r += add_key(keys, "reinstate", REINSTATE, 0);
+	r += add_key(keys, "fail", FAIL, 0);
 	r += add_key(keys, "paths", PATHS, 0);
 	r += add_key(keys, "maps", MAPS, 0);
 	r += add_key(keys, "path", PATH, 1);
@@ -282,7 +286,6 @@
 		return NULL;
 
 	p = reply;
-	p += sprintf(p, "\n");
 
 	vector_foreach_slot (handlers, h, i) {
 		fp = h->fingerprint;
@@ -311,7 +314,7 @@
 
 	if (!cmdvec) {
 		*reply = genhelp_handler();
-		*len = strlen(*reply);
+		*len = strlen(*reply) + 1;
 		return 0;
 	}
 

Modified: multipath-tools/upstream/current/multipathd/cli.h
==============================================================================
--- multipath-tools/upstream/current/multipathd/cli.h	(original)
+++ multipath-tools/upstream/current/multipathd/cli.h	Wed Feb  1 23:48:32 2006
@@ -1,15 +1,38 @@
-#define LIST		1
-#define ADD		(1 << 1)
-#define DEL		(1 << 2)
-#define SWITCH		(1 << 3)
-#define PATHS		(1 << 4)
-#define MAPS		(1 << 5)
-#define PATH		(1 << 6)
-#define MAP		(1 << 7)
-#define GROUP		(1 << 8)
-#define DUMP		(1 << 9)
-#define PATHVEC		(1 << 10)
-#define RECONFIGURE	(1 << 11)
+enum {
+	__LIST,
+	__ADD,
+	__DEL,
+	__SWITCH,
+	__SUSPEND,
+	__RESUME,
+	__REINSTATE,
+	__FAIL,
+	__PATHS,
+	__MAPS,
+	__PATH,
+	__MAP,
+	__GROUP,
+	__DUMP,
+	__PATHVEC,
+	__RECONFIGURE
+};
+
+#define LIST		(1 << __LIST)
+#define ADD		(1 << __ADD)
+#define DEL		(1 << __DEL)
+#define SWITCH		(1 << __SWITCH)
+#define SUSPEND		(1 << __SUSPEND)
+#define RESUME		(1 << __RESUME)
+#define REINSTATE	(1 << __REINSTATE)
+#define FAIL		(1 << __FAIL)
+#define PATHS		(1 << __PATHS)
+#define MAPS		(1 << __MAPS)
+#define PATH		(1 << __PATH)
+#define MAP		(1 << __MAP)
+#define GROUP		(1 << __GROUP)
+#define DUMP		(1 << __DUMP)
+#define PATHVEC		(1 << __PATHVEC)
+#define RECONFIGURE	(1 << __RECONFIGURE)
 
 #define MAX_REPLY_LEN 1000
 

Modified: multipath-tools/upstream/current/multipathd/cli_handlers.c
==============================================================================
--- multipath-tools/upstream/current/multipathd/cli_handlers.c	(original)
+++ multipath-tools/upstream/current/multipathd/cli_handlers.c	Wed Feb  1 23:48:32 2006
@@ -1,6 +1,7 @@
 #include <memory.h>
 #include <vector.h>
 #include <structs.h>
+#include <libdevmapper.h>
 #include <devmapper.h>
 #include <config.h>
 #include <blacklist.h>
@@ -11,23 +12,23 @@
 int
 cli_list_paths (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 
-	return show_paths(reply, len, allpaths);
+	return show_paths(reply, len, vecs);
 }
 
 int
 cli_list_maps (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 
-	return show_maps(reply, len, allpaths);
+	return show_maps(reply, len, vecs);
 }
 
 int
 cli_add_path (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, PATH);
 
 	if (blacklist(conf->blist, param)) {
@@ -35,34 +36,34 @@
 		*len = strlen(*reply) + 1;
 		return 0;
 	}
-	return uev_add_path(param, allpaths);
+	return uev_add_path(param, vecs);
 }
 
 int
 cli_del_path (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, PATH);
 
-	return uev_remove_path(param, allpaths);
+	return uev_remove_path(param, vecs);
 }
 
 int
 cli_add_map (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, MAP);
 
-	return uev_add_map(param, allpaths);
+	return uev_add_map(param, vecs);
 }
 
 int
 cli_del_map (void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, MAP);
 
-	return uev_remove_map(param, allpaths);
+	return uev_remove_map(param, vecs);
 }
 
 int
@@ -77,15 +78,89 @@
 int
 cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 			
-	return dump_pathvec(reply, len, allpaths);
+	return dump_pathvec(reply, len, vecs);
 }
 
 int
 cli_reconfigure(void * v, char ** reply, int * len, void * data)
 {
-	struct paths * allpaths = (struct paths *)data;
+	struct vectors * vecs = (struct vectors *)data;
 			
-	return reconfigure(allpaths);
+	return reconfigure(vecs);
+}
+
+int
+cli_suspend(void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * param = get_keyparam(v, MAP);
+	int r = dm_simplecmd(DM_DEVICE_SUSPEND, param);
+
+	if (!r) /* error */
+		return 1;
+	
+	struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+
+	if (!mpp)
+		return 1;
+	
+	dm_get_info(param, &mpp->dmi);
+	return 0;
+}
+
+int
+cli_resume(void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * param = get_keyparam(v, MAP);
+	int r = dm_simplecmd(DM_DEVICE_RESUME, param);
+
+	if (!r) /* error */
+		return 1;
+	
+	struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+
+	if (!mpp)
+		return 1;
+	
+	dm_get_info(param, &mpp->dmi);
+	return 0;
+}
+
+int
+cli_reinstate(void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * param = get_keyparam(v, PATH);
+	struct path * pp;
+	
+	pp = find_path_by_dev(vecs->pathvec, param);
+
+	if (!pp)
+		 pp = find_path_by_devt(vecs->pathvec, param);
+
+	if (!pp || !pp->mpp || !pp->mpp->alias)
+		return 1;
+
+	return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
+}
+
+int
+cli_fail(void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * param = get_keyparam(v, PATH);
+	struct path * pp;
+	
+	pp = find_path_by_dev(vecs->pathvec, param);
+
+	if (!pp)
+		 pp = find_path_by_devt(vecs->pathvec, param);
+
+	if (!pp || !pp->mpp || !pp->mpp->alias)
+		return 1;
+
+	return dm_fail_path(pp->mpp->alias, pp->dev_t);
 }

Modified: multipath-tools/upstream/current/multipathd/cli_handlers.h
==============================================================================
--- multipath-tools/upstream/current/multipathd/cli_handlers.h	(original)
+++ multipath-tools/upstream/current/multipathd/cli_handlers.h	Wed Feb  1 23:48:32 2006
@@ -7,3 +7,7 @@
 int cli_switch_group(void * v, char ** reply, int * len, void * data);
 int cli_dump_pathvec(void * v, char ** reply, int * len, void * data);
 int cli_reconfigure(void * v, char ** reply, int * len, void * data);
+int cli_suspend(void * v, char ** reply, int * len, void * data);
+int cli_resume(void * v, char ** reply, int * len, void * data);
+int cli_reinstate(void * v, char ** reply, int * len, void * data);
+int cli_fail(void * v, char ** reply, int * len, void * data);

Modified: multipath-tools/upstream/current/multipathd/main.c
==============================================================================
--- multipath-tools/upstream/current/multipathd/main.c	(original)
+++ multipath-tools/upstream/current/multipathd/main.c	Wed Feb  1 23:48:32 2006
@@ -3,6 +3,9 @@
 #include <libdevmapper.h>
 #include <wait.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
 
 /*
  * libsysfs
@@ -63,9 +66,13 @@
 #define unlock(a) \
 	fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
 	pthread_mutex_unlock(a)
+#define lock_cleanup_pop(a) \
+	fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
+	pthread_cleanup_pop(1);
 #else
 #define lock(a) pthread_mutex_lock(a)
 #define unlock(a) pthread_mutex_unlock(a)
+#define lock_cleanup_pop(a) pthread_cleanup_pop(1);
 #endif
 
 pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
@@ -79,7 +86,7 @@
 	pthread_t thread;
 	int event_nr;
 	char mapname[WWID_SIZE];
-	struct paths *allpaths;
+	struct vectors *vecs;
 };
 
 static struct event_thread *
@@ -94,13 +101,43 @@
 }
 
 static void
+free_waiter (void * data)
+{
+	struct event_thread * wp = (struct event_thread *)data;
+
+	if (wp->dmt)
+		dm_task_destroy(wp->dmt);
+	FREE(wp);
+}
+
+static void
+stop_waiter_thread (struct multipath * mpp, struct vectors * vecs)
+{
+	struct event_thread * wp = (struct event_thread *)mpp->waiter;
+	pthread_t thread;
+	
+	if (!wp) {
+		condlog(3, "%s: no waiter thread", mpp->alias);
+		return;
+	}
+	thread = wp->thread;
+
+	if (!wp) {
+		condlog(3, "%s: thread not started", mpp->alias);
+		return;
+	}
+	condlog(2, "%s: stop event checker thread", wp->mapname);
+	pthread_kill(thread, SIGHUP);
+}
+
+static void
 cleanup_lock (void * data)
 {
-	unlock((pthread_mutex_t *)data);
+	pthread_mutex_unlock((pthread_mutex_t *)data);
 }
 
 static void
-set_paths_owner (struct paths * allpaths, struct multipath * mpp)
+adopt_paths (struct vectors * vecs, struct multipath * mpp)
 {
 	int i;
 	struct path * pp;
@@ -108,7 +145,7 @@
 	if (!mpp)
 		return;
 
-	vector_foreach_slot (allpaths->pathvec, pp, i) {
+	vector_foreach_slot (vecs->pathvec, pp, i) {
 		if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
 			condlog(4, "%s ownership set", pp->dev_t);
 			pp->mpp = mpp;
@@ -117,15 +154,31 @@
 }
 
 static void
-unset_paths_owner (struct paths * allpaths, struct multipath * mpp)
+orphan_path (struct path * pp)
+{
+	pp->mpp = NULL;
+	pp->checkfn = NULL;
+	pp->dmstate = PSTATE_UNDEF;
+	pp->checker_context = NULL;
+	pp->getuid = NULL;
+	pp->getprio = NULL;
+
+	if (pp->fd >= 0)
+		close(pp->fd);
+
+	pp->fd = -1;
+}
+
+static void
+orphan_paths (struct vectors * vecs, struct multipath * mpp)
 {
 	int i;
 	struct path * pp;
 
-	vector_foreach_slot (allpaths->pathvec, pp, i) {
+	vector_foreach_slot (vecs->pathvec, pp, i) {
 		if (pp->mpp == mpp) {
 			condlog(4, "%s is orphaned", pp->dev_t);
-			pp->mpp = NULL;
+			orphan_path(pp);
 		}
 	}
 }
@@ -193,42 +246,165 @@
 static void
 set_multipath_wwid (struct multipath * mpp)
 {
-	char * wwid;
-
-	wwid = get_mpe_wwid(mpp->alias);
+	if (mpp->wwid)
+		return;
 
-	if (wwid) {
-		strncpy(mpp->wwid, wwid, WWID_SIZE);
-		wwid = NULL;
-	} else
-		strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
+	dm_get_uuid(mpp->alias, mpp->wwid);
 }
 
 static int
-setup_multipath (struct paths * allpaths, struct multipath * mpp)
+pathcount (struct multipath *mpp, int state)
+{
+	struct pathgroup *pgp;
+	struct path *pp;
+	int i, j;
+	int count = 0;
+
+	vector_foreach_slot (mpp->pg, pgp, i)
+		vector_foreach_slot (pgp->paths, pp, j)
+			if (pp->state == state)
+				count++;
+	return count;
+}
+
+/*
+ * mpp->no_path_retry:
+ *   -2 (QUEUE) : queue_if_no_path enabled, never turned off
+ *   -1 (FAIL)  : fail_if_no_path
+ *    0 (UNDEF) : nothing
+ *   >0         : queue_if_no_path enabled, turned off after polling n times
+ */
+static void
+update_queue_mode_del_path(struct multipath *mpp)
+{
+	if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
+		/*
+		 * Enter retry mode.
+		 * meaning of +1: retry_tick may be decremented in
+		 *                checkerloop before starting retry.
+		 */
+		mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
+		condlog(1, "%s: Entering recovery mode: max_retries=%d",
+			mpp->alias, mpp->no_path_retry);
+	}
+	condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
+}
+
+static void
+update_queue_mode_add_path(struct multipath *mpp)
+{
+	if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
+		/* come back to normal mode from retry mode */
+		mpp->retry_tick = 0;
+		dm_queue_if_no_path(mpp->alias, 1);
+		condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
+		condlog(1, "%s: Recovered to normal mode", mpp->alias);
+	}
+	condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
+}
+
+static void
+set_no_path_retry(struct multipath *mpp)
+{
+	mpp->retry_tick = 0;
+	mpp->nr_active = pathcount(mpp, PATH_UP);
+	select_no_path_retry(mpp);
+
+	switch (mpp->no_path_retry) {
+	case NO_PATH_RETRY_UNDEF:
+		break;
+	case NO_PATH_RETRY_FAIL:
+		dm_queue_if_no_path(mpp->alias, 0);
+		break;
+	case NO_PATH_RETRY_QUEUE:
+		dm_queue_if_no_path(mpp->alias, 1);
+		break;
+	default:
+		dm_queue_if_no_path(mpp->alias, 1);
+		if (mpp->nr_active == 0) {
+			/* Enter retry mode */
+			mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+			condlog(1, "%s: Entering recovery mode: max_retries=%d",
+				mpp->alias, mpp->no_path_retry);
+		}
+		break;
+	}
+}
+
+static struct hwentry *
+extract_hwe_from_path(struct multipath * mpp)
+{
+	struct path * pp;
+	struct pathgroup * pgp;
+
+	pgp = VECTOR_SLOT(mpp->pg, 0);
+	pp = VECTOR_SLOT(pgp->paths, 0);
+
+	return pp->hwe;
+}
+
+static void
+remove_map (struct multipath * mpp, struct vectors * vecs)
+{
+	int i;
+
+	stop_waiter_thread(mpp, vecs);
+
+	/*
+	 * clear references to this map
+	 */
+	orphan_paths(vecs, mpp);
+
+	/*
+	 * purge the multipath vector
+	 */
+	i = find_slot(vecs->mpvec, (void *)mpp);
+	vector_del_slot(vecs->mpvec, i);
+
+	/*
+	 * final free
+	 */
+	free_multipath(mpp, KEEP_PATHS);
+	mpp = NULL;
+}
+
+static void
+remove_maps (struct vectors * vecs)
 {
 	int i;
+	struct multipath * mpp;
+
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
+		remove_map(mpp, vecs);
+		i--;
+	}
+
+	vector_free(vecs->mpvec);
+	vecs->mpvec = NULL;
+}
+
+static int
+setup_multipath (struct vectors * vecs, struct multipath * mpp)
+{
+	if (dm_get_info(mpp->alias, &mpp->dmi))
+		goto out;
 
 	set_multipath_wwid(mpp);
 	mpp->mpe = find_mpe(mpp->wwid);
 	condlog(4, "discovered map %s", mpp->alias);
 
-	if (update_multipath_strings(mpp, allpaths->pathvec))
+	if (update_multipath_strings(mpp, vecs->pathvec))
 		goto out;
 
-	set_paths_owner(allpaths, mpp);
+	adopt_paths(vecs, mpp);
+	mpp->hwe = extract_hwe_from_path(mpp);
 	select_pgfailback(mpp);
+	set_no_path_retry(mpp);
 
 	return 0;
 out:
-	/*
-	 * purge the multipath vector
-	 */
-	if ((i = find_slot(allpaths->mpvec, (void *)mpp)) != -1)
-		vector_del_slot(allpaths->mpvec, i);
-
-	free_multipath(mpp, KEEP_PATHS);
-	condlog(0, "failed to setup multipath");
+	condlog(0, "%s: failed to setup multipath", mpp->alias);
+	remove_map(mpp, vecs);
 	return 1;
 }
 
@@ -250,10 +426,9 @@
 			vector_foreach_slot (pgp->paths, pp, j)
 				pathinfo(pp, conf->hwtable, DI_PRIO);
 
-	select_path_group(mpp); /* sets mpp->nextpg */
-	pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
+	mpp->bestpg = select_path_group(mpp);
 
-	if (pgp && pgp->status != PGSTATE_ACTIVE)
+	if (mpp->bestpg != mpp->nextpg)
 		return 1;
 
 	return 0;
@@ -262,19 +437,13 @@
 static void
 switch_pathgroup (struct multipath * mpp)
 {
-	struct pathgroup * pgp;
-	
-	pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
-	
-	if (pgp && pgp->status != PGSTATE_ACTIVE) {
-		dm_switchgroup(mpp->alias, mpp->nextpg);
-		condlog(2, "%s: switch to path group #%i",
-			 mpp->alias, mpp->nextpg);
-	}
+	dm_switchgroup(mpp->alias, mpp->bestpg);
+	condlog(2, "%s: switch to path group #%i",
+		 mpp->alias, mpp->bestpg);
 }
 
 static int
-update_multipath (struct paths *allpaths, char *mapname)
+update_multipath (struct vectors *vecs, char *mapname)
 {
 	struct multipath *mpp;
 	struct pathgroup  *pgp;
@@ -282,7 +451,7 @@
 	int i, j;
 	int r = 1;
 
-	mpp = find_mp(allpaths->mpvec, mapname);
+	mpp = find_mp_by_alias(vecs->mpvec, mapname);
 
 	if (!mpp)
 		goto out;
@@ -290,7 +459,7 @@
 	free_pgvec(mpp->pg, KEEP_PATHS);
 	mpp->pg = NULL;
 
-	if (setup_multipath(allpaths, mpp))
+	if (setup_multipath(vecs, mpp))
 		goto out; /* mpp freed in setup_multipath */
 
 	/*
@@ -304,6 +473,7 @@
 			if (pp->state != PATH_DOWN) {
 				condlog(2, "%s: mark as failed", pp->dev_t);
 				pp->state = PATH_DOWN;
+				update_queue_mode_del_path(mpp);
 
 				/*
 				 * if opportune,
@@ -322,16 +492,6 @@
 	return r;
 }
 
-static void
-free_waiter (void * data)
-{
-	struct event_thread * wp = (struct event_thread *)data;
-
-	if (wp->dmt)
-		dm_task_destroy(wp->dmt);
-	FREE(wp);
-}
-
 static sigset_t unblock_sighup(void)
 {
 	sigset_t set, old;
@@ -359,22 +519,37 @@
 	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
 		return 1;
 
-	if (!dm_task_set_name(waiter->dmt, waiter->mapname))
+	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+		dm_task_destroy(waiter->dmt);
 		return 1;
+	}
 
 	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
-						      waiter->event_nr))
+						      waiter->event_nr)) {
+		dm_task_destroy(waiter->dmt);
 		return 1;
+	}
 
 	dm_task_no_open_count(waiter->dmt);
-
+	
+	/* accept wait interruption */
 	set = unblock_sighup();
-	dm_task_run(waiter->dmt);
+
+	/* interruption spits messages */
+	dm_shut_log();
+
+	/* wait */
+	r = dm_task_run(waiter->dmt);
+
+	/* wait is over : event or interrupt */
 	pthread_sigmask(SIG_SETMASK, &set, NULL);
-	pthread_testcancel();
+	//dm_restore_log();
+
+	if (!r) /* wait interrupted by signal */
+		return -1;
+
 	dm_task_destroy(waiter->dmt);
 	waiter->dmt = NULL;
-
 	waiter->event_nr++;
 
 	/*
@@ -395,11 +570,10 @@
 		 * 4) a path reinstate : nothing to do
 		 * 5) a switch group : nothing to do
 		 */
-		pthread_cleanup_push(cleanup_lock, waiter->allpaths->lock);
-		lock(waiter->allpaths->lock);
-
-		r = update_multipath(waiter->allpaths, waiter->mapname);
-		pthread_cleanup_pop(1);
+		pthread_cleanup_push(cleanup_lock, waiter->vecs->lock);
+		lock(waiter->vecs->lock);
+		r = update_multipath(waiter->vecs, waiter->mapname);
+		lock_cleanup_pop(waiter->vecs->lock);
 
 		if (r)
 			return -1; /* stop the thread */
@@ -431,9 +605,7 @@
 		if (r < 0)
 			break;
 
-		pthread_testcancel();
 		sleep(r);
-		pthread_testcancel();
 	}
 
 	pthread_cleanup_pop(1);
@@ -441,26 +613,7 @@
 }
 
 static int
-stop_waiter_thread (struct multipath * mpp, struct paths * allpaths)
-{
-	struct event_thread * wp = (struct event_thread *)mpp->waiter;
-	pthread_t thread = wp->thread;
-	int r;
-
-	if (!wp)
-		return 1;
-
-	condlog(2, "%s: reap event checker", wp->mapname);
-
-	if ((r = pthread_cancel(thread)))
-		return r;
-
-	pthread_kill(thread, SIGHUP);
-	return 0;
-}
-
-static int
-start_waiter_thread (struct multipath * mpp, struct paths * allpaths)
+start_waiter_thread (struct multipath * mpp, struct vectors * vecs)
 {
 	pthread_attr_t attr;
 	struct event_thread * wp;
@@ -481,7 +634,7 @@
 
 	mpp->waiter = (void *)wp;
 	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
-	wp->allpaths = allpaths;
+	wp->vecs = vecs;
 
 	if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
 		condlog(0, "%s: cannot create event checker", wp->mapname);
@@ -498,68 +651,20 @@
 	return 1;
 }
 
-static void
-remove_map (struct multipath * mpp, struct paths * allpaths)
-{
-	int i;
-
-	/*
-	 * stop the DM event waiter thread
-	 */
-	if (stop_waiter_thread(mpp, allpaths)) {
-		condlog(0, "%s: error canceling waiter thread", mpp->alias);
-		/*
-		 * warrior mode
-		 */
-		free_waiter(mpp->waiter);
-	}
-
-	/*
-	 * clear references to this map
-	 */
-	unset_paths_owner(allpaths, mpp);
-
-	/*
-	 * purge the multipath vector
-	 */
-	i = find_slot(allpaths->mpvec, (void *)mpp);
-	vector_del_slot(allpaths->mpvec, i);
-
-	/*
-	 * final free
-	 */
-	free_multipath(mpp, KEEP_PATHS);
-	mpp = NULL;
-}
-
-static void
-remove_maps (struct paths * allpaths)
-{
-	int i;
-	struct multipath * mpp;
-
-	vector_foreach_slot (allpaths->mpvec, mpp, i)
-		remove_map(mpp, allpaths);
-
-	vector_free(allpaths->mpvec);
-	allpaths->mpvec = NULL;
-}
-
 int
-uev_add_map (char * devname, struct paths * allpaths)
+uev_add_map (char * devname, struct vectors * vecs)
 {
-	int major, minor, i;
+	int major, minor;
 	char dev_t[BLK_DEV_SIZE];
 	char * alias;
 	struct multipath * mpp;
 
-	if (sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE))
-		return 1;
-
-	if (sscanf(dev_t, "%d:%d", &major, &minor) != 2)
-		return 1;
-
-	alias = dm_mapname(major, minor);
+	if (sscanf(devname, "dm-%d", &minor) == 1 &&
+	    !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
+	    sscanf(dev_t, "%d:%d", &major, &minor) == 2)
+		alias = dm_mapname(major, minor);
+	else
+		alias = STRDUP(devname);
 		
 	if (!alias)
 		return 1;
@@ -570,7 +675,7 @@
 		return 0;
 	}
 
-	mpp = find_mp(allpaths->mpvec, alias);
+	mpp = find_mp_by_alias(vecs->mpvec, alias);
 
 	if (mpp) {
 		/*
@@ -578,7 +683,7 @@
 		 * we missed a remove map event (not sent ?)
 		 */
 		condlog(2, "%s: already registered", alias);
-		remove_map(mpp, allpaths);
+		remove_map(mpp, vecs);
 	}
 
 	/*
@@ -589,69 +694,62 @@
 	if (!mpp)
 		return 1;
 
-	mpp->minor = minor;
 	mpp->alias = alias;
 
-	if (setup_multipath(allpaths, mpp))
+	if (setup_multipath(vecs, mpp))
 		return 1; /* mpp freed in setup_multipath */
 
-	if (!vector_alloc_slot(allpaths->mpvec))
+	if (!vector_alloc_slot(vecs->mpvec))
 		goto out;
 
-	vector_set_slot(allpaths->mpvec, mpp);
-	set_paths_owner(allpaths, mpp);
+	vector_set_slot(vecs->mpvec, mpp);
+	adopt_paths(vecs, mpp);
 
-	if (start_waiter_thread(mpp, allpaths))
+	if (start_waiter_thread(mpp, vecs))
 		goto out;
 
 	return 0;
 out:
 	condlog(2, "%s: add devmap failed", mpp->alias);
-	/*
-	 * purge the multipath vector
-	 */
-	if ((i = find_slot(allpaths->mpvec, (void *)mpp)) != -1)
-		vector_del_slot(allpaths->mpvec, i);
-
-	free_multipath(mpp, KEEP_PATHS);
+	remove_map(mpp, vecs);
 	return 1;
 }
 
 int
-uev_remove_map (char * devname, struct paths * allpaths)
+uev_remove_map (char * devname, struct vectors * vecs)
 {
 	int minor;
 	struct multipath * mpp;
 
-	if (sscanf(devname, "dm-%d", &minor) != 1)
-		return 1;
-
-	mpp = find_mp_by_minor(allpaths->mpvec, minor);
+	if (sscanf(devname, "dm-%d", &minor) == 1)
+		mpp = find_mp_by_minor(vecs->mpvec, minor);
+	else
+		mpp = find_mp_by_alias(vecs->mpvec, devname);
 
 	if (!mpp) {
 		condlog(3, "%s: devmap not registered, can't remove",
 			devname);
-		return 1;
+		return 0;
 	}
 
 	condlog(2, "remove %s devmap", mpp->alias);
-	remove_map(mpp, allpaths);
+	remove_map(mpp, vecs);
 
 	return 0;
 }
 
 int
-uev_add_path (char * devname, struct paths * allpaths)
+uev_add_path (char * devname, struct vectors * vecs)
 {
 	struct path * pp;
 
-	pp = find_path_by_dev(allpaths->pathvec, devname);
+	pp = find_path_by_dev(vecs->pathvec, devname);
 
 	if (pp) {
 		condlog(3, "%s: already in pathvec");
 		return 1;
 	}
-	pp = store_pathinfo(allpaths->pathvec, conf->hwtable,
+	pp = store_pathinfo(vecs->pathvec, conf->hwtable,
 		       devname, DI_SYSFS | DI_WWID);
 
 	if (!pp) {
@@ -660,39 +758,45 @@
 	}
 
 	condlog(2, "%s: path checker registered", devname);
-	pp->mpp = find_mp_by_wwid(allpaths->mpvec, pp->wwid);
+	pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
 
-	if (pp->mpp)
+	if (pp->mpp) {
 		condlog(4, "%s: ownership set to %s",
 				pp->dev_t, pp->mpp->alias);
-	else
+	} else {
 		condlog(4, "%s: orphaned", pp->dev_t);
+		orphan_path(pp);
+	}
 
 	return 0;
 }
 
 int
-uev_remove_path (char * devname, struct paths * allpaths)
+uev_remove_path (char * devname, struct vectors * vecs)
 {
 	int i;
 	struct path * pp;
 
-	pp = find_path_by_dev(allpaths->pathvec, devname);
+	pp = find_path_by_dev(vecs->pathvec, devname);
 
 	if (!pp) {
 		condlog(3, "%s: not in pathvec");
 		return 1;
 	}
+
+	if (pp->mpp && pp->state == PATH_UP)
+		update_queue_mode_del_path(pp->mpp);
+
 	condlog(2, "remove %s path checker", devname);
-	i = find_slot(allpaths->pathvec, (void *)pp);
-	vector_del_slot(allpaths->pathvec, i);
+	i = find_slot(vecs->pathvec, (void *)pp);
+	vector_del_slot(vecs->pathvec, i);
 	free_path(pp);
 
 	return 0;
 }
 
 int
-show_paths (char ** r, int * len, struct paths * allpaths)
+show_paths (char ** r, int * len, struct vectors * vecs)
 {
 	int i;
 	struct path * pp;
@@ -700,16 +804,19 @@
 	char * reply;
 	struct path_layout pl;
 
-	get_path_layout(&pl, allpaths->pathvec);
+	get_path_layout(&pl, vecs->pathvec);
 	reply = MALLOC(MAX_REPLY_LEN);
 
 	if (!reply)
 		return 1;
 
 	c = reply;
-	c += sprintf(c, "\n");
 
-	vector_foreach_slot(allpaths->pathvec, pp, i)
+	if (VECTOR_SIZE(vecs->pathvec) > 0)
+		c += snprint_path_header(c, reply + MAX_REPLY_LEN - c,
+					 PRINT_PATH_CHECKER, &pl);
+
+	vector_foreach_slot(vecs->pathvec, pp, i)
 		c += snprint_path(c, reply + MAX_REPLY_LEN - c,
 			       	  PRINT_PATH_CHECKER, pp, &pl);
 
@@ -719,7 +826,7 @@
 }
 
 int
-show_maps (char ** r, int *len, struct paths * allpaths)
+show_maps (char ** r, int *len, struct vectors * vecs)
 {
 	int i;
 	struct multipath * mpp;
@@ -727,16 +834,18 @@
 	char * reply;
 	struct map_layout ml;
 
-	get_map_layout(&ml, allpaths->mpvec);
+	get_map_layout(&ml, vecs->mpvec);
 	reply = MALLOC(MAX_REPLY_LEN);
 
 	if (!reply)
 		return 1;
 
 	c = reply;
-	c += sprintf(c, "\n");
+	if (VECTOR_SIZE(vecs->mpvec) > 0)
+		c += snprint_map_header(c, reply + MAX_REPLY_LEN - c,
+					PRINT_MAP_FAILBACK, &ml);
 
-	vector_foreach_slot(allpaths->mpvec, mpp, i)
+	vector_foreach_slot(vecs->mpvec, mpp, i)
 		c += snprint_map(c, reply + MAX_REPLY_LEN - c,
 			       	 PRINT_MAP_FAILBACK, mpp, &ml);
 
@@ -746,14 +855,14 @@
 }
 
 int
-dump_pathvec (char ** r, int * len, struct paths * allpaths)
+dump_pathvec (char ** r, int * len, struct vectors * vecs)
 {
 	int i;
 	struct path * pp;
 	char * reply;
 	char * p;
 
-	*len = VECTOR_SIZE(allpaths->pathvec) * sizeof(struct path);
+	*len = VECTOR_SIZE(vecs->pathvec) * sizeof(struct path);
 	reply = (char *)MALLOC(*len);
 	*r = reply;
 
@@ -762,35 +871,35 @@
 
 	p = reply;
 
-	vector_foreach_slot (allpaths->pathvec, pp, i) {
+	vector_foreach_slot (vecs->pathvec, pp, i) {
 		memcpy((void *)p, pp, sizeof(struct path));
 		p += sizeof(struct path);
 	}
 
-	return 0;
+	/* return negative to hint caller not to add "ok" to the dump */
+	return -1;
 }
 
 static int
-get_dm_mpvec (struct paths * allpaths)
+map_discovery (struct vectors * vecs)
 {
 	int i;
 	struct multipath * mpp;
 
-	if (dm_get_maps(allpaths->mpvec, "multipath"))
+	if (dm_get_maps(vecs->mpvec, "multipath"))
 		return 1;
 
-	vector_foreach_slot (allpaths->mpvec, mpp, i) {
-		if (setup_multipath(allpaths, mpp))
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
+		if (setup_multipath(vecs, mpp))
 			return 1;
-		mpp->minor = dm_get_minor(mpp->alias);
-		start_waiter_thread(mpp, allpaths);
+		start_waiter_thread(mpp, vecs);
 	}
 
 	return 0;
 }
 
 int
-reconfigure (struct paths * allpaths)
+reconfigure (struct vectors * vecs)
 {
 	struct config * old = conf;
 	struct multipath * mpp;
@@ -807,11 +916,13 @@
 	conf->verbosity = old->verbosity;
 	free_config(old);
 
-	vector_foreach_slot (allpaths->mpvec, mpp, i) {
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
 		mpp->mpe = find_mpe(mpp->wwid);
-		set_paths_owner(allpaths, mpp);
+		mpp->hwe = extract_hwe_from_path(mpp);
+		adopt_paths(vecs, mpp);
+		set_no_path_retry(mpp);
 	}
-	vector_foreach_slot (allpaths->pathvec, pp, i) {
+	vector_foreach_slot (vecs->pathvec, pp, i) {
 		select_checkfn(pp);
 		select_getuid(pp);
 		select_getprio(pp);
@@ -823,60 +934,76 @@
 int
 uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
 {
-	struct paths * allpaths;
+	struct vectors * vecs;
 	int r;
 	
 	*reply = NULL;
 	*len = 0;
-	allpaths = (struct paths *)trigger_data;
+	vecs = (struct vectors *)trigger_data;
 
-	pthread_cleanup_push(cleanup_lock, allpaths->lock);
-	lock(allpaths->lock);
+	pthread_cleanup_push(cleanup_lock, vecs->lock);
+	lock(vecs->lock);
 
-	r = parse_cmd(str, reply, len, allpaths);
+	r = parse_cmd(str, reply, len, vecs);
 
-	if (r) {
+	if (r > 0) {
 		*reply = STRDUP("fail\n");
 		*len = strlen(*reply) + 1;
 		r = 1;
 	}
-	else if (*len == 0) {
+	else if (!r && *len == 0) {
 		*reply = STRDUP("ok\n");
 		*len = strlen(*reply) + 1;
 		r = 0;
 	}
+	/* else if (r < 0) leave *reply alone */
 
-	pthread_cleanup_pop(1);
+	lock_cleanup_pop(vecs->lock);
 	return r;
 }
 
+static int
+uev_discard(char * devpath)
+{
+	char a[10], b[10];
+
+	/*
+	 * keep only block devices, discard partitions
+	 */
+	if (sscanf(devpath, "/block/%10s", a) != 1 ||
+	    sscanf(devpath, "/block/%10[^/]/%10s", a, b) == 2) {
+		condlog(4, "discard event on %s", devpath);
+		return 1;
+	}
+	return 0;
+}
+
 int 
 uev_trigger (struct uevent * uev, void * trigger_data)
 {
 	int r = 0;
 	char devname[32];
-	struct paths * allpaths;
+	struct vectors * vecs;
 
-	allpaths = (struct paths *)trigger_data;
-	pthread_cleanup_push(cleanup_lock, allpaths->lock);
-	lock(allpaths->lock);
+	vecs = (struct vectors *)trigger_data;
 
-	if (strncmp(uev->devpath, "/block", 6))
+	if (uev_discard(uev->devpath))
 		goto out;
 
 	basename(uev->devpath, devname);
+	lock(vecs->lock);
 
 	/*
 	 * device map add/remove event
 	 */
 	if (!strncmp(devname, "dm-", 3)) {
 		if (!strncmp(uev->action, "add", 3)) {
-			r = uev_add_map(devname, allpaths);
+			r = uev_add_map(devname, vecs);
 			goto out;
 		}
 #if 0
 		if (!strncmp(uev->action, "remove", 6)) {
-			r = uev_remove_map(devname, allpaths);
+			r = uev_remove_map(devname, vecs);
 			goto out;
 		}
 #endif
@@ -890,25 +1017,25 @@
 		goto out;
 
 	if (!strncmp(uev->action, "add", 3)) {
-		r = uev_add_path(devname, allpaths);
+		r = uev_add_path(devname, vecs);
 		goto out;
 	}
 	if (!strncmp(uev->action, "remove", 6)) {
-		r = uev_remove_path(devname, allpaths);
+		r = uev_remove_path(devname, vecs);
 		goto out;
 	}
 
 out:
-	FREE(uev);
-	pthread_cleanup_pop(1);
+	unlock(vecs->lock);
 	return r;
 }
 
 static void *
 ueventloop (void * ap)
 {
-	uevent_listen(&uev_trigger, ap);
-
+	if (uevent_listen(&uev_trigger, ap))
+		fprintf(stderr, "error starting uevent listener");
+		
 	return NULL;
 }
 
@@ -930,6 +1057,10 @@
 	add_handler(SWITCH+MAP+GROUP, cli_switch_group);
 	add_handler(DUMP+PATHVEC, cli_dump_pathvec);
 	add_handler(RECONFIGURE, cli_reconfigure);
+	add_handler(SUSPEND+MAP, cli_suspend);
+	add_handler(RESUME+MAP, cli_resume);
+	add_handler(REINSTATE+PATH, cli_reinstate);
+	add_handler(FAIL+PATH, cli_fail);
 
 	uxsock_listen(&uxsock_trigger, ap);
 
@@ -962,6 +1093,7 @@
 		 pp->dev_t, pp->mpp->alias);
 
 	dm_fail_path(pp->mpp->alias, pp->dev_t);
+	update_queue_mode_del_path(pp->mpp);
 }
 
 /*
@@ -970,11 +1102,14 @@
 static void
 reinstate_path (struct path * pp)
 {
-	if (pp->mpp) {
-		if (dm_reinstate(pp->mpp->alias, pp->dev_t))
-			condlog(0, "%s: reinstate failed", pp->dev_t);
-		else
-			condlog(2, "%s: reinstated", pp->dev_t);
+	if (!pp->mpp)
+		return;
+
+	if (dm_reinstate_path(pp->mpp->alias, pp->dev_t))
+		condlog(0, "%s: reinstate failed", pp->dev_t);
+	else {
+		condlog(2, "%s: reinstated", pp->dev_t);
+		update_queue_mode_add_path(pp->mpp);
 	}
 }
 
@@ -1002,15 +1137,16 @@
 }
 
 static void
-mpvec_garbage_collector (struct paths * allpaths)
+mpvec_garbage_collector (struct vectors * vecs)
 {
 	struct multipath * mpp;
 	int i;
 
-	vector_foreach_slot (allpaths->mpvec, mpp, i) {
-		if (!dm_map_present(mpp->alias)) {
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
+		if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
 			condlog(2, "%s: remove dead map", mpp->alias);
-			remove_map(mpp, allpaths);
+			remove_map(mpp, vecs);
+			i--;
 		}
 	}
 }
@@ -1034,10 +1170,27 @@
 	}
 }
 
+static void
+retry_count_tick(vector mpvec)
+{
+	struct multipath *mpp;
+	int i;
+
+	vector_foreach_slot (mpvec, mpp, i) {
+		if (mpp->retry_tick) {
+			condlog(4, "%s: Retrying.. No active path", mpp->alias);
+			if(--mpp->retry_tick == 0) {
+				dm_queue_if_no_path(mpp->alias, 0);
+				condlog(2, "%s: Disable queueing", mpp->alias);
+			}
+		}
+	}
+}
+
 static void *
 checkerloop (void *ap)
 {
-	struct paths *allpaths;
+	struct vectors *vecs;
 	struct path *pp;
 	int i, count = 0;
 	int newstate;
@@ -1046,26 +1199,28 @@
 	mlockall(MCL_CURRENT | MCL_FUTURE);
 
 	memset(checker_msg, 0, MAX_CHECKER_MSG_SIZE);
-	allpaths = (struct paths *)ap;
+	vecs = (struct vectors *)ap;
 
 	condlog(2, "path checkers start up");
 
+	/*
+	 * init the path check interval
+	 */
+	vector_foreach_slot (vecs->pathvec, pp, i) {
+		pp->checkint = conf->checkint;
+	}
+
 	while (1) {
-		pthread_cleanup_push(cleanup_lock, allpaths->lock);
-		lock(allpaths->lock);
+		pthread_cleanup_push(cleanup_lock, vecs->lock);
+		lock(vecs->lock);
 		condlog(4, "tick");
 
-		vector_foreach_slot (allpaths->pathvec, pp, i) {
+		vector_foreach_slot (vecs->pathvec, pp, i) {
 			if (!pp->mpp)
 				continue;
 
-			if (pp->tick) {
-				/*
-				 * don't check this path yet
-				 */
-				pp->tick--;
-				continue;
-			}
+			if (pp->tick && --pp->tick)
+				continue; /* don't check this path yet */
 
 			/*
 			 * provision a next check soonest,
@@ -1119,14 +1274,14 @@
 				 * need to switch group ?
 				 */
 				update_multipath_strings(pp->mpp,
-							 allpaths->pathvec);
+							 vecs->pathvec);
 
 				/*
 				 * schedule defered failback
 				 */
 				if (pp->mpp->pgfailback > 0)
 					pp->mpp->failback_tick =
-						pp->mpp->pgfailback;
+						pp->mpp->pgfailback + 1;
 				else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
 				    need_switch_pathgroup(pp->mpp, 1))
 					switch_pathgroup(pp->mpp);
@@ -1165,64 +1320,65 @@
 			if (need_switch_pathgroup(pp->mpp, 0)) {
 				if (pp->mpp->pgfailback > 0)
 					pp->mpp->failback_tick =
-						pp->mpp->pgfailback;
+						pp->mpp->pgfailback + 1;
 				else if (pp->mpp->pgfailback ==
 						-FAILBACK_IMMEDIATE)
 					switch_pathgroup(pp->mpp);
 			}
 		}
-		defered_failback_tick(allpaths->mpvec);
+		defered_failback_tick(vecs->mpvec);
+		retry_count_tick(vecs->mpvec);
 
 		if (count)
 			count--;
 		else {
 			condlog(4, "map garbage collection");
-			mpvec_garbage_collector(allpaths);
+			mpvec_garbage_collector(vecs);
 			count = MAPGCINT;
 		}
 		
-		pthread_cleanup_pop(1);
+		lock_cleanup_pop(vecs->lock);
 		sleep(1);
 	}
 	return NULL;
 }
 
-static struct paths *
+static struct vectors *
 init_paths (void)
 {
-	struct paths * allpaths;
+	struct vectors * vecs;
 
-	allpaths = (struct paths *)MALLOC(sizeof(struct paths));
+	vecs = (struct vectors *)MALLOC(sizeof(struct vectors));
 
-	if (!allpaths)
+	if (!vecs)
 		return NULL;
 
-	allpaths->lock = 
+	vecs->lock = 
 		(pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t));
 
-	if (!allpaths->lock)
+	if (!vecs->lock)
 		goto out;
 
-	allpaths->pathvec = vector_alloc();
+	vecs->pathvec = vector_alloc();
 
-	if (!allpaths->pathvec)
+	if (!vecs->pathvec)
 		goto out1;
 		
-	allpaths->mpvec = vector_alloc();
+	vecs->mpvec = vector_alloc();
 
-	if (!allpaths->mpvec)
+	if (!vecs->mpvec)
 		goto out2;
 	
-	pthread_mutex_init(allpaths->lock, NULL);
+	pthread_mutex_init(vecs->lock, NULL);
 
-	return allpaths;
+	return vecs;
 
 out2:
-	vector_free(allpaths->pathvec);
+	vector_free(vecs->pathvec);
 out1:
-	FREE(allpaths->lock);
+	FREE(vecs->lock);
 out:
-	FREE(allpaths);
+	FREE(vecs);
 	condlog(0, "failed to init paths");
 	return NULL;
 }
@@ -1305,7 +1461,7 @@
 {
 	pthread_t check_thr, uevent_thr, uxlsnr_thr;
 	pthread_attr_t attr;
-	struct paths * allpaths;
+	struct vectors * vecs;
 
 	mlockall(MCL_CURRENT | MCL_FUTURE);
 
@@ -1337,9 +1493,9 @@
 	signal_init();
 	setscheduler();
 	set_oom_adj(-17);
-	allpaths = init_paths();
+	vecs = init_paths();
 
-	if (!allpaths)
+	if (!vecs)
 		exit(1);
 
 	if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
@@ -1352,8 +1508,8 @@
 	 * no paths and/or no multipaths are valid scenarii
 	 * vectors maintenance will be driven by events
 	 */
-	path_discovery(allpaths->pathvec, conf, DI_SYSFS | DI_WWID);
-	get_dm_mpvec(allpaths);
+	path_discovery(vecs->pathvec, conf, DI_SYSFS | DI_WWID | DI_CHECKER);
+	map_discovery(vecs);
 
 	/*
 	 * start threads
@@ -1362,32 +1518,37 @@
 	pthread_attr_setstacksize(&attr, 64 * 1024);
 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 	
-	pthread_create(&check_thr, &attr, checkerloop, allpaths);
-	pthread_create(&uevent_thr, &attr, ueventloop, allpaths);
-	pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, allpaths);
+	pthread_create(&check_thr, &attr, checkerloop, vecs);
+	pthread_create(&uevent_thr, &attr, ueventloop, vecs);
+	pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, vecs);
 
 	pthread_cond_wait(&exit_cond, &exit_mutex);
 
 	/*
 	 * exit path
 	 */
-	lock(allpaths->lock);
-	remove_maps(allpaths);
-	free_pathvec(allpaths->pathvec, FREE_PATHS);
+	lock(vecs->lock);
+	remove_maps(vecs);
+	free_pathvec(vecs->pathvec, FREE_PATHS);
 
 	pthread_cancel(check_thr);
 	pthread_cancel(uevent_thr);
 	pthread_cancel(uxlsnr_thr);
 
 	free_keys(keys);
+	keys = NULL;
 	free_handlers(handlers);
+	handlers = NULL;
 	free_polls();
 
-	unlock(allpaths->lock);
-	pthread_mutex_destroy(allpaths->lock);
-	FREE(allpaths->lock);
-	FREE(allpaths);
+	unlock(vecs->lock);
+	pthread_mutex_destroy(vecs->lock);
+	FREE(vecs->lock);
+	vecs->lock = NULL;
+	FREE(vecs);
+	vecs = NULL;
 	free_config(conf);
+	conf = NULL;
 
 	condlog(2, "--------shut down-------");
 	
@@ -1401,6 +1562,53 @@
 	exit(0);
 }
 
+static int
+daemonize(void)
+{
+	int pid;
+	int in_fd, out_fd;
+
+	if( (pid = fork()) < 0){
+		fprintf(stderr, "Failed first fork : %s\n", strerror(errno));
+		return -1;
+	}
+	else if (pid != 0)
+		return pid;
+
+	setsid();
+
+	if ( (pid = fork()) < 0)
+		fprintf(stderr, "Failed second fork : %s\n", strerror(errno));
+	else if (pid != 0)
+		_exit(0);
+
+	in_fd = open("/dev/null", O_RDONLY);
+	if (in_fd < 0){
+		fprintf(stderr, "cannot open /dev/null for input : %s\n",
+			strerror(errno));
+		_exit(0);
+	}
+	out_fd = open("/dev/console", O_WRONLY);
+	if (out_fd < 0){
+		fprintf(stderr, "cannot open /dev/console for output : %s\n",
+			strerror(errno));
+		_exit(0);
+	}
+
+	close(STDIN_FILENO);
+	dup(in_fd);
+	close(STDOUT_FILENO);
+	dup(out_fd);
+	close(STDERR_FILENO);
+	dup(out_fd);
+
+	close(in_fd);
+	close(out_fd);
+	chdir("/");
+	umask(0);
+	return 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1449,7 +1657,7 @@
 	if (!logsink)
 		err = 0;
 	else
-		err = fork();
+		err = daemonize();
 	
 	if (err < 0)
 		/* error */

Modified: multipath-tools/upstream/current/multipathd/main.h
==============================================================================
--- multipath-tools/upstream/current/multipathd/main.h	(original)
+++ multipath-tools/upstream/current/multipathd/main.h	Wed Feb  1 23:48:32 2006
@@ -6,19 +6,19 @@
 #define MAPGCINT 5
 #define MAX_CHECKINT CHECKINT << 2
 
-struct paths {
+struct vectors {
 	pthread_mutex_t *lock;
 	vector pathvec;
 	vector mpvec;
 };
 
-int reconfigure (struct paths *);
-int show_paths (char **, int *, struct paths *);
-int show_maps (char **, int *, struct paths *);
-int dump_pathvec (char **, int *, struct paths * allpaths);
-int uev_add_path (char *, struct paths *);
-int uev_remove_path (char *, struct paths *);
-int uev_add_map (char *, struct paths *);
-int uev_remove_map (char *, struct paths *);
+int reconfigure (struct vectors *);
+int show_paths (char **, int *, struct vectors *);
+int show_maps (char **, int *, struct vectors *);
+int dump_pathvec (char **, int *, struct vectors *);
+int uev_add_path (char *, struct vectors *);
+int uev_remove_path (char *, struct vectors *);
+int uev_add_map (char *, struct vectors *);
+int uev_remove_map (char *, struct vectors *);
 
 #endif /* MAIN_H */

Modified: multipath-tools/upstream/current/multipathd/uxclnt.c
==============================================================================
--- multipath-tools/upstream/current/multipathd/uxclnt.c	(original)
+++ multipath-tools/upstream/current/multipathd/uxclnt.c	Wed Feb  1 23:48:32 2006
@@ -25,11 +25,17 @@
 
 	while ((line = readline("multipathd> "))) {
 		size_t len;
+		size_t llen = strlen(line);
 
-		if (send_packet(fd, line, strlen(line) + 1) != 0) break;
+		if (!llen) {
+			free(line);
+			continue;
+		}
+
+		if (send_packet(fd, line, llen + 1) != 0) break;
 		if (recv_packet(fd, &reply, &len) != 0) break;
 
-		printf("%s\n", reply);
+		printf("%s", reply);
 
 		if (line && *line)
 			add_history(line);
@@ -47,7 +53,7 @@
 	send_packet(fd, inbuf, strlen(inbuf) + 1);
 	recv_packet(fd, &reply, &len);
 
-	printf("%s\n", reply);
+	printf("%s", reply);
 	FREE(reply);
 }
 	

Modified: multipath-tools/upstream/current/path_priority/pp_alua/Makefile
==============================================================================
--- multipath-tools/upstream/current/path_priority/pp_alua/Makefile	(original)
+++ multipath-tools/upstream/current/path_priority/pp_alua/Makefile	Wed Feb  1 23:48:32 2006
@@ -22,9 +22,6 @@
 
 ifneq ($(shell ls $(TOPDIR)/Makefile.inc 2>/dev/null),)
 include $(TOPDIR)/Makefile.inc
-else
-# "out of tree building"
-STRIP		= strip --strip-all -R .comment -R .note
 endif
 
 CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -DDEBUG=$(DEBUG)
@@ -33,14 +30,12 @@
 
 glibc:	$(OBJS)
 	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 
 klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
-	$(STRIP) $(EXEC)
 
 install: $(BUILD) $(EXEC).8.gz
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 
 uninstall:

Modified: multipath-tools/upstream/current/path_priority/pp_alua/mpath_prio_alua.8
==============================================================================
--- multipath-tools/upstream/current/path_priority/pp_alua/mpath_prio_alua.8	(original)
+++ multipath-tools/upstream/current/path_priority/pp_alua/mpath_prio_alua.8	Wed Feb  1 23:48:32 2006
@@ -137,7 +137,7 @@
 .B  Notes:
 .IP \(bu 2
 Depending on your default configuration not all keywords are required
-.RB "(e.g. if your " default_path_checker " is set to tur you don't have to"
+.RB "(e.g. if your " path_checker " is set to tur you don't have to"
 .RB "use the " path_checker " statement in the device section)."
 .IP \(bu
 .RB "The entries for " vendor " and " product " must be strings that are 8"

Modified: multipath-tools/upstream/current/path_priority/pp_balance_units/Makefile
==============================================================================
--- multipath-tools/upstream/current/path_priority/pp_balance_units/Makefile	(original)
+++ multipath-tools/upstream/current/path_priority/pp_balance_units/Makefile	Wed Feb  1 23:48:32 2006
@@ -27,18 +27,16 @@
 
 glibc: prepare $(OBJS)
 	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 	
 klibc: prepare $(OBJS)
 	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-	$(STRIP) $(EXEC)
 
 $(MULTIPATHLIB)-$(BUILD).a:
 	make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)

Modified: multipath-tools/upstream/current/path_priority/pp_emc/Makefile
==============================================================================
--- multipath-tools/upstream/current/path_priority/pp_emc/Makefile	(original)
+++ multipath-tools/upstream/current/path_priority/pp_emc/Makefile	Wed Feb  1 23:48:32 2006
@@ -11,14 +11,12 @@
 
 glibc:	$(OBJS)
 	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-	$(STRIP) $(EXEC)
 
 klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
-	$(STRIP) $(EXEC)
 
 install: $(EXEC)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)

Added: multipath-tools/upstream/current/path_priority/pp_random/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/path_priority/pp_random/Makefile	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,27 @@
+EXEC		= mpath_prio_random
+BUILD		= glibc
+OBJS		= pp_random.o
+
+TOPDIR		= ../..
+include $(TOPDIR)/Makefile.inc
+
+CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
+
+all: $(BUILD)
+
+glibc:	$(OBJS)
+	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
+
+klibc:	$(OBJS)
+	$(CC) -static -o $(EXEC) $(OBJS)
+
+install: $(EXEC)
+	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+
+uninstall:
+	rm $(DESTDIR)$(bindir)/$(EXEC)
+clean:	
+	rm -f *.o $(EXEC)
+
+%.o:	%.c
+	$(CC) $(CFLAGS) -c -o $@ $<

Added: multipath-tools/upstream/current/path_priority/pp_random/pp_random.c
==============================================================================
--- (empty file)
+++ multipath-tools/upstream/current/path_priority/pp_random/pp_random.c	Wed Feb  1 23:48:32 2006
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+
+int main(void)
+{
+	struct timeval tv;
+	
+	gettimeofday(&tv, NULL);
+	srand((unsigned int)tv.tv_usec);
+	printf("%i\n", 1+(int) (10.0*rand()/(RAND_MAX+1.0)));
+	return 0;
+}



More information about the pkg-lvm-commits mailing list