From 5c5ecaa98db879b6c2ba7ec13a498fa9e47fcc5140d0608cc91a9dd67867edfe Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Mon, 15 Jan 2007 23:25:57 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/multipath-tools?expand=0&rev=1 --- .gitattributes | 23 + .gitignore | 1 + 71-multipath.rules | 25 + 72-multipath-compat.rules | 10 + boot.multipath | 104 + kpartx_id | 110 + mpath_id | 19 + multipath-tools-0.4.7.tar.bz2 | 3 + multipath-tools-git-update.patch | 3933 +++++++++++++++++++++++++++ multipath-tools-no-gz-for-manpage | 140 + multipath-tools-online-device.patch | 107 + multipath-tools-strip.patch | 121 + multipath-tools.changes | 398 +++ multipath-tools.spec | 322 +++ multipathd | 155 ++ ready | 0 16 files changed, 5471 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 71-multipath.rules create mode 100644 72-multipath-compat.rules create mode 100644 boot.multipath create mode 100644 kpartx_id create mode 100644 mpath_id create mode 100644 multipath-tools-0.4.7.tar.bz2 create mode 100644 multipath-tools-git-update.patch create mode 100644 multipath-tools-no-gz-for-manpage create mode 100644 multipath-tools-online-device.patch create mode 100644 multipath-tools-strip.patch create mode 100644 multipath-tools.changes create mode 100644 multipath-tools.spec create mode 100644 multipathd create mode 100644 ready diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/71-multipath.rules b/71-multipath.rules new file mode 100644 index 0000000..1d1dc86 --- /dev/null +++ b/71-multipath.rules @@ -0,0 +1,25 @@ +# +# persistent links for device-mapper devices +# only hardware-backed device-mapper devices (ie multipath, dmraid, +# and kpartx) have meaningful persistent device names +# + +KERNEL!="dm-*", GOTO="multipath_end" +ACTION=="add|remove", GOTO="multipath_end" + +ACTION=="change", IMPORT{program}=="/sbin/kpartx_id %M %m" + +# Create persistent links for tables +ACTION=="change", ENV{ID_DM_TABLE}=="mpath|dmraid", ENV{ID_DM_TYPE}=="?*", \ + SYMLINK+="disk/by-id/$env{ID_DM_TYPE}-$env{ID_DM_NAME}" + +# Create dm tables for partitions +ACTION=="change", ENV{ID_DM_TABLE}=="mpath|dmraid", \ + RUN+="/sbin/kpartx -a -p _part /dev/mapper/$env{ID_DM_NAME}" + +# Create persistent links for partitions +ACTION=="change", ENV{ID_DM_TABLE}=="part", ENV{ID_DM_TYPE}=="?*", \ + SYMLINK+="disk/by-id/$env{ID_DM_TYPE}-$env{ID_DM_NAME}-part$env{ID_DM_PART}" + +LABEL="multipath_end" + diff --git a/72-multipath-compat.rules b/72-multipath-compat.rules new file mode 100644 index 0000000..bc1fcdd --- /dev/null +++ b/72-multipath-compat.rules @@ -0,0 +1,10 @@ +# +# SLES9 compability symlinks for multipathed devices +# + +# Devices +ENV{ID_DMTYPE}=="multipath", ENV{ID_MPATH}=="?*", \ + SYMLINK+="disk/by-name/$env{ID_MPATH}" +# Partitions +ENV{ID_DMTYPE}=="linear", ENV{ID_MPATH}=="?*", \ + SYMLINK+="disk/by-name/$env{ID_MPATH}" diff --git a/boot.multipath b/boot.multipath new file mode 100644 index 0000000..3cf67f6 --- /dev/null +++ b/boot.multipath @@ -0,0 +1,104 @@ +#! /bin/sh +# Copyright (c) 2005 SuSE GmbH Nuernberg, Germany. +# +# Author: Hannes Reinecke +# +# init.d/boot.multipath +# +### BEGIN INIT INFO +# Provides: boot.multipath +# Required-Start: boot.device-mapper boot.udev +# Required-Stop: +# Default-Start: B +# Default-Stop: +# Description: Create multipath device targets +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +PROGRAM=/sbin/multipath + +# Set the maximum number of open files +MAX_OPEN_FDS=4096 + +test -x $PROGRAM || exit 5 + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - misc error +# 2 - invalid or excess args +# 3 - unimplemented feature (e.g. reload) +# 4 - insufficient privilege +# 5 - program not installed +# 6 - program not configured +# 7 - program is not running +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signalling is not supported) are +# considered a success. + +case "$1" in + start) + echo -n "Creating multipath targets" + # Check whether multipath daemon is already running + if /sbin/multipathd -k"list paths" > /dev/null 2>&1 ; then + echo -n " (multipathd running)" + rc_status -v + rc_exit + fi + + # Load prerequisite module + modprobe dm-multipath + + # Be a chicken and flush all existing maps + $PROGRAM -F + + # Clear /dev/disk/by-name/ prior to start-up; multipath will + # recreate them. + rm -f /dev/disk/by-name/* 2>&1 >/dev/null + + # Set the maximum number of open files + if [ -n "$MAX_OPEN_FDS" ] ; then + ulimit -n $MAX_OPEN_FDS + fi + + # Start the program directly as checkproc doesn't work here + $PROGRAM -v 0 + + # Create all partitions which might have been missing + /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -p -part" + + # Remember status and be verbose + rc_status -v + sleep 1 + ;; + stop) + # Remove all partition mappings + if dmsetup ls | grep -q -- -part; then + /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -d -p -part" + fi + + # And remove the multipath mappings themselves + for map in $(/sbin/dmsetup ls --target multipath | cut -f 1); do + /sbin/dmsetup remove $map + done + ;; + *) + echo "Usage: $0 {start|stop}" + exit 1 + ;; +esac +rc_exit diff --git a/kpartx_id b/kpartx_id new file mode 100644 index 0000000..b02de49 --- /dev/null +++ b/kpartx_id @@ -0,0 +1,110 @@ +#!/bin/bash +# +# kpartx_id +# +# Generates ID information for device-mapper tables. +# +# Copyright (C) 2006 SUSE Linux Products GmbH +# Author: +# Hannes Reinecke +# +# +# 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 version 2 of the License. +# +# This script generates ID information used to generate persistent symlinks. +# It relies on the UUID strings generated by the various programs; the name +# of the tables are of no consequence. +# +# Please note that dmraid does not provide the UUIDs (yet); a patch has been +# sent upstream but has not been accepted yet. +# + +DMSETUP=/sbin/dmsetup + +MAJOR=$1 +MINOR=$2 + +if [ -z "$MAJOR" -o -z "$MINOR" ]; then + echo "usage: $0 major minor" + exit 1; +fi + +# Device-mapper not installed; not an error +if [ ! -x $DMSETUP ] ; then + exit 0 +fi + +# Get the table info +tblinfo=$($DMSETUP info -c --noheadings -o name,uuid -j $MAJOR -m $MINOR) +if [ $? -ne 0 ] || [ -z "$tblinfo" ]; then + exit $? +fi + +set -- $(IFS=":"; echo $tblinfo) +tblname=$1 +tbluuid=$2 + +if [ -z "$tbluuid" ] ; then + exit 0 +fi + +# Table UUIDs are always '-'. +dmuuid=${tbluuid#*-} +dmtbl=${tbluuid%%-*} +dmpart=${dmtbl#part} +# kpartx types are 'part' +if [ "$dmpart" == "$dmtbl" ] ; then + dmpart= +else + dmtbl=part +fi + +# Set the name of the table. We're only interested in dmraid, +# multipath, and kparts tables; everything else is ignored. +if [ "$dmtbl" == "part" ] ; then + # The name of the kpartx table is the name of the parent table + dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid) + # We need the dependencies of the parent table to figure out + # the type if the parent is a multipath table + case "$dmparent" in + mpath-*) + dmdeps=$($DMSETUP deps -u $dmuuid) + ;; + esac +elif [ "$dmtbl" == "mpath" ] ; then + dmname=$tblname + # We need the dependencies of the table to figure out the type + dmdeps=$($DMSETUP deps -u $tbluuid) +elif [ "$dmtbl" == "dmraid" ] ; then + dmname=$tblname +fi + +if [ -z "$dmname" ] ; then + exit 0 +fi + +echo "ID_DM_TABLE=$dmtbl" +echo "ID_DM_NAME=$dmname" +[ -n "$dmpart" ] && echo "ID_DM_PART=$dmpart" + +# Figure out the type of the map. For non-multipath maps it's +# always 'raid'. +if [ -n "$dmdeps" ] ; then + case "$dmdeps" in + *\(94,*) + echo "ID_DM_TYPE=dasd" + ;; + *\(9*) + echo "ID_DM_TYPE=raid" + ;; + *) + echo "ID_DM_TYPE=scsi" + ;; + esac +else + echo "ID_DM_TYPE=raid" +fi + +exit 0 diff --git a/mpath_id b/mpath_id new file mode 100644 index 0000000..0ff4949 --- /dev/null +++ b/mpath_id @@ -0,0 +1,19 @@ +#!/bin/sh + +major=$1 +minor=$2 + +mpstatus=$(/sbin/dmsetup status -j $major -m $minor --target multipath) +if [ -z "$mpstatus" ]; then + exit 1 +fi + +mpid=$(/sbin/dmsetup info -c --noopencount --noheadings -o name -j $major -m $minor) + +if [ -z "$mpid" ]; then + exit 1 +fi +echo ID_MPATH=\"$mpid\" + +exit 0 + diff --git a/multipath-tools-0.4.7.tar.bz2 b/multipath-tools-0.4.7.tar.bz2 new file mode 100644 index 0000000..ff8ac06 --- /dev/null +++ b/multipath-tools-0.4.7.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b48684c9ce956bb2294640a92f1da8ddea4e991e4d7b974697660de5e44a9d7 +size 139312 diff --git a/multipath-tools-git-update.patch b/multipath-tools-git-update.patch new file mode 100644 index 0000000..7cec1df --- /dev/null +++ b/multipath-tools-git-update.patch @@ -0,0 +1,3933 @@ + Makefile | 4 + devmap_name/devmap_name.8 | 2 + kpartx/devmapper.c | 46 ++- + kpartx/devmapper.h | 4 + kpartx/kpartx.8 | 2 + kpartx/kpartx.c | 15 - + libcheckers/checkers.h | 54 +++ + libcheckers/emc_clariion.c | 13 - + libcheckers/hp_sw.c | 3 + libcheckers/readsector0.c | 9 + libcheckers/tur.c | 2 + libmultipath/Makefile | 3 + libmultipath/callout.c | 2 + libmultipath/config.c | 75 +++- + libmultipath/config.h | 6 + libmultipath/configure.c | 60 ++- + libmultipath/configure.h | 2 + libmultipath/debug.c | 5 + libmultipath/debug.h | 4 + libmultipath/devmapper.c | 38 ++ + libmultipath/discovery.c | 41 +- + libmultipath/discovery.h | 6 + libmultipath/dmparser.c | 19 + + libmultipath/hwtable.c | 202 +++++++++-- + libmultipath/lock.c | 8 + libmultipath/lock.h | 22 + + libmultipath/parser.c | 15 + + libmultipath/parser.h | 1 + libmultipath/pgpolicies.h | 2 + libmultipath/print.c | 43 ++ + libmultipath/propsel.c | 33 +- + libmultipath/structs.c | 9 + libmultipath/structs.h | 12 - + libmultipath/structs_vec.c | 94 +++++ + libmultipath/structs_vec.h | 14 - + libmultipath/util.c | 9 + libmultipath/util.h | 1 + libmultipath/version.h | 37 ++ + libmultipath/waiter.c | 234 +++++++++++++ + libmultipath/waiter.h | 23 + + multipath-tools.spec.in | 1 + multipath.conf.annotated | 6 + multipath/main.c | 18 + + multipath/main.h | 39 -- + multipath/multipath.8 | 15 - + multipathd/cli.c | 3 + multipathd/cli_handlers.c | 6 + multipathd/main.c | 385 +-------------------- + multipathd/multipathd.8 | 6 + path_priority/pp_alua/main.c | 4 + path_priority/pp_alua/mpath_prio_alua.8 | 2 + path_priority/pp_alua/rtpg.c | 36 ++ + path_priority/pp_alua/spc3.h | 4 + path_priority/pp_balance_units/pp_balance_units.c | 74 ++-- + path_priority/pp_hds_modular/Makefile | 22 + + path_priority/pp_hds_modular/pp_hds_modular.c | 252 ++++++++++++++ + path_priority/pp_tpc/pp_tpc.c | 12 - + 57 files changed, 1375 insertions(+), 684 deletions(-) + +diff --git a/Makefile b/Makefile +index 83ae2fe..aacede3 100644 +--- a/Makefile ++++ b/Makefile +@@ -22,7 +22,11 @@ export KRNLOBJ + + 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 + +diff --git a/devmap_name/devmap_name.8 b/devmap_name/devmap_name.8 +index f4f03c3..86d0931 100644 +--- a/devmap_name/devmap_name.8 ++++ b/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 +diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c +index 1253941..5b27487 100644 +--- a/kpartx/devmapper.c ++++ b/kpartx/devmapper.c +@@ -7,6 +7,10 @@ #include + #include + #include + #include ++#include ++ ++#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 @@ dm_simplecmd (int task, const char *name + + 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 @@ dm_addmap (int task, const char *name, c + 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 @@ out: + 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; ++} +diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h +index 9607476..e20e456 100644 +--- a/kpartx/devmapper.h ++++ b/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); +diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8 +index 259ce3f..87b07ce 100644 +--- a/kpartx/kpartx.8 ++++ b/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 +diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c +index 2198302..0ee0cb3 100644 +--- a/kpartx/kpartx.c ++++ b/kpartx/kpartx.c +@@ -192,6 +192,7 @@ main(int argc, char **argv){ + 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 @@ main(int argc, char **argv){ + } + + 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 @@ main(int argc, char **argv){ + } + + 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 @@ #endif + 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, +diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h +index ac795ed..219dfaf 100644 +--- a/libcheckers/checkers.h ++++ b/libcheckers/checkers.h +@@ -2,7 +2,44 @@ #ifndef _CHECKERS_H + #define _CHECKERS_H + + /* +- * path states ++ * ++ * Userspace (multipath/multipathd) path states ++ * ++ * PATH_WILD: ++ * - Use: None of the checkers (returned if we don't have an fd) ++ * - Description: Corner case where "fd <= 0" for path fd (see checker_check()) ++ * ++ * PATH_UNCHECKED: ++ * - Use: Only in directio checker ++ * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT ++ * not include in flags, or O_DIRECT read fails ++ * - Notes: ++ * - multipathd: uses it to skip over paths in sync_map_state() ++ * - multipath: used in update_paths(); if state==PATH_UNCHECKED, call ++ * pathinfo() ++ * ++ * PATH_DOWN: ++ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur) ++ * - Description: Either a) SG_IO ioctl failed, or b) check condition on some ++ * SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and ++ * you shouldn't try to send commands to it ++ * ++ * PATH_UP: ++ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur) ++ * - Description: Path is up and I/O can be sent to it ++ * ++ * PATH_SHAKY: ++ * - Use: Only emc_clariion ++ * - Description: Indicates path not available for "normal" operations ++ * ++ * PATH_GHOST: ++ * - Use: Only hp_sw ++ * - Description: Indicates a "passive/standby" path on active/passive HP ++ * arrays. These paths will return valid answers to certain SCSI commands ++ * (tur, read_capacity, inquiry, start_stop), but will fail I/O commands. ++ * The path needs an initialization command to be sent to it in order for ++ * I/Os to succeed. ++ * + */ + #define PATH_WILD -1 + #define PATH_UNCHECKED 0 +@@ -20,6 +57,21 @@ #define READSECTOR0 "readsector0" + #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 +diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c +index 1d7b684..a883e3d 100644 +--- a/libcheckers/emc_clariion.c ++++ b/libcheckers/emc_clariion.c +@@ -57,7 +57,7 @@ int emc_clariion(struct checker * c) + 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"); +@@ -89,14 +89,11 @@ int emc_clariion(struct checker * c) + return PATH_SHAKY; + } + +-#if 0 +- /* This is not actually an error as the failover to this group +- * _would_ bind the path */ +- if ( /* LUN should at least be bound somewhere */ +- sense_buffer[4] != 0x00) { +- return PATH_UP; ++ if ( /* LUN should at least be bound somewhere and not be LUNZ */ ++ sense_buffer[4] == 0x00) { ++ MSG(c, "emc_clariion_checker: Logical Unit is unbound or LUNZ"); ++ return PATH_DOWN; + } +-#endif + + /* + * store the LUN WWN there and compare that it indeed did not +diff --git a/libcheckers/hp_sw.c b/libcheckers/hp_sw.c +index 509e9c4..b9731ff 100644 +--- a/libcheckers/hp_sw.c ++++ b/libcheckers/hp_sw.c +@@ -19,7 +19,6 @@ #define TUR_CMD_LEN 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 @@ do_tur (int fd) + 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) +diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c +index e368fb4..dd18528 100644 +--- a/libcheckers/readsector0.c ++++ b/libcheckers/readsector0.c +@@ -16,7 +16,6 @@ #include "checkers.h" + #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" +@@ -35,8 +34,8 @@ void readsector0_free (struct checker * + return; + } + +-static int +-sg_read (int sg_fd, unsigned char * buff) ++int ++sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff) + { + /* defaults */ + int blocks = 1; +@@ -46,7 +45,6 @@ sg_read (int sg_fd, unsigned char * buff + int * diop = NULL; + + unsigned char rdCmd[cdbsz]; +- unsigned char senseBuff[SENSE_BUFF_LEN]; + struct sg_io_hdr io_hdr; + int res; + int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; +@@ -98,9 +96,10 @@ extern int + readsector0 (struct checker * c) + { + unsigned char buf[512]; ++ unsigned char sbuf[SENSE_BUFF_LEN]; + int ret; + +- ret = sg_read(c->fd, &buf[0]); ++ ret = sg_read(c->fd, &buf[0], &sbuf[0]); + + switch (ret) + { +diff --git a/libcheckers/tur.c b/libcheckers/tur.c +index d40a273..e79bc0a 100644 +--- a/libcheckers/tur.c ++++ b/libcheckers/tur.c +@@ -51,7 +51,7 @@ tur (struct checker * c) + 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); +diff --git a/libmultipath/Makefile b/libmultipath/Makefile +index 8a14b04..5d8c586 100644 +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -6,7 +6,7 @@ BUILD = glibc + + 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 @@ OBJS = memory.o parser.o vector.o devmap + 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 +diff --git a/libmultipath/callout.c b/libmultipath/callout.c +index 46b89e6..b0bc503 100644 +--- a/libmultipath/callout.c ++++ b/libmultipath/callout.c +@@ -78,7 +78,7 @@ int execute_program(char *path, char *va + /* dup write side of pipe to STDOUT */ + dup(fds[1]); + +- retval = execv(argv[0], argv); ++ retval = execvp(argv[0], argv); + + exit(-1); + case -1: +diff --git a/libmultipath/config.c b/libmultipath/config.c +index 1068755..528e475 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -20,26 +20,61 @@ #include "config.h" + #include "blacklist.h" + #include "defaults.h" + ++static struct hwentry * ++find_hwe_strmatch (vector hwtable, char * vendor, char * product, char * revision) ++{ ++ int i; ++ struct hwentry *hwe, *ret = NULL; ++ ++ vector_foreach_slot (hwtable, hwe, i) { ++ if (hwe->vendor && vendor && strcmp(hwe->vendor, vendor)) ++ continue; ++ ++ if (hwe->product && product && strcmp(hwe->product, product)) ++ continue; ++ ++ if (hwe->revision && revision && strcmp(hwe->revision, revision)) ++ continue; ++ ++ ret = hwe; ++ break; ++ } ++ return ret; ++} ++ + struct hwentry * +-find_hwe (vector hwtable, char * vendor, char * product) ++find_hwe (vector hwtable, char * vendor, char * product, char * revision) + { + int i; + struct hwentry *hwe, *ret = NULL; +- regex_t vre, pre; ++ regex_t vre, pre, rre; + + 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 (hwe->product && ++ regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) { ++ regfree(&vre); + break; +- if (regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) { ++ } ++ if (hwe->revision && ++ regcomp(&rre, hwe->revision, REG_EXTENDED|REG_NOSUB)) { + regfree(&vre); ++ regfree(&pre); + 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)) && ++ (!hwe->revision || !regexec(&rre, revision, 0, NULL, 0))) + ret = hwe; +- +- regfree(&pre); +- regfree(&vre); ++ ++ if (hwe->revision) ++ regfree(&rre); ++ if (hwe->product) ++ regfree(&pre); ++ if (hwe->vendor) ++ regfree(&vre); + + if (ret) + break; +@@ -91,6 +126,9 @@ free_hwe (struct hwentry * hwe) + if (hwe->product) + FREE(hwe->product); + ++ if (hwe->revision) ++ FREE(hwe->revision); ++ + if (hwe->selector) + FREE(hwe->selector); + +@@ -204,23 +242,12 @@ set_param_str(char * str) + 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, struct hwentry * dhwe) + { + struct hwentry * hwe; + +- if (dup_hwe(hwtable, dhwe->vendor, dhwe->product)) ++ if (find_hwe_strmatch(hwtable, dhwe->vendor, dhwe->product, dhwe->revision)) + return 0; + + if (!(hwe = alloc_hwe())) +@@ -232,6 +259,9 @@ store_hwe (vector hwtable, struct hwentr + if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product))) + goto out; + ++ if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision))) ++ goto out; ++ + if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid))) + goto out; + +@@ -305,7 +335,7 @@ free_config (struct config * conf) + free_blacklist_device(conf->blist_device); + free_mptable(conf->mptable); + free_hwtable(conf->hwtable); +- ++ free_keywords(conf->keywords); + FREE(conf); + } + +@@ -332,6 +362,7 @@ load_config (char * file) + * 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; +diff --git a/libmultipath/config.h b/libmultipath/config.h +index 6e5633a..0c3b640 100644 +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -11,6 +11,7 @@ enum devtypes { + struct hwentry { + char * vendor; + char * product; ++ char * revision; + char * getuid; + char * getprio; + char * features; +@@ -48,7 +49,7 @@ struct config { + int with_sysfs; + int pgpolicy; + struct checker * checker; +- int dev_type; ++ enum devtypes dev_type; + int minio; + int checkint; + int max_checkint; +@@ -67,6 +68,7 @@ struct config { + char * hwhandler; + char * bindings_file; + ++ vector keywords; + vector mptable; + vector hwtable; + +@@ -77,7 +79,7 @@ struct config { + + struct config * conf; + +-struct hwentry * find_hwe (vector hwtable, char * vendor, char * product); ++struct hwentry * find_hwe (vector hwtable, char * vendor, char * product, char *revision); + struct mpentry * find_mpe (char * wwid); + char * get_mpe_wwid (char * alias); + +diff --git a/libmultipath/configure.c b/libmultipath/configure.c +index 1ba4356..9d17022 100644 +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -145,11 +145,6 @@ select_action (struct multipath * mpp, v + 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 @@ lock_multipath (struct multipath * mpp, + + /* + * 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 @@ domap (struct multipath * mpp) + /* + * 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 @@ domap (struct multipath * mpp) + * 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 @@ #else + 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 +@@ -444,7 +441,7 @@ coalesce_paths (struct vectors * vecs, v + if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL) + return 1; + +- if (pp1->priority < 0) ++ if (pp1->priority == PRIO_UNDEF) + mpp->action = ACT_REJECT; + + if (!mpp->paths) { +@@ -471,7 +468,7 @@ coalesce_paths (struct vectors * vecs, v + mpp->size); + mpp->action = ACT_REJECT; + } +- if (pp2->priority < 0) ++ if (pp2->priority == PRIO_UNDEF) + mpp->action = ACT_REJECT; + } + verify_paths(mpp, vecs, NULL); +@@ -486,19 +483,18 @@ coalesce_paths (struct vectors * vecs, v + + r = domap(mpp); + +- if (!r) { ++ if (r == DOMAP_FAIL || r == DOMAP_RETRY) { + condlog(3, "%s: domap (%u) failure " + "for create/reload map", + mpp->alias, r); +- remove_map(mpp, vecs, NULL, 0); +- continue; +- } +- else if (r < 0) { +- 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 @@ coalesce_paths (struct vectors * vecs, v + } + + 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, tmpwwid[WWID_SIZE]; + + if (dev_type == DEV_NONE) + return NULL; +@@ -606,6 +602,12 @@ get_refwwid (char * dev, int dev_type, v + goto out; + } + if (dev_type == DEV_DEVMAP) { ++ ++ if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) { ++ refwwid = tmpwwid; ++ goto out; ++ } ++ + /* + * may be a binding + */ +diff --git a/libmultipath/configure.h b/libmultipath/configure.h +index 42ee9b0..1cbbe82 100644 +--- a/libmultipath/configure.h ++++ b/libmultipath/configure.h +@@ -25,5 +25,5 @@ int setup_map (struct multipath * mpp); + 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); + +diff --git a/libmultipath/debug.c b/libmultipath/debug.c +index 099ab52..fa06cbd 100644 +--- a/libmultipath/debug.c ++++ b/libmultipath/debug.c +@@ -29,17 +29,16 @@ #if DAEMON + 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); +diff --git a/libmultipath/debug.h b/libmultipath/debug.h +index e7612a9..74ed531 100644 +--- a/libmultipath/debug.h ++++ b/libmultipath/debug.h +@@ -11,11 +11,11 @@ #include "log_pthread.h" + 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 */ +diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c +index 4328036..b8571ad 100644 +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -11,6 +11,7 @@ #include + #include + #include + #include ++#include + + #include + +@@ -23,6 +24,10 @@ #include "devmapper.h" + #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, ...) + { +@@ -100,6 +105,7 @@ dm_simplecmd (int task, const char *name + goto out; + + dm_task_no_open_count(dmt); ++ dm_task_skip_lockfs(dmt); /* for DM_DEVICE_RESUME */ + + r = dm_task_run (dmt); + +@@ -113,6 +119,7 @@ dm_addmap (int task, const char *name, c + 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 +130,26 @@ dm_addmap (int task, const char *name, c + 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; +@@ -203,6 +223,7 @@ dm_get_uuid(char *name, char *uuid) + { + struct dm_task *dmt; + const char *uuidtmp; ++ int r = 1; + + dmt = dm_task_create(DM_DEVICE_INFO); + if (!dmt) +@@ -215,15 +236,19 @@ dm_get_uuid(char *name, char *uuid) + 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'; + ++ r = 0; + uuidout: + dm_task_destroy(dmt); +- +- return 0; ++ return r; + } + + extern int +@@ -591,6 +616,7 @@ dm_get_maps (vector mp, char * type) + goto out1; + + dm_get_uuid(names->name, mpp->wwid); ++ dm_get_info(names->name, &mpp->dmi); + } + + if (!vector_alloc_slot(mp)) +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index cf8289c..f21e5bc 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -165,7 +165,7 @@ sysfs_get_##fname (char * sysfs_path, ch + 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 @@ devt2devname (char *devname, char *devt) + 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; + +@@ -295,7 +295,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u + { INQUIRY_CMD, 0, 0, 0, 0, 0 }; + unsigned char sense_b[SENSE_BUFF_LEN]; + struct sg_io_hdr io_hdr; +- ++ + if (cmddt) + inqCmdBlk[1] |= 2; + if (evpd) +@@ -313,10 +313,10 @@ do_inq(int sg_fd, int cmddt, int evpd, u + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_b; + io_hdr.timeout = DEF_TIMEOUT; +- ++ + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) + return -1; +- ++ + /* treat SG_ERR here to get rid of sg_err.[ch] */ + io_hdr.status &= 0x7e; + if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && +@@ -339,24 +339,26 @@ do_inq(int sg_fd, int cmddt, int evpd, u + 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 +@@ -440,7 +442,7 @@ scsi_sysfs_pathinfo (struct path * pp) + /* + * set the hwe configlet pointer + */ +- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id); ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev); + + /* + * host / bus / target / lun +@@ -524,7 +526,7 @@ ccw_sysfs_pathinfo (struct path * pp) + /* + * set the hwe configlet pointer + */ +- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id); ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL); + + /* + * host / bus / target / lun +@@ -597,7 +599,7 @@ static int + 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); + } + +@@ -636,14 +638,14 @@ get_prio (struct path * pp) + pp->getprio_selected = 1; + } + if (!pp->getprio) { +- pp->priority = 1; ++ pp->priority = PRIO_DEFAULT; + } else if (apply_format(pp->getprio, &buff[0], pp)) { + condlog(0, "error formatting prio callout command"); +- pp->priority = -1; ++ pp->priority = PRIO_UNDEF; + return 1; + } else if (execute_program(buff, prio, 16)) { + condlog(0, "error calling out %s", buff); +- pp->priority = -1; ++ pp->priority = PRIO_UNDEF; + return 1; + } else + pp->priority = atoi(prio); +@@ -699,7 +701,12 @@ pathinfo (struct path *pp, vector hwtabl + if (mask & DI_CHECKER && get_state(pp)) + goto blank; + +- if (mask & DI_PRIO && pp->state != PATH_DOWN) ++ /* ++ * Retrieve path priority for even PATH_DOWN paths if it has never ++ * been successfully obtained before. ++ */ ++ if (mask & DI_PRIO && ++ (pp->state != PATH_DOWN || pp->priority != PRIO_UNDEF)) + get_prio(pp); + + if (mask & DI_WWID && !strlen(pp->wwid)) +diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h +index cdc9627..ab62a59 100644 +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -5,7 +5,6 @@ #define SYSFS_PATH_SIZE 255 + #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 @@ #ifndef BLKGETSIZE + #define BLKGETSIZE _IO(0x12,96) + #endif + ++#ifndef DEF_TIMEOUT ++#define DEF_TIMEOUT 300000 ++#endif ++ + /* + * exerpt from sg_err.h + */ +@@ -30,7 +33,6 @@ int sysfs_get_size (char * sysfs_path, c + 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); +diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c +index 2b170c6..631933d 100644 +--- a/libmultipath/dmparser.c ++++ b/libmultipath/dmparser.c +@@ -84,11 +84,14 @@ assemble_map (struct multipath * mp) + freechar -= shift; + + vector_foreach_slot (pgp->paths, pp, j) { +- if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority) +- minio *= pp->priority; ++ int tmp_minio = minio; ++ ++ if (mp->rr_weight == RR_WEIGHT_PRIO ++ && pp->priority > 0) ++ tmp_minio = minio * pp->priority; + + shift = snprintf(p, freechar, " %s %d", +- pp->dev_t, minio); ++ pp->dev_t, tmp_minio); + if (shift >= freechar) { + fprintf(stderr, "mp->params too small\n"); + return 1; +@@ -117,6 +120,7 @@ disassemble_map (vector pathvec, char * + int num_pg_args = 0; + int num_paths = 0; + int num_paths_args = 0; ++ int def_minio = 0; + struct path * pp; + struct pathgroup * pgp; + +@@ -305,12 +309,15 @@ #endif + if (k == 0 && !strncmp(mpp->selector, + "round-robin", 11)) { + p += get_word(p, &word); +- mpp->minio = atoi(word); ++ def_minio = atoi(word); + +- if (mpp->rr_weight) +- mpp->minio /= mpp->rr_weight; ++ if (mpp->rr_weight == RR_WEIGHT_PRIO ++ && pp->priority > 0) ++ def_minio /= pp->priority; + + FREE(word); ++ if (def_minio != mpp->minio) ++ mpp->minio = def_minio; + } + else + p += get_word(p, NULL); +diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c +index 5c7d625..ac126c0 100644 +--- a/libmultipath/hwtable.c ++++ b/libmultipath/hwtable.c +@@ -12,13 +12,34 @@ #include "pgpolicies.h" + * Tuning suggestions on these parameters should go to + * dm-devel@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@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@free.fr +@@ -54,14 +75,14 @@ static struct hwentry default_hw[] = { + .checker_name = HP_SW, + }, + { +- .vendor = "{COMPAQ,HP}", +- .product = "{MSA,HSV}1*", ++ .vendor = "(COMPAQ|HP)", ++ .product = "(MSA|HSV)1.*", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = "1 hp_sw", + .selector = DEFAULT_SELECTOR, +- .pgpolicy = GROUP_BY_SERIAL, ++ .pgpolicy = MULTIBUS, + .pgfailback = FAILBACK_UNDEF, + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, +@@ -70,7 +91,7 @@ static struct hwentry default_hw[] = { + }, + { + .vendor = "HP", +- .product = "HSV2*", ++ .product = "A6189A", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = DEFAULT_FEATURES, +@@ -85,7 +106,8 @@ static struct hwentry default_hw[] = { + }, + { + .vendor = "HP", +- .product = "DF[456]00", ++ .product = "HSV20.*", ++ .revision = "[123].*", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = DEFAULT_FEATURES, +@@ -96,10 +118,41 @@ static struct hwentry default_hw[] = { + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, + .minio = DEFAULT_MINIO, +- .checker_name = READSECTOR0, ++ .checker_name = HP_SW, ++ }, ++ { ++ .vendor = "HP", ++ .product = "HSV20.*", ++ .revision = "[^123].*", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "/sbin/mpath_prio_alua /dev/%n", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .selector = DEFAULT_SELECTOR, ++ .pgpolicy = MULTIBUS, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_UNDEF, ++ .minio = DEFAULT_MINIO, ++ .checker_name = TUR, ++ }, ++ { ++ .vendor = "HP", ++ .product = "HSV21.*", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "/sbin/mpath_prio_alua /dev/%n", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .selector = DEFAULT_SELECTOR, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = FAILBACK_UNDEF, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_UNDEF, ++ .minio = DEFAULT_MINIO, ++ .checker_name = TUR, + }, + /* +- * DDN controler family ++ * DDN controller family + * + * Maintainer : Christophe Varoqui + * Mail : christophe.varoqui@free.fr +@@ -120,7 +173,7 @@ static struct hwentry default_hw[] = { + .checker_name = READSECTOR0, + }, + /* +- * EMC / Clariion controler family ++ * EMC / Clariion controller family + * + * Maintainer : Edward Goggin, EMC + * Mail : egoggin@emc.com +@@ -128,7 +181,7 @@ static struct hwentry default_hw[] = { + { + .vendor = "EMC", + .product = "SYMMETRIX", +- .getuid = "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n", ++ .getuid = "scsi_id -g -u -ppre-spc3-83 -s /block/%n", + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, +@@ -142,10 +195,10 @@ static struct hwentry default_hw[] = { + }, + { + .vendor = "DGC", +- .product = "*", ++ .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 +210,7 @@ static struct hwentry default_hw[] = { + .checker_name = EMC_CLARIION, + }, + /* +- * Fujitsu controler family ++ * Fujitsu controller family + * + * Maintainer : Christophe Varoqui + * Mail : christophe.varoqui@free.fr +@@ -178,14 +231,14 @@ static struct hwentry default_hw[] = { + .checker_name = READSECTOR0, + }, + /* +- * Hitachi controler family ++ * Hitachi controller family + * +- * Maintainer : Christophe Varoqui +- * Mail : christophe.varoqui@free.fr ++ * Maintainer : Matthias Rudolph ++ * Mail : matthias.rudolph@hds.com + */ + { +- .vendor = "HITACHI", +- .product = "{A6189A,OPEN-}", ++ .vendor = "(HITACHI|HP)", ++ .product = "OPEN-.*", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = DEFAULT_FEATURES, +@@ -198,10 +251,25 @@ static struct hwentry default_hw[] = { + .minio = DEFAULT_MINIO, + .checker_name = READSECTOR0, + }, ++ { ++ .vendor = "HITACHI", ++ .product = "DF.*", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "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@suse.de + */ + { +@@ -224,7 +292,23 @@ static struct hwentry default_hw[] = { + .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, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_UNDEF, ++ .minio = DEFAULT_MINIO, ++ .checker_name = TUR, ++ }, ++ { ++ /* IBM Netfinity Fibre Channel RAID Controller Unit */ ++ .vendor = "IBM", ++ .product = "3526", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "mpath_prio_tpc /dev/%n", + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, +@@ -254,7 +338,7 @@ static struct hwentry default_hw[] = { + { + /* IBM ESS F20 aka Shark */ + .vendor = "IBM", +- .product = "2105F20", ++ .product = "2105(800|F20)", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = "1 queue_if_no_path", +@@ -268,11 +352,11 @@ static struct hwentry default_hw[] = { + .checker_name = TUR, + }, + { +- /* IBM DS6000 / SAN Volume Controller */ ++ /* IBM DS6000 */ + .vendor = "IBM", +- .product = "{1750500,2145}", ++ .product = "1750500", + .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, +@@ -300,10 +384,27 @@ static struct hwentry default_hw[] = { + .checker_name = TUR, + }, + { ++ /* IBM SAN Volume Controller */ ++ .vendor = "IBM", ++ .product = "2145", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "mpath_prio_alua /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 = DEFAULT_MINIO, ++ .checker_name = TUR, ++ }, ++ { + /* IBM S/390 ECKD DASD */ + .vendor = "IBM", + .product = "S/390 DASD ECKD", +- .getuid = "/sbin/dasdview -j /dev/%n", ++ .bl_product = "S/390.*", ++ .getuid = "dasd_id /dev/%n", + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, +@@ -315,29 +416,50 @@ static struct hwentry default_hw[] = { + .minio = DEFAULT_MINIO, + .checker_name = DIRECTIO, + }, +- /* +- * NETAPP controler family ++ /* ++ * NETAPP controller family + * +- * Maintainer : Igor Feoktistov +- * Mail : igorf@netapp.com ++ * Maintainer : Dave Wysochanski ++ * Mail : davidw@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@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@free.fr +@@ -346,7 +468,7 @@ static struct hwentry default_hw[] = { + .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 +504,7 @@ static struct hwentry default_hw[] = { + .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 +525,7 @@ static struct hwentry default_hw[] = { + .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, +@@ -422,7 +544,7 @@ static struct hwentry default_hw[] = { + */ + { + .vendor = "SUN", +- .product = "{StorEdge 3510,T4}", ++ .product = "(StorEdge 3510|T4)", + .getuid = DEFAULT_GETUID, + .getprio = NULL, + .features = DEFAULT_FEATURES, +diff --git a/libmultipath/lock.c b/libmultipath/lock.c +new file mode 100644 +index 0000000..0ca8783 +--- /dev/null ++++ b/libmultipath/lock.c +@@ -0,0 +1,8 @@ ++#include ++#include "lock.h" ++ ++void cleanup_lock (void * data) ++{ ++ unlock((pthread_mutex_t *)data); ++} ++ +diff --git a/libmultipath/lock.h b/libmultipath/lock.h +new file mode 100644 +index 0000000..6afecda +--- /dev/null ++++ b/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 */ +diff --git a/libmultipath/parser.c b/libmultipath/parser.c +index 9b0b5c2..f9c555e 100644 +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -25,6 +25,13 @@ #include "memory.h" + /* 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 @@ keyword_alloc(vector keywords, char *str + 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 @@ free_keywords(vector keywords) + struct keyword *keyword; + int i; + ++ if (!keywords) ++ return; ++ + for (i = 0; i < VECTOR_SIZE(keywords); i++) { + keyword = VECTOR_SLOT(keywords, i); + if (keyword->sub) +diff --git a/libmultipath/parser.h b/libmultipath/parser.h +index f0fdd94..95d4e6f 100644 +--- a/libmultipath/parser.h ++++ b/libmultipath/parser.h +@@ -76,6 +76,7 @@ extern void *set_value(vector strvec); + 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); + +diff --git a/libmultipath/pgpolicies.h b/libmultipath/pgpolicies.h +index 66c3c29..1f010a3 100644 +--- a/libmultipath/pgpolicies.h ++++ b/libmultipath/pgpolicies.h +@@ -9,7 +9,7 @@ #endif + + #define POLICY_NAME_SIZE 32 + +-/* Storage controlers capabilities */ ++/* Storage controllers capabilities */ + enum iopolicies { + IOPOLICY_UNDEF, + FAILOVER, +diff --git a/libmultipath/print.c b/libmultipath/print.c +index 6cc63e2..260aed1 100644 +--- a/libmultipath/print.c ++++ b/libmultipath/print.c +@@ -13,8 +13,8 @@ #include "structs.h" + #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 @@ snprint_uint (char * buff, size_t len, u + 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 @@ snprint_action (char * buff, size_t len, + } + } + ++/* ++ * path info printing functions ++ */ + static int + snprint_path_uuid (char * buff, size_t len, struct path * pp) + { +@@ -292,8 +305,8 @@ snprint_dm_path_state (char * buff, size + 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 @@ snprint_multipath (char * line, int len, + 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 @@ snprint_multipath (char * line, int len, + 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 @@ snprint_pathgroup (char * line, int len, + 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 @@ snprint_multipath_topology (char * buff, + 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) +diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c +index 79cee8b..1f0021a 100644 +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -15,6 +15,7 @@ #include "debug.h" + #include "pgpolicies.h" + #include "alias.h" + #include "defaults.h" ++#include "devmapper.h" + + pgpolicyfn *pgpolicies[] = { + NULL, +@@ -41,7 +42,7 @@ select_rr_weight (struct multipath * mp) + } + 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 @@ select_pgfailback (struct multipath * mp + } + 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 @@ select_pgpolicy (struct multipath * mp) + 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 @@ select_selector (struct multipath * mp) + } + 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 @@ select_alias (struct multipath * mp) + 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 @@ select_features (struct multipath * mp) + { + 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 @@ select_hwhandler (struct multipath * mp) + { + 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 @@ select_checker(struct path *pp) + + 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 @@ select_getuid (struct path * pp) + { + 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 @@ select_getprio (struct path * pp) + { + 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 @@ select_no_path_retry(struct multipath *m + } + 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 @@ select_minio (struct multipath * mp) + } + 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; + } +diff --git a/libmultipath/structs.c b/libmultipath/structs.c +index 024e790..db3f824 100644 +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -16,6 +16,7 @@ #include "config.h" + #include "debug.h" + #include "structs_vec.h" + #include "blacklist.h" ++#include "waiter.h" + + struct path * + alloc_path (void) +@@ -30,6 +31,7 @@ alloc_path (void) + pp->sg_id.scsi_id = -1; + pp->sg_id.lun = -1; + pp->fd = -1; ++ pp->priority = PRIO_UNDEF; + } + return pp; + } +@@ -365,3 +367,10 @@ pathcount (struct multipath * mpp, int s + + return count; + } ++ ++struct path * ++first_path (struct multipath * mpp) ++{ ++ struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0); ++ return VECTOR_SLOT(pgp->paths, 0); ++} +diff --git a/libmultipath/structs.h b/libmultipath/structs.h +index 2b96cfb..7db7faa 100644 +--- a/libmultipath/structs.h ++++ b/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 +@@ -18,6 +18,9 @@ #define NO_PATH_RETRY_UNDEF 0 + #define NO_PATH_RETRY_FAIL -1 + #define NO_PATH_RETRY_QUEUE -2 + ++#define PRIO_UNDEF -1 ++#define PRIO_DEFAULT 1 ++ + enum free_path_switch { + KEEP_PATHS, + FREE_PATHS +@@ -142,7 +145,7 @@ struct multipath { + struct mpentry * mpe; + struct hwentry * hwe; + +- /* daemon store a data blob for DM event waiter threads */ ++ /* threads */ + void * waiter; + + /* stats */ +@@ -183,10 +186,11 @@ struct multipath * find_mp_by_minor (vec + + 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 */ +diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c +index 86bf2a5..1a6d8e2 100644 +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -14,6 +14,7 @@ #include "dmparser.h" + #include "config.h" + #include "propsel.h" + #include "discovery.h" ++#include "waiter.h" + + + /* +@@ -58,8 +59,8 @@ adopt_paths (vector pathvec, struct mult + + 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 @@ orphan_paths (vector pathvec, struct mul + + 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 @@ verify_paths(struct multipath * mpp, str + 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); ++} ++ +diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h +index 348e9e5..81d9eaa 100644 +--- a/libmultipath/structs_vec.h ++++ b/libmultipath/structs_vec.h +@@ -9,17 +9,6 @@ #endif + 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 @@ struct multipath * add_map_without_path + 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 */ +diff --git a/libmultipath/util.c b/libmultipath/util.c +index 376ca04..911ec55 100644 +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -30,6 +30,15 @@ strcmp_chomp(char *str1, char *str2) + } + + 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); +diff --git a/libmultipath/util.h b/libmultipath/util.h +index 51f052a..e86bae2 100644 +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -2,6 +2,7 @@ #ifndef _UTIL_H + #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); +diff --git a/libmultipath/version.h b/libmultipath/version.h +new file mode 100644 +index 0000000..d577ec9 +--- /dev/null ++++ b/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 */ +diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c +new file mode 100644 +index 0000000..75ed90c +--- /dev/null ++++ b/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 ++#include ++#include ++#include ++#include ++ ++#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; ++} ++ +diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h +new file mode 100644 +index 0000000..0223924 +--- /dev/null ++++ b/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 */ +diff --git a/multipath-tools.spec.in b/multipath-tools.spec.in +index 494f09e..9d6a7ea 100644 +--- a/multipath-tools.spec.in ++++ b/multipath-tools.spec.in +@@ -50,6 +50,7 @@ rm -rf $RPM_BUILD_ROOT + %{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 +diff --git a/multipath.conf.annotated b/multipath.conf.annotated +index a1f04b7..f55c367 100644 +--- a/multipath.conf.annotated ++++ b/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 @@ #devices { + # # + # # 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 +diff --git a/multipath/main.c b/multipath/main.c +index 98f7207..accb230 100644 +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -46,8 +46,7 @@ #include + #include + #include + #include +- +-#include "main.h" ++#include + + static int + filter_pathvec (vector pathvec, char * refwwid) +@@ -73,7 +72,7 @@ static void + usage (char * progname) + { + fprintf (stderr, VERSION_STRING); +- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n", ++ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n", + progname); + fprintf (stderr, + "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \ +@@ -84,6 +83,7 @@ usage (char * progname) + "\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-h\t\tprint this usage text\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" \ +@@ -134,7 +134,7 @@ update_paths (struct multipath * mpp) + if (pp->state == PATH_UNCHECKED) + pathinfo(pp, conf->hwtable, DI_CHECKER); + +- if (!pp->priority) ++ if (pp->priority == PRIO_UNDEF) + pathinfo(pp, conf->hwtable, DI_PRIO); + } + } +@@ -281,8 +281,10 @@ configure (void) + + filter_pathvec(pathvec, refwwid); + +- if (conf->list) ++ if (conf->list) { ++ r = 0; + goto out; ++ } + + /* + * core logic entry point +@@ -305,7 +307,7 @@ main (int argc, char *argv[]) + 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 +324,7 @@ main (int argc, char *argv[]) + if (load_config(DEFAULT_CONFIGFILE)) + exit(1); + +- while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -365,6 +367,8 @@ #endif + usage(argv[0]); + } + break; ++ case 'h': ++ usage(argv[0]); + case ':': + fprintf(stderr, "Missing option arguement\n"); + usage(argv[0]); +diff --git a/multipath/main.h b/multipath/main.h +deleted file mode 100644 +index 8d5b285..0000000 +--- a/multipath/main.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- * Soft: Description here... +- * +- * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $ +- * +- * Author: Copyright (C) 2003 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. +- */ +- +-#ifndef _MAIN_H +-#define _MAIN_H +- +-/* +- * Build version +- */ +-#define PROG "multipath" +- +-#define VERSION_CODE 0x000407 +-#define DATE_CODE 0x030c06 +- +-#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 +diff --git a/multipath/multipath.8 b/multipath/multipath.8 +index 7133598..693872b 100644 +--- a/multipath/multipath.8 ++++ b/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 +@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco + .RB [\| \-v\ \c + .IR verbosity \|] + .RB [\| \-d \|] +-.RB [\| \-l | \-ll | \-f | \-F \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-F \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -29,6 +29,9 @@ print the created or updated multipath n + print all info : detected paths, coalesced paths (ie multipaths) and device maps + .RE + .TP ++.B \-h ++print usage text ++.TP + .B \-d + dry run, do not create or update devmaps + .TP +@@ -38,12 +41,6 @@ show the current multipath topology from + .B \-ll + show the current multipath topology from all available information (sysfs, the device mapper, path checkers ...) + .TP +-.TP +-.BI \-D " major:minor" +-update only the devmap the path pointed by +-.I major:minor +-is in +-.TP + .B \-f + flush a multipath device map specified as parameter, if unused + .TP +@@ -64,7 +61,7 @@ all paths in 1 priority group + 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. +diff --git a/multipathd/cli.c b/multipathd/cli.c +index 475819b..bd0d03b 100644 +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include "cli.h" + +@@ -305,6 +306,8 @@ genhelp_handler (void) + 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; +diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c +index 92d8221..b5d8e00 100644 +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -71,7 +71,7 @@ show_map_topology (char ** r, int * len, + + 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 @@ show_maps_topology (char ** r, int * len + 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 @@ cli_list_map_topology (void * v, char ** + 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) +diff --git a/multipathd/main.c b/multipathd/main.c +index 55a2c49..0b70714 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -55,136 +55,29 @@ #include "uxlsnr.h" + #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 @@ coalesce_maps(struct vectors *vecs, vect + { + 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 @@ coalesce_maps(struct vectors *vecs, vect + 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 @@ sync_map_state(struct multipath *mpp) + 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 @@ ev_remove_path (char * devname, struct v + } + 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 @@ out: + 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 @@ static void + 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 @@ static void + defered_failback_tick (vector mpvec) + { + struct multipath * mpp; +- int i; ++ unsigned int i; + + vector_foreach_slot (mpvec, mpp, i) { + /* +@@ -1163,7 +835,7 @@ static void + 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 @@ checkerloop (void *ap) + { + 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 @@ configure (struct vectors * vecs, int st + 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 @@ configure (struct vectors * vecs, int st + /* + * save new set of maps formed by considering current path state + */ ++ vector_free(vecs->mpvec); + vecs->mpvec = mpvec; + + /* +@@ -1435,6 +1109,7 @@ reconfigure (struct vectors * vecs) + 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 @@ init_vecs (void) + 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_init(void) + 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 @@ setscheduler (void) + { + int res; + static struct sched_param sched_param = { +- sched_priority: 99 ++ .sched_priority = 99 + }; + + res = sched_setscheduler (0, SCHED_RR, &sched_param); +diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 +index 48b1b04..88ae9c6 100644 +--- a/multipathd/multipathd.8 ++++ b/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 @@ multipathd \- multipath daemon + + 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" +diff --git a/path_priority/pp_alua/main.c b/path_priority/pp_alua/main.c +index 190fbdc..ba8da99 100644 +--- a/path_priority/pp_alua/main.c ++++ b/path_priority/pp_alua/main.c +@@ -12,8 +12,6 @@ + * + * This file is released under the GPL. + */ +-#include +- + #include + #include + +@@ -241,7 +239,7 @@ main (int argc, char **argv) + mknod( + devicepath, + S_IFBLK|S_IRUSR|S_IWUSR, +- MKDEV(major, minor) ++ makedev(major, minor) + ); + + } +diff --git a/path_priority/pp_alua/mpath_prio_alua.8 b/path_priority/pp_alua/mpath_prio_alua.8 +index 4843bcd..58568a5 100644 +--- a/path_priority/pp_alua/mpath_prio_alua.8 ++++ b/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 +diff --git a/path_priority/pp_alua/rtpg.c b/path_priority/pp_alua/rtpg.c +index 9aea560..701f9d5 100644 +--- a/path_priority/pp_alua/rtpg.c ++++ b/path_priority/pp_alua/rtpg.c +@@ -21,6 +21,7 @@ #include + #include + #include + #include ++#include + + #define __user + #include +@@ -28,7 +29,7 @@ #include + #include "rtpg.h" + + #define SENSE_BUFF_LEN 32 +-#define DEF_TIMEOUT 60000 ++#define DEF_TIMEOUT 300000 + + /* + * Macro used to print debug messaged. +@@ -251,14 +252,38 @@ do_rtpg(int fd, void* resp, long resplen + int + get_asymmetric_access_state(int fd, unsigned int tpg) + { +- unsigned char buf[128]; ++ unsigned char *buf; + struct rtpg_data * tpgd; + struct rtpg_tpg_dscr * dscr; + int rc; +- +- rc = do_rtpg(fd, buf, sizeof(buf)); ++ int buflen; ++ uint32_t scsi_buflen; ++ ++ buflen = 128; /* Initial value from old code */ ++ buf = (unsigned char *)malloc(buflen); ++ if (!buf) { ++ PRINT_DEBUG ("malloc failed: could not allocate" ++ "%u bytes\n", buflen); ++ return -RTPG_RTPG_FAILED; ++ } ++ rc = do_rtpg(fd, buf, buflen); + if (rc < 0) + return rc; ++ scsi_buflen = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; ++ if (buflen < (scsi_buflen + 4)) { ++ free(buf); ++ buf = (unsigned char *)malloc(scsi_buflen); ++ if (!buf) { ++ PRINT_DEBUG ("malloc failed: could not allocate" ++ "%u bytes\n", scsi_buflen); ++ return -RTPG_RTPG_FAILED; ++ } ++ buflen = scsi_buflen; ++ rc = do_rtpg(fd, buf, buflen); ++ if (rc < 0) ++ goto out; ++ } ++ + + tpgd = (struct rtpg_data *) buf; + rc = -RTPG_TPG_NOT_FOUND; +@@ -274,7 +299,8 @@ get_asymmetric_access_state(int fd, unsi + } + } + } +- ++out: ++ free(buf); + return rc; + } + +diff --git a/path_priority/pp_alua/spc3.h b/path_priority/pp_alua/spc3.h +index 11f5dbd..bddbbdd 100644 +--- a/path_priority/pp_alua/spc3.h ++++ b/path_priority/pp_alua/spc3.h +@@ -148,10 +148,10 @@ struct inquiry_data { + /* ......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 */ +diff --git a/path_priority/pp_balance_units/pp_balance_units.c b/path_priority/pp_balance_units/pp_balance_units.c +index 307a959..ea70f13 100644 +--- a/path_priority/pp_balance_units/pp_balance_units.c ++++ b/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 FILE_NAME_SIZE 255 + #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 @@ struct path { + char serial[SERIAL_SIZE]; + }; + +-struct controler { ++struct controller { + char serial[SERIAL_SIZE]; + int path_count; + }; +@@ -172,7 +172,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u + } + + static int +-get_serial (char * str, char * devt) ++get_serial (char * str, int maxlen, char * devt) + { + int fd; + int len; +@@ -181,20 +181,22 @@ get_serial (char * str, char * devt) + 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 @@ get_paths (vector pathvec) + 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 @@ get_paths (vector pathvec) + } + + 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 @@ get_controlers (vector controlers, vecto + } + + 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 @@ int + 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 @@ main (int argc, char **argv) + if (optinddev_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", +diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile +new file mode 100644 +index 0000000..a0249a5 +--- /dev/null ++++ b/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) +diff --git a/path_priority/pp_hds_modular/pp_hds_modular.c b/path_priority/pp_hds_modular/pp_hds_modular.c +new file mode 100644 +index 0000000..f38ebcf +--- /dev/null ++++ b/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 ++ * ++ * This file is released under the GPL. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* 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] \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 \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); ++} ++ +diff --git a/path_priority/pp_tpc/pp_tpc.c b/path_priority/pp_tpc/pp_tpc.c +index 76e7c47..a7ed7ad 100644 +--- a/path_priority/pp_tpc/pp_tpc.c ++++ b/path_priority/pp_tpc/pp_tpc.c +@@ -62,18 +62,13 @@ int sgi_tpc_prio(const char *dev) + goto out; + } + +- if ( /* Auto-volume Transfer Enabled */ +- (sense_buffer[8] & 0x80) != 0x80 ) { +- fprintf(stderr, "Auto-volume Transfer not enabled"); +- } +- + if ( /* Current Volume Path Bit */ + ( sense_buffer[8] & 0x01) == 0x01 ) { + /* + * This volume was owned by the controller receiving + * the inquiry command. + */ +- ret |= 0x02; ++ ret |= 0x01; + } + + /* Volume Preferred Path Priority */ +@@ -83,7 +78,7 @@ int sgi_tpc_prio(const char *dev) + * Access to this volume is most preferred through + * this path and other paths with this value. + */ +- ret |= 0x04; ++ ret |= 0x02; + break; + case 0x02: + /* +@@ -91,8 +86,7 @@ int sgi_tpc_prio(const char *dev) + * as a secondary path. Typically this path would be used + * for fail-over situations. + */ +- ret |= 0x01; +- break; ++ /* Fallthrough */ + default: + /* Reserved values */ + break; diff --git a/multipath-tools-no-gz-for-manpage b/multipath-tools-no-gz-for-manpage new file mode 100644 index 0000000..e07c7ea --- /dev/null +++ b/multipath-tools-no-gz-for-manpage @@ -0,0 +1,140 @@ +diff --git a/devmap_name/Makefile b/devmap_name/Makefile +index 380c85b..5551c9b 100644 +--- a/devmap_name/Makefile ++++ b/devmap_name/Makefile +@@ -22,21 +22,19 @@ prepare: + + glibc: prepare $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + klibc: prepare $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + install: + install -d $(DESTDIR)$(bindir) + install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + install -d $(DESTDIR)$(mandir) +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ rm $(DESTDIR)$(mandir)/$(EXEC).8 + + clean: + rm -f core *.o $(EXEC) *.gz +diff --git a/kpartx/Makefile b/kpartx/Makefile +index bf6e6c1..691ecbe 100644 +--- a/kpartx/Makefile ++++ b/kpartx/Makefile +@@ -27,11 +27,9 @@ prepare: + + glibc: prepare $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz +- ++ + klibc: prepare $(OBJS) + $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + $(MULTIPATHLIB)-$(BUILD).a: + make -C $(multipathdir) BUILD=$(BUILD) +@@ -40,7 +38,7 @@ install: + install -d $(DESTDIR)$(bindir) + install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) + install -d $(DESTDIR)$(mandir) +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + + uninstall: + rm -f $(DESTDIR)$(bindir)/$(EXEC) +diff --git a/multipath/Makefile b/multipath/Makefile +index 646dfc2..add1972 100644 +--- a/multipath/Makefile ++++ b/multipath/Makefile +@@ -25,11 +25,9 @@ prepare: + + glibc: prepare $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + klibc: prepare $(OBJS) + $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + $(CHECKERSLIB)-$(BUILD).a: + make -C $(checkersdir) BUILD=$(BUILD) $(BUILD) +@@ -43,12 +41,12 @@ install: + install -d $(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) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + + uninstall: + rm $(DESTDIR)/etc/udev/rules.d/multipath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ rm $(DESTDIR)$(mandir)/$(EXEC).8 + + clean: + rm -f core *.o $(EXEC) *.gz +diff --git a/multipathd/Makefile b/multipathd/Makefile +index 8ad25ee..da351dc 100644 +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -35,7 +35,6 @@ klibc: + + $(EXEC): clean $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + $(CHECKERSLIB)-glibc.a: + $(MAKE) -C $(checkersdir) BUILD=glibc glibc +@@ -48,12 +47,12 @@ install: + install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) + install -d $(DESTDIR)$(rcdir) + install -d $(DESTDIR)$(mandir) +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + + uninstall: + rm -f $(DESTDIR)$(bindir)/$(EXEC) + rm -f $(DESTDIR)$(rcdir)/$(EXEC) +- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ rm -f $(DESTDIR)$(mandir)/$(EXEC).8 + + clean: + $(MAKE) -C $(multipathdir) prepare DAEMON=1 +diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile +index 983ffe3..c38990e 100644 +--- a/path_priority/pp_alua/Makefile ++++ b/path_priority/pp_alua/Makefile +@@ -35,20 +35,17 @@ glibc: $(OBJS) + klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + +-install: $(BUILD) $(EXEC).8.gz ++install: $(BUILD) $(EXEC).8 + $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) +- $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ $(INSTALL) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/$(EXEC).8 + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ rm $(DESTDIR)$(mandir)/$(EXEC).8 + + clean: + rm -f *.o *.gz $(EXEC) + +-$(EXEC).8.gz: $(EXEC).8 +- $(GZIP) $< >$@ +- + main.o: main.c rtpg.h spc3.h + + rtpg.o: rtpg.c rtpg.h spc3.h diff --git a/multipath-tools-online-device.patch b/multipath-tools-online-device.patch new file mode 100644 index 0000000..b8970a3 --- /dev/null +++ b/multipath-tools-online-device.patch @@ -0,0 +1,107 @@ +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -209,6 +209,44 @@ sysfs_get_size (char * sysfs_path, char + return 0; + } + ++int ++sysfs_get_online (char * sysfs_path, char * dev) ++{ ++ char attr_path[SYSFS_PATH_SIZE]; ++ char attr_buff[SYSFS_PATH_SIZE]; ++ long r; ++ char *p; ++ ++ if (safe_sprintf(attr_path, "%s/block/%s/online", sysfs_path, dev)) ++ return -1; ++ ++ if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) ++ return -1; ++ ++ r = strtol(attr_buff,&p, 10); ++ ++ if (attr_buff != p && r > 0) ++ return 1; ++ ++ return 0; ++} ++ ++int writeattr (char *path, const char *value) ++{ ++ struct sysfs_attribute *attr; ++ int retval; ++ ++ attr = sysfs_open_attribute(path); ++ if (!attr) ++ return -1; ++ ++ retval = sysfs_write_attribute(attr, value, strlen(value)); ++ ++ sysfs_close_attribute(attr); ++ ++ return retval > 0? -1 : 0; ++} ++ + /* + * udev might be slow creating node files : wait + */ +@@ -565,6 +603,30 @@ sysfs_pathinfo(struct path * curpath) + return 0; + } + ++extern int ++online_device(struct path *curpath) ++{ ++ int online; ++ char attr_path[FILE_NAME_SIZE]; ++ ++ online = sysfs_get_online(sysfs_path, curpath->dev); ++ if (online > 0) ++ return 0; ++ else if(online < 0) ++ return 1; ++ ++ if(safe_sprintf(attr_path, "%s/block/%s/device/online", ++ sysfs_path, curpath->dev)) { ++ condlog(0, "attr_path too small"); ++ return 1; ++ } ++ ++ condlog(1,"%s: setting device online", curpath->dev); ++ writeattr(attr_path, "1"); ++ ++ return 0; ++} ++ + static int + apply_format (char * string, char * cmd, struct path * pp) + { +diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -28,6 +28,7 @@ int sysfs_get_dev (char * sysfs_path, ch + + int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *); + int path_discovery (vector pathvec, struct config * conf, int flag); ++int online_device (struct path *curpath); + + void basename (char *, char *); + int get_serial (char * buff, int fd); +diff --git a/multipathd/main.c b/multipathd/main.c +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1185,6 +1185,13 @@ checkerloop (void *ap) + condlog(0, "%s: checkfn is void", pp->dev); + continue; + } ++ ++ /* ++ * Set the device online for checkers ++ * to run successfully ++ */ ++ online_device(pp); ++ + newstate = pp->checkfn(pp->fd, checker_msg, + &pp->checker_context); + diff --git a/multipath-tools-strip.patch b/multipath-tools-strip.patch new file mode 100644 index 0000000..c90c069 --- /dev/null +++ b/multipath-tools-strip.patch @@ -0,0 +1,121 @@ +--- devmap_name/Makefile ++++ devmap_name/Makefile +@@ -28,7 +28,7 @@ + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + install -d $(DESTDIR)$(mandir) + install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + +--- kpartx/Makefile ++++ kpartx/Makefile +@@ -36,7 +36,7 @@ + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir) + install -d $(DESTDIR)$(mandir) + install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + +--- multipath/Makefile ++++ multipath/Makefile +@@ -37,7 +37,7 @@ + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + install -d $(DESTDIR)/etc/udev/rules.d + install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/ + install -d $(DESTDIR)$(mandir) +--- multipathd/Makefile ++++ multipathd/Makefile +@@ -44,7 +44,7 @@ + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir) + install -d $(DESTDIR)$(rcdir) + install -d $(DESTDIR)$(mandir) + install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) +--- path_priority/pp_alua/Makefile ++++ path_priority/pp_alua/Makefile +@@ -36,7 +36,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(BUILD) $(EXEC).8 +- $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ $(INSTALL) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + $(INSTALL) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/$(EXEC).8 + + uninstall: +--- path_priority/pp_balance_units/Makefile ++++ path_priority/pp_balance_units/Makefile +@@ -35,7 +35,7 @@ + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +--- path_priority/pp_emc/Makefile ++++ path_priority/pp_emc/Makefile +@@ -14,7 +14,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +--- path_priority/pp_hds_modular/Makefile ++++ path_priority/pp_hds_modular/Makefile +@@ -14,7 +14,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +--- path_priority/pp_netapp/Makefile ++++ path_priority/pp_netapp/Makefile +@@ -14,7 +14,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +--- path_priority/pp_random/Makefile ++++ path_priority/pp_random/Makefile +@@ -14,7 +14,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +--- path_priority/pp_tpc/Makefile ++++ path_priority/pp_tpc/Makefile +@@ -14,7 +14,7 @@ + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) diff --git a/multipath-tools.changes b/multipath-tools.changes new file mode 100644 index 0000000..b54107b --- /dev/null +++ b/multipath-tools.changes @@ -0,0 +1,398 @@ +------------------------------------------------------------------- +Mon Dec 4 16:51:13 CET 2006 - dmueller@suse.de + +- don't build as root + +------------------------------------------------------------------- +Fri Nov 17 11:55:00 CET 2006 - hare@suse.de + +- integrate upstream fixes +- update udev rule for YaST2 dmraid support (217807]) + +------------------------------------------------------------------- +Mon Nov 6 13:11:17 CET 2006 - hare@suse.de + +- Really fixup udev rule (216167). + +------------------------------------------------------------------- +Fri Oct 20 02:07:47 CEST 2006 - ro@suse.de + +- make it build + +------------------------------------------------------------------- +Mon Sep 25 10:03:49 CEST 2006 - hare@suse.de + +- update to latest fixes from git tree +- remove fixes integrated in upstream +- fixup udev rule (#203688) + +------------------------------------------------------------------- +Thu Sep 14 00:18:10 CEST 2006 - ro@suse.de + +- use device-mapper-devel in BuildRequires + +------------------------------------------------------------------- +Thu Aug 31 10:56:01 CEST 2006 - hare@suse.de + +- include latest fixes from git tree +- update kpartx_id and udev rules to work + with dmraid. +- Fix return value for multipath -l + +------------------------------------------------------------------- +Thu Aug 17 02:07:59 CEST 2006 - ro@suse.de + +- workaround problem in git-patch + normal patch can't do a "rename", so copy file first + +------------------------------------------------------------------- +Tue Jul 11 15:04:59 CEST 2006 - hare@suse.de + +- Update to official version 0.4.7 +- Refactor git update to apply to 0.4.7 + +------------------------------------------------------------------- +Wed Jun 28 13:51:36 CEST 2006 - hare@suse.de + +- Remove blacklisting of dasd device node, + use product_blacklist instead (#188688) + +------------------------------------------------------------------- +Mon Jun 12 15:14:41 CEST 2006 - hare@suse.de + +- Add 72-multipath-compat.rules to create 'by-name' + symlink again for compability (#183663) + +------------------------------------------------------------------- +Fri Jun 2 12:47:05 CEST 2006 - hare@suse.de + +- Merge in fixed from upstream + - Set device-mapper name correctly (#181127) + +------------------------------------------------------------------- +Thu Jun 1 17:29:23 CEST 2006 - hare@suse.de + +- Merge in fixes from upstream + - Fixup aliasing handling + - Fix string length in pp_alua +- Use correct regexp patterns for hwtable (#177842) +- Fixup 71-multipath.rules to work correctly with the + updated device-mapper online/offline events (#176516 - LTC23961) +- Add kpartx_id for the updated 71-multipath.rules + +------------------------------------------------------------------- +Mon May 22 17:16:00 CEST 2006 - schwab@suse.de + +- Don't strip binaries. + +------------------------------------------------------------------- +Tue May 2 12:48:56 CEST 2006 - hare@suse.de + +- Merge in fixes from upstream + - Merged local patches + - Added hds_modular prioritizer +- Remove merged patches +- Allow for setting of maximum number of open files (#149979) +- Implement 'stop' for init scripts + +------------------------------------------------------------------- +Mon Apr 10 09:48:16 CEST 2006 - hare@suse.de + +- Lowering priority for pp_tpc +- Split off DS6000 to fixup priority handler (#161347) + +------------------------------------------------------------------- +Wed Apr 5 12:14:53 CEST 2006 - hare@suse.de + +- Disable debug messages in pp_tpc. + +------------------------------------------------------------------- +Wed Mar 29 09:27:50 CEST 2006 - hare@suse.de + +- Explicitely create partitions at boot time (#159927) + +------------------------------------------------------------------- +Thu Mar 23 11:36:25 CET 2006 - hare@suse.de + +- Add hwtable entry for IBM 3526. + +------------------------------------------------------------------- +Tue Mar 14 16:40:41 CET 2006 - hare@suse.de + +- Fix another typo in mpath_id. + +------------------------------------------------------------------- +Tue Mar 14 16:20:33 CET 2006 - hare@suse.de + +- Fix typo in mpath_id. + +------------------------------------------------------------------- +Mon Mar 13 13:29:08 CET 2006 - hare@suse.de + +- Fix autobuild warnings. +- Include some minor fixed from upstream. + +------------------------------------------------------------------- +Thu Mar 9 11:28:11 CET 2006 - hare@suse.de + +- Add mpath_id program to call kpartx only on multipathed + devices (#149995 - LTC21557). +- Include latest fixes from upstream. + +------------------------------------------------------------------- +Wed Feb 8 16:13:15 CET 2006 - hare@suse.de + +- Add device blacklisting (#85778) +- Further manpage installation fixes (#146179, #147053, #147911) + +------------------------------------------------------------------- +Wed Jan 25 21:38:27 CET 2006 - mls@suse.de + +- converted neededforbuild to BuildRequires + +------------------------------------------------------------------- +Thu Jan 19 13:59:32 CET 2006 - hare@suse.de + +- Fix manpage installation. + +------------------------------------------------------------------- +Tue Jan 17 09:01:03 CET 2006 - hare@suse.de + +- Include latest git fixes +- Remove old patches which are now upstream +- Add new hwtable entry for shark (#142176) + +------------------------------------------------------------------- +Fri Dec 16 15:20:47 CET 2005 - hare@suse.de + +- Fix dependencies for /etc/init.d/boot.multipath +- Fix kpartx rules to generate proper partition names. + +------------------------------------------------------------------- +Wed Dec 7 16:49:02 CET 2005 - hare@suse.de + +- Update to multipath-tools-0.4.6 +- Include latest git fixes +- Port patches from SLES9 SP3 + +------------------------------------------------------------------- +Mon Oct 31 12:30:14 CET 2005 - dmueller@suse.de + +- don't build as root + +------------------------------------------------------------------- +Mon Sep 5 17:40:04 CEST 2005 - matz@suse.de + +- Fix broken usage of self-defined syscall [#114933]. + +------------------------------------------------------------------- +Fri Aug 26 16:00:36 CEST 2005 - hare@suse.de + +- Fix kpartx DASD partition support + +------------------------------------------------------------------- +Thu Aug 4 16:45:27 CEST 2005 - hare@suse.de + +- Add 'directio' path checker +- Add support for S/390 DASD (PAV enablement). +- Update to package from SLES9 + +------------------------------------------------------------------- +Thu Jun 23 10:05:56 CEST 2005 - lmb@suse.de + +- LUs with a WWN containing "fd" were blacklisted (#93562). + +------------------------------------------------------------------- +Thu Jun 16 16:33:42 CEST 2005 - lmb@suse.de + +- Remove stray newline character from /dev/disk/by-name/ entries + (#85798, #86763) +- Clear /dev/disk/by-name/ on boot. (#85978) +- scsi_id now handles EMC Symmetrix; remove work-around for #86760. + +------------------------------------------------------------------- +Wed Jun 15 13:31:47 CEST 2005 - meissner@suse.de + +- use RPM_OPT_FLAGS. + +------------------------------------------------------------------- +Mon Jun 13 23:51:59 CEST 2005 - ro@suse.de + +- neededforbuild: udev -> sysfsutils + +------------------------------------------------------------------- +Tue Jun 7 15:38:36 CEST 2005 - lmb@suse.de + +- Import fixes from upstream. +- Hardware table updates for IBM ESS and EMC CX (#81688). +- Reinstate paths correctly after failure/restore cycle (#85781, + #86444). +- Create map names again and fix segfault in devmap_name (#85798). + +------------------------------------------------------------------- +Tue May 24 15:16:16 CEST 2005 - hare@suse.de + +- Fix segmentation fault with EMC Symmetrix (#85614). +- Update EMC Symmetrix entry in hwtable. + +------------------------------------------------------------------- +Mon May 23 12:21:31 CEST 2005 - hare@suse.de + +- Add hwtable entry for IBM DS6000. (#63903) +- Do a rescan for devices if multipath command line option is set. + +------------------------------------------------------------------- +Fri May 20 15:29:45 CEST 2005 - hare@suse.de + +- Fix devmap_name to use mapname and return proper status (#84748). + +------------------------------------------------------------------- +Thu May 12 12:10:39 CEST 2005 - lmb@suse.de + +- Don't complain about default prio callout command (#81695). +- Reflect recent changes in boot.multipath as well as multipathd init + scripts. +- Actually fail paths when they are detected to be failed by multipathd + (#81679). +- killproc/startproc/checkproc can't be used with multipathd because of + the way the daemon switches to its own namespace (#80443). + +------------------------------------------------------------------- +Mon May 9 11:18:35 CEST 2005 - hare@suse.de + +- Use proper path checker for SGI TPC arrays. +- Update hwtable entries for SGI TP9400 and SGI TP9500. +- Write correct PID file (#80443). + +------------------------------------------------------------------- +Mon Apr 25 11:41:33 CEST 2005 - lmb@suse.de + +- Update to 0.4.4: pp_alua now licensed as GPL (#78628). +- multipath-tools-oom-adj.patch: oom_adj to a valid value. + +------------------------------------------------------------------- +Thu Apr 21 10:50:05 CEST 2005 - lmb@suse.de + +- Update to 0.4.4-pre18 which fixes the multipathd to initialize + correctly in the absence of a configuration file (79239). + +------------------------------------------------------------------- +Wed Apr 20 16:05:56 CEST 2005 - lmb@suse.de + +- Put multipath cache back into /dev because /var might not be mounted. +- Correct hwtable entry SGI TP9400, TP9500 and IBM 3542. + +------------------------------------------------------------------- +Wed Apr 20 13:32:51 CEST 2005 - lmb@suse.de + +- Update to 0.4.4-pre16 +- Build against device-mapper.1.01.xx correctly. + +------------------------------------------------------------------- +Tue Apr 19 12:02:49 CEST 2005 - lmb@suse.de + +- Build w/o device-mapper update again. + +------------------------------------------------------------------- +Mon Apr 18 14:21:59 CEST 2005 - lmb@suse.de + +- Update to 0.4.4-pre14 +- Build versus device-mapper-1.01.01 to prevent deadlocks in + kernel-space. +- Fix devmap_name to work with udev. +- Fix startup of multipathd w/o configuration file present. + +------------------------------------------------------------------- +Fri Apr 15 14:46:19 CEST 2005 - lmb@suse.de + +- Add path priority checker for EMC CLARiiON and make necessary + adjustments so that it gets called by default (#62491). +- Set the default udev dir to '/dev' + +------------------------------------------------------------------- +Fri Apr 15 13:18:42 CEST 2005 - hare@suse.de + +- Fix to allocate default strings (#78056) +- Fix default entry for TPC9500. + +------------------------------------------------------------------- +Wed Apr 13 08:30:21 CEST 2005 - hare@suse.de + +- Added pp_alua path priority checker. +- Update to multipath-tools-0.4.4-pre12. + +------------------------------------------------------------------- +Mon Apr 11 13:32:05 CEST 2005 - hare@suse.de + +- Update to multipath-tools-0.4.4-pre10. + +------------------------------------------------------------------- +Fri Apr 8 09:38:16 CEST 2005 - hare@suse.de + +- Update multipath to handle only true multipath devices (#62491). +- Update kpartx to use the device mapper target name if available. +- Add boot.multipath script for early set up of multipath targets. + +------------------------------------------------------------------- +Thu Mar 31 09:32:12 CEST 2005 - hare@suse.de + +- Update devmap_name to select targets by table type (#62493). + +------------------------------------------------------------------- +Tue Jan 25 11:16:26 CET 2005 - lmb@suse.de + +- Update to 0.4.2 and fix some bugs + add support for the extended DM + multipath kernel module. (#47491) + +------------------------------------------------------------------- +Thu Nov 11 18:15:15 CET 2004 - hare@suse.de + +- Fix bugs to make it work on S/390 (#47491). + +------------------------------------------------------------------- +Fri Nov 5 13:58:00 CET 2004 - hare@suse.de + +- Update to version 0.3.6 (#47491). +- Fix multipath init script +- Install configuration file example. +- Install multipathd in /sbin instead of /usr/bin. + +------------------------------------------------------------------- +Tue Jul 20 09:22:11 CEST 2004 - fehr@suse.de + +- updated README mp-tools-issues.pdf (see #40640) + +------------------------------------------------------------------- +Wed Jun 9 12:18:01 CEST 2004 - fehr@suse.de + +- added pdf with README to package (see #40640) + +------------------------------------------------------------------- +Thu Jun 3 18:11:41 CEST 2004 - fehr@suse.de + +- updated to version 0.2.1 +- removed patches zero-currpath.patch and rm-newline-in-name.patch + already contained in 0.2.1 + +------------------------------------------------------------------- +Thu Jun 3 09:38:49 CEST 2004 - fehr@suse.de + +- added patch zero-currpath.patch (see bugzilla #40640) + +------------------------------------------------------------------- +Wed May 26 20:14:05 CEST 2004 - uli@suse.de + +- fixed to build on s390x + +------------------------------------------------------------------- +Wed May 26 10:57:37 CEST 2004 - fehr@suse.de + +- added patch rm-newline-in-name.patch (see bugzilla #40640) + +------------------------------------------------------------------- +Tue May 25 10:43:15 CEST 2004 - fehr@suse.de + +- created initial version of a SuSE package from version 0.2.0 of + multipath tools + +------------------------------------------------------------------- diff --git a/multipath-tools.spec b/multipath-tools.spec new file mode 100644 index 0000000..cc8f892 --- /dev/null +++ b/multipath-tools.spec @@ -0,0 +1,322 @@ +# +# spec file for package multipath-tools (Version 0.4.7) +# +# Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany. +# This file and all modifications and additions to the pristine +# package are under the same license as the package itself. +# +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: multipath-tools +BuildRequires: device-mapper-devel readline-devel sysfsutils +URL: http://christophe.varoqui.free.fr/ +License: BSD License and BSD-like, GNU General Public License (GPL) +Group: System/Base +Requires: device-mapper +%if %suse_version > 800 +PreReq: %insserv_prereq +%endif +Autoreqprov: on +Version: 0.4.7 +Release: 29 +Summary: Tools to Manage Multipathed Devices with the device-mapper +Source: multipath-tools-%{version}.tar.bz2 +Source1: multipathd +Source3: 71-multipath.rules +Source4: boot.multipath +Source5: mpath_id +Source6: kpartx_id +Source7: 72-multipath-compat.rules +BuildRoot: %{_tmppath}/%{name}-%{version}-build +Patch0: %{name}-git-update.patch +Patch10: %{name}-online-device.patch +Patch11: %{name}-no-gz-for-manpage +Patch15: %{name}-strip.patch + +%description +This package provides the tools to manage multipathed devices by +instructing the device-mapper multipath module what to do. The tools +are: + +- multipath: scans the system for multipathed devices, assembles + them, and updates the device-mapper's maps + +- multipathd: waits for maps events then execs multipath + +- devmap-name: provides a meaningful device name to udev for devmaps + +- kpartx: maps linear devmaps to device partitions, which makes +multipath maps partionable + + + +Authors: +-------- + Christophe Varoqui + +%prep +%setup -n multipath-tools-%{version} +%patch0 -p1 +%patch11 -p1 +%patch15 + +%build +make OPTFLAGS="$RPM_OPT_FLAGS" BUILD=glibc + +%install +mkdir -p $RPM_BUILD_ROOT/sbin +mkdir -p $RPM_BUILD_ROOT%{_mandir}/man8 +make DESTDIR=$RPM_BUILD_ROOT install +rm $RPM_BUILD_ROOT/etc/udev/rules.d/multipath.rules +install -m 644 %{SOURCE3} $RPM_BUILD_ROOT/etc/udev/rules.d +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT/etc/udev/rules.d +mkdir -p $RPM_BUILD_ROOT/etc/init.d +install -m 744 %{SOURCE1} $RPM_BUILD_ROOT/etc/init.d +install -m 744 %{SOURCE4} $RPM_BUILD_ROOT/etc/init.d +install -m 755 %{SOURCE5} $RPM_BUILD_ROOT/sbin +install -m 755 %{SOURCE6} $RPM_BUILD_ROOT/sbin +mkdir -p $RPM_BUILD_ROOT/var/cache/multipath/ + +%clean +[ "$RPM_BUILD_ROOT" != / ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; + +%post +#%{insserv /etc/init.d/multipathd} +#%{fillup_and_insserv boot.multipath} + +%postun +%{insserv_cleanup} + +%files +%defattr(-,root,root) +%doc AUTHOR COPYING README ChangeLog +%doc multipath.conf* +%config /etc/init.d/multipathd +%config /etc/init.d/boot.multipath +%config /etc/udev +/sbin/devmap_name +/sbin/multipath +/sbin/kpartx +/sbin/mpath_id +/sbin/kpartx_id +/sbin/multipathd +/sbin/mpath_prio_netapp +/sbin/mpath_prio_balance_units +/sbin/mpath_prio_random +/sbin/mpath_prio_alua +/sbin/mpath_prio_emc +/sbin/mpath_prio_tpc +/sbin/mpath_prio_hds_modular +%attr (0700, root, root) /var/cache/multipath +%{_mandir}/man8/devmap_name.8* +%{_mandir}/man8/multipath.8* +%{_mandir}/man8/kpartx.8* +%{_mandir}/man8/multipathd.8* +%{_mandir}/man8/mpath_prio_alua.8* + +%changelog -n multipath-tools +* Mon Dec 04 2006 - dmueller@suse.de +- don't build as root +* Fri Nov 17 2006 - hare@suse.de +- integrate upstream fixes +- update udev rule for YaST2 dmraid support (217807]) +* Mon Nov 06 2006 - hare@suse.de +- Really fixup udev rule (216167). +* Fri Oct 20 2006 - ro@suse.de +- make it build +* Mon Sep 25 2006 - hare@suse.de +- update to latest fixes from git tree +- remove fixes integrated in upstream +- fixup udev rule (#203688) +* Thu Sep 14 2006 - ro@suse.de +- use device-mapper-devel in BuildRequires +* Thu Aug 31 2006 - hare@suse.de +- include latest fixes from git tree +- update kpartx_id and udev rules to work + with dmraid. +- Fix return value for multipath -l +* Thu Aug 17 2006 - ro@suse.de +- workaround problem in git-patch + normal patch can't do a "rename", so copy file first +* Tue Jul 11 2006 - hare@suse.de +- Update to official version 0.4.7 +- Refactor git update to apply to 0.4.7 +* Wed Jun 28 2006 - hare@suse.de +- Remove blacklisting of dasd device node, + use product_blacklist instead (#188688) +* Mon Jun 12 2006 - hare@suse.de +- Add 72-multipath-compat.rules to create 'by-name' + symlink again for compability (#183663) +* Fri Jun 02 2006 - hare@suse.de +- Merge in fixed from upstream + - Set device-mapper name correctly (#181127) +* Thu Jun 01 2006 - hare@suse.de +- Merge in fixes from upstream + - Fixup aliasing handling + - Fix string length in pp_alua +- Use correct regexp patterns for hwtable (#177842) +- Fixup 71-multipath.rules to work correctly with the + updated device-mapper online/offline events (#176516 - LTC23961) +- Add kpartx_id for the updated 71-multipath.rules +* Mon May 22 2006 - schwab@suse.de +- Don't strip binaries. +* Tue May 02 2006 - hare@suse.de +- Merge in fixes from upstream + - Merged local patches + - Added hds_modular prioritizer +- Remove merged patches +- Allow for setting of maximum number of open files (#149979) +- Implement 'stop' for init scripts +* Mon Apr 10 2006 - hare@suse.de +- Lowering priority for pp_tpc +- Split off DS6000 to fixup priority handler (#161347) +* Wed Apr 05 2006 - hare@suse.de +- Disable debug messages in pp_tpc. +* Wed Mar 29 2006 - hare@suse.de +- Explicitely create partitions at boot time (#159927) +* Thu Mar 23 2006 - hare@suse.de +- Add hwtable entry for IBM 3526. +* Tue Mar 14 2006 - hare@suse.de +- Fix another typo in mpath_id. +* Tue Mar 14 2006 - hare@suse.de +- Fix typo in mpath_id. +* Mon Mar 13 2006 - hare@suse.de +- Fix autobuild warnings. +- Include some minor fixed from upstream. +* Thu Mar 09 2006 - hare@suse.de +- Add mpath_id program to call kpartx only on multipathed + devices (#149995 - LTC21557). +- Include latest fixes from upstream. +* Wed Feb 08 2006 - hare@suse.de +- Add device blacklisting (#85778) +- Further manpage installation fixes (#146179, #147053, #147911) +* Wed Jan 25 2006 - mls@suse.de +- converted neededforbuild to BuildRequires +* Thu Jan 19 2006 - hare@suse.de +- Fix manpage installation. +* Tue Jan 17 2006 - hare@suse.de +- Include latest git fixes +- Remove old patches which are now upstream +- Add new hwtable entry for shark (#142176) +* Fri Dec 16 2005 - hare@suse.de +- Fix dependencies for /etc/init.d/boot.multipath +- Fix kpartx rules to generate proper partition names. +* Wed Dec 07 2005 - hare@suse.de +- Update to multipath-tools-0.4.6 +- Include latest git fixes +- Port patches from SLES9 SP3 +* Mon Oct 31 2005 - dmueller@suse.de +- don't build as root +* Mon Sep 05 2005 - matz@suse.de +- Fix broken usage of self-defined syscall [#114933]. +* Fri Aug 26 2005 - hare@suse.de +- Fix kpartx DASD partition support +* Thu Aug 04 2005 - hare@suse.de +- Add 'directio' path checker +- Add support for S/390 DASD (PAV enablement). +- Update to package from SLES9 +* Thu Jun 23 2005 - lmb@suse.de +- LUs with a WWN containing "fd" were blacklisted (#93562). +* Thu Jun 16 2005 - lmb@suse.de +- Remove stray newline character from /dev/disk/by-name/ entries + (#85798, #86763) +- Clear /dev/disk/by-name/ on boot. (#85978) +- scsi_id now handles EMC Symmetrix; remove work-around for #86760. +* Wed Jun 15 2005 - meissner@suse.de +- use RPM_OPT_FLAGS. +* Mon Jun 13 2005 - ro@suse.de +- neededforbuild: udev -> sysfsutils +* Tue Jun 07 2005 - lmb@suse.de +- Import fixes from upstream. +- Hardware table updates for IBM ESS and EMC CX (#81688). +- Reinstate paths correctly after failure/restore cycle (#85781, + [#86444]). +- Create map names again and fix segfault in devmap_name (#85798). +* Tue May 24 2005 - hare@suse.de +- Fix segmentation fault with EMC Symmetrix (#85614). +- Update EMC Symmetrix entry in hwtable. +* Mon May 23 2005 - hare@suse.de +- Add hwtable entry for IBM DS6000. (#63903) +- Do a rescan for devices if multipath command line option is set. +* Fri May 20 2005 - hare@suse.de +- Fix devmap_name to use mapname and return proper status (#84748). +* Thu May 12 2005 - lmb@suse.de +- Don't complain about default prio callout command (#81695). +- Reflect recent changes in boot.multipath as well as multipathd init + scripts. +- Actually fail paths when they are detected to be failed by multipathd + (#81679). +- killproc/startproc/checkproc can't be used with multipathd because of + the way the daemon switches to its own namespace (#80443). +* Mon May 09 2005 - hare@suse.de +- Use proper path checker for SGI TPC arrays. +- Update hwtable entries for SGI TP9400 and SGI TP9500. +- Write correct PID file (#80443). +* Mon Apr 25 2005 - lmb@suse.de +- Update to 0.4.4: pp_alua now licensed as GPL (#78628). +- multipath-tools-oom-adj.patch: oom_adj to a valid value. +* Thu Apr 21 2005 - lmb@suse.de +- Update to 0.4.4-pre18 which fixes the multipathd to initialize + correctly in the absence of a configuration file (79239). +* Wed Apr 20 2005 - lmb@suse.de +- Put multipath cache back into /dev because /var might not be mounted. +- Correct hwtable entry SGI TP9400, TP9500 and IBM 3542. +* Wed Apr 20 2005 - lmb@suse.de +- Update to 0.4.4-pre16 +- Build against device-mapper.1.01.xx correctly. +* Tue Apr 19 2005 - lmb@suse.de +- Build w/o device-mapper update again. +* Mon Apr 18 2005 - lmb@suse.de +- Update to 0.4.4-pre14 +- Build versus device-mapper-1.01.01 to prevent deadlocks in + kernel-space. +- Fix devmap_name to work with udev. +- Fix startup of multipathd w/o configuration file present. +* Fri Apr 15 2005 - lmb@suse.de +- Add path priority checker for EMC CLARiiON and make necessary + adjustments so that it gets called by default (#62491). +- Set the default udev dir to '/dev' +* Fri Apr 15 2005 - hare@suse.de +- Fix to allocate default strings (#78056) +- Fix default entry for TPC9500. +* Wed Apr 13 2005 - hare@suse.de +- Added pp_alua path priority checker. +- Update to multipath-tools-0.4.4-pre12. +* Mon Apr 11 2005 - hare@suse.de +- Update to multipath-tools-0.4.4-pre10. +* Fri Apr 08 2005 - hare@suse.de +- Update multipath to handle only true multipath devices (#62491). +- Update kpartx to use the device mapper target name if available. +- Add boot.multipath script for early set up of multipath targets. +* Thu Mar 31 2005 - hare@suse.de +- Update devmap_name to select targets by table type (#62493). +* Tue Jan 25 2005 - lmb@suse.de +- Update to 0.4.2 and fix some bugs + add support for the extended DM + multipath kernel module. (#47491) +* Thu Nov 11 2004 - hare@suse.de +- Fix bugs to make it work on S/390 (#47491). +* Fri Nov 05 2004 - hare@suse.de +- Update to version 0.3.6 (#47491). +- Fix multipath init script +- Install configuration file example. +- Install multipathd in /sbin instead of /usr/bin. +* Tue Jul 20 2004 - fehr@suse.de +- updated README mp-tools-issues.pdf (see #40640) +* Wed Jun 09 2004 - fehr@suse.de +- added pdf with README to package (see #40640) +* Thu Jun 03 2004 - fehr@suse.de +- updated to version 0.2.1 +- removed patches zero-currpath.patch and rm-newline-in-name.patch + already contained in 0.2.1 +* Thu Jun 03 2004 - fehr@suse.de +- added patch zero-currpath.patch (see bugzilla #40640) +* Wed May 26 2004 - uli@suse.de +- fixed to build on s390x +* Wed May 26 2004 - fehr@suse.de +- added patch rm-newline-in-name.patch (see bugzilla #40640) +* Tue May 25 2004 - fehr@suse.de +- created initial version of a SuSE package from version 0.2.0 of + multipath tools diff --git a/multipathd b/multipathd new file mode 100644 index 0000000..9aae27d --- /dev/null +++ b/multipathd @@ -0,0 +1,155 @@ +#! /bin/sh +# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany. +# +# Author: Thorsten Kukuk +# +# init.d/routed +# +# and symbolic its link +# +# /usr/sbin/rcrouted +# +### BEGIN INIT INFO +# Provides: multipathd +# Required-Start: $syslog +# Required-Stop: +# Default-Start: 3 5 +# Default-Stop: 0 1 2 4 6 +# Description: Starts multipath daemon +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +DAEMON=/sbin/multipathd +PIDFILE=/var/run/multipathd.pid + +# Set the maximum number of open files +MAX_OPEN_FDS=4096 + +test -x $DAEMON || exit 5 + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + +# Return values acc. to LSB for all commands but status: +# 0 - success +# 1 - misc error +# 2 - invalid or excess args +# 3 - unimplemented feature (e.g. reload) +# 4 - insufficient privilege +# 5 - program not installed +# 6 - program not configured +# 7 - program is not running +# +# Note that starting an already running service, stopping +# or restarting a not-running service as well as the restart +# with force-reload (in case signalling is not supported) are +# considered a success. + +case "$1" in + start) + echo -n "Starting multipathd" + + modprobe dm-multipath + + # Set the maximum number of open files + if [ -n "$MAX_OPEN_FDS" ] ; then + ulimit -n $MAX_OPEN_FDS + fi + + if [ -f $PIDFILE ]; then + PID="$(cat $PIDFILE)" + PROCNAME="$(ps -o cmd --no-headers $PID)" + fi + + if [ "$PROCNAME" != "$DAEMON" ]; then + $DAEMON + fi + + # Remember status and be verbose + rc_status -v + sleep 1 + ;; + stop) + echo -n "Shutting down multipathd" + # Because of the way how multipathd sets up its own namespace + # and chroots to it, killproc cannot be used with this process. + # So implement a cruder version: + if [ -f $PIDFILE ]; then + PID="$(cat $PIDFILE)" + PROCNAME="$(ps -o cmd --no-headers $PID)" + fi + + if [ "$PROCNAME" == "$DAEMON" ]; then + kill -TERM $PID + fi + + # Remember status and be verbose + rc_status -v + ;; + try-restart) + ## Stop the service and if this succeeds (i.e. the + ## service was running before), start it again. + $0 status >/dev/null && $0 restart + + # Remember status and be quiet + rc_status + ;; + restart|force-reload) + ## Stop the service and regardless of whether it was + ## running or not, start it again. + $0 stop + $0 start + + # Remember status and be quiet + rc_status + ;; + reload) + ## Like force-reload, but if daemon does not support + ## signalling, do nothing (!) + + # If it does not support reload: + exit 3 + ;; + status) + echo -n "Checking for multipathd: " + + # Status has a slightly different for the status command: + # 0 - service running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running + + if [ -f $PIDFILE ]; then + PID="$(cat $PIDFILE)" + PROCNAME="$(ps -o cmd --no-headers $PID)" + if [ "$PROCNAME" == "$DAEMON" ]; then + (exit 0) + else + (exit 1) + fi + else + (exit 3) + fi + + rc_status -v + ;; + probe) + ## Optional: Probe for the necessity of a reload, + ## give out the argument which is required for a reload. + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" + exit 1 + ;; +esac +rc_exit diff --git a/ready b/ready new file mode 100644 index 0000000..473a0f4