r396 - in multipath-tools/trunk/debian: . patches

Guido Guenther agx at alioth.debian.org
Wed Dec 20 10:52:02 CET 2006


Author: agx
Date: Wed Dec 20 10:52:01 2006
New Revision: 396

Added:
   multipath-tools/trunk/debian/patches/
   multipath-tools/trunk/debian/patches/exclude-quilt
   multipath-tools/trunk/debian/patches/git-40b575955cc189aa993e6a030b66b5fef6bcf288.patch
   multipath-tools/trunk/debian/patches/series
Modified:
   multipath-tools/trunk/debian/changelog
   multipath-tools/trunk/debian/control
   multipath-tools/trunk/debian/multipath-tools.init
   multipath-tools/trunk/debian/rules
Log:
  * Acknowledge NMU - thanks John! (closes: #382244)
  * use quilt for the git patch
  * remove Bastian and Andres from Uploaders on their request
  * cleanup pp_hds_modular so the package is rebuildable several times


Modified: multipath-tools/trunk/debian/changelog
==============================================================================
--- multipath-tools/trunk/debian/changelog	(original)
+++ multipath-tools/trunk/debian/changelog	Wed Dec 20 10:52:01 2006
@@ -1,8 +1,27 @@
 multipath-tools (0.4.7-2) UNRELEASED; urgency=low
 
+  [ Bastian Blank ]
   * Use /lib/udev/scsi_id. (closes: #358985)
 
- -- Bastian Blank <waldi at debian.org>  Wed, 29 Mar 2006 12:09:43 +0200
+  [ Guido Guenther ]
+  * Acknowledge NMU - thanks John! (closes: #382244)
+  * use quilt for the git patch
+  * remove Bastian and Andres from Uploaders on their request
+  * cleanup pp_hds_modular so the package is rebuildable several times
+
+ -- Guido Guenther <agx at sigxcpu.org>  Mon, 18 Dec 2006 16:08:47 +0100
+
+multipath-tools (0.4.7-1.1) unstable; urgency=medium
+
+  * Added missing dependency on dmsetup.  Closes: #381068.
+  * Fixed PID file handling.  Closes: #294066.
+  * Pulled in numerous fixes from upstream git tree to fix
+    various segfaults, spewing garbage onto the console, etc.
+    Tree is now synced to upstream git as of commit
+    40b575955cc189aa993e6a030b66b5fef6bcf288 on July 19, 2006, 
+    which is the current state of the upstream tree.  Closes: #382214.
+
+ -- John Goerzen <jgoerzen at complete.org>  Wed,  9 Aug 2006 11:52:08 -0500
 
 multipath-tools (0.4.7-1) unstable; urgency=low
 

Modified: multipath-tools/trunk/debian/control
==============================================================================
--- multipath-tools/trunk/debian/control	(original)
+++ multipath-tools/trunk/debian/control	Wed Dec 20 10:52:01 2006
@@ -3,12 +3,12 @@
 Priority: extra
 Maintainer: Debian LVM Team <pkg-lvm-maintainers at lists.alioth.debian.org>
 Uploaders: Bastian Blank <waldi at debian.org>, Andres Salomon <dilinger at debian.org>
-Build-Depends: debhelper (>> 4.0.0), po-debconf, libdevmapper-dev (>= 2:1.01.0), libsysfs-dev, libreadline5-dev
+Build-Depends: debhelper (>> 4.0.0), po-debconf, libdevmapper-dev (>= 2:1.01.0), libsysfs-dev, libreadline5-dev, quilt
 Standards-Version: 3.6.1
 
 Package: multipath-tools
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, udev (>> 0.086), initscripts (>= 2.85-16)
+Depends: ${shlibs:Depends}, ${misc:Depends}, udev (>> 0.086), initscripts (>= 2.85-16), dmsetup
 Description: Command-line utilities for administering multipath disk access
  These tools are in charge of maintaining the disk multipath device maps and
  react to path and map events.

Modified: multipath-tools/trunk/debian/multipath-tools.init
==============================================================================
--- multipath-tools/trunk/debian/multipath-tools.init	(original)
+++ multipath-tools/trunk/debian/multipath-tools.init	Wed Dec 20 10:52:01 2006
@@ -2,7 +2,7 @@
 
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 DAEMON=/sbin/multipathd
-NAME=multipath-tools
+NAME=multipathd
 DESC="multipath daemon"
 
 test -x $DAEMON || exit 0
@@ -36,7 +36,7 @@
 	echo "."
 	;;
   *)
-	N=/etc/init.d/$NAME
+	N=/etc/init.d/multipath-tools
 	echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
 	exit 1
 	;;

Added: multipath-tools/trunk/debian/patches/exclude-quilt
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/debian/patches/exclude-quilt	Wed Dec 20 10:52:01 2006
@@ -0,0 +1,13 @@
+Index: multipath-tools/Makefile
+===================================================================
+--- multipath-tools.orig/Makefile	2006-12-17 20:22:51.000000000 +0100
++++ multipath-tools/Makefile	2006-12-17 20:23:04.000000000 +0100
+@@ -20,7 +20,7 @@
+ export KRNLSRC
+ export KRNLOBJ
+ 
+-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib)
++BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -vE '^lib|/\.pc')
+ 
+ ifeq   ($(MULTIPATH_VERSION),)
+ VERSION = $(shell basename ${PWD} | cut -d'-' -f3)

Added: multipath-tools/trunk/debian/patches/git-40b575955cc189aa993e6a030b66b5fef6bcf288.patch
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/debian/patches/git-40b575955cc189aa993e6a030b66b5fef6bcf288.patch	Wed Dec 20 10:52:01 2006
@@ -0,0 +1,3114 @@
+diff -u multipath-tools-0.4.7/multipath.conf.annotated multipath-tools-0.4.7/multipath.conf.annotated
+--- multipath-tools-0.4.7/multipath.conf.annotated
++++ multipath-tools-0.4.7/multipath.conf.annotated
+@@ -237,7 +237,7 @@
+ ##
+ ## name  : devices
+ ## scope : multipath & multipathd
+-## desc  : list of per storage controler settings
++## desc  : list of per storage controller settings
+ ##	  overrides default settings (device_maps block)
+ ##         overriden by per multipath settings (multipaths block)
+ ##
+@@ -245,7 +245,7 @@
+ #	#
+ #	# name  : device
+ #	# scope : multipath & multipathd
+-#	# desc  : settings for this specific storage controler
++#	# desc  : settings for this specific storage controller
+ #	#
+ #	device {
+ #		#
+@@ -260,7 +260,7 @@
+ #		# name    : path_grouping_policy
+ #		# scope   : multipath
+ #		# desc    : path grouping policy to apply to multipath hosted
+-#		#           by this storage controler
++#		#           by this storage controller
+ #		# values  : failover        = 1 path per priority group
+ #		#           multibus        = all valid paths in 1 priority
+ #		#                             group
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_alua/mpath_prio_alua.8
++++ multipath-tools-0.4.7/path_priority/pp_alua/mpath_prio_alua.8
+@@ -1,4 +1,4 @@
+-.TH MPATH_PRIO_ALUA 8 "7. June 2005" "multipath-tools" \
++.TH MPATH_PRIO_ALUA 8 "July 2006" "multipath-tools" \
+ "Linux Administrator's Manual"
+ .SH NAME
+ mpath_prio_alua \- Path priority tool based on Asymmetric LUn Access
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_alua/rtpg.c
++++ multipath-tools-0.4.7/path_priority/pp_alua/rtpg.c
+@@ -28,7 +28,7 @@
+ #include "rtpg.h"
+ 
+ #define SENSE_BUFF_LEN  32
+-#define DEF_TIMEOUT     60000
++#define DEF_TIMEOUT     300000
+ 
+ /*
+  * Macro used to print debug messaged.
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_alua/spc3.h
++++ multipath-tools-0.4.7/path_priority/pp_alua/spc3.h
+@@ -148,10 +148,10 @@
+ 					/* ......x. = command queue support  */
+ 					/* .......x = vs2                    */
+ 	unsigned char	vendor_identification[8];
+-	unsigned char	product_identification[8];
++	unsigned char	product_identification[16];
+ 	unsigned char	product_revision[4];
+ 	unsigned char	vendor_specific[20];
+-	unsigned char	b48;		/* xxxx.... = reserved               */
++	unsigned char	b56;		/* xxxx.... = reserved               */
+ 					/* ....xx.. = clocking               */
+ 					/* ......x. = qas                    */
+ 					/* .......x = ius                    */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_balance_units/pp_balance_units.c
++++ multipath-tools-0.4.7/path_priority/pp_balance_units/pp_balance_units.c
+@@ -3,15 +3,15 @@
+  * This code is GPLv2, see license file
+  *
+  * This path prioritizer aims to balance logical units over all
+- * controlers available. The logic is :
++ * controllers available. The logic is :
+  *
+  * - list all paths in all primary path groups
+- * - for each path, get the controler's serial
+- * - compute the number of active paths attached to each controler
+- * - compute the max number of paths attached to the same controler
++ * - for each path, get the controller's serial
++ * - compute the number of active paths attached to each controller
++ * - compute the max number of paths attached to the same controller
+  * - if sums are already balanced or if the path passed as parameter is
+- *   attached to controler with less active paths, then return 
+- *   (max_path_attached_to_one_controler - number_of_paths_on_this_controler)
++ *   attached to controller with less active paths, then return 
++ *   (max_path_attached_to_one_controller - number_of_paths_on_this_controller)
+  * - else, or if anything goes wrong, return 1 as a default prio
+  *
+  */
+@@ -38,7 +38,7 @@
+ #define INQUIRY_CMDLEN  6
+ #define INQUIRY_CMD     0x12
+ #define SENSE_BUFF_LEN  32
+-#define DEF_TIMEOUT     60000
++#define DEF_TIMEOUT     300000
+ #define RECOVERED_ERROR 0x01
+ #define MX_ALLOC_LEN    255
+ #define SCSI_CHECK_CONDITION    0x2
+@@ -61,7 +61,7 @@
+ 	char serial[SERIAL_SIZE];
+ };
+ 
+-struct controler {
++struct controller {
+ 	char serial[SERIAL_SIZE];
+ 	int path_count;
+ };
+@@ -172,7 +172,7 @@
+ }
+ 
+ static int
+-get_serial (char * str, char * devt)
++get_serial (char * str, int maxlen, char * devt)
+ {
+ 	int fd;
+         int len;
+@@ -181,20 +181,22 @@
+ 	fd = opennode(devt, O_RDONLY);
+ 
+ 	if (fd < 0)
+-                return 0;
++                return 1;
+ 
+ 	if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ 		len = buff[3];
++		if (len >= maxlen)
++			return 1;
+ 		if (len > 0) {
+ 			memcpy(str, buff + 4, len);
+ 			buff[len] = '\0';
+ 		}
+ 		close(fd);
+-		return 1;
++		return 0;
+ 	}
+ 
+ 	closenode(devt, fd);
+-        return 0;
++        return 1;
+ }
+ 
+ static void *
+@@ -358,7 +360,7 @@
+ 			if (pos == BEFOREPG)
+ 				pos = INPG;
+ 
+-			get_serial(pp->serial, pp->dev_t);
++			get_serial(pp->serial, SERIAL_SIZE, pp->dev_t);
+ 			vector_alloc_slot(pathvec);
+ 			vector_set_slot(pathvec, pp);
+ 			debug("store %s [%s]",
+@@ -370,40 +372,40 @@
+ }
+ 
+ static void *
+-find_controler (vector controlers, char * serial)
++find_controller (vector controllers, char * serial)
+ {
+ 	int i;
+-	struct controler * cp;
++	struct controller * cp;
+ 
+-	if (!controlers)
++	if (!controllers)
+ 		return NULL;
+ 
+-	vector_foreach_slot (controlers, cp, i)
++	vector_foreach_slot (controllers, cp, i)
+ 		if (!strncmp(cp->serial, serial, SERIAL_SIZE))
+ 				return cp;
+ 	return NULL;
+ }
+ 
+ static void
+-get_controlers (vector controlers, vector pathvec)
++get_controllers (vector controllers, vector pathvec)
+ {
+ 	int i;
+ 	struct path * pp;
+-	struct controler * cp;
++	struct controller * cp;
+ 	
+-	if (!controlers)
++	if (!controllers)
+ 		return;
+ 
+ 	vector_foreach_slot (pathvec, pp, i) {
+ 		if (!pp || !strlen(pp->serial))
+ 			continue;
+ 		
+-		cp = find_controler(controlers, pp->serial);
++		cp = find_controller(controllers, pp->serial);
+ 
+ 		if (!cp) {
+-			cp = zalloc(sizeof(struct controler));
+-			vector_alloc_slot(controlers);
+-			vector_set_slot(controlers, cp);
++			cp = zalloc(sizeof(struct controller));
++			vector_alloc_slot(controllers);
++			vector_set_slot(controllers, cp);
+ 			strncpy(cp->serial, pp->serial, SERIAL_SIZE);
+ 		}
+ 		cp->path_count++;	
+@@ -411,17 +413,17 @@
+ }
+ 
+ static int
+-get_max_path_count (vector controlers)
++get_max_path_count (vector controllers)
+ {
+ 	int i;
+ 	int max = 0;
+-	struct controler * cp;
++	struct controller * cp;
+ 
+-	if (!controlers)
++	if (!controllers)
+ 		return 0;
+ 
+-	vector_foreach_slot (controlers, cp, i) {
+-		debug("controler %s : %i paths", cp->serial, cp->path_count);
++	vector_foreach_slot (controllers, cp, i) {
++		debug("controller %s : %i paths", cp->serial, cp->path_count);
+ 		if(cp->path_count > max)
+ 			max = cp->path_count;
+ 	}
+@@ -433,9 +435,9 @@
+ main (int argc, char **argv)
+ {
+ 	vector pathvec = NULL;
+-	vector controlers = NULL;
++	vector controllers = NULL;
+ 	struct path * ref_path = NULL;
+-	struct controler * cp = NULL;
++	struct controller * cp = NULL;
+ 	int max_path_count = 0;
+ 
+ 	ref_path = zalloc(sizeof(struct path));
+@@ -449,18 +451,18 @@
+ 	if (optind<argc)
+ 		strncpy(ref_path->dev_t, argv[optind], WORD_SIZE);
+ 
+-	get_serial(ref_path->serial, ref_path->dev_t);
++	get_serial(ref_path->serial, SERIAL_SIZE, ref_path->dev_t);
+ 
+ 	if (!ref_path->serial || !strlen(ref_path->serial))
+ 		exit_tool(0);
+ 
+ 	pathvec = vector_alloc();
+-	controlers = vector_alloc();
++	controllers = vector_alloc();
+ 
+ 	get_paths(pathvec);
+-	get_controlers(controlers, pathvec);
+-	max_path_count = get_max_path_count(controlers);
+-	cp = find_controler(controlers, ref_path->serial);
++	get_controllers(controllers, pathvec);
++	max_path_count = get_max_path_count(controllers);
++	cp = find_controller(controllers, ref_path->serial);
+ 
+ 	if (!cp) {
+ 		debug("no other active path on serial %s\n",
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_hds_modular/Makefile
++++ multipath-tools-0.4.7/path_priority/pp_hds_modular/Makefile
+@@ -0,0 +1,22 @@
++EXEC		= mpath_prio_hds_modular
++BUILD		= glibc
++OBJS		= pp_hds_modular.o
++
++TOPDIR		= ../..
++include $(TOPDIR)/Makefile.inc
++
++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)
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/path_priority/pp_hds_modular/pp_hds_modular.c
++++ multipath-tools-0.4.7/path_priority/pp_hds_modular/pp_hds_modular.c
+@@ -0,0 +1,252 @@
++/*
++ * (C) Copyright HDS GmbH 2006. All Rights Reserved.
++ *
++ * pp_hds_modular.c
++ * Version 1.12
++ *
++ * Prioritizer for multipath tools device mapper and HDS Storage
++ *
++ * Hitachis Modular Storage contains two controllers for redundancy. The
++ * Storage internal LUN (LDEV) will normally allocated via two pathes to the
++ * server (one path per controller). For performance reasons should the server
++ * access to a LDEV only via one controller. The other path to the other
++ * controller is stand-by. It is also possible to allocate more as one path
++ * for a LDEV per controller. Here is active/active access allowed. The other
++ * pathes via the other controller are stand-by.
++ * 
++ * This prioritizer checks with inquiry commands the represented LDEV and
++ * Controller number and gives back a priority followed by this scheme :
++ *
++ * CONTROLLER ODD  and LDEV  ODD: PRIORITY 1
++ * CONTROLLER ODD  and LDEV EVEN: PRIORITY 0
++ * CONTROLLER EVEN and LDEV  ODD: PRIORITY 0
++ * CONTROLLER EVEN and LDEV EVEN: PRIORITY 1
++ *
++ * In the storage you can define for each LDEV a owner controller. If the
++ * server makes IOs via the other controller the storage will switch the
++ * ownership automatically. In this case you can see in the storage that the
++ * current controller is different from the default controller, but this is
++ * absolutely no problem.
++ *
++ * With this prioritizer it is possible to establish a static load balancing.
++ * Half of the LUNs are accessed via one HBA/storage controller and the other
++ * half via the other HBA/storage controller.
++ *
++ * In cluster environmemnts (RAC) it also guarantees that all cluster nodes
++ * have access to the LDEVs via the same controller.
++ * 
++ * You can run the prioritizer manually in verbose mode :
++ * # pp_hds_modular -v 8:224
++ * VENDOR:  HITACHI
++ * PRODUCT: DF600F-CM
++ * SERIAL:  0x0105
++ * LDEV:    0x00C6
++ * CTRL:    1
++ * PORT:    B
++ * CTRL ODD, LDEV EVEN, PRIO 0
++ *
++ * The items VENDOR and PRODUCT helps you to make the correct entries in file
++ * /etc/multipath.conf :
++ * # cat /etc/multipath.conf
++ * ...
++ * devices {
++ *        device {
++ *                vendor                  "HITACHI"
++ *                product                 "DF600F"
++ *                path_grouping_policy    group_by_prio
++ *                prio_callout            "/sbin/pp_hds_modular %d"
++ *                path_checker            readsector0
++ *                getuid_callout          "/sbin/scsi_id -g -u -s /block/%n"
++ *                failback                immediate
++ *        }
++ *        device {
++ *                vendor                  "HITACHI"
++ *                product                 "DF600F-CM"
++ *                path_grouping_policy    group_by_prio
++ *                prio_callout            "/sbin/pp_hds_modular %d"
++ *                path_checker            readsector0
++ *                getuid_callout          "/sbin/scsi_id -g -u -s /block/%n"
++ *                failback                immediate
++ *
++ *
++ * Author: Matthias Rudolph <matthias.rudolph at hds.com>
++ *
++ * This file is released under the GPL.
++ *
++ */
++
++#include <unistd.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/ioctl.h>
++#include <stdlib.h>
++#include <libdevmapper.h>
++#include <memory.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <scsi/sg.h> /* take care: fetches glibc's /usr/include/scsi/sg.h */
++
++#define INQ_REPLY_LEN 255
++#define INQ_CMD_CODE 0x12
++#define INQ_CMD_LEN 6
++#define FILE_NAME_SIZE 255
++#define safe_sprintf(var, format, args...)	\
++	snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
++#define safe_snprintf(var, size, format, args...)      \
++	snprintf(var, size, format, ##args) >= size
++
++int verbose;
++
++int hds_modular_prio(char * major_minor)
++{
++	int sg_fd, k, i;
++	char vendor[32];
++	char product[32];
++	char serial[32];
++	char ldev[32];
++	char ctrl[32];
++	char port[32];
++	char devpath[FILE_NAME_SIZE];
++	unsigned int major;
++	unsigned int minor;
++	unsigned char inqCmdBlk[INQ_CMD_LEN] = 
++		{INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0};
++	unsigned char inqBuff[INQ_REPLY_LEN];
++	unsigned char sense_buffer[32];
++	sg_io_hdr_t io_hdr;
++
++	sscanf(major_minor, "%u:%u", &major, &minor);
++	memset(devpath, 0, FILE_NAME_SIZE);
++
++	if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
++			 major, minor))
++		exit(1);
++
++	unlink (devpath);
++	mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor));
++
++	if ((sg_fd = open(devpath, O_RDONLY)) < 0) exit(1);
++	if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
++		exit(1);
++
++	memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
++	io_hdr.interface_id = 'S';
++	io_hdr.cmd_len = sizeof(inqCmdBlk);
++	io_hdr.mx_sb_len = sizeof(sense_buffer);
++	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
++	io_hdr.dxfer_len = INQ_REPLY_LEN;
++	io_hdr.dxferp = inqBuff;
++	io_hdr.cmdp = inqCmdBlk;
++	io_hdr.sbp = sense_buffer;
++	io_hdr.timeout = 2000;     /* TimeOut = 2 seconds */
++
++        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) exit(1);
++	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) exit(1);
++
++	for (i = 0; i <  8 ; i++) vendor[i]  = inqBuff[i+8];
++	vendor[8] = 0;
++	for (i = 0; i < 16 ; i++) product[i] = inqBuff[i+16];
++	product[16] = 0;
++	for (i = 0; i <  4 ; i++) serial[i]  = inqBuff[i+40];
++	serial[4] = 0;
++	for (i = 0; i <  4 ; i++) ldev[i]    = inqBuff[i+44];
++	ldev[4] = 0;
++	ctrl[0] = inqBuff[49];
++	ctrl[1] = 0;
++	port[0] = inqBuff[50];
++	port[1] = 0;
++
++	close(sg_fd);
++
++	if (1 == verbose) {
++		printf("VENDOR:  %s\n", vendor);
++		printf("PRODUCT: %s\n", product);
++		printf("SERIAL:  0x%s\n", serial);
++		printf("LDEV:    0x%s\n", ldev);
++		printf("CTRL:    %s\n", ctrl);
++		printf("PORT:    %s\n", port);
++	}
++	switch( ctrl[0] ) {
++		case '0': case '2': case '4': case '6': case '8':
++			switch( ldev[3] ) {
++				case '0': case '2': case '4': case '6':
++				case '8': case 'A': case 'C': case 'E':
++					if (1 == verbose)
++						printf("CTRL EVEN, LDEV EVEN, "
++						       "PRIO 1\n");
++					return 1;
++					break;
++				case '1': case '3': case '5': case '7':
++				case '9': case 'B': case 'D': case 'F':
++					if (1 == verbose)
++						printf("CTRL EVEN, LDEV ODD, "
++						       "PRIO 0\n");
++					return 0;
++					break;
++
++			}
++		case '1': case '3': case '5': case '7': case '9':
++			switch( ldev[3] ) {
++				case '0': case '2': case '4': case '6':
++				case '8': case 'A': case 'C': case 'E':
++					if (1 == verbose)
++						printf("CTRL ODD, LDEV EVEN, "
++						       "PRIO 0\n");
++					return 0;
++					break;
++				case '1': case '3': case '5': case '7':
++				case '9': case 'B': case 'D': case 'F':
++					if (1 == verbose)
++						printf("CTRL ODD, LDEV ODD, "
++						       "PRIO 1\n");
++					return 1;
++					break;
++			}
++	}
++	exit(1);
++}
++
++void print_help(void)
++{
++	printf("Usage:       "
++			"pp_hds_modular [-v] <device_major:device_minor>\n");
++	printf("Option:      "
++			"-v verbose mode\n");
++	printf("Description: "
++			"Prioritizer for Multipath Tools and HDS Storage\n");
++	printf("Version:     "
++			"1.12\n");
++	printf("Author:      "
++			"Matthias Rudolph <matthias.rudolph at hds.com>\n");
++	return;
++}
++
++int main(int argc, char * argv[])
++{
++	int prio;
++
++	if (2 == argc) {
++		if (0 == strcmp(argv[1], "-h")) {
++			print_help();
++			exit(0);
++		}
++		else {
++			verbose = 0;
++			prio = hds_modular_prio(argv[1]);
++			printf("%d\n", prio);
++			exit(0);
++		}
++	}
++
++	if ((3 == argc) && (0 == strcmp(argv[1], "-v"))) {
++		verbose = 1;
++		prio = hds_modular_prio(argv[2]);
++		printf("%d\n", prio);
++		exit(0);
++	}
++	print_help();
++	exit(1);
++}
++
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/Makefile
++++ multipath-tools-0.4.7/libmultipath/Makefile
+@@ -6,7 +6,7 @@
+ 
+ include ../Makefile.inc
+ 
+-CFLAGS = -I$(checkersdir)
++CFLAGS += -I$(checkersdir)
+ 
+ OBJS = memory.o parser.o vector.o devmapper.o callout.o \
+        hwtable.o blacklist.o util.o dmparser.o config.o \
+@@ -18,6 +18,7 @@
+ PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
+ 
+ ifeq ($(strip $(DAEMON)),1)
++	OBJS += lock.o waiter.o
+ 	CFLAGS += -DDAEMON
+ 	CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
+ else
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/callout.c
++++ multipath-tools-0.4.7/libmultipath/callout.c
+@@ -78,7 +78,7 @@
+ 		/* dup write side of pipe to STDOUT */
+ 		dup(fds[1]);
+ 
+-		retval = execv(argv[0], argv);
++		retval = execvp(argv[0], argv);
+ 
+ 		exit(-1);
+ 	case -1:
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/config.c
++++ multipath-tools-0.4.7/libmultipath/config.c
+@@ -28,14 +28,16 @@
+ 	regex_t vre, pre;
+ 
+ 	vector_foreach_slot (hwtable, hwe, i) {
+-		if (regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
++		if (hwe->vendor &&
++		    regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
+ 			break;
+-		if (regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
++		if (hwe->product &&
++		    regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
+ 			regfree(&vre);
+ 			break;
+ 		}
+-		if (!regexec(&vre, vendor, 0, NULL, 0) &&
+-		    !regexec(&pre, product, 0, NULL, 0))
++		if ((!hwe->vendor || !regexec(&vre, vendor, 0, NULL, 0)) &&
++		    (!hwe->product || !regexec(&pre, product, 0, NULL, 0)))
+ 			ret = hwe;
+ 		
+ 		regfree(&pre);
+@@ -305,7 +307,7 @@
+ 	free_blacklist_device(conf->blist_device);
+ 	free_mptable(conf->mptable);
+ 	free_hwtable(conf->hwtable);
+-
++	free_keywords(conf->keywords);
+ 	FREE(conf);
+ }
+ 
+@@ -332,6 +334,7 @@
+ 	 * read the config file
+ 	 */
+ 	if (filepresent(file)) {
++		set_current_keywords(&conf->keywords);
+ 		if (init_data(file, init_keywords)) {
+ 			condlog(0, "error parsing config file");
+ 			goto out;
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/config.h
++++ multipath-tools-0.4.7/libmultipath/config.h
+@@ -48,7 +48,7 @@
+ 	int with_sysfs;
+ 	int pgpolicy;
+ 	struct checker * checker;
+-	int dev_type;
++	enum devtypes dev_type;
+ 	int minio;
+ 	int checkint;
+ 	int max_checkint;
+@@ -67,6 +67,7 @@
+ 	char * hwhandler;
+ 	char * bindings_file;
+ 
++	vector keywords;
+ 	vector mptable;
+ 	vector hwtable;
+ 
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/configure.c
++++ multipath-tools-0.4.7/libmultipath/configure.c
+@@ -145,11 +145,6 @@
+ 			mpp->action = ACT_RENAME;
+ 			return;
+ 		}
+-		else {
+-			condlog(3, "%s: set ACT_CREATE (map does not exist)",
+-				mpp->alias);
+-			mpp->action = ACT_CREATE;
+-		}
+ 		mpp->action = ACT_CREATE;
+ 		condlog(3, "%s: set ACT_CREATE (map does not exist)",
+ 			mpp->alias);
+@@ -286,11 +281,13 @@
+ 
+ /*
+  * 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.
+  */
++#define DOMAP_RETRY	-1
++#define DOMAP_FAIL	0
++#define DOMAP_OK	1
++#define DOMAP_EXIST	2
++#define DOMAP_DRY	3
++
+ extern int
+ domap (struct multipath * mpp)
+ {
+@@ -299,15 +296,15 @@
+ 	/*
+ 	 * last chance to quit before touching the devmaps
+ 	 */
+-	if (conf->dry_run) {
++	if (conf->dry_run && mpp->action != ACT_NOTHING) {
+ 		print_multipath_topology(mpp, conf->verbosity);
+-		return 0;
++		return DOMAP_DRY;
+ 	}
+ 
+ 	switch (mpp->action) {
+ 	case ACT_REJECT:
+ 	case ACT_NOTHING:
+-		return 2;
++		return DOMAP_EXIST;
+ 
+ 	case ACT_SWITCHPG:
+ 		dm_switchgroup(mpp->alias, mpp->bestpg);
+@@ -317,13 +314,13 @@
+ 		 * retry.
+ 		 */
+ 		reinstate_paths(mpp);
+-		return 2;
++		return DOMAP_EXIST;
+ 
+ 	case ACT_CREATE:
+ 		if (lock_multipath(mpp, 1)) {
+ 			condlog(3, "%s: failed to create map (in use)",
+ 				mpp->alias);
+-			return -1;
++			return DOMAP_RETRY;
+ 		}
+ 		dm_shut_log();
+ 
+@@ -377,9 +374,9 @@
+ 		condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
+                         mpp->size, DEFAULT_TARGET, mpp->params);
+ #endif
++		return DOMAP_OK;
+ 	}
+-
+-	return r;
++	return DOMAP_FAIL;
+ }
+ 
+ static int
+@@ -486,19 +483,18 @@
+ 
+ 		r = domap(mpp);
+ 
+-		if (!r) {
+-			condlog(3, "%s: domap (%u) failure "
+-				   "for create/reload map",
+-				mpp->alias, r);
+-			remove_map(mpp, vecs, NULL, 0);
+-			continue;
+-		}
+-		else if (r < 0) {
++		if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
+ 			condlog(3, "%s: domap (%u) failure "
+ 				   "for create/reload map",
+ 				mpp->alias, r);
+-			return r;
++			if (r == DOMAP_FAIL) {
++				remove_map(mpp, vecs, NULL, 0);
++				continue;
++			} else /* if (r == DOMAP_RETRY) */
++				return r;
+ 		}
++		if (r == DOMAP_DRY)
++			continue;
+ 
+ 		if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ 			if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+@@ -547,11 +543,11 @@
+ }
+ 
+ extern char *
+-get_refwwid (char * dev, int dev_type, vector pathvec)
++get_refwwid (char * dev, enum devtypes dev_type, vector pathvec)
+ {
+ 	struct path * pp;
+ 	char buff[FILE_NAME_SIZE];
+-	char * refwwid;
++	char * refwwid = NULL;
+ 
+ 	if (dev_type == DEV_NONE)
+ 		return NULL;
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/configure.h
++++ multipath-tools-0.4.7/libmultipath/configure.h
+@@ -25,5 +25,5 @@
+ int domap (struct multipath * mpp);
+ int reinstate_paths (struct multipath *mpp);
+ int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid);
+-char * get_refwwid (char * dev, int dev_type, vector pathvec);
++char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec);
+ 
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/debug.c
++++ multipath-tools-0.4.7/libmultipath/debug.c
+@@ -29,17 +29,16 @@
+ 			struct tm *tb = localtime(&t);
+ 			char buff[16];
+ 			
+-			strftime(buff, 16, "%b %d %H:%M:%S", tb); 
++			strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
++			buff[sizeof(buff)-1] = '\0';
+ 
+ 			fprintf(stdout, "%s | ", buff);
+ 			vfprintf(stdout, fmt, ap);
+-			fprintf(stdout, "\n");
+ 		}
+ 		else
+ 			log_safe(prio + 3, fmt, ap);
+ #else
+ 		vfprintf(stdout, fmt, ap);
+-		fprintf(stdout, "\n");
+ #endif
+ 	}
+ 	va_end(ap);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/debug.h
++++ multipath-tools-0.4.7/libmultipath/debug.h
+@@ -11,11 +11,11 @@
+ int logsink;
+ 
+ #define condlog(prio, fmt, args...) \
+-	dlog(logsink, prio, fmt, ##args)
++	dlog(logsink, prio, fmt "\n", ##args)
+ 
+ #else /* DAEMON */
+ 
+ #define condlog(prio, fmt, args...) \
+-	dlog(0, prio, fmt, ##args)
++	dlog(0, prio, fmt "\n", ##args)
+ 
+ #endif /* DAEMON */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/devmapper.c
++++ multipath-tools-0.4.7/libmultipath/devmapper.c
+@@ -11,6 +11,7 @@
+ #include <ctype.h>
+ #include <linux/kdev_t.h>
+ #include <unistd.h>
++#include <errno.h>
+ 
+ #include <checkers.h>
+ 
+@@ -23,6 +24,10 @@
+ #define MAX_WAIT 5
+ #define LOOPS_PER_SEC 5
+ 
++#define UUID_PREFIX "mpath-"
++#define UUID_PREFIX_LEN 6
++
++
+ static void
+ dm_dummy_log (int level, const char *file, int line, const char *f, ...)
+ {
+@@ -113,6 +118,7 @@
+ 	   const char *params, unsigned long long size, const char *uuid) {
+ 	int r = 0;
+ 	struct dm_task *dmt;
++	char *prefixed_uuid = NULL;
+ 
+ 	if (!(dmt = dm_task_create (task)))
+ 		return 0;
+@@ -123,13 +129,26 @@
+ 	if (!dm_task_add_target (dmt, 0, size, target, params))
+ 		goto addout;
+ 
+-	if (uuid && !dm_task_set_uuid(dmt, uuid))
+-		goto addout;
++	if (uuid){
++		prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
++		if (!prefixed_uuid) {
++			condlog(0, "cannot create prefixed uuid : %s\n",
++				strerror(errno));
++			goto addout;
++		}
++		sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
++		if (!dm_task_set_uuid(dmt, prefixed_uuid))
++			goto freeout;
++	}
+ 
+ 	dm_task_no_open_count(dmt);
+ 
+ 	r = dm_task_run (dmt);
+ 
++	freeout:
++	if (prefixed_uuid)
++		free(prefixed_uuid);
++
+ 	addout:
+ 	dm_task_destroy (dmt);
+ 	return r;
+@@ -215,8 +234,12 @@
+                 goto uuidout;
+ 
+ 	uuidtmp = dm_task_get_uuid(dmt);
+-	if (uuidtmp)
+-		strcpy(uuid, uuidtmp);
++	if (uuidtmp) {
++		if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
++			strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
++		else
++			strcpy(uuid, uuidtmp);
++	}
+ 	else
+ 		uuid[0] = '\0';
+ 
+@@ -591,6 +614,7 @@
+ 				goto out1;
+ 
+ 			dm_get_uuid(names->name, mpp->wwid);
++			dm_get_info(names->name, &mpp->dmi);
+ 		}
+ 
+ 		if (!vector_alloc_slot(mp))
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/discovery.c
++++ multipath-tools-0.4.7/libmultipath/discovery.c
+@@ -165,7 +165,7 @@
+ 		goto out; \
+ \
+ 	strncpy(buff, attr->value, attr->len - 1); \
+-	buff[attr->len - 1] = '\0'; \
++	strchop(buff); \
+ 	sysfs_close_attribute(attr); \
+ 	return 0; \
+ out: \
+@@ -237,7 +237,7 @@
+ 	struct dlist * ls;
+ 	char attr_path[FILE_NAME_SIZE];
+ 	char block_path[FILE_NAME_SIZE];
+-	struct sysfs_attribute * attr;
++	struct sysfs_attribute * attr = NULL;
+ 	struct sysfs_class * class;
+ 	struct sysfs_class_device * dev;
+ 
+@@ -339,24 +339,26 @@
+         return -1;
+ }
+ 
+-int
+-get_serial (char * str, int fd)
++static int
++get_serial (char * str, int maxlen, int fd)
+ {
+         int len = 0;
+         char buff[MX_ALLOC_LEN + 1] = {0};
+ 
+ 	if (fd < 0)
+-                return 0;
++                return 1;
+ 
+ 	if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ 		len = buff[3];
++		if (len >= maxlen)
++			return 1;
+ 		if (len > 0) {
+ 			memcpy(str, buff + 4, len);
+ 			str[len] = '\0';
+ 		}
+-		return 1;
++		return 0;
+ 	}
+-        return 0;
++        return 1;
+ }
+ 
+ static int
+@@ -597,7 +599,7 @@
+ scsi_ioctl_pathinfo (struct path * pp, int mask)
+ {
+ 	if (mask & DI_SERIAL) {
+-		get_serial(pp->serial, pp->fd);
++		get_serial(pp->serial, SERIAL_SIZE, pp->fd);
+ 		condlog(3, "%s: serial = %s", pp->dev, pp->serial);
+ 	}
+ 
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/discovery.h
++++ multipath-tools-0.4.7/libmultipath/discovery.h
+@@ -5,7 +5,6 @@
+ #define INQUIRY_CMDLEN  6
+ #define INQUIRY_CMD     0x12
+ #define SENSE_BUFF_LEN  32
+-#define DEF_TIMEOUT     60000
+ #define RECOVERED_ERROR 0x01
+ #define MX_ALLOC_LEN    255
+ #define TUR_CMD_LEN     6
+@@ -14,6 +13,10 @@
+ #define BLKGETSIZE      _IO(0x12,96)
+ #endif
+ 
++#ifndef DEF_TIMEOUT
++#define DEF_TIMEOUT	300000
++#endif
++
+ /*
+  * exerpt from sg_err.h
+  */
+@@ -30,7 +33,6 @@
+ int path_discovery (vector pathvec, struct config * conf, int flag);
+ 
+ void basename (char *, char *);
+-int get_serial (char * buff, int fd);
+ int do_tur (char *);
+ int devt2devname (char *, char *);
+ int pathinfo (struct path *, vector hwtable, int mask);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/hwtable.c
++++ multipath-tools-0.4.7/libmultipath/hwtable.c
+@@ -12,13 +12,34 @@
+  * Tuning suggestions on these parameters should go to
+  * dm-devel at redhat.com
+  * 
+- * You are welcome to claim maintainership over a controler
++ * You are welcome to claim maintainership over a controller
+  * family. Please mail the currently enlisted maintainer and
+  * the upstream package maintainer.
+  */
+ static struct hwentry default_hw[] = {
+ 	/*
+-	 * StorageWorks controler family
++	 * Apple controller family
++	 *
++	 * Maintainer : Shyam Sundar
++	 * Mail : g.shyamsundar at yahoo.co.in
++	 */
++	{
++		.vendor        = "APPLE*",
++		.product       = "Xserve RAID ",
++		.getuid        = DEFAULT_GETUID,
++		.getprio       = NULL,
++		.features      = DEFAULT_FEATURES,
++		.hwhandler     = DEFAULT_HWHANDLER,
++		.selector      = DEFAULT_SELECTOR,
++		.pgpolicy      = MULTIBUS,
++		.pgfailback    = FAILBACK_UNDEF,
++		.rr_weight     = RR_WEIGHT_NONE,
++		.no_path_retry = NO_PATH_RETRY_UNDEF,
++		.minio         = DEFAULT_MINIO,
++		.checker_name  = DEFAULT_CHECKER,
++	},
++	/*
++	 * StorageWorks controller family
+ 	 *
+ 	 * Maintainer : Christophe Varoqui
+ 	 * Mail : christophe.varoqui at free.fr
+@@ -70,22 +91,7 @@
+ 	},
+ 	{
+ 		.vendor        = "HP",
+-		.product       = "HSV2*",
+-		.getuid        = DEFAULT_GETUID,
+-		.getprio       = NULL,
+-		.features      = DEFAULT_FEATURES,
+-		.hwhandler     = DEFAULT_HWHANDLER,
+-		.selector      = DEFAULT_SELECTOR,
+-		.pgpolicy      = MULTIBUS,
+-		.pgfailback    = FAILBACK_UNDEF,
+-		.rr_weight     = RR_WEIGHT_NONE,
+-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+-		.minio         = DEFAULT_MINIO,
+-		.checker_name  = READSECTOR0,
+-	},
+-	{
+-		.vendor        = "HP",
+-		.product       = "DF[456]00",
++		.product       = "{HSV2*,A6189A}",
+ 		.getuid        = DEFAULT_GETUID,
+ 		.getprio       = NULL,
+ 		.features      = DEFAULT_FEATURES,
+@@ -99,7 +105,7 @@
+ 		.checker_name  = READSECTOR0,
+ 	},
+ 	/*
+-	 * DDN controler family
++	 * DDN controller family
+ 	 *
+ 	 * Maintainer : Christophe Varoqui
+ 	 * Mail : christophe.varoqui at free.fr
+@@ -120,7 +126,7 @@
+ 		.checker_name  = READSECTOR0,
+ 	},
+ 	/*
+-	 * EMC / Clariion controler family
++	 * EMC / Clariion controller family
+ 	 *
+ 	 * Maintainer : Edward Goggin, EMC
+ 	 * Mail : egoggin at emc.com
+@@ -145,7 +151,7 @@
+ 		.product       = "*",
+ 		.bl_product    = "LUNZ",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_emc /dev/%n",
++		.getprio       = "mpath_prio_emc /dev/%n",
+ 		.features      = "1 queue_if_no_path",
+ 		.hwhandler     = "1 emc",
+ 		.selector      = DEFAULT_SELECTOR,
+@@ -157,7 +163,7 @@
+ 		.checker_name  = EMC_CLARIION,
+ 	},
+ 	/*
+-	 * Fujitsu controler family
++	 * Fujitsu controller family
+ 	 *
+ 	 * Maintainer : Christophe Varoqui
+ 	 * Mail : christophe.varoqui at free.fr
+@@ -178,14 +184,14 @@
+ 		.checker_name  = READSECTOR0,
+ 	},
+ 	/*
+-	 * Hitachi controler family
++	 * Hitachi controller family
+ 	 *
+-	 * Maintainer : Christophe Varoqui
+-	 * Mail : christophe.varoqui at free.fr
++	 * Maintainer : Matthias Rudolph
++	 * Mail : matthias.rudolph at hds.com
+ 	 */
+ 	{
+-		.vendor        = "HITACHI",
+-		.product       = "{A6189A,OPEN-}",
++		.vendor        = "{HITACHI,HP}",
++		.product       = "OPEN-*",
+ 		.getuid        = DEFAULT_GETUID,
+ 		.getprio       = NULL,
+ 		.features      = DEFAULT_FEATURES,
+@@ -198,10 +204,25 @@
+ 		.minio         = DEFAULT_MINIO,
+ 		.checker_name  = READSECTOR0,
+ 	},
++	{
++		.vendor        = "HITACHI",
++		.product       = "DF*",
++		.getuid        = DEFAULT_GETUID,
++		.getprio       = "/sbin/mpath_prio_hds_modular %d",
++		.features      = DEFAULT_FEATURES,
++		.hwhandler     = DEFAULT_HWHANDLER,
++		.selector      = DEFAULT_SELECTOR,
++		.pgpolicy      = GROUP_BY_PRIO,
++		.pgfailback    = -FAILBACK_IMMEDIATE,
++		.rr_weight     = RR_WEIGHT_NONE,
++		.no_path_retry = NO_PATH_RETRY_UNDEF,
++		.minio         = DEFAULT_MINIO,
++		.checker_name  = READSECTOR0,
++	},
+ 	/*
+-	 * IBM controler family
++	 * IBM controller family
+ 	 *
+-	 * Maintainer : Hannes Reinecke, Suse
++	 * Maintainer : Hannes Reinecke, SuSE
+ 	 * Mail : hare at suse.de
+ 	 */
+ 	{
+@@ -224,7 +245,7 @@
+ 		.vendor        = "IBM",
+ 		.product       = "1742",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
++		.getprio       = "mpath_prio_tpc /dev/%n",
+ 		.features      = DEFAULT_FEATURES,
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+@@ -254,7 +275,7 @@
+ 	{
+ 		/* IBM ESS F20 aka Shark */
+ 		.vendor        = "IBM",
+-		.product       = "2105F20",
++		.product       = "2105{800,F20}",
+ 		.getuid        = DEFAULT_GETUID,
+ 		.getprio       = NULL,
+ 		.features      = "1 queue_if_no_path",
+@@ -272,7 +293,7 @@
+ 		.vendor        = "IBM",
+ 		.product       = "{1750500,2145}",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
++		.getprio       = "mpath_prio_alua /dev/%n",
+ 		.features      = "1 queue_if_no_path",
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+@@ -303,7 +324,7 @@
+ 		/* IBM S/390 ECKD DASD */
+ 		.vendor        = "IBM",
+ 		.product       = "S/390 DASD ECKD",
+-		.getuid        = "/sbin/dasdview -j /dev/%n",
++		.getuid        = "/sbin/dasd_id /dev/%n",
+ 		.getprio       = NULL,
+ 		.features      = DEFAULT_FEATURES,
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+@@ -315,29 +336,50 @@
+ 		.minio         = DEFAULT_MINIO,
+ 		.checker_name  = DIRECTIO,
+ 	},
+-	/*
+-	 * NETAPP controler family
++ 	/*
++	 * NETAPP controller family
+ 	 *
+-	 * Maintainer : Igor Feoktistov
+-	 * Mail : igorf at netapp.com
++	 * Maintainer : Dave Wysochanski
++	 * Mail : davidw at netapp.com
+ 	 */
+ 	{
+ 		.vendor        = "NETAPP",
+-		.product       = "LUN",
++		.product       = "LUN.*",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_netapp /dev/%n",
++		.getprio       = "mpath_prio_netapp /dev/%n",
+ 		.features      = "1 queue_if_no_path",
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+ 		.pgpolicy      = GROUP_BY_PRIO,
+-		.pgfailback    = FAILBACK_UNDEF,
++		.pgfailback    = -FAILBACK_IMMEDIATE,
+ 		.rr_weight     = RR_WEIGHT_NONE,
+ 		.no_path_retry = NO_PATH_RETRY_UNDEF,
+-		.minio         = DEFAULT_MINIO,
++		.minio         = 128,
++		.checker_name  = READSECTOR0,
++	},
++ 	/*
++	 * IBM NSeries (NETAPP) controller family
++	 *
++	 * Maintainer : Dave Wysochanski
++	 * Mail : davidw at netapp.com
++	 */
++	{
++		.vendor        = "IBM",
++		.product       = "Nseries.*",
++		.getuid        = DEFAULT_GETUID,
++		.getprio       = "mpath_prio_netapp /dev/%n",
++		.features      = "1 queue_if_no_path",
++		.hwhandler     = DEFAULT_HWHANDLER,
++		.selector      = DEFAULT_SELECTOR,
++		.pgpolicy      = GROUP_BY_PRIO,
++		.pgfailback    = -FAILBACK_IMMEDIATE,
++		.rr_weight     = RR_WEIGHT_NONE,
++		.no_path_retry = NO_PATH_RETRY_UNDEF,
++		.minio         = 128,
+ 		.checker_name  = READSECTOR0,
+ 	},
+ 	/*
+-	 * Pillar Data controler family
++	 * Pillar Data controller family
+ 	 *
+ 	 * Maintainer : Christophe Varoqui
+ 	 * Mail : christophe.varoqui at free.fr
+@@ -346,7 +388,7 @@
+ 		.vendor        = "Pillar",
+ 		.product       = "Axiom 500",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_alua %d",
++		.getprio       = "mpath_prio_alua %d",
+ 		.features      = DEFAULT_FEATURES,
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+@@ -382,7 +424,7 @@
+ 		.vendor        = "SGI",
+ 		.product       = "TP9[45]00",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
++		.getprio       = "mpath_prio_tpc /dev/%n",
+ 		.features      = DEFAULT_FEATURES,
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+@@ -403,7 +445,7 @@
+ 		.vendor        = "STK",
+ 		.product       = "OPENstorage D280",
+ 		.getuid        = DEFAULT_GETUID,
+-		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
++		.getprio       = "mpath_prio_tpc /dev/%n",
+ 		.features      = DEFAULT_FEATURES,
+ 		.hwhandler     = DEFAULT_HWHANDLER,
+ 		.selector      = DEFAULT_SELECTOR,
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/lock.c
++++ multipath-tools-0.4.7/libmultipath/lock.c
+@@ -0,0 +1,8 @@
++#include <pthread.h>
++#include "lock.h"
++
++void cleanup_lock (void * data)
++{
++	unlock((pthread_mutex_t *)data);
++}
++
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/lock.h
++++ multipath-tools-0.4.7/libmultipath/lock.h
+@@ -0,0 +1,22 @@
++#ifndef _LOCK_H
++#define _LOCK_H
++
++#ifdef LCKDBG
++#define lock(a) \
++	        fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
++        pthread_mutex_lock(a)
++#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
++
++void cleanup_lock (void * data);
++
++#endif /* _LOCK_H */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/parser.c
++++ multipath-tools-0.4.7/libmultipath/parser.c
+@@ -25,6 +25,13 @@
+ /* local vars */
+ static int sublevel = 0;
+ vector keywords = NULL;
++vector *keywords_addr = NULL;
++
++void set_current_keywords (vector *k)
++{
++	keywords_addr = k;
++	keywords = NULL;
++}
+ 
+ int
+ keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+@@ -53,7 +60,10 @@
+ int
+ install_keyword_root(char *string, int (*handler) (vector))
+ {
+-	return keyword_alloc(keywords, string, handler, NULL);
++	int r = keyword_alloc(keywords, string, handler, NULL);
++	if (!r)
++		*keywords_addr = keywords;
++	return r;
+ }
+ 
+ void
+@@ -100,6 +110,9 @@
+ 	struct keyword *keyword;
+ 	int i;
+ 
++	if (!keywords)
++		return;
++
+ 	for (i = 0; i < VECTOR_SIZE(keywords); i++) {
+ 		keyword = VECTOR_SLOT(keywords, i);
+ 		if (keyword->sub)
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/parser.h
++++ multipath-tools-0.4.7/libmultipath/parser.h
+@@ -76,6 +76,7 @@
+ extern int process_stream(vector keywords);
+ extern int init_data(char *conf_file, void (*init_keywords) (void));
+ extern struct keyword * find_keyword(vector v, char * name);
++void set_current_keywords (vector *k);
+ int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+ 		    void *data);
+ 
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/pgpolicies.h
++++ multipath-tools-0.4.7/libmultipath/pgpolicies.h
+@@ -9,7 +9,7 @@
+ 
+ #define POLICY_NAME_SIZE 32
+ 
+-/* Storage controlers capabilities */
++/* Storage controllers capabilities */
+ enum iopolicies { 
+ 	IOPOLICY_UNDEF,
+ 	FAILOVER,
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/print.c
++++ multipath-tools-0.4.7/libmultipath/print.c
+@@ -13,8 +13,8 @@
+ #include "structs_vec.h"
+ #include "print.h"
+ #include "dmparser.h"
+-#include "configure.h"
+ #include "config.h"
++#include "configure.h"
+ #include "pgpolicies.h"
+ #include "defaults.h"
+ #include "parser.h"
+@@ -52,16 +52,26 @@
+ static int
+ snprint_size (char * buff, size_t len, unsigned long long size)
+ {
+-	if (size < (1 << 11))
+-		return snprintf(buff, len, "%llu kB", size >> 1);
+-	else if (size < (1 << 21))
+-		return snprintf(buff, len, "%llu MB", size >> 11);
+-	else if (size < (1 << 31))
+-		return snprintf(buff, len, "%llu GB", size >> 21);
++	float s = (float)(size >> 1); /* start with KB */
++	char fmt[6] = {};
++	char units[] = {'K','M','G','T','P'};
++	char *u = units;
++	
++	while (s >= 1024 && *u != 'P') {
++		s = s / 1024;
++		u++;
++	}
++	if (s < 10)
++		snprintf(fmt, 6, "%%.1f%c", *u);
+ 	else
+-		return snprintf(buff, len, "%llu TB", size >> 31);
++		snprintf(fmt, 6, "%%.0f%c", *u);
++
++	return snprintf(buff, len, fmt, s);
+ }
+ 
++/*
++ * multipath info printing functions
++ */
+ static int
+ snprint_name (char * buff, size_t len, struct multipath * mpp)
+ {
+@@ -222,6 +232,9 @@
+ 	}
+ }
+ 
++/*
++ * path info printing functions
++ */
+ static int
+ snprint_path_uuid (char * buff, size_t len, struct path * pp)
+ {
+@@ -292,8 +305,8 @@
+ static int
+ snprint_vpr (char * buff, size_t len, struct path * pp)
+ {
+-	return snprintf(buff, len, "%s/%s/%s",
+-		        pp->vendor_id, pp->product_id, pp->rev);
++	return snprintf(buff, len, "%s,%s",
++		        pp->vendor_id, pp->product_id);
+ }
+ 
+ static int
+@@ -496,7 +509,7 @@
+ 	char * f = format; /* format string cursor */
+ 	int fwd;
+ 	struct multipath_data * data;
+-	char buff[MAX_FIELD_LEN];
++	char buff[MAX_FIELD_LEN] = {};
+ 
+ 	do {
+ 		if (!TAIL)
+@@ -515,6 +528,7 @@
+ 		data->snprint(buff, MAX_FIELD_LEN, mpp);
+ 		PRINT(c, TAIL, buff);
+ 		PAD(data->width);
++		buff[0] = '\0';
+ 	} while (*f++);
+ 
+ 	line[c - line - 1] = '\n';
+@@ -631,7 +645,7 @@
+ extern void
+ print_multipath_topology (struct multipath * mpp, int verbosity)
+ {
+-	char buff[MAX_LINE_LEN * MAX_LINES];
++	char buff[MAX_LINE_LEN * MAX_LINES] = {};
+ 
+ 	snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
+ 				   mpp, verbosity);
+@@ -662,7 +676,10 @@
+ 	c += sprintf(c, "%%n");
+ 	
+ 	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
+-		c += sprintf(c, " (%%w)");
++		c += sprintf(c, " (%%w) ");
++
++	c += sprintf(c, "%%d ");
++	c += snprint_vpr(c, 24, first_path(mpp));
+ 
+ 	fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
+ 	if (fwd > len)
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/propsel.c
++++ multipath-tools-0.4.7/libmultipath/propsel.c
+@@ -15,6 +15,7 @@
+ #include "pgpolicies.h"
+ #include "alias.h"
+ #include "defaults.h"
++#include "devmapper.h"
+ 
+ pgpolicyfn *pgpolicies[] = {
+ 	NULL,
+@@ -41,7 +42,7 @@
+ 	}
+ 	if (mp->hwe && mp->hwe->rr_weight) {
+ 		mp->rr_weight = mp->hwe->rr_weight;
+-		condlog(3, "%s: rr_weight = %i (controler setting)",
++		condlog(3, "%s: rr_weight = %i (controller setting)",
+ 			mp->alias, mp->rr_weight);
+ 		return 0;
+ 	}
+@@ -68,7 +69,7 @@
+ 	}
+ 	if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
+ 		mp->pgfailback = mp->hwe->pgfailback;
+-		condlog(3, "%s: pgfailback = %i (controler setting)",
++		condlog(3, "%s: pgfailback = %i (controller setting)",
+ 			mp->alias, mp->pgfailback);
+ 		return 0;
+ 	}
+@@ -112,7 +113,7 @@
+ 		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ 		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+ 				  mp->pgpolicy);
+-		condlog(3, "%s: pgpolicy = %s (controler setting)",
++		condlog(3, "%s: pgpolicy = %s (controller setting)",
+ 			mp->alias, pgpolicy_name);
+ 		return 0;
+ 	}
+@@ -144,7 +145,7 @@
+ 	}
+ 	if (mp->hwe && mp->hwe->selector) {
+ 		mp->selector = mp->hwe->selector;
+-		condlog(3, "%s: selector = %s (controler setting)",
++		condlog(3, "%s: selector = %s (controller setting)",
+ 			mp->alias, mp->selector);
+ 		return 0;
+ 	}
+@@ -164,6 +165,16 @@
+ 		if (conf->user_friendly_names)
+ 			mp->alias = get_user_friendly_alias(mp->wwid,
+ 					conf->bindings_file);
++		if (mp->alias == NULL){
++			char *alias;
++			if ((alias = MALLOC(WWID_SIZE)) != NULL){
++				if (dm_get_name(mp->wwid, DEFAULT_TARGET,
++						alias) == 1)
++					mp->alias = alias;
++				else
++					FREE(alias);
++			}
++		}
+ 		if (mp->alias == NULL)
+ 			mp->alias = mp->wwid;
+ 	}
+@@ -176,7 +187,7 @@
+ {
+ 	if (mp->hwe && mp->hwe->features) {
+ 		mp->features = mp->hwe->features;
+-		condlog(3, "%s: features = %s (controler setting)",
++		condlog(3, "%s: features = %s (controller setting)",
+ 			mp->alias, mp->features);
+ 		return 0;
+ 	}
+@@ -191,7 +202,7 @@
+ {
+ 	if (mp->hwe && mp->hwe->hwhandler) {
+ 		mp->hwhandler = mp->hwe->hwhandler;
+-		condlog(3, "%s: hwhandler = %s (controler setting)",
++		condlog(3, "%s: hwhandler = %s (controller setting)",
+ 			mp->alias, mp->hwhandler);
+ 		return 0;
+ 	}
+@@ -208,7 +219,7 @@
+ 
+ 	if (pp->hwe && pp->hwe->checker) {
+ 		checker_get(c, pp->hwe->checker);
+-		condlog(3, "%s: path checker = %s (controler setting)",
++		condlog(3, "%s: path checker = %s (controller setting)",
+ 			pp->dev, checker_name(c));
+ 		return 0;
+ 	}
+@@ -229,7 +240,7 @@
+ {
+ 	if (pp->hwe && pp->hwe->getuid) {
+ 		pp->getuid = pp->hwe->getuid;
+-		condlog(3, "%s: getuid = %s (controler setting)",
++		condlog(3, "%s: getuid = %s (controller setting)",
+ 			pp->dev, pp->getuid);
+ 		return 0;
+ 	}
+@@ -250,7 +261,7 @@
+ {
+ 	if (pp->hwe && pp->hwe->getprio) {
+ 		pp->getprio = pp->hwe->getprio;
+-		condlog(3, "%s: getprio = %s (controler setting)",
++		condlog(3, "%s: getprio = %s (controller setting)",
+ 			pp->dev, pp->getprio);
+ 		return 0;
+ 	}
+@@ -276,7 +287,7 @@
+ 	}
+ 	if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ 		mp->no_path_retry = mp->hwe->no_path_retry;
+-		condlog(3, "%s: no_path_retry = %i (controler setting)",
++		condlog(3, "%s: no_path_retry = %i (controller setting)",
+ 			mp->alias, mp->no_path_retry);
+ 		return 0;
+ 	}
+@@ -303,7 +314,7 @@
+ 	}
+ 	if (mp->hwe && mp->hwe->minio) {
+ 		mp->minio = mp->hwe->minio;
+-		condlog(3, "%s: minio = %i (controler setting)",
++		condlog(3, "%s: minio = %i (controller setting)",
+ 			mp->alias, mp->minio);
+ 		return 0;
+ 	}
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/structs.c
++++ multipath-tools-0.4.7/libmultipath/structs.c
+@@ -16,6 +16,7 @@
+ #include "debug.h"
+ #include "structs_vec.h"
+ #include "blacklist.h"
++#include "waiter.h"
+ 
+ struct path *
+ alloc_path (void)
+@@ -365,3 +366,10 @@
+ 
+ 	return count;
+ }
++
++struct path *
++first_path (struct multipath * mpp)
++{
++	struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0);
++	return VECTOR_SLOT(pgp->paths, 0);
++}
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/structs.h
++++ multipath-tools-0.4.7/libmultipath/structs.h
+@@ -1,8 +1,8 @@
+ #ifndef _STRUCTS_H
+ #define _STRUCTS_H
+ 
+-#define WWID_SIZE		64
+-#define SERIAL_SIZE		17
++#define WWID_SIZE		128
++#define SERIAL_SIZE		64
+ #define NODE_NAME_SIZE		19
+ #define PATH_STR_SIZE  		16
+ #define PARAMS_SIZE		1024
+@@ -142,7 +142,7 @@
+ 	struct mpentry * mpe;
+ 	struct hwentry * hwe;
+ 
+-	/* daemon store a data blob for DM event waiter threads */
++	/* threads */
+ 	void * waiter;
+ 
+ 	/* stats */
+@@ -183,10 +183,11 @@
+ 	
+ struct path * find_path_by_devt (vector pathvec, char * devt);
+ struct path * find_path_by_dev (vector pathvec, char * dev);
++struct path * first_path (struct multipath * mpp);
+ 
+ int pathcountgr (struct pathgroup *, int);
+ int pathcount (struct multipath *, int);
+ 
+ char sysfs_path[FILE_NAME_SIZE];
+ 
+-#endif
++#endif /* _STRUCTS_H */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/structs_vec.c
++++ multipath-tools-0.4.7/libmultipath/structs_vec.c
+@@ -14,6 +14,7 @@
+ #include "config.h"
+ #include "propsel.h"
+ #include "discovery.h"
++#include "waiter.h"
+ 
+ 
+ /*
+@@ -58,8 +59,8 @@
+ 
+ 	vector_foreach_slot (pathvec, pp, i) {
+ 		if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
+-			condlog(3, "%s ownership set to %s",
+-				pp->dev_t, mpp->alias);
++			condlog(3, "%s: ownership set to %s",
++				pp->dev, mpp->alias);
+ 			pp->mpp = mpp;
+ 			
+ 			if (!mpp->paths && !(mpp->paths = vector_alloc()))
+@@ -96,7 +97,7 @@
+ 
+ 	vector_foreach_slot (pathvec, pp, i) {
+ 		if (pp->mpp == mpp) {
+-			condlog(4, "%s is orphaned", pp->dev_t);
++			condlog(4, "%s: orphaned", pp->dev);
+ 			orphan_path(pp);
+ 		}
+ 	}
+@@ -382,3 +383,90 @@
+ 	return count;
+ }
+ 
++int update_multipath (struct vectors *vecs, char *mapname)
++{
++	struct multipath *mpp;
++	struct pathgroup  *pgp;
++	struct path *pp;
++	int i, j;
++	int r = 1;
++
++	mpp = find_mp_by_alias(vecs->mpvec, mapname);
++
++	if (!mpp)
++		goto out;
++
++	free_pgvec(mpp->pg, KEEP_PATHS);
++	mpp->pg = NULL;
++
++	if (setup_multipath(vecs, mpp))
++		goto out; /* mpp freed in setup_multipath */
++
++	/*
++	 * compare checkers states with DM states
++	 */
++	vector_foreach_slot (mpp->pg, pgp, i) {
++		vector_foreach_slot (pgp->paths, pp, j) {
++			if (pp->dmstate != PSTATE_FAILED)
++				continue;
++
++			if (pp->state != PATH_DOWN) {
++				int oldstate = pp->state;
++				condlog(2, "%s: mark as failed", pp->dev_t);
++				mpp->stat_path_failures++;
++				pp->state = PATH_DOWN;
++				if (oldstate == PATH_UP ||
++				    oldstate == PATH_GHOST)
++					update_queue_mode_del_path(mpp);
++
++				/*
++				 * if opportune,
++				 * schedule the next check earlier
++				 */
++				if (pp->tick > conf->checkint)
++					pp->tick = conf->checkint;
++			}
++		}
++	}
++	r = 0;
++out:
++	if (r)
++		condlog(0, "failed to update multipath");
++	return r;
++}
++
++/*
++ * 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
++ */
++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->stat_queueing_timeouts++;
++		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);
++}
++
++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);
++}
++
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/structs_vec.h
++++ multipath-tools-0.4.7/libmultipath/structs_vec.h
+@@ -9,17 +9,6 @@
+ 	vector mpvec;
+ };
+ 
+-#if DAEMON
+-struct event_thread {
+-	struct dm_task *dmt;
+-	pthread_t thread;
+-	int event_nr;
+-	char mapname[WWID_SIZE];
+-	struct vectors *vecs;
+-	struct multipath *mpp;
+-};
+-#endif
+-
+ typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
+ typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
+ 
+@@ -44,5 +33,8 @@
+ 				start_waiter_thread_func *start_waiter);
+ struct multipath * add_map_with_path (struct vectors * vecs,
+ 				struct path * pp, int add_vec);
++int update_multipath (struct vectors *vecs, char *mapname);
++void update_queue_mode_del_path(struct multipath *mpp);
++void update_queue_mode_add_path(struct multipath *mpp);
+ 
+ #endif /* _STRUCTS_VEC_H */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/util.c
++++ multipath-tools-0.4.7/libmultipath/util.c
+@@ -30,6 +30,15 @@
+ }
+ 
+ void
++strchop(char *str)
++{
++	int i;
++
++	for (i=strlen(str)-1; i >=0 && isspace(str[i]); --i) ;
++	str[++i] = '\0';
++}
++
++void
+ basename (char * str1, char * str2)
+ {
+ 	char *p = str1 + (strlen(str1) - 1);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/util.h
++++ multipath-tools-0.4.7/libmultipath/util.h
+@@ -2,6 +2,7 @@
+ #define _UTIL_H
+ 
+ int strcmp_chomp(char *, char *);
++void strchop(char *);
+ void basename (char * src, char * dst);
+ int filepresent (char * run);
+ int get_word (char * sentence, char ** word);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/version.h
++++ multipath-tools-0.4.7/libmultipath/version.h
+@@ -0,0 +1,37 @@
++/*
++ * Soft:        multipath device mapper target autoconfig
++ *
++ * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
++ *
++ * Author:      Christophe Varoqui
++ *
++ *              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.
++ *
++ *              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.
++ *
++ * Copyright (c) 2006 Christophe Varoqui
++ */
++#ifndef _VERSION_H
++#define _VERSION_H
++
++#define VERSION_CODE 0x000407
++#define DATE_CODE    0x030c06
++
++#define PROG    "multipath-tools"
++
++#define MULTIPATH_VERSION(version)      \
++	(version >> 16) & 0xFF,         \
++	(version >> 8) & 0xFF,          \
++	version & 0xFF
++
++#define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n",  \
++		MULTIPATH_VERSION(VERSION_CODE),                \
++		MULTIPATH_VERSION(DATE_CODE)
++
++#endif /* _VERSION_H */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/waiter.c
++++ multipath-tools-0.4.7/libmultipath/waiter.c
+@@ -0,0 +1,234 @@
++/*
++ * Copyright (c) 2004, 2005 Christophe Varoqui
++ * Copyright (c) 2005 Kiyoshi Ueda, NEC
++ * Copyright (c) 2005 Benjamin Marzinski, Redhat
++ * Copyright (c) 2005 Edward Goggin, EMC
++ */
++#include <unistd.h>
++#include <libdevmapper.h>
++#include <sys/mman.h>
++#include <pthread.h>
++#include <signal.h>
++
++#include "vector.h"
++#include "memory.h"
++#include "checkers.h"
++#include "structs.h"
++#include "structs_vec.h"
++#include "devmapper.h"
++#include "debug.h"
++#include "lock.h"
++#include "waiter.h"
++
++struct event_thread *alloc_waiter (void)
++{
++
++	struct event_thread *wp;
++
++	wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
++
++	return wp;
++}
++
++void free_waiter (void *data)
++{
++	struct event_thread *wp = (struct event_thread *)data;
++
++	/*
++	 * indicate in mpp that the wp is already freed storage
++	 */
++	lock(wp->vecs->lock);
++
++	if (wp->mpp)
++		/*
++		 * be careful, mpp may already be freed -- null if so
++		 */
++		wp->mpp->waiter = NULL;
++	else
++		condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
++
++	unlock(wp->vecs->lock);
++
++	if (wp->dmt)
++		dm_task_destroy(wp->dmt);
++
++	FREE(wp);
++}
++
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
++{
++	struct event_thread *wp = (struct event_thread *)mpp->waiter;
++	
++	if (!wp) {
++		condlog(3, "%s: no waiter thread", mpp->alias);
++		return;
++	}
++	condlog(2, "%s: stop event checker thread", wp->mapname);
++	pthread_kill((pthread_t)wp->thread, SIGUSR1);
++}
++
++static sigset_t unblock_signals(void)
++{
++	sigset_t set, old;
++
++	sigemptyset(&set);
++	sigaddset(&set, SIGHUP);
++	sigaddset(&set, SIGUSR1);
++	pthread_sigmask(SIG_UNBLOCK, &set, &old);
++	return old;
++}
++
++/*
++ * returns the reschedule delay
++ * negative means *stop*
++ */
++int waiteventloop (struct event_thread *waiter)
++{
++	sigset_t set;
++	int event_nr;
++	int r;
++
++	if (!waiter->event_nr)
++		waiter->event_nr = dm_geteventnr(waiter->mapname);
++
++	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
++		condlog(0, "%s: devmap event #%i dm_task_create error",
++				waiter->mapname, waiter->event_nr);
++		return 1;
++	}
++
++	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
++		condlog(0, "%s: devmap event #%i dm_task_set_name error",
++				waiter->mapname, waiter->event_nr);
++		dm_task_destroy(waiter->dmt);
++		return 1;
++	}
++
++	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
++						      waiter->event_nr)) {
++		condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
++				waiter->mapname, waiter->event_nr);
++		dm_task_destroy(waiter->dmt);
++		return 1;
++	}
++
++	dm_task_no_open_count(waiter->dmt);
++	
++	/* accept wait interruption */
++	set = unblock_signals();
++
++	/* 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);
++	//dm_restore_log();
++
++	if (!r) /* wait interrupted by signal */
++		return -1;
++
++	dm_task_destroy(waiter->dmt);
++	waiter->dmt = NULL;
++	waiter->event_nr++;
++
++	/*
++	 * upon event ...
++	 */
++	while (1) {
++		condlog(3, "%s: devmap event #%i",
++				waiter->mapname, waiter->event_nr);
++
++		/*
++		 * event might be :
++		 *
++		 * 1) a table reload, which means our mpp structure is
++		 *    obsolete : refresh it through update_multipath()
++		 * 2) a path failed by DM : mark as such through
++		 *    update_multipath()
++		 * 3) map has gone away : stop the thread.
++		 * 4) a path reinstate : nothing to do
++		 * 5) a switch group : nothing to do
++		 */
++		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 */
++
++		event_nr = dm_geteventnr(waiter->mapname);
++
++		if (waiter->event_nr == event_nr)
++			return 1; /* upon problem reschedule 1s later */
++
++		waiter->event_nr = event_nr;
++	}
++	return -1; /* never reach there */
++}
++
++void *waitevent (void *et)
++{
++	int r;
++	struct event_thread *waiter;
++
++	mlockall(MCL_CURRENT | MCL_FUTURE);
++
++	waiter = (struct event_thread *)et;
++	pthread_cleanup_push(free_waiter, et);
++
++	while (1) {
++		r = waiteventloop(waiter);
++
++		if (r < 0)
++			break;
++
++		sleep(r);
++	}
++
++	pthread_cleanup_pop(1);
++	return NULL;
++}
++
++int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
++{
++	pthread_attr_t attr;
++	struct event_thread *wp;
++
++	if (!mpp)
++		return 0;
++
++	if (pthread_attr_init(&attr))
++		goto out;
++
++	pthread_attr_setstacksize(&attr, 32 * 1024);
++	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++
++	wp = alloc_waiter();
++
++	if (!wp)
++		goto out;
++
++	mpp->waiter = (void *)wp;
++	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
++	wp->vecs = vecs;
++	wp->mpp = mpp;
++
++	if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
++		condlog(0, "%s: cannot create event checker", wp->mapname);
++		goto out1;
++	}
++	condlog(2, "%s: event checker started", wp->mapname);
++
++	return 0;
++out1:
++	free_waiter(wp);
++	mpp->waiter = NULL;
++out:
++	condlog(0, "failed to start waiter thread");
++	return 1;
++}
++
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libmultipath/waiter.h
++++ multipath-tools-0.4.7/libmultipath/waiter.h
+@@ -0,0 +1,23 @@
++#ifndef _WAITER_H
++#define _WAITER_H
++
++#if DAEMON
++
++struct event_thread {
++	struct dm_task *dmt;
++	pthread_t thread;
++	int event_nr;
++	char mapname[WWID_SIZE];
++	struct vectors *vecs;
++	struct multipath *mpp;
++};
++
++struct event_thread * alloc_waiter (void);
++void free_waiter (void *data);
++void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
++int waiteventloop (struct event_thread *waiter);
++void *waitevent (void *et);
++
++#endif /* DAEMON */
++#endif /* _WAITER_H */
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipath/main.c
++++ multipath-tools-0.4.7/multipath/main.c
+@@ -46,8 +46,7 @@
+ #include <alias.h>
+ #include <configure.h>
+ #include <pgpolicies.h>
+-
+-#include "main.h"
++#include <version.h>
+ 
+ static int
+ filter_pathvec (vector pathvec, char * refwwid)
+@@ -305,7 +304,7 @@
+ 	int arg;
+ 	extern char *optarg;
+ 	extern int optind;
+-	int i, r;
++	int i, r = 1;
+ 
+ 	if (getuid() != 0) {
+ 		fprintf(stderr, "need to be root\n");
+@@ -322,7 +321,7 @@
+ 	if (load_config(DEFAULT_CONFIGFILE))
+ 		exit(1);
+ 
+-	while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
++	while ((arg = getopt(argc, argv, ":dl::FfM:v:p:b:")) != EOF ) {
+ 		switch(arg) {
+ 		case 1: printf("optarg : %s\n",optarg);
+ 			break;
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipath/multipath.8
++++ multipath-tools-0.4.7/multipath/multipath.8
+@@ -1,4 +1,4 @@
+-.TH MULTIPATH 8 "February 2004" "" "Linux Administrator's Manual"
++.TH MULTIPATH 8 "July 2006" "" "Linux Administrator's Manual"
+ .SH NAME
+ multipath \- Device mapper target autoconfig
+ .SH SYNOPSIS
+@@ -64,7 +64,7 @@
+ 1 priority group per serial
+ .TP
+ .B group_by_prio
+-1 priority group per priority value. Priorities are determined by callout programs specified as a global, per-controler or per-multipath option in the configuration file
++1 priority group per priority value. Priorities are determined by callout programs specified as a global, per-controller or per-multipath option in the configuration file
+ .TP
+ .B group_by_node_name
+ 1 priority group per target node name. Target node names are fetched in /sys/class/fc_transport/target*/node_name.
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/kpartx/devmapper.c
++++ multipath-tools-0.4.7/kpartx/devmapper.c
+@@ -7,6 +7,10 @@
+ #include <libdevmapper.h>
+ #include <ctype.h>
+ #include <linux/kdev_t.h>
++#include <errno.h>
++
++#define UUID_PREFIX "part%d-"
++#define MAX_PREFIX_LEN 8
+ 
+ extern int
+ dm_prereq (char * str, int x, int y, int z)
+@@ -68,9 +72,10 @@
+ 
+ extern int
+ dm_addmap (int task, const char *name, const char *target,
+-	   const char *params, unsigned long size) {
++	   const char *params, unsigned long size, const char *uuid, int part) {
+ 	int r = 0;
+ 	struct dm_task *dmt;
++	char *prefixed_uuid;
+ 
+ 	if (!(dmt = dm_task_create (task)))
+ 		return 0;
+@@ -81,10 +86,26 @@
+ 	if (!dm_task_add_target (dmt, 0, size, target, params))
+ 		goto addout;
+ 
++	if (task == DM_DEVICE_CREATE && uuid) {
++		prefixed_uuid = malloc(MAX_PREFIX_LEN + strlen(uuid) + 1);
++		if (!prefixed_uuid) {
++			fprintf(stderr, "cannot create prefixed uuid : %s\n",
++				strerror(errno));
++			goto addout;
++		}
++		sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid);
++		if (!dm_task_set_uuid(dmt, prefixed_uuid))
++			goto freeout;
++	}
++
+ 	dm_task_no_open_count(dmt);
+ 
+ 	r = dm_task_run (dmt);
+ 
++	freeout:
++	if (prefixed_uuid)
++		free(prefixed_uuid);
++
+ 	addout:
+ 	dm_task_destroy (dmt);
+ 	return r;
+@@ -178,3 +199,26 @@
+ 	return ret;
+ }
+ 
++char *
++dm_mapuuid(int major, int minor)
++{
++	struct dm_task *dmt;
++	char *tmp, *uuid = NULL;
++
++	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
++		return NULL;
++
++	dm_task_no_open_count(dmt);
++	dm_task_set_major(dmt, major);
++	dm_task_set_minor(dmt, minor);
++
++	if (!dm_task_run(dmt))
++		goto out;
++
++	tmp = dm_task_get_uuid(dmt);
++	if (tmp[0] != '\0')
++		uuid = strdup(tmp);
++out:
++	dm_task_destroy(dmt);
++	return uuid;
++}
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/kpartx/devmapper.h
++++ multipath-tools-0.4.7/kpartx/devmapper.h
+@@ -1,6 +1,8 @@
+ 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);
++int dm_addmap (int, const char *, const char *, const char *, unsigned long,
++	       char *, int);
+ int dm_map_present (char *);
+ char * dm_mapname(int major, int minor);
+ dev_t dm_get_first_dep(char *devname);
++char * dm_mapuuid(int major, int minor);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/kpartx/kpartx.8
++++ multipath-tools-0.4.7/kpartx/kpartx.8
+@@ -1,4 +1,4 @@
+-.TH KPARTX 8 "February 2004" "" "Linux Administrator's Manual"
++.TH KPARTX 8 "July 2006" "" "Linux Administrator's Manual"
+ .SH NAME
+ kpartx \- Create device maps from partition tables
+ .SH SYNOPSIS
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/kpartx/kpartx.c
++++ multipath-tools-0.4.7/kpartx/kpartx.c
+@@ -192,6 +192,7 @@
+ 	char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
+ 	char * loopdev = NULL;
+ 	char * delim = NULL;
++	char *uuid = NULL;
+ 	int loopro = 0;
+ 	int hotplug = 0;
+ 	struct stat buf;
+@@ -284,11 +285,6 @@
+ 	}
+ 
+ 	if (S_ISREG (buf.st_mode)) {
+-		loopdev = malloc(LO_NAME_SIZE * sizeof(char));
+-		
+-		if (!loopdev)
+-			exit(1);
+-
+ 		/* already looped file ? */
+ 		loopdev = find_loop_by_file(device);
+ 
+@@ -313,6 +309,13 @@
+ 	}
+ 	
+ 	off = find_devname_offset(device);
++
++	if (!loopdev)
++		uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
++				  (unsigned int)MINOR(buf.st_rdev));
++	if (!uuid)
++		uuid = device + off;
++		
+ 	fd = open(device, O_RDONLY);
+ 
+ 	if (fd == -1) {
+@@ -420,7 +423,7 @@
+ 					DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
+ 
+ 				dm_addmap(op, partname, DM_TARGET, params,
+-					  slices[j].size);
++					  slices[j].size, uuid, j+1);
+ 
+ 				if (op == DM_DEVICE_RELOAD)
+ 					dm_simplecmd(DM_DEVICE_RESUME,
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipathd/cli.c
++++ multipath-tools-0.4.7/multipathd/cli.c
+@@ -4,6 +4,7 @@
+ #include <memory.h>
+ #include <vector.h>
+ #include <util.h>
++#include <version.h>
+ 
+ #include "cli.h"
+ 
+@@ -305,6 +306,8 @@
+ 		return NULL;
+ 
+ 	p = reply;
++	p += sprintf(p, VERSION_STRING);
++	p += sprintf(p, "CLI commands reference:\n");
+ 
+ 	vector_foreach_slot (handlers, h, i) {
+ 		fp = h->fingerprint;
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipathd/cli_handlers.c
++++ multipath-tools-0.4.7/multipathd/cli_handlers.c
+@@ -71,7 +71,7 @@
+ 
+ 		c = reply;
+ 
+-		c += snprint_multipath_topology( c, reply + maxlen - c, mpp, 2);
++		c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
+ 		again = ((c - reply) == (maxlen - 1));
+ 
+ 		if (again)
+@@ -92,7 +92,8 @@
+ 	char * reply;
+ 	unsigned int maxlen = INITIAL_REPLY_LEN;
+ 	int again = 1;
+-
++ 
++	get_path_layout(vecs->pathvec);
+ 	reply = MALLOC(maxlen);
+ 
+ 	while (again) {
+@@ -183,6 +184,7 @@
+ 	struct vectors * vecs = (struct vectors *)data;
+ 	char * param = get_keyparam(v, MAP);
+ 	
++	get_path_layout(vecs->pathvec);
+ 	mpp = find_mp_by_str(vecs->mpvec, param);
+ 
+ 	if (!mpp)
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipathd/main.c
++++ multipath-tools-0.4.7/multipathd/main.c
+@@ -55,136 +55,29 @@
+ #include "uxclnt.h"
+ #include "cli.h"
+ #include "cli_handlers.h"
++#include "lock.h"
++#include "waiter.h"
+ 
+ #define FILE_NAME_SIZE 256
+ #define CMDSIZE 160
+ 
+ #define LOG_MSG(a,b) \
+-	if (strlen(b)) condlog(a, "%s: %s", pp->dev_t, b);
+-
+-#ifdef LCKDBG
+-#define lock(a) \
+-	fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
+-	pthread_mutex_lock(a)
+-#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
++	if (strlen(b)) condlog(a, "%s: %s", pp->dev, b);
+ 
+ pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
+ 
+ /*
+- * structs
++ * global copy of vecs for use in sig handlers
+  */
+-struct vectors * gvecs; /* global copy of vecs for use in sig handlers */
+-
+-static struct event_thread *
+-alloc_waiter (void)
+-{
+-
+-	struct event_thread * wp;
+-
+-	wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+-
+-	return wp;
+-}
+-
+-static void
+-free_waiter (void * data)
+-{
+-	struct event_thread * wp = (struct event_thread *)data;
+-
+-	/*
+-	 * indicate in mpp that the wp is already freed storage
+-	 */
+-	lock(wp->vecs->lock);
+-
+-	if (wp->mpp)
+-		/*
+-		 * be careful, mpp may already be freed -- null if so
+-		 */
+-		wp->mpp->waiter = NULL;
+-	else
+-		condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
+-
+-	unlock(wp->vecs->lock);
+-
+-	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;
+-	
+-	if (!wp) {
+-		condlog(3, "%s: no waiter thread", mpp->alias);
+-		return;
+-	}
+-	condlog(2, "%s: stop event checker thread", wp->mapname);
+-	pthread_kill((pthread_t)wp->thread, SIGUSR1);
+-}
+-
+-static void
+-cleanup_lock (void * data)
+-{
+-	unlock((pthread_mutex_t *)data);
+-}
+-
+-/*
+- * 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->stat_queueing_timeouts++;
+-		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);
+-}
++struct vectors * gvecs;
+ 
+ static int
+ need_switch_pathgroup (struct multipath * mpp, int refresh)
+ {
+ 	struct pathgroup * pgp;
+ 	struct path * pp;
+-	int i, j;
++	unsigned int i, j;
+ 
+ 	if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
+ 		return 0;
+@@ -219,7 +112,8 @@
+ {
+ 	struct multipath * ompp;
+ 	vector ompv = vecs->mpvec;
+-	int i, j;
++	unsigned int i;
++	int j;
+ 
+ 	vector_foreach_slot (ompv, ompp, i) {
+ 		if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
+@@ -253,234 +147,12 @@
+ 	return 0;
+ }
+ 
+-static int
+-update_multipath (struct vectors *vecs, char *mapname)
+-{
+-	struct multipath *mpp;
+-	struct pathgroup  *pgp;
+-	struct path *pp;
+-	int i, j;
+-	int r = 1;
+-
+-	mpp = find_mp_by_alias(vecs->mpvec, mapname);
+-
+-	if (!mpp)
+-		goto out;
+-
+-	free_pgvec(mpp->pg, KEEP_PATHS);
+-	mpp->pg = NULL;
+-
+-	if (setup_multipath(vecs, mpp))
+-		goto out; /* mpp freed in setup_multipath */
+-
+-	/*
+-	 * compare checkers states with DM states
+-	 */
+-	vector_foreach_slot (mpp->pg, pgp, i) {
+-		vector_foreach_slot (pgp->paths, pp, j) {
+-			if (pp->dmstate != PSTATE_FAILED)
+-				continue;
+-
+-			if (pp->state != PATH_DOWN) {
+-				int oldstate = pp->state;
+-				condlog(2, "%s: mark as failed", pp->dev_t);
+-				mpp->stat_path_failures++;
+-				pp->state = PATH_DOWN;
+-				if (oldstate == PATH_UP ||
+-				    oldstate == PATH_GHOST)
+-					update_queue_mode_del_path(mpp);
+-
+-				/*
+-				 * if opportune,
+-				 * schedule the next check earlier
+-				 */
+-				if (pp->tick > conf->checkint)
+-					pp->tick = conf->checkint;
+-			}
+-		}
+-	}
+-	r = 0;
+-out:
+-	if (r)
+-		condlog(0, "failed to update multipath");
+-
+-	return r;
+-}
+-
+-static sigset_t unblock_signals(void)
+-{
+-	sigset_t set, old;
+-
+-	sigemptyset(&set);
+-	sigaddset(&set, SIGHUP);
+-	sigaddset(&set, SIGUSR1);
+-	pthread_sigmask(SIG_UNBLOCK, &set, &old);
+-	return old;
+-}
+-
+-/*
+- * returns the reschedule delay
+- * negative means *stop*
+- */
+-static int
+-waiteventloop (struct event_thread * waiter)
+-{
+-	sigset_t set;
+-	int event_nr;
+-	int r;
+-
+-	if (!waiter->event_nr)
+-		waiter->event_nr = dm_geteventnr(waiter->mapname);
+-
+-	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+-		condlog(0, "%s: devmap event #%i dm_task_create error",
+-				waiter->mapname, waiter->event_nr);
+-		return 1;
+-	}
+-
+-	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+-		condlog(0, "%s: devmap event #%i dm_task_set_name error",
+-				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(waiter->dmt);
+-		return 1;
+-	}
+-
+-	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
+-						      waiter->event_nr)) {
+-		condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+-				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(waiter->dmt);
+-		return 1;
+-	}
+-
+-	dm_task_no_open_count(waiter->dmt);
+-	
+-	/* accept wait interruption */
+-	set = unblock_signals();
+-
+-	/* 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);
+-	//dm_restore_log();
+-
+-	if (!r) /* wait interrupted by signal */
+-		return -1;
+-
+-	dm_task_destroy(waiter->dmt);
+-	waiter->dmt = NULL;
+-	waiter->event_nr++;
+-
+-	/*
+-	 * upon event ...
+-	 */
+-	while (1) {
+-		condlog(3, "%s: devmap event #%i",
+-				waiter->mapname, waiter->event_nr);
+-
+-		/*
+-		 * event might be :
+-		 *
+-		 * 1) a table reload, which means our mpp structure is
+-		 *    obsolete : refresh it through update_multipath()
+-		 * 2) a path failed by DM : mark as such through
+-		 *    update_multipath()
+-		 * 3) map has gone away : stop the thread.
+-		 * 4) a path reinstate : nothing to do
+-		 * 5) a switch group : nothing to do
+-		 */
+-		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 */
+-
+-		event_nr = dm_geteventnr(waiter->mapname);
+-
+-		if (waiter->event_nr == event_nr)
+-			return 1; /* upon problem reschedule 1s later */
+-
+-		waiter->event_nr = event_nr;
+-	}
+-	return -1; /* never reach there */
+-}
+-
+-static void *
+-waitevent (void * et)
+-{
+-	int r;
+-	struct event_thread *waiter;
+-
+-	mlockall(MCL_CURRENT | MCL_FUTURE);
+-
+-	waiter = (struct event_thread *)et;
+-	pthread_cleanup_push(free_waiter, et);
+-
+-	while (1) {
+-		r = waiteventloop(waiter);
+-
+-		if (r < 0)
+-			break;
+-
+-		sleep(r);
+-	}
+-
+-	pthread_cleanup_pop(1);
+-	return NULL;
+-}
+-
+-static int
+-start_waiter_thread (struct multipath * mpp, struct vectors * vecs)
+-{
+-	pthread_attr_t attr;
+-	struct event_thread * wp;
+-
+-	if (!mpp)
+-		return 0;
+-
+-	if (pthread_attr_init(&attr))
+-		goto out;
+-
+-	pthread_attr_setstacksize(&attr, 32 * 1024);
+-	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+-
+-	wp = alloc_waiter();
+-
+-	if (!wp)
+-		goto out;
+-
+-	mpp->waiter = (void *)wp;
+-	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+-	wp->vecs = vecs;
+-	wp->mpp = mpp;
+-
+-	if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
+-		condlog(0, "%s: cannot create event checker", wp->mapname);
+-		goto out1;
+-	}
+-	condlog(2, "%s: event checker started", wp->mapname);
+-
+-	return 0;
+-out1:
+-	free_waiter(wp);
+-	mpp->waiter = NULL;
+-out:
+-	condlog(0, "failed to start waiter thread");
+-	return 1;
+-}
+-
+ static void
+ sync_map_state(struct multipath *mpp)
+ {
+-	int i, j;
+ 	struct pathgroup *pgp;
+         struct path *pp;
++	unsigned int i, j;
+ 
+ 	vector_foreach_slot (mpp->pg, pgp, i){
+ 		vector_foreach_slot (pgp->paths, pp, j){
+@@ -502,7 +174,7 @@
+ static void
+ sync_maps_state(vector mpvec)
+ {
+-	int i;
++	unsigned int i;
+ 	struct multipath *mpp;
+ 
+ 	vector_foreach_slot (mpvec, mpp, i) 
+@@ -863,7 +535,7 @@
+ 				}
+ 				sync_map_state(mpp);
+ 
+-				condlog(3, "%s path removed from devmap %s",
++				condlog(3, "%s: path removed from map %s",
+ 					devname, mpp->alias);
+ 			}
+ 			free_pathvec(rpvec, KEEP_PATHS);
+@@ -898,8 +570,8 @@
+ static int
+ map_discovery (struct vectors * vecs)
+ {
+-	int i;
+ 	struct multipath * mpp;
++	unsigned int i;
+ 
+ 	if (dm_get_maps(vecs->mpvec, "multipath"))
+ 		return 1;
+@@ -1129,7 +801,7 @@
+ mpvec_garbage_collector (struct vectors * vecs)
+ {
+ 	struct multipath * mpp;
+-	int i;
++	unsigned int i;
+ 
+ 	vector_foreach_slot (vecs->mpvec, mpp, i) {
+ 		if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
+@@ -1144,7 +816,7 @@
+ defered_failback_tick (vector mpvec)
+ {
+ 	struct multipath * mpp;
+-	int i;
++	unsigned int i;
+ 
+ 	vector_foreach_slot (mpvec, mpp, i) {
+ 		/*
+@@ -1163,7 +835,7 @@
+ retry_count_tick(vector mpvec)
+ {
+ 	struct multipath *mpp;
+-	int i;
++	unsigned int i;
+ 
+ 	vector_foreach_slot (mpvec, mpp, i) {
+ 		if (mpp->retry_tick) {
+@@ -1182,8 +854,9 @@
+ {
+ 	struct vectors *vecs;
+ 	struct path *pp;
+-	int i, count = 0;
++	int count = 0;
+ 	int newstate;
++	unsigned int i;
+ 
+ 	mlockall(MCL_CURRENT | MCL_FUTURE);
+ 	vecs = (struct vectors *)ap;
+@@ -1351,10 +1024,10 @@
+ 	vector mpvec;
+ 	int i;
+ 
+-	if (!(vecs->pathvec = vector_alloc()))
++	if (!vecs->pathvec && !(vecs->pathvec = vector_alloc()))
+ 		return 1;
+ 	
+-	if (!(vecs->mpvec = vector_alloc()))
++	if (!vecs->mpvec && !(vecs->mpvec = vector_alloc()))
+ 		return 1;
+ 	
+ 	if (!(mpvec = vector_alloc()))
+@@ -1406,6 +1079,7 @@
+ 	/*
+ 	 * save new set of maps formed by considering current path state
+ 	 */
++	vector_free(vecs->mpvec);
+ 	vecs->mpvec = mpvec;
+ 
+ 	/*
+@@ -1435,6 +1109,7 @@
+ 	if (VECTOR_SIZE(vecs->pathvec))
+ 		free_pathvec(vecs->pathvec, FREE_PATHS);
+ 
++	vecs->pathvec = NULL;
+ 	conf = NULL;
+ 
+ 	if (load_config(DEFAULT_CONFIGFILE))
+@@ -1467,24 +1142,10 @@
+ 	if (!vecs->lock)
+ 		goto out;
+ 
+-	vecs->pathvec = vector_alloc();
+-
+-	if (!vecs->pathvec)
+-		goto out1;
+-		
+-	vecs->mpvec = vector_alloc();
+-
+-	if (!vecs->mpvec)
+-		goto out2;
+-	
+ 	pthread_mutex_init(vecs->lock, NULL);
+ 
+ 	return vecs;
+ 
+-out2:
+-	vector_free(vecs->pathvec);
+-out1:
+-	FREE(vecs->lock);
+ out:
+ 	FREE(vecs);
+ 	condlog(0, "failed to init paths");
+@@ -1543,7 +1204,7 @@
+ 	signal_set(SIGUSR1, sigusr1);
+ 	signal_set(SIGINT, sigend);
+ 	signal_set(SIGTERM, sigend);
+-	signal_set(SIGKILL, sigend);
++	signal(SIGPIPE, SIG_IGN);
+ }
+ 
+ static void
+@@ -1551,7 +1212,7 @@
+ {
+         int res;
+ 	static struct sched_param sched_param = {
+-		sched_priority: 99
++		.sched_priority = 99
+ 	};
+ 
+         res = sched_setscheduler (0, SCHED_RR, &sched_param);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipathd/multipathd.8
++++ multipath-tools-0.4.7/multipathd/multipathd.8
+@@ -1,4 +1,4 @@
+-.TH MULTIPATHD 8 "October 2004" "Linux Administrator's Manual"
++.TH MULTIPATHD 8 "July 2006" "Linux Administrator's Manual"
+ .SH NAME
+ multipathd \- multipath daemon
+ .SH SYNOPSYS
+@@ -6,10 +6,10 @@
+ 
+ This daemon is in charge of checking for failed paths. When this happens,
+ it will reconfigure the multipath map the path belongs to, so that this map 
+-regain its maximum performance and redundancy.
++regains its maximum performance and redundancy.
+ 
+ This daemon executes the external multipath config tool when events occur. 
+-In turn, the multipath tool signals the multipathd daemon it is done with 
++In turn, the multipath tool signals the multipathd daemon when it is done with 
+ devmap reconfiguration, so that it can refresh its failed path list.
+ 
+ .SH "SEE ALSO"
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/devmap_name/devmap_name.8
++++ multipath-tools-0.4.7/devmap_name/devmap_name.8
+@@ -1,4 +1,4 @@
+-.TH DEVMAP_NAME 8 "February 2004" "" "Linux Administrator's Manual"
++.TH DEVMAP_NAME 8 "July 2006" "" "Linux Administrator's Manual"
+ .SH NAME
+ devmap_name \- Query device-mapper name
+ .SH SYNOPSIS
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libcheckers/checkers.h
++++ multipath-tools-0.4.7/libcheckers/checkers.h
+@@ -20,6 +20,21 @@
+ #define DEFAULT_CHECKER READSECTOR0
+ 
+ /*
++ * Overloaded storage response time can be very long.
++ * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
++ * as a path failure. multipathd then proactively evicts the path from the DM
++ * multipath table in this case.
++ *
++ * This generaly snow balls and ends up in full eviction and IO errors for end
++ * users. Bad. This may also cause SCSI bus resets, causing disruption for all
++ * local and external storage hardware users.
++ * 
++ * Provision a long timeout. Longer than any real-world application would cope
++ * with.
++ */
++#define DEF_TIMEOUT	300000
++
++/*
+  * strings lengths
+  */
+ #define CHECKER_NAME_LEN 16
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libcheckers/emc_clariion.c
++++ multipath-tools-0.4.7/libcheckers/emc_clariion.c
+@@ -57,7 +57,7 @@
+ 	io_hdr.dxferp = sense_buffer;
+ 	io_hdr.cmdp = inqCmdBlk;
+ 	io_hdr.sbp = sb;
+-	io_hdr.timeout = 60000;
++	io_hdr.timeout = DEF_TIMEOUT;
+ 	io_hdr.pack_id = 0;
+ 	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ 		MSG(c, "emc_clariion_checker: sending query command failed");
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libcheckers/hp_sw.c
++++ multipath-tools-0.4.7/libcheckers/hp_sw.c
+@@ -19,7 +19,6 @@
+ #define INQUIRY_CMDLEN		6
+ #define INQUIRY_CMD		0x12
+ #define SENSE_BUFF_LEN		32
+-#define DEF_TIMEOUT		60000
+ #define SCSI_CHECK_CONDITION	0x2
+ #define SCSI_COMMAND_TERMINATED	0x22
+ #define SG_ERR_DRIVER_SENSE	0x08
+@@ -111,7 +110,7 @@
+         io_hdr.dxfer_direction = SG_DXFER_NONE;
+         io_hdr.cmdp = turCmdBlk;
+         io_hdr.sbp = sense_buffer;
+-        io_hdr.timeout = 20000;
++        io_hdr.timeout = DEF_TIMEOUT;
+         io_hdr.pack_id = 0;
+ 
+         if (ioctl(fd, SG_IO, &io_hdr) < 0)
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libcheckers/readsector0.c
++++ multipath-tools-0.4.7/libcheckers/readsector0.c
+@@ -16,7 +16,6 @@
+ #include "../libmultipath/sg_include.h"
+ 
+ #define SENSE_BUFF_LEN 32
+-#define DEF_TIMEOUT 60000
+ 
+ #define MSG_READSECTOR0_UP	"readsector0 checker reports path is up"
+ #define MSG_READSECTOR0_DOWN	"readsector0 checker reports path is down"
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/libcheckers/tur.c
++++ multipath-tools-0.4.7/libcheckers/tur.c
+@@ -51,7 +51,7 @@
+         io_hdr.dxfer_direction = SG_DXFER_NONE;
+         io_hdr.cmdp = turCmdBlk;
+         io_hdr.sbp = sense_buffer;
+-        io_hdr.timeout = 20000;
++        io_hdr.timeout = DEF_TIMEOUT;
+         io_hdr.pack_id = 0;
+         if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ 		MSG(c, MSG_TUR_DOWN);
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/Makefile
++++ multipath-tools-0.4.7/Makefile
+@@ -22,7 +22,11 @@
+ 
+ BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib)
+ 
++ifeq   ($(MULTIPATH_VERSION),)
+ VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
++else
++VERSION = $(MULTIPATH_VERSION)
++endif
+ 
+ all: recurse
+ 
+only in patch2:
+unchanged:
+--- multipath-tools-0.4.7.orig/multipath-tools.spec.in
++++ multipath-tools-0.4.7/multipath-tools.spec.in
+@@ -50,6 +50,7 @@
+ %{prefix}/sbin/mpath_prio_balance_units
+ %{prefix}/sbin/mpath_prio_netapp
+ %{prefix}/sbin/mpath_prio_tpc
++%{prefix}/sbin/mpath_prio_hds_modular
+ %{prefix}/usr/share/man/man8/devmap_name.8.gz
+ %{prefix}/usr/share/man/man8/multipath.8.gz
+ %{prefix}/usr/share/man/man8/kpartx.8.gz
+
+-- System Information:
+Debian Release: testing/unstable
+  APT prefers unstable
+  APT policy: (500, 'unstable')
+Architecture: i386 (i686)
+Shell:  /bin/sh linked to /bin/bash
+Kernel: Linux 2.6.17.2
+Locale: LANG=C, LC_CTYPE=en_US (charmap=ISO-8859-1)
+
+
+

Added: multipath-tools/trunk/debian/patches/series
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/debian/patches/series	Wed Dec 20 10:52:01 2006
@@ -0,0 +1,2 @@
+git-40b575955cc189aa993e6a030b66b5fef6bcf288.patch
+exclude-quilt

Modified: multipath-tools/trunk/debian/rules
==============================================================================
--- multipath-tools/trunk/debian/rules	(original)
+++ multipath-tools/trunk/debian/rules	Wed Dec 20 10:52:01 2006
@@ -1,21 +1,25 @@
 #!/usr/bin/make -f
 
+include /usr/share/quilt/quilt.make
+
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
 
 build: build-stamp
-build-stamp:
+build-stamp: patch
 	dh_testdir
 
 	$(MAKE)
 
 	touch $@
 
-clean:
+clean: unpatch
 	dh_testdir
 	rm -f build-stamp
 
 	-$(MAKE) clean
+	# work around Makefile not cleaning up everything:
+	rm -rf path_priority/pp_hds_modular/
 
 	dh_clean
 



More information about the pkg-lvm-commits mailing list