diff -Nru multipath-tools-0.4.9/debian/changelog multipath-tools-0.4.9/debian/changelog --- multipath-tools-0.4.9/debian/changelog 2015-07-15 16:19:21.000000000 +0000 +++ multipath-tools-0.4.9/debian/changelog 2015-12-01 16:25:58.000000000 +0000 @@ -1,3 +1,70 @@ +multipath-tools (0.4.9-3ubuntu12.15.04.2) vivid; urgency=medium + + * Remove 0024-ignore-usb.patch: Ignore USB devices. Verification fails + for this fix; it is superseded by the patches below. + * Cherry-picked patches to ignore local non-mpath devices: + (LP: #1386637, #1468897) + - 0001-multipath-add-checker_timeout-default-config-option.patch + - 0002-Make-params-variable-local.patch + - 0003-libmultipath-Fix-possible-string-overflow.patch + - 0004-Update-hwtable-factorization.patch + - 0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch + - 0006-Remove-sysfs_attr-cache.patch + - 0007-Move-setup_thread_attr-to-uevent.c.patch + - 0008-Use-lists-for-uevent-processing.patch + - 0009-Start-uevent-service-handler-from-main-thread.patch + - 0010-libmultipath-rework-sysfs-handling.patch + - 0011-Rework-sysfs-device-handling-in-multipathd.patch + - 0012-Only-check-offline-status-for-SCSI-devices.patch + - 0013-Check-for-offline-path-in-get_prio.patch + - 0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch + - 0015-Update-dev_loss_tmo-for-no_path_retry.patch + - 0016-Reload-map-for-device-read-only-setting-changes.patch + - 0017-multipath-get-right-sysfs-value-for-checker_timeout.patch + - 0018-multipath-handle-offlined-paths.patch + - 0019-multipath-fix-scsi-timeout-code.patch + - 0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch + - 0021-multipath-cleanup-dev_loss_tmo-issues.patch + - 0022-Fix-for-setting-0-to-fast_io_fail.patch + - 0023-Fix-fast_io_fail-capping.patch + - 0024-multipath-enable-getting-uevents-through-libudev.patch + - 0025-Use-devpath-as-argument-for-sysfs-functions.patch + - 0026-multipathd-remove-references-to-sysfs_device.patch + - 0027-multipathd-use-struct-path-as-argument-for-event-pro.patch + - 0028-Add-global-udev-reference-pointer-to-config.patch + - 0029-Use-udev-enumeration-during-discovery.patch + - 0030-use-struct-udev_device-during-discovery.patch + - 0031-More-debugging-output-when-synchronizing-path-states.patch + - 0032-Use-struct-udev_device-instead-of-sysdev.patch + - 0033-discovery-Fixup-cciss-discovery.patch + - 0035-Use-udev-devices-during-discovery.patch + - 0036-Remove-all-references-to-hand-craftes-sysfs-code.patch + - 0037-multipath-libudev-cleanup-and-bugfixes.patch + - 0038-multipath-check-if-a-device-belongs-to-multipath.patch + - 0039-multipath-and-wwids_file-multipath.conf-option.patch + - 0040-multipath-Check-blacklists-as-soon-as-possible.patch + - 0041-add-wwids-file-cleanup-options.patch + - 0042-add-find_multipaths-option.patch + - 0043-alloc-keywords.patch + * Other changes to support the above patches: + - debian/rules: don't ship 95-multipath.rules udev rules anymore; they are + not necessary with multipath-tools listening for udev events directly. + - debian/multipath.udev: removed. + - debian/multipath-tools.postinst: run multipath -W so that we get a + properly formed wwids file on upgrade. + - debian/initramfs/hooks: copy the wwids file in the initramfs so that it + is available when multipath-tools initially discovers path to possibly + bring up the rootfs. + * debian/patches/0014-kpartx-long-path.patch: have kpartx match loopback + files by device and inode rather than by path, as paths are not complete + enough to do specific matching for long paths (> 64 chars) or relative + paths. (LP: #1469143) + * debian/initramfs/local-premount: wait for udev to settle before the call + to resolve_device() in local_mount_root(), so the by-uuid/ symlinks have + a chance to be updated by the multipath udev rules (LP: #1503286). + + -- Mathieu Trudel-Lapierre Tue, 01 Dec 2015 11:25:51 -0500 + multipath-tools (0.4.9-3ubuntu12.15.04.1) vivid; urgency=medium [ Mauricio Faria de Oliveira ] diff -Nru multipath-tools-0.4.9/debian/initramfs/hooks multipath-tools-0.4.9/debian/initramfs/hooks --- multipath-tools-0.4.9/debian/initramfs/hooks 2015-07-13 18:31:31.000000000 +0000 +++ multipath-tools-0.4.9/debian/initramfs/hooks 2015-12-01 15:23:08.000000000 +0000 @@ -25,6 +25,14 @@ fi } +add_wwids() +{ + if [ -r /etc/multipath/wwids ]; then + mkdir -p $DESTDIR/etc/multipath + cp /etc/multipath/wwids $DESTDIR/etc/multipath + fi +} + add_udev_rules() { for rules in 95-multipath.rules; do @@ -43,6 +51,7 @@ [ -r /etc/multipath.conf ] && cp /etc/multipath.conf $DESTDIR/etc/ add_bindings +add_wwids for x in dm-multipath dm-round-robin dm-emc; do manual_add_modules ${x} diff -Nru multipath-tools-0.4.9/debian/initramfs/local-premount multipath-tools-0.4.9/debian/initramfs/local-premount --- multipath-tools-0.4.9/debian/initramfs/local-premount 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/initramfs/local-premount 2015-12-01 15:24:25.000000000 +0000 @@ -0,0 +1,28 @@ +#!/bin/sh + +set -e + +PREREQ="" + +prereqs() +{ + echo "${PREREQ}" +} + +case "${1}" in + prereqs) + prereqs + exit 0 + ;; +esac + +. /scripts/functions + +if [ -x /sbin/multipath ] +then + [ "$quiet" != "y" ] && log_begin_msg "Waiting for udev to settle (multipath)" + udevadm settle --timeout=121 || true + [ "$quiet" != "y" ] && log_end_msg +fi + +exit 0 diff -Nru multipath-tools-0.4.9/debian/multipath-tools.postinst multipath-tools-0.4.9/debian/multipath-tools.postinst --- multipath-tools-0.4.9/debian/multipath-tools.postinst 2015-07-13 18:31:31.000000000 +0000 +++ multipath-tools-0.4.9/debian/multipath-tools.postinst 2015-12-01 15:21:59.000000000 +0000 @@ -28,6 +28,8 @@ echo "done." fi fi + # Make sure we write up a WWIDs file for the new version + multipath -W || : ;; abort-upgrade|abort-remove|abort-deconfigure) diff -Nru multipath-tools-0.4.9/debian/multipath.udev multipath-tools-0.4.9/debian/multipath.udev --- multipath-tools-0.4.9/debian/multipath.udev 2015-07-13 18:31:31.000000000 +0000 +++ multipath-tools-0.4.9/debian/multipath.udev 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# -# udev rules for multipathing. -# The persistent symlinks are created with the kpartx rules -# - -# Coalesce multipath devices before multipathd is running (initramfs, early -# boot) -ACTION=="add|change", SUBSYSTEM=="block", RUN+="/sbin/multipath -v0 /dev/$name" - diff -Nru multipath-tools-0.4.9/debian/patches/0001-multipath-add-checker_timeout-default-config-option.patch multipath-tools-0.4.9/debian/patches/0001-multipath-add-checker_timeout-default-config-option.patch --- multipath-tools-0.4.9/debian/patches/0001-multipath-add-checker_timeout-default-config-option.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0001-multipath-add-checker_timeout-default-config-option.patch 2015-07-28 19:22:42.000000000 +0000 @@ -0,0 +1,452 @@ +From 8d3f07da9aef6178eb6d5591015c3e7719ccf3b6 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 18 Nov 2010 22:34:11 -0600 +Subject: [PATCH] multipath: add checker_timeout default config option + +Due to errors with some storage arrays, occasionally a scsi request will get +competely dropped. When this happens, fast_io_fail_tmo and dev_loss_tmo don't +get triggered, and a sychronous checker function might have to wait for the +full timeout. Right now those timeouts are hard-coded to 5 minutes. This +patch changes them to use the scsi cmd timeout, +/sys/block/sd/device/timeout, by default. This can be overridden by the new +default config parameter, checker_timeout, so that user can manually set +an upper bound on how long a sychronous checker might be blocked, without +modifying the generic scsi cmd timeout. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/checkers.h | 15 +-------------- + libmultipath/checkers/emc_clariion.c | 4 ++-- + libmultipath/checkers/hp_sw.c | 12 ++++++------ + libmultipath/checkers/libsg.c | 5 +++-- + libmultipath/checkers/libsg.h | 3 ++- + libmultipath/checkers/rdac.c | 9 +++++---- + libmultipath/checkers/readsector0.c | 2 +- + libmultipath/checkers/tur.c | 2 +- + libmultipath/config.h | 1 + + libmultipath/dict.c | 29 +++++++++++++++++++++++++++++ + libmultipath/discovery.c | 27 +++++++++++++++++++++++++++ + libmultipath/discovery.h | 1 + + libmultipath/propsel.c | 19 +++++++++++++++++-- + multipath.conf.annotated | 9 +++++++++ + multipath/multipath.conf.5 | 5 +++++ + 15 files changed, 110 insertions(+), 33 deletions(-) + +Index: b/libmultipath/checkers.h +=================================================================== +--- a/libmultipath/checkers.h ++++ b/libmultipath/checkers.h +@@ -68,20 +68,6 @@ enum path_check_state { + + #define DEFAULT_CHECKER DIRECTIO + +-/* +- * 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 + #define ASYNC_TIMEOUT_SEC 30 + + /* +@@ -96,6 +82,7 @@ struct checker { + struct list_head node; + int fd; + int sync; ++ unsigned int timeout; + int disable; + char name[CHECKER_NAME_LEN]; + char message[CHECKER_MSG_LEN]; /* comm with callers */ +Index: b/libmultipath/checkers/emc_clariion.c +=================================================================== +--- a/libmultipath/checkers/emc_clariion.c ++++ b/libmultipath/checkers/emc_clariion.c +@@ -113,7 +113,7 @@ int libcheck_check (struct checker * c) + io_hdr.dxferp = sense_buffer; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sb; +- io_hdr.timeout = DEF_TIMEOUT; ++ io_hdr.timeout = c->timeout; + io_hdr.pack_id = 0; + if (ioctl(c->fd, SG_IO, &io_hdr) < 0) { + MSG(c, "emc_clariion_checker: sending query command failed"); +@@ -182,7 +182,7 @@ int libcheck_check (struct checker * c) + unsigned char buf[4096]; + + memset(buf, 0, 4096); +- ret = sg_read(c->fd, &buf[0], sbb = &sb[0]); ++ ret = sg_read(c->fd, &buf[0], sbb = &sb[0], c->timeout); + if (ret == PATH_DOWN) { + hexadecimal_to_ascii(ct->wwn, wwnstr); + +Index: b/libmultipath/checkers/hp_sw.c +=================================================================== +--- a/libmultipath/checkers/hp_sw.c ++++ b/libmultipath/checkers/hp_sw.c +@@ -46,7 +46,7 @@ void libcheck_free (struct checker * c) + + static int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, +- void *resp, int mx_resp_len, int noisy) ++ void *resp, int mx_resp_len, int noisy, unsigned int timeout) + { + unsigned char inqCmdBlk[INQUIRY_CMDLEN] = + { INQUIRY_CMD, 0, 0, 0, 0, 0 }; +@@ -70,7 +70,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u + io_hdr.dxferp = resp; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_b; +- io_hdr.timeout = DEF_TIMEOUT; ++ io_hdr.timeout = timeout; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) + return 1; +@@ -98,7 +98,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u + } + + static int +-do_tur (int fd) ++do_tur (int fd, unsigned int timeout) + { + unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; + struct sg_io_hdr io_hdr; +@@ -111,7 +111,7 @@ do_tur (int fd) + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; +- io_hdr.timeout = DEF_TIMEOUT; ++ io_hdr.timeout = timeout; + io_hdr.pack_id = 0; + + if (ioctl(fd, SG_IO, &io_hdr) < 0) +@@ -128,12 +128,12 @@ libcheck_check (struct checker * c) + { + char buff[MX_ALLOC_LEN]; + +- if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) { ++ if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0, c->timeout)) { + MSG(c, MSG_HP_SW_DOWN); + return PATH_DOWN; + } + +- if (do_tur(c->fd)) { ++ if (do_tur(c->fd, c->timeout)) { + MSG(c, MSG_HP_SW_GHOST); + return PATH_GHOST; + } +Index: b/libmultipath/checkers/libsg.c +=================================================================== +--- a/libmultipath/checkers/libsg.c ++++ b/libmultipath/checkers/libsg.c +@@ -11,7 +11,8 @@ + #include "../libmultipath/sg_include.h" + + int +-sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff) ++sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff, ++ unsigned int timeout) + { + /* defaults */ + int blocks = 1; +@@ -51,7 +52,7 @@ sg_read (int sg_fd, unsigned char * buff + io_hdr.dxferp = buff; + io_hdr.mx_sb_len = SENSE_BUFF_LEN; + io_hdr.sbp = senseBuff; +- io_hdr.timeout = DEF_TIMEOUT; ++ io_hdr.timeout = timeout; + io_hdr.pack_id = (int)start_block; + if (diop && *diop) + io_hdr.flags |= SG_FLAG_DIRECT_IO; +Index: b/libmultipath/checkers/libsg.h +=================================================================== +--- a/libmultipath/checkers/libsg.h ++++ b/libmultipath/checkers/libsg.h +@@ -3,6 +3,7 @@ + + #define SENSE_BUFF_LEN 32 + +-int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff); ++int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff, ++ unsigned int timeout); + + #endif /* _LIBSG_H */ +Index: b/libmultipath/checkers/rdac.c +=================================================================== +--- a/libmultipath/checkers/rdac.c ++++ b/libmultipath/checkers/rdac.c +@@ -18,7 +18,6 @@ + #define INQUIRY_CMDLEN 6 + #define INQUIRY_CMD 0x12 + #define SENSE_BUFF_LEN 32 +-#define RDAC_DEF_TIMEOUT 60000 + #define SCSI_CHECK_CONDITION 0x2 + #define SCSI_COMMAND_TERMINATED 0x22 + #define SG_ERR_DRIVER_SENSE 0x08 +@@ -43,7 +42,8 @@ void libcheck_free (struct checker * c) + } + + static int +-do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len) ++do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len, ++ unsigned int timeout) + { + unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 }; + unsigned char sense_b[SENSE_BUFF_LEN]; +@@ -62,7 +62,7 @@ do_inq(int sg_fd, unsigned int pg_op, vo + io_hdr.dxferp = resp; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_b; +- io_hdr.timeout = RDAC_DEF_TIMEOUT; ++ io_hdr.timeout = timeout; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) + return 1; +@@ -104,7 +104,8 @@ libcheck_check (struct checker * c) + int ret; + + memset(&inq, 0, sizeof(struct volume_access_inq)); +- if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) { ++ if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq), ++ c->timeout)) { + ret = PATH_DOWN; + goto done; + } else if ((inq.PQ_PDT & 0x20) || (inq.PQ_PDT & 0x7f)) { +Index: b/libmultipath/checkers/readsector0.c +=================================================================== +--- a/libmultipath/checkers/readsector0.c ++++ b/libmultipath/checkers/readsector0.c +@@ -29,7 +29,7 @@ int libcheck_check (struct checker * c) + unsigned char sbuf[SENSE_BUFF_LEN]; + int ret; + +- ret = sg_read(c->fd, &buf[0], &sbuf[0]); ++ ret = sg_read(c->fd, &buf[0], &sbuf[0], c->timeout); + + switch (ret) + { +Index: b/libmultipath/checkers/tur.c +=================================================================== +--- a/libmultipath/checkers/tur.c ++++ b/libmultipath/checkers/tur.c +@@ -55,7 +55,7 @@ libcheck_check (struct checker * c) + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; +- io_hdr.timeout = DEF_TIMEOUT; ++ io_hdr.timeout = c->timeout; + io_hdr.pack_id = 0; + if (ioctl(c->fd, SG_IO, &io_hdr) < 0) { + MSG(c, MSG_TUR_DOWN); +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -77,6 +77,7 @@ struct config { + int max_fds; + int force_reload; + int queue_without_daemon; ++ int checker_timeout; + int daemon; + int flush_on_last_del; + int attribute_flags; +Index: b/libmultipath/dict.c +=================================================================== +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -395,6 +395,25 @@ def_queue_without_daemon(vector strvec) + } + + static int ++def_checker_timeout_handler(vector strvec) ++{ ++ unsigned int checker_timeout; ++ char *buff; ++ ++ buff = set_value(strvec); ++ if (!buff) ++ return 1; ++ ++ if (sscanf(buff, "%u", &checker_timeout) == 1) ++ conf->checker_timeout = checker_timeout; ++ else ++ conf->checker_timeout = 0; ++ ++ free(buff); ++ return 0; ++} ++ ++static int + def_pg_timeout_handler(vector strvec) + { + int pg_timeout; +@@ -2036,6 +2055,15 @@ snprint_def_queue_without_daemon (char * + } + + static int ++snprint_def_checker_timeout (char *buff, int len, void *data) ++{ ++ if (!conf->checker_timeout) ++ return 0; ++ ++ return snprintf(buff, len, "%u", conf->checker_timeout); ++} ++ ++static int + snprint_def_pg_timeout (char * buff, int len, void * data) + { + if (conf->pg_timeout == DEFAULT_PGTIMEOUT) +@@ -2123,6 +2151,7 @@ init_keywords(void) + install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight); + install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry); + install_keyword("queue_without_daemon", &def_queue_without_daemon, &snprint_def_queue_without_daemon); ++ install_keyword("checker_timeout", &def_checker_timeout_handler, &snprint_def_checker_timeout); + install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout); + install_keyword("flush_on_last_del", &def_flush_on_last_del_handler, &snprint_def_flush_on_last_del); + install_keyword("user_friendly_names", &names_handler, &snprint_def_user_friendly_names); +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -165,6 +165,31 @@ sysfs_get_dev (struct sysfs_device * dev + } + + int ++sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout) ++{ ++ char *attr; ++ char attr_path[SYSFS_PATH_SIZE]; ++ int r; ++ unsigned int t; ++ ++ if (safe_sprintf(attr_path, "%s/device", dev->devpath)) ++ return 1; ++ ++ attr = sysfs_attr_get_value(dev->devpath, "timeout"); ++ if (!attr) ++ return 1; ++ ++ r = sscanf(attr, "%u\n", &t); ++ ++ if (r != 1) ++ return 1; ++ ++ *timeout = t * 1000; ++ ++ return 0; ++} ++ ++int + sysfs_get_size (struct sysfs_device * dev, unsigned long long * size) + { + char *attr; +@@ -820,6 +845,8 @@ get_state (struct path * pp, int daemon) + } + if (daemon) + checker_set_async(c); ++ if (!conf->checker_timeout) ++ sysfs_get_timeout(pp->sysdev, &(c->timeout)); + state = checker_check(c); + condlog(3, "%s: state = %i", pp->dev, state); + if (state == PATH_DOWN && strlen(checker_message(c))) +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -35,6 +35,7 @@ int pathinfo (struct path *, vector hwta + struct path * store_pathinfo (vector pathvec, vector hwtable, + char * devname, int flag); + int sysfs_set_scsi_tmo (struct multipath *mpp); ++int sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout); + + /* + * discovery bitmask +Index: b/libmultipath/propsel.c +=================================================================== +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -16,6 +16,7 @@ + #include "defaults.h" + #include "devmapper.h" + #include "prio.h" ++#include "discovery.h" + + pgpolicyfn *pgpolicies[] = { + NULL, +@@ -292,17 +293,31 @@ select_checker(struct path *pp) + checker_get(c, pp->hwe->checker_name); + condlog(3, "%s: path checker = %s (controller setting)", + pp->dev, checker_name(c)); +- return 0; ++ goto out; + } + if (conf->checker_name) { + checker_get(c, conf->checker_name); + condlog(3, "%s: path checker = %s (config file default)", + pp->dev, checker_name(c)); +- return 0; ++ goto out; + } + checker_get(c, DEFAULT_CHECKER); + condlog(3, "%s: path checker = %s (internal default)", + pp->dev, checker_name(c)); ++out: ++ if (conf->checker_timeout) { ++ c->timeout = conf->checker_timeout * 1000; ++ condlog(3, "%s: checker timeout = %u ms (config file default)", ++ pp->dev, c->timeout); ++ } ++ else if (sysfs_get_timeout(pp->sysdev, &c->timeout) == 0) ++ condlog(3, "%s: checker timeout = %u ms (sysfs setting)", ++ pp->dev, c->timeout); ++ else { ++ c->timeout = DEF_TIMEOUT; ++ condlog(3, "%s: checker timeout = %u ms (internal default)", ++ pp->dev, c->timeout); ++ } + return 0; + } + +Index: b/multipath.conf.annotated +=================================================================== +--- a/multipath.conf.annotated ++++ b/multipath.conf.annotated +@@ -211,6 +211,15 @@ + # gid disk + # + # # ++# # name : checker_timeout ++# # scope : multipath & multipathd ++# # desc : The timeout to use for path checkers that issue scsi ++# # commands with an explicit timeout, in seconds. ++# # values : n > 0 ++# # default : taken from /sys/block/sd/device/timeout ++# checker_timeout 60 ++# ++# # + # # name : fast_io_fail_tmo + # # scope : multipath & multipathd + # # desc : The number of seconds the scsi layer will wait after a +Index: b/multipath/multipath.conf.5 +=================================================================== +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -241,6 +241,11 @@ maximum number of open fds is taken from + 1024. To be safe, this should be set to the maximum number of paths plus 32, + if that number is greated than 1024. + .TP ++.B checker_timeout ++Specify the timeout to user for path checkers that issue scsi commands with an ++explict timeout, in seconds; default taken from ++.I /sys/block/sd/device/timeout ++.TP + .B fast_io_fail_tmo + Specify the number of seconds the scsi layer will wait after a problem has been + detected on a FC remote port before failing IO to devices on that remote port. diff -Nru multipath-tools-0.4.9/debian/patches/0002-Make-params-variable-local.patch multipath-tools-0.4.9/debian/patches/0002-Make-params-variable-local.patch --- multipath-tools-0.4.9/debian/patches/0002-Make-params-variable-local.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0002-Make-params-variable-local.patch 2015-07-28 20:26:39.000000000 +0000 @@ -0,0 +1,470 @@ +From 15fd093e5e42321b5bde02db8b404e6f23507a96 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 22 Oct 2009 16:25:57 +0200 +Subject: [PATCH] Make params variable local + +The 'params' structure field in struct multipath is a purely local +variable, and as such shouldn't be part of the main structure. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/configure.c | 38 ++++++++++++++++++++------------------ + libmultipath/configure.h | 4 ++-- + libmultipath/devmapper.c | 34 ++++++++++++++++++++-------------- + libmultipath/devmapper.h | 8 ++++---- + libmultipath/dmparser.c | 6 +++--- + libmultipath/dmparser.h | 2 +- + libmultipath/print.c | 6 +++--- + libmultipath/print.h | 2 +- + libmultipath/structs.h | 1 - + libmultipath/structs_vec.c | 6 ++++-- + multipath/main.c | 6 ++++-- + multipathd/cli_handlers.c | 6 ++++-- + multipathd/main.c | 10 ++++++---- + 13 files changed, 72 insertions(+), 57 deletions(-) + +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -37,11 +37,11 @@ + #include "util.h" + + extern int +-setup_map (struct multipath * mpp) ++setup_map (struct multipath * mpp, char * params, int params_size) + { + struct pathgroup * pgp; + int i; +- ++ + /* + * don't bother if devmap size is unknown + */ +@@ -100,7 +100,7 @@ setup_map (struct multipath * mpp) + * transform the mp->pg vector of vectors of paths + * into a mp->params strings to feed the device-mapper + */ +- if (assemble_map(mpp)) { ++ if (assemble_map(mpp, params, params_size)) { + condlog(0, "%s: problem assembing map", mpp->alias); + return 1; + } +@@ -312,7 +312,7 @@ lock_multipath (struct multipath * mpp, + #define DOMAP_DRY 3 + + extern int +-domap (struct multipath * mpp) ++domap (struct multipath * mpp, char * params) + { + int r = 0; + +@@ -352,28 +352,28 @@ domap (struct multipath * mpp) + break; + } + +- r = dm_addmap_create(mpp); ++ r = dm_addmap_create(mpp, params); + + if (!r) +- r = dm_addmap_create_ro(mpp); ++ r = dm_addmap_create_ro(mpp, params); + + lock_multipath(mpp, 0); + break; + + case ACT_RELOAD: +- r = dm_addmap_reload(mpp); ++ r = dm_addmap_reload(mpp, params); + if (!r) +- r = dm_addmap_reload_ro(mpp); ++ r = dm_addmap_reload_ro(mpp, params); + if (r) + r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias); + break; + +- case ACT_RESIZE: +- r = dm_addmap_reload(mpp); +- if (!r) +- r = dm_addmap_reload_ro(mpp); +- if (r) +- r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1); ++ case ACT_RESIZE: ++ r = dm_addmap_reload(mpp, params); ++ if (!r) ++ r = dm_addmap_reload_ro(mpp, params); ++ if (r) ++ r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1); + break; + + case ACT_RENAME: +@@ -398,7 +398,7 @@ domap (struct multipath * mpp) + /* multipath daemon mode */ + mpp->stat_map_loads++; + condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias, +- mpp->size, TGT_MPATH, mpp->params); ++ mpp->size, TGT_MPATH, params); + /* + * Required action is over, reset for the stateful daemon. + * But don't do it for creation as we use in the caller the +@@ -440,6 +440,7 @@ coalesce_paths (struct vectors * vecs, v + int r = 1; + int k, i; + char empty_buff[WWID_SIZE]; ++ char params[PARAMS_SIZE]; + struct multipath * mpp; + struct path * pp1; + struct path * pp2; +@@ -511,8 +512,9 @@ coalesce_paths (struct vectors * vecs, v + mpp->action = ACT_REJECT; + } + verify_paths(mpp, vecs, NULL); +- +- if (setup_map(mpp)) { ++ ++ params[0] = '\0'; ++ if (setup_map(mpp, params, PARAMS_SIZE)) { + remove_map(mpp, vecs, 0); + continue; + } +@@ -520,7 +522,7 @@ coalesce_paths (struct vectors * vecs, v + if (mpp->action == ACT_UNDEF) + select_action(mpp, curmp, force_reload); + +- r = domap(mpp); ++ r = domap(mpp, params); + + if (r == DOMAP_FAIL || r == DOMAP_RETRY) { + condlog(3, "%s: domap (%u) failure " +Index: b/libmultipath/configure.h +=================================================================== +--- a/libmultipath/configure.h ++++ b/libmultipath/configure.h +@@ -23,8 +23,8 @@ enum actions { + #define FLUSH_ONE 1 + #define FLUSH_ALL 2 + +-int setup_map (struct multipath * mpp); +-int domap (struct multipath * mpp); ++int setup_map (struct multipath * mpp, char * params, int params_size ); ++int domap (struct multipath * mpp, char * params); + int reinstate_paths (struct multipath *mpp); + int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload); + char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec); +Index: b/libmultipath/devmapper.c +=================================================================== +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -188,8 +188,8 @@ dm_simplecmd_noflush (int task, const ch + } + + extern int +-dm_addmap (int task, const char *target, struct multipath *mpp, int use_uuid, +- int ro) { ++dm_addmap (int task, const char *target, struct multipath *mpp, char * params, ++ int use_uuid, int ro) { + int r = 0; + struct dm_task *dmt; + char *prefixed_uuid = NULL; +@@ -200,7 +200,7 @@ dm_addmap (int task, const char *target, + if (!dm_task_set_name (dmt, mpp->alias)) + goto addout; + +- if (!dm_task_add_target (dmt, 0, mpp->size, target, mpp->params)) ++ if (!dm_task_add_target (dmt, 0, mpp->size, target, params)) + goto addout; + + if (ro) +@@ -227,6 +227,8 @@ dm_addmap (int task, const char *target, + if (mpp->attribute_flags & (1 << ATTR_GID) && + !dm_task_set_gid(dmt, mpp->gid)) + goto freeout; ++ condlog(4, "%s: addmap [0 %llu %s %s]\n", mpp->alias, mpp->size, ++ target, params); + + dm_task_no_open_count(dmt); + +@@ -246,9 +248,9 @@ dm_addmap (int task, const char *target, + } + + static int +-_dm_addmap_create (struct multipath *mpp, int ro) { ++_dm_addmap_create (struct multipath *mpp, char * params, int ro) { + int r; +- r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, 1, ro); ++ r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro); + /* + * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD. + * Failing the second part leaves an empty map. Clean it up. +@@ -265,23 +267,23 @@ _dm_addmap_create (struct multipath *mpp + #define ADDMAP_RO 1 + + extern int +-dm_addmap_create (struct multipath *mpp) { +- return _dm_addmap_create(mpp, ADDMAP_RW); ++dm_addmap_create (struct multipath *mpp, char *params) { ++ return _dm_addmap_create(mpp, params, ADDMAP_RW); + } + + extern int +-dm_addmap_create_ro (struct multipath *mpp) { +- return _dm_addmap_create(mpp, ADDMAP_RO); ++dm_addmap_create_ro (struct multipath *mpp, char *params) { ++ return _dm_addmap_create(mpp, params, ADDMAP_RO); + } + + extern int +-dm_addmap_reload (struct multipath *mpp) { +- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, 0, ADDMAP_RW); ++dm_addmap_reload (struct multipath *mpp, char *params) { ++ return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RW); + } + + extern int +-dm_addmap_reload_ro (struct multipath *mpp) { +- return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, 0, ADDMAP_RO); ++dm_addmap_reload_ro (struct multipath *mpp, char *params) { ++ return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params, 0, ADDMAP_RO); + } + + extern int +@@ -340,6 +342,10 @@ dm_get_map(char * name, unsigned long lo + if (size) + *size = length; + ++ if (!outparams) { ++ r = 0; ++ goto out; ++ } + if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE) + r = 0; + out: +@@ -748,7 +754,7 @@ dm_get_maps (vector mp) + goto out1; + + if (info > 0) { +- if (dm_get_map(names->name, &mpp->size, mpp->params)) ++ if (dm_get_map(names->name, &mpp->size, NULL)) + goto out1; + + if (dm_get_status(names->name, mpp->status)) +Index: b/libmultipath/devmapper.h +=================================================================== +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -10,10 +10,10 @@ void dm_init(void); + int dm_prereq (void); + int dm_simplecmd_flush (int, const char *, int); + int dm_simplecmd_noflush (int, const char *); +-int dm_addmap_create (struct multipath *mpp); +-int dm_addmap_create_ro (struct multipath *mpp); +-int dm_addmap_reload (struct multipath *mpp); +-int dm_addmap_reload_ro (struct multipath *mpp); ++int dm_addmap_create (struct multipath *mpp, char *params); ++int dm_addmap_create_ro (struct multipath *mpp, char *params); ++int dm_addmap_reload (struct multipath *mpp, char *params); ++int dm_addmap_reload_ro (struct multipath *mpp, char *params); + int dm_map_present (const char *); + int dm_get_map(char *, unsigned long long *, char *); + int dm_get_status(char *, char *); +Index: b/libmultipath/dmparser.c +=================================================================== +--- a/libmultipath/dmparser.c ++++ b/libmultipath/dmparser.c +@@ -47,7 +47,7 @@ merge_words (char ** dst, char * word, i + * Transforms the path group vector into a proper device map string + */ + int +-assemble_map (struct multipath * mp) ++assemble_map (struct multipath * mp, char * params, int len) + { + int i, j; + int shift, freechar; +@@ -57,8 +57,8 @@ assemble_map (struct multipath * mp) + struct path * pp; + + minio = mp->minio; +- p = mp->params; +- freechar = sizeof(mp->params); ++ p = params; ++ freechar = len; + + shift = snprintf(p, freechar, "%s %s %i %i", + mp->features, mp->hwhandler, +Index: b/libmultipath/dmparser.h +=================================================================== +--- a/libmultipath/dmparser.h ++++ b/libmultipath/dmparser.h +@@ -1,3 +1,3 @@ +-int assemble_map (struct multipath *); ++int assemble_map (struct multipath *, char *, int); + int disassemble_map (vector, char *, struct multipath *); + int disassemble_status (char *, struct multipath *); +Index: b/libmultipath/print.c +=================================================================== +--- a/libmultipath/print.c ++++ b/libmultipath/print.c +@@ -1352,11 +1352,11 @@ print_pathgroup (struct pathgroup * pgp, + } + + extern void +-print_map (struct multipath * mpp) ++print_map (struct multipath * mpp, char * params) + { +- if (mpp->size && mpp->params) ++ if (mpp->size && params) + printf("0 %llu %s %s\n", +- mpp->size, TGT_MPATH, mpp->params); ++ mpp->size, TGT_MPATH, params); + return; + } + +Index: b/libmultipath/print.h +=================================================================== +--- a/libmultipath/print.h ++++ b/libmultipath/print.h +@@ -55,7 +55,7 @@ void print_multipath_topology (struct mu + void print_path (struct path * pp, char * style); + void print_multipath (struct multipath * mpp, char * style); + void print_pathgroup (struct pathgroup * pgp, char * style); +-void print_map (struct multipath * mpp); ++void print_map (struct multipath * mpp, char * params); + void print_all_paths (vector pathvec, int banner); + void print_all_paths_custo (vector pathvec, int banner, char *fmt); + void print_hwtable (vector hwtable); +Index: b/libmultipath/structs.h +=================================================================== +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -180,7 +180,6 @@ struct multipath { + unsigned long long size; + vector paths; + vector pg; +- char params[PARAMS_SIZE]; + char status[PARAMS_SIZE]; + struct dm_info * dmi; + +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -240,13 +240,15 @@ extract_hwe_from_path(struct multipath * + static int + update_multipath_table (struct multipath *mpp, vector pathvec) + { ++ char params[PARAMS_SIZE] = {0}; ++ + if (!mpp) + return 1; + +- if (dm_get_map(mpp->alias, &mpp->size, mpp->params)) ++ if (dm_get_map(mpp->alias, &mpp->size, params)) + return 1; + +- if (disassemble_map(pathvec, mpp->params, mpp)) ++ if (disassemble_map(pathvec, params, mpp)) + return 1; + + return 0; +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -160,6 +160,7 @@ get_dm_mpvec (vector curmp, vector pathv + { + int i; + struct multipath * mpp; ++ char params[PARAMS_SIZE]; + + if (dm_get_maps(curmp)) + return 1; +@@ -177,10 +178,11 @@ get_dm_mpvec (vector curmp, vector pathv + continue; + } + +- condlog(3, "params = %s", mpp->params); ++ dm_get_map(mpp->alias, &mpp->size, params); ++ condlog(3, "params = %s", params); + condlog(3, "status = %s", mpp->status); + +- disassemble_map(pathvec, mpp->params, mpp); ++ disassemble_map(pathvec, params, mpp); + + /* + * disassemble_map() can add new paths to pathvec. +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -423,11 +423,13 @@ cli_del_map (void * v, char ** reply, in + int resize_map(struct multipath *mpp, unsigned long long size, + struct vectors * vecs) + { ++ char params[PARAMS_SIZE] = {0}; ++ + mpp->size = size; + update_mpp_paths(mpp, vecs->pathvec); +- setup_map(mpp); ++ setup_map(mpp, params, PARAMS_SIZE); + mpp->action = ACT_RESIZE; +- if (domap(mpp) <= 0) { ++ if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed to resize map : %s", mpp->alias, + strerror(errno)); + return 1; +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -352,6 +352,7 @@ ev_add_path (char * devname, struct vect + struct multipath * mpp; + struct path * pp; + char empty_buff[WWID_SIZE] = {0}; ++ char params[PARAMS_SIZE] = {0}; + + if (strstr(devname, "..") != NULL) { + /* +@@ -444,7 +445,7 @@ rescan: + /* + * push the map to the device-mapper + */ +- if (setup_map(mpp)) { ++ if (setup_map(mpp, params, PARAMS_SIZE)) { + condlog(0, "%s: failed to setup map for addition of new " + "path %s", mpp->alias, devname); + goto out; +@@ -452,7 +453,7 @@ rescan: + /* + * reload the map for the multipath mapped device + */ +- if (domap(mpp) <= 0) { ++ if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed in domap for addition of new " + "path %s", mpp->alias, devname); + /* +@@ -508,6 +509,7 @@ ev_remove_path (char * devname, struct v + struct multipath * mpp; + struct path * pp; + int i, retval = 0; ++ char params[PARAMS_SIZE] = {0}; + + pp = find_path_by_dev(vecs->pathvec, devname); + +@@ -562,7 +564,7 @@ ev_remove_path (char * devname, struct v + */ + } + +- if (setup_map(mpp)) { ++ if (setup_map(mpp, params, PARAMS_SIZE)) { + condlog(0, "%s: failed to setup map for" + " removal of path %s", mpp->alias, + devname); +@@ -572,7 +574,7 @@ ev_remove_path (char * devname, struct v + * reload the map + */ + mpp->action = ACT_RELOAD; +- if (domap(mpp) <= 0) { ++ if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed in domap for " + "removal of path %s", + mpp->alias, devname); diff -Nru multipath-tools-0.4.9/debian/patches/0003-libmultipath-Fix-possible-string-overflow.patch multipath-tools-0.4.9/debian/patches/0003-libmultipath-Fix-possible-string-overflow.patch --- multipath-tools-0.4.9/debian/patches/0003-libmultipath-Fix-possible-string-overflow.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0003-libmultipath-Fix-possible-string-overflow.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,335 @@ +From 98614e20996f3a5b887dd7e50f6a5f874eda6be9 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Tue, 3 May 2011 16:27:29 +0200 +Subject: [PATCH] libmultipath: Fix possible string overflow + +basenamecpy() and devt2devname() need to be passed in the +length of the string into which the modified value should +be copied. Otherwise a string overflow can be induced. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/configure.c | 13 +++-- + libmultipath/discovery.c | 62 +-------------------------- + libmultipath/discovery.h | 1 + libmultipath/util.c | 107 ++++++++++++++++++++++++++++++++++++++++++++--- + libmultipath/util.h | 3 - + multipath/main.c | 3 - + 6 files changed, 116 insertions(+), 73 deletions(-) + +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -600,9 +600,13 @@ get_refwwid (char * dev, enum devtypes d + return NULL; + + if (dev_type == DEV_DEVNODE) { +- basenamecpy(dev, buff); ++ if (basenamecpy(dev, buff, FILE_NAME_SIZE) == 0) { ++ condlog(1, "basename failed for '%s' (%s)", ++ dev, buff); ++ return NULL; ++ } ++ + pp = find_path_by_dev(pathvec, buff); +- + if (!pp) { + pp = alloc_path(); + +@@ -625,9 +629,8 @@ get_refwwid (char * dev, enum devtypes d + + if (dev_type == DEV_DEVT) { + pp = find_path_by_devt(pathvec, dev); +- + if (!pp) { +- if (devt2devname(buff, dev)) ++ if (devt2devname(buff, FILE_NAME_SIZE, dev)) + return NULL; + + pp = alloc_path(); +@@ -639,7 +642,7 @@ get_refwwid (char * dev, enum devtypes d + + if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID)) + return NULL; +- ++ + if (store_path(pathvec, pp)) { + free_path(pp); + return NULL; +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -336,62 +336,6 @@ opennode (char * dev, int mode) + return open(devpath, mode); + } + +-extern int +-devt2devname (char *devname, char *devt) +-{ +- FILE *fd; +- unsigned int tmpmaj, tmpmin, major, minor; +- char dev[FILE_NAME_SIZE]; +- char block_path[FILE_NAME_SIZE]; +- struct stat statbuf; +- +- memset(block_path, 0, FILE_NAME_SIZE); +- if (sscanf(devt, "%u:%u", &major, &minor) != 2) { +- condlog(0, "Invalid device number %s", devt); +- return 1; +- } +- +- if (!(fd = fopen("/proc/partitions", "r"))) { +- condlog(0, "Cannot open /proc/partitions"); +- return 1; +- } +- +- while (!feof(fd)) { +- int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev); +- if (!r) { +- r = fscanf(fd,"%*s\n"); +- continue; +- } +- if (r != 3) +- continue; +- +- if ((major == tmpmaj) && (minor == tmpmin)) { +- if (snprintf(block_path, FILE_NAME_SIZE, "/sys/block/%s", dev) >= FILE_NAME_SIZE) { +- condlog(0, "device name %s is too long\n", dev); +- fclose(fd); +- return 1; +- } +- break; +- } +- } +- fclose(fd); +- +- if (strncmp(block_path,"/sys/block", 10)) +- return 1; +- +- if (stat(block_path, &statbuf) < 0) { +- condlog(0, "No sysfs entry for %s\n", block_path); +- return 1; +- } +- +- if (S_ISDIR(statbuf.st_mode) == 0) { +- condlog(0, "sysfs entry %s is not a directory\n", block_path); +- return 1; +- } +- basenamecpy(block_path, devname); +- return 0; +-} +- + int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len) +@@ -560,7 +504,7 @@ scsi_sysfs_pathinfo (struct path * pp, s + /* + * host / bus / target / lun + */ +- basenamecpy(parent->devpath, attr_path); ++ basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE); + + sscanf(attr_path, "%i:%i:%i:%i", + &pp->sg_id.host_no, +@@ -619,7 +563,7 @@ ccw_sysfs_pathinfo (struct path * pp, st + /* + * host / bus / target / lun + */ +- basenamecpy(parent->devpath, attr_path); ++ basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE); + pp->sg_id.lun = 0; + sscanf(attr_path, "%i.%i.%x", + &pp->sg_id.host_no, +@@ -643,7 +587,7 @@ cciss_sysfs_pathinfo (struct path * pp, + /* + * host / bus / target / lun + */ +- basenamecpy(dev->devpath, attr_path); ++ basenamecpy(dev->devpath, attr_path, FILE_NAME_SIZE); + pp->sg_id.lun = 0; + pp->sg_id.channel = 0; + sscanf(attr_path, "cciss!c%id%i", +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -28,7 +28,6 @@ int sysfs_get_dev (struct sysfs_device * + int path_discovery (vector pathvec, struct config * conf, int flag); + + int do_tur (char *); +-int devt2devname (char *, char *); + int path_offline (struct path *); + int get_state (struct path * pp, int daemon); + int pathinfo (struct path *, vector hwtable, int mask); +Index: b/libmultipath/util.c +=================================================================== +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -6,8 +6,9 @@ + + #include "debug.h" + #include "memory.h" +- +-#define PARAMS_SIZE 255 ++#include "checkers.h" ++#include "vector.h" ++#include "structs.h" + + int + strcmp_chomp(char *str1, char *str2) +@@ -38,10 +39,21 @@ strchop(char *str) + str[++i] = '\0'; + } + +-void +-basenamecpy (char * str1, char * str2) ++int ++basenamecpy (char * str1, char * str2, int str2len) + { +- char *p = str1 + (strlen(str1) - 1); ++ char *p; ++ ++ if (!str1 || !strlen(str1)) ++ return 0; ++ ++ if (strlen(str1) > str2len) ++ return 0; ++ ++ if (!str2) ++ return 0; ++ ++ p = str1 + (strlen(str1) - 1); + + while (*--p != '/' && p != str1) + continue; +@@ -49,7 +61,10 @@ basenamecpy (char * str1, char * str2) + if (p != str1) + p++; + +- strcpy(str2, p); ++ strncpy(str2, p, str2len); ++ str2[str2len - 1] = '\0'; ++ strchop(str2); ++ return strlen(str2); + } + + int +@@ -156,3 +171,83 @@ void remove_trailing_chars(char *path, c + path[--len] = '\0'; + } + ++extern int ++devt2devname (char *devname, int devname_len, char *devt) ++{ ++ FILE *fd; ++ unsigned int tmpmaj, tmpmin, major, minor; ++ char dev[FILE_NAME_SIZE]; ++ char block_path[PATH_SIZE]; ++ struct stat statbuf; ++ ++ memset(block_path, 0, sizeof(block_path)); ++ if (sscanf(devt, "%u:%u", &major, &minor) != 2) { ++ condlog(0, "Invalid device number %s", devt); ++ return 1; ++ } ++ ++ if (devname_len > FILE_NAME_SIZE) ++ devname_len = FILE_NAME_SIZE; ++ ++ sprintf(block_path,"/sys/dev/block/%u:%u", major, minor); ++ if (stat(block_path, &statbuf) == 0) { ++ /* Newer kernels have /sys/dev/block */ ++ if (S_ISLNK(statbuf.st_mode) && ++ readlink(block_path, dev, FILE_NAME_SIZE) > 0) { ++ char *p = strrchr(dev, '/'); ++ ++ if (!p) { ++ condlog(0, "No sysfs entry for %s\n", ++ block_path); ++ return 1; ++ } ++ p++; ++ strncpy(devname, p, devname_len); ++ return 0; ++ } ++ } ++ memset(block_path, 0, sizeof(block_path)); ++ ++ if (!(fd = fopen("/proc/partitions", "r"))) { ++ condlog(0, "Cannot open /proc/partitions"); ++ return 1; ++ } ++ ++ while (!feof(fd)) { ++ int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev); ++ if (!r) { ++ r = fscanf(fd,"%*s\n"); ++ continue; ++ } ++ if (r != 3) ++ continue; ++ ++ if ((major == tmpmaj) && (minor == tmpmin)) { ++ if (snprintf(block_path, sizeof(block_path), ++ "/sys/block/%s", dev) >= sizeof(block_path)) { ++ condlog(0, "device name %s is too long\n", dev); ++ fclose(fd); ++ return 1; ++ } ++ break; ++ } ++ } ++ fclose(fd); ++ ++ if (strncmp(block_path,"/sys/block", 10)) { ++ condlog(3, "device %s not found\n", dev); ++ return 1; ++ } ++ ++ if (stat(block_path, &statbuf) < 0) { ++ condlog(0, "No sysfs entry for %s\n", block_path); ++ return 1; ++ } ++ ++ if (S_ISDIR(statbuf.st_mode) == 0) { ++ condlog(0, "sysfs entry %s is not a directory\n", block_path); ++ return 1; ++ } ++ basenamecpy(block_path, devname, devname_len); ++ return 0; ++} +Index: b/libmultipath/util.h +=================================================================== +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -3,12 +3,13 @@ + + int strcmp_chomp(char *, char *); + void strchop(char *); +-void basenamecpy (char * src, char * dst); ++int basenamecpy (char * src, char * dst, int); + int filepresent (char * run); + int get_word (char * sentence, char ** word); + size_t strlcpy(char *dst, const char *src, size_t size); + size_t strlcat(char *dst, const char *src, size_t size); + void remove_trailing_chars(char *path, char c); ++int devt2devname (char *, int, char *); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -132,7 +132,8 @@ update_paths (struct multipath * mpp) + + vector_foreach_slot (pgp->paths, pp, j) { + if (!strlen(pp->dev)) { +- if (devt2devname(pp->dev, pp->dev_t)) { ++ if (devt2devname(pp->dev, FILE_NAME_SIZE, ++ pp->dev_t)) { + /* + * path is not in sysfs anymore + */ diff -Nru multipath-tools-0.4.9/debian/patches/0004-Update-hwtable-factorization.patch multipath-tools-0.4.9/debian/patches/0004-Update-hwtable-factorization.patch --- multipath-tools-0.4.9/debian/patches/0004-Update-hwtable-factorization.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0004-Update-hwtable-factorization.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,220 @@ +From 091ba626b70279dcdd8741c8c0e2c0b581f0d334 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 5 May 2011 08:35:01 +0200 +Subject: [PATCH] Update hwtable factorization + +During hwtable factorization we should _not_ merge the entries, +as the original entries might be regular expressions. Thus they +might match more devices than the new, user-provided one. +So during factorization we should _not_ remove duplicate +entries, but rather update the new entries with the missing +defaults and scan the table backwards. +With this we'll be using the modified entries for the matching +devices _only_, leaving all others intact. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/config.c | 128 ++++++++++++++++++++++++++++++-------------------- + libmultipath/vector.h | 2 + 2 files changed, 79 insertions(+), 51 deletions(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -50,42 +50,64 @@ find_hwe_strmatch (vector hwtable, struc + return ret; + } + ++static int ++hwe_regmatch (struct hwentry *hwe1, struct hwentry *hwe2) ++{ ++ regex_t vre, pre, rre; ++ int retval = 1; ++ ++ if (hwe1->vendor && ++ regcomp(&vre, hwe1->vendor, REG_EXTENDED|REG_NOSUB)) ++ goto out; ++ ++ if (hwe1->product && ++ regcomp(&pre, hwe1->product, REG_EXTENDED|REG_NOSUB)) ++ goto out_vre; ++ ++ if (hwe1->revision && ++ regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB)) ++ goto out_pre; ++ ++ if ((!hwe1->vendor || !hwe2->vendor || ++ !regexec(&vre, hwe2->vendor, 0, NULL, 0)) && ++ (!hwe1->product || !hwe2->product || ++ !regexec(&pre, hwe2->product, 0, NULL, 0)) && ++ (!hwe1->revision || !hwe2->revision || ++ !regexec(&rre, hwe2->revision, 0, NULL, 0))) ++ retval = 0; ++ ++ if (hwe1->revision) ++ regfree(&rre); ++out_pre: ++ if (hwe1->product) ++ regfree(&pre); ++out_vre: ++ if (hwe1->vendor) ++ regfree(&vre); ++out: ++ return retval; ++} ++ + struct hwentry * + find_hwe (vector hwtable, char * vendor, char * product, char * revision) + { + int i; +- struct hwentry *hwe, *ret = NULL; +- regex_t vre, pre, rre; +- +- vector_foreach_slot (hwtable, hwe, i) { +- 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 (hwe->revision && +- regcomp(&rre, hwe->revision, REG_EXTENDED|REG_NOSUB)) { +- regfree(&vre); +- regfree(&pre); +- break; +- } +- 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; +- +- if (hwe->revision) +- regfree(&rre); +- if (hwe->product) +- regfree(&pre); +- if (hwe->vendor) +- regfree(&vre); ++ struct hwentry hwe, *tmp, *ret = NULL; + +- if (ret) +- break; ++ hwe.vendor = vendor; ++ hwe.product = product; ++ hwe.revision = revision; ++ /* ++ * Search backwards here. ++ * User modified entries are attached at the end of ++ * the list, so we have to check them first before ++ * continuing to the generic entries ++ */ ++ vector_foreach_slot_backwards (hwtable, tmp, i) { ++ if (hwe_regmatch(tmp, &hwe)) ++ continue; ++ ret = tmp; ++ break; + } + return ret; + } +@@ -257,20 +279,18 @@ set_param_str(char * str) + } + + #define merge_str(s) \ +- if (hwe2->s) { \ +- if (hwe1->s) \ +- FREE(hwe1->s); \ +- if (!(hwe1->s = set_param_str(hwe2->s))) \ ++ if (!dst->s && src->s) { \ ++ if (!(dst->s = set_param_str(src->s))) \ + return 1; \ + } + + #define merge_num(s) \ +- if (hwe2->s) \ +- hwe1->s = hwe2->s ++ if (!dst->s && src->s) \ ++ dst->s = src->s + + + static int +-merge_hwe (struct hwentry * hwe1, struct hwentry * hwe2) ++merge_hwe (struct hwentry * dst, struct hwentry * src) + { + merge_str(vendor); + merge_str(product); +@@ -363,21 +383,20 @@ out: + } + + static int +-factorize_hwtable (vector hw) ++factorize_hwtable (vector hw, int n) + { + struct hwentry *hwe1, *hwe2; + int i, j; + + vector_foreach_slot(hw, hwe1, i) { +- j = i+1; ++ if (i == n) ++ break; ++ j = n; + vector_foreach_slot_after(hw, hwe2, j) { + if (hwe_strmatch(hwe1, hwe2)) + continue; + /* dup */ +- merge_hwe(hwe1, hwe2); +- free_hwe(hwe2); +- vector_del_slot(hw, j); +- j--; ++ merge_hwe(hwe2, hwe1); + } + } + return 0; +@@ -477,19 +496,26 @@ load_config (char * file) + /* + * read the config file + */ ++ set_current_keywords(&conf->keywords); + if (filepresent(file)) { +- set_current_keywords(&conf->keywords); ++ int builtin_hwtable_size; ++ ++ builtin_hwtable_size = VECTOR_SIZE(conf->hwtable); + if (init_data(file, init_keywords)) { + condlog(0, "error parsing config file"); + goto out; + } +- } ++ if (VECTOR_SIZE(conf->hwtable) > builtin_hwtable_size) { ++ /* ++ * remove duplica in hwtable. config file ++ * takes precedence over build-in hwtable ++ */ ++ factorize_hwtable(conf->hwtable, builtin_hwtable_size); ++ } + +- /* +- * remove duplica in hwtable. config file takes precedence +- * over build-in hwtable +- */ +- factorize_hwtable(conf->hwtable); ++ } else { ++ init_keywords(); ++ } + + /* + * fill the voids left in the config file +Index: b/libmultipath/vector.h +=================================================================== +--- a/libmultipath/vector.h ++++ b/libmultipath/vector.h +@@ -39,6 +39,8 @@ typedef struct _vector *vector; + for (i = 0; (v) && i < (v)->allocated && ((p) = (v)->slot[i]); i++) + #define vector_foreach_slot_after(v,p,i) \ + for (; (v) && i < (v)->allocated && ((p) = (v)->slot[i]); i++) ++#define vector_foreach_slot_backwards(v,p,i) \ ++ for (i = VECTOR_SIZE(v); i > 0 && ((p) = (v)->slot[i-1]); i--) + + /* Prototypes */ + extern vector vector_alloc(void); diff -Nru multipath-tools-0.4.9/debian/patches/0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch multipath-tools-0.4.9/debian/patches/0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch --- multipath-tools-0.4.9/debian/patches/0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,54 @@ +From 35f543f7f2ef1e6f5e7a73144103bf29f8de4594 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Fri, 25 Sep 2009 11:51:25 +0200 +Subject: [PATCH] Fixup strip trailing whitespaces for getuid return value + +The getuid callout might return a wwid with trailing +spaces (or containing only spaces). The existing +fixup code will only work if the getuid callout +returns a wwid with the entire space used up. +So fixup this and also update the logging output +to correctly state '' if the getuid was +found to be empty. + +References: bnc#542085 + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -826,8 +826,7 @@ get_prio (struct path * pp) + static int + get_uid (struct path * pp) + { +- char buff[CALLOUT_MAX_SIZE]; +- int i; ++ char buff[CALLOUT_MAX_SIZE], *c; + + if (!pp->getuid) + select_getuid(pp); +@@ -841,12 +840,14 @@ get_uid (struct path * pp) + return 1; + } + /* Strip any trailing blanks */ +- i = WWID_SIZE - 1; +- while (i > 0 && pp->wwid[i] == ' ') { +- pp->wwid[i] = '\0'; +- i--; ++ c = strchr(pp->wwid, '\0'); ++ c--; ++ while (c && c >= pp->wwid && *c == ' ') { ++ *c = '\0'; ++ c--; + } +- condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid); ++ condlog(3, "%s: uid = %s (callout)", pp->dev, ++ *pp->wwid == '\0' ? "" : pp->wwid); + return 0; + } + diff -Nru multipath-tools-0.4.9/debian/patches/0006-Remove-sysfs_attr-cache.patch multipath-tools-0.4.9/debian/patches/0006-Remove-sysfs_attr-cache.patch --- multipath-tools-0.4.9/debian/patches/0006-Remove-sysfs_attr-cache.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0006-Remove-sysfs_attr-cache.patch 2015-07-28 19:22:43.000000000 +0000 @@ -0,0 +1,523 @@ +From 6888db0777e46ff057de5a48e522a5ac573f6115 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Mon, 4 May 2009 14:11:18 +0200 +Subject: [PATCH] Remove sysfs_attr cache + +The sysfs attribute cache was meant to speed up sysfs accesses. +However, we need to update the cache values on each access, so +there is no speedup to be had. +So remove it and save memory. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 98 +++++++++++------------ + libmultipath/sysfs.c | 193 ++++++++++++++++------------------------------- + libmultipath/sysfs.h | 7 - + multipathd/main.c | 6 - + 4 files changed, 120 insertions(+), 184 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -128,16 +128,22 @@ path_discovery (vector pathvec, struct c + #define declare_sysfs_get_str(fname) \ + extern int \ + sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \ +-{ \ +- char *attr; \ +-\ +- attr = sysfs_attr_get_value(dev->devpath, #fname); \ +- if (!attr) \ +- return 1; \ +- if (strlcpy(buff, attr, len) != strlen(attr)) \ +- return 2; \ +- strchop(buff); \ +- return 0; \ ++{ \ ++ int size; \ ++ \ ++ size = sysfs_attr_get_value(dev->devpath, #fname, buff, len); \ ++ if (!size) { \ ++ condlog(3, "%s: attribute %s not found in sysfs", \ ++ dev->kernel, #fname); \ ++ return 1; \ ++ } \ ++ if (size == len) { \ ++ condlog(3, "%s: overflow in attribute %s", \ ++ dev->kernel, #fname); \ ++ return 2; \ ++ } \ ++ strchop(buff); \ ++ return 0; \ + } + + declare_sysfs_get_str(devtype); +@@ -146,43 +152,32 @@ declare_sysfs_get_str(vendor); + declare_sysfs_get_str(model); + declare_sysfs_get_str(rev); + declare_sysfs_get_str(state); +- +-int +-sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len) +-{ +- char *attr; +- +- attr = sysfs_attr_get_value(dev->devpath, "dev"); +- if (!attr) { +- condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel); +- return 1; +- } +- if (strlcpy(buff, attr, len) != strlen(attr)) { +- condlog(3, "%s: overflow in 'dev' attribute", dev->kernel); +- return 2; +- } +- return 0; +-} ++declare_sysfs_get_str(dev); + + int + sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout) + { +- char *attr; +- char attr_path[SYSFS_PATH_SIZE]; ++ char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE]; ++ size_t len; + int r; + unsigned int t; + + if (safe_sprintf(attr_path, "%s/device", dev->devpath)) + return 1; + +- attr = sysfs_attr_get_value(dev->devpath, "timeout"); +- if (!attr) ++ len = sysfs_attr_get_value(dev->devpath, "timeout", attr, NAME_SIZE); ++ if (!len) { ++ condlog(3, "%s: No timeout value in sysfs", dev->devpath); + return 1; ++ } + + r = sscanf(attr, "%u\n", &t); + +- if (r != 1) ++ if (r != 1) { ++ condlog(3, "%s: Cannot parse timeout attribute '%s'", ++ dev->devpath, attr); + return 1; ++ } + + *timeout = t * 1000; + +@@ -192,17 +187,23 @@ sysfs_get_timeout(struct sysfs_device *d + int + sysfs_get_size (struct sysfs_device * dev, unsigned long long * size) + { +- char *attr; ++ char attr[NAME_SIZE]; ++ size_t len; + int r; + +- attr = sysfs_attr_get_value(dev->devpath, "size"); +- if (!attr) ++ len = sysfs_attr_get_value(dev->devpath, "size", attr, NAME_SIZE); ++ if (!len) { ++ condlog(3, "%s: No size attribute in sysfs", dev->devpath); + return 1; ++ } + + r = sscanf(attr, "%llu\n", size); + +- if (r != 1) ++ if (r != 1) { ++ condlog(3, "%s: Cannot parse size attribute '%s'", ++ dev->devpath, attr); + return 1; ++ } + + return 0; + } +@@ -212,7 +213,8 @@ sysfs_get_fc_nodename (struct sysfs_devi + unsigned int host, unsigned int channel, + unsigned int target) + { +- char attr_path[SYSFS_PATH_SIZE], *attr; ++ char attr_path[SYSFS_PATH_SIZE]; ++ size_t len; + + if (safe_sprintf(attr_path, + "/class/fc_transport/target%i:%i:%i", +@@ -221,13 +223,11 @@ sysfs_get_fc_nodename (struct sysfs_devi + return 1; + } + +- attr = sysfs_attr_get_value(attr_path, "node_name"); +- if (attr) { +- strlcpy(node, attr, strlen(attr)); +- return 0; +- } ++ len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE); ++ if (!len) ++ return 1; + +- return 1; ++ return 0; + } + + static int +@@ -293,7 +293,7 @@ sysfs_set_scsi_tmo (struct multipath *mp + if (mpp->dev_loss){ + snprintf(value, 11, "%u", mpp->dev_loss); + if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", +- value)) { ++ value, 11)) { + condlog(0, "%s failed to set %s/dev_loss_tmo", + mpp->alias, attr_path); + return 1; +@@ -305,7 +305,7 @@ sysfs_set_scsi_tmo (struct multipath *mp + else + snprintf(value, 11, "%u", mpp->fast_io_fail); + if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo", +- value)) { ++ value, 11)) { + condlog(0, + "%s failed to set %s/fast_io_fail_tmo", + mpp->alias, attr_path); +@@ -605,14 +605,14 @@ cciss_sysfs_pathinfo (struct path * pp, + static int + common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev) + { +- char *attr; ++ size_t len; + +- attr = sysfs_attr_get_value(dev->devpath, "dev"); +- if (!attr) { ++ len = sysfs_attr_get_value(dev->devpath, "dev", ++ pp->dev_t, BLK_DEV_SIZE); ++ if (!len) { + condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); + return 1; + } +- strlcpy(pp->dev_t, attr, BLK_DEV_SIZE); + + condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); + +Index: b/libmultipath/sysfs.c +=================================================================== +--- a/libmultipath/sysfs.c ++++ b/libmultipath/sysfs.c +@@ -37,15 +37,6 @@ + + char sysfs_path[PATH_SIZE]; + +-/* attribute value cache */ +-static LIST_HEAD(attr_list); +-struct sysfs_attr { +- struct list_head node; +- char path[PATH_SIZE]; +- char *value; /* points to value_local if value is cached */ +- char value_local[NAME_SIZE]; +-}; +- + /* list of sysfs devices */ + static LIST_HEAD(sysfs_dev_list); + struct sysfs_dev { +@@ -62,24 +53,15 @@ int sysfs_init(char *path, size_t len) + strlcpy(sysfs_path, "/sys", sizeof(sysfs_path)); + dbg("sysfs_path='%s'", sysfs_path); + +- INIT_LIST_HEAD(&attr_list); + INIT_LIST_HEAD(&sysfs_dev_list); + return 0; + } + + void sysfs_cleanup(void) + { +- struct sysfs_attr *attr_loop; +- struct sysfs_attr *attr_temp; +- + struct sysfs_dev *sysdev_loop; + struct sysfs_dev *sysdev_temp; + +- list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) { +- list_del(&attr_loop->node); +- free(attr_loop); +- } +- + list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) { + list_del(&sysdev_loop->node); + free(sysdev_loop); +@@ -356,130 +338,95 @@ void sysfs_device_put(struct sysfs_devic + return; + } + +-int +-sysfs_attr_set_value(const char *devpath, const char *attr_name, +- const char *value) ++size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, ++ char *attr_value, int attr_len) + { + char path_full[PATH_SIZE]; +- int sysfs_len; ++ const char *path; + struct stat statbuf; +- int fd, value_len, ret = -1; ++ int fd; ++ ssize_t size; ++ size_t sysfs_len; ++ ++ if (!attr_value || !attr_len) ++ return 0; ++ ++ attr_value[0] = '\0'; ++ size = 0; + + dbg("open '%s'/'%s'", devpath, attr_name); +- sysfs_len = snprintf(path_full, PATH_SIZE, "%s%s/%s", sysfs_path, +- devpath, attr_name); +- if (sysfs_len >= PATH_SIZE || sysfs_len < 0) { +- if (sysfs_len < 0) +- dbg("cannot copy sysfs path %s%s/%s : %s", sysfs_path, +- devpath, attr_name, strerror(errno)); +- else +- dbg("sysfs_path %s%s/%s too large", sysfs_path, +- devpath, attr_name); +- goto out; +- } ++ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); ++ if(sysfs_len >= sizeof(path_full)) ++ sysfs_len = sizeof(path_full) - 1; ++ path = &path_full[sysfs_len]; ++ strlcat(path_full, devpath, sizeof(path_full)); ++ strlcat(path_full, "/", sizeof(path_full)); ++ strlcat(path_full, attr_name, sizeof(path_full)); + + if (stat(path_full, &statbuf) != 0) { +- dbg("stat '%s' failed: %s" path_full, strerror(errno)); ++ dbg("stat '%s' failed: %s", path_full, strerror(errno)); + goto out; + } + + /* skip directories */ +- if (S_ISDIR(statbuf.st_mode)) +- goto out; ++ if (S_ISDIR(statbuf.st_mode)) ++ goto out; + +- if ((statbuf.st_mode & S_IWUSR) == 0) ++ /* skip non-readable files */ ++ if ((statbuf.st_mode & S_IRUSR) == 0) + goto out; + +- fd = open(path_full, O_WRONLY); ++ /* read attribute value */ ++ fd = open(path_full, O_RDONLY); + if (fd < 0) { + dbg("attribute '%s' can not be opened: %s", + path_full, strerror(errno)); + goto out; + } +- value_len = strlen(value) + 1; +- ret = write(fd, value, value_len); +- if (ret == value_len) +- ret = 0; +- else if (ret < 0) +- dbg("write to %s failed: %s", path_full, strerror(errno)); +- else { +- dbg("tried to write %d to %s. Wrote %d\n", value_len, +- path_full, ret); +- ret = -1; +- } ++ size = read(fd, attr_value, attr_len); + close(fd); ++ if (size < 0) ++ goto out; ++ if (size == attr_len) { ++ dbg("overflow in attribute '%s', truncating", path_full); ++ size--; ++ } ++ ++ /* got a valid value, store and return it */ ++ attr_value[size] = '\0'; ++ remove_trailing_chars(attr_value, '\n'); ++ + out: +- return ret; ++ return size; + } + +- +-char *sysfs_attr_get_value(const char *devpath, const char *attr_name) ++ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, ++ const char *value, int value_len) + { + char path_full[PATH_SIZE]; +- const char *path; +- char value[NAME_SIZE]; +- struct sysfs_attr *attr_loop; +- struct sysfs_attr *attr = NULL; + struct stat statbuf; + int fd; +- ssize_t size; ++ ssize_t size = 0; + size_t sysfs_len; + +- dbg("open '%s'/'%s'", devpath, attr_name); +- sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); +- if(sysfs_len >= sizeof(path_full)) +- sysfs_len = sizeof(path_full) - 1; +- path = &path_full[sysfs_len]; +- strlcat(path_full, devpath, sizeof(path_full)); +- strlcat(path_full, "/", sizeof(path_full)); +- strlcat(path_full, attr_name, sizeof(path_full)); +- +- /* look for attribute in cache */ +- list_for_each_entry(attr_loop, &attr_list, node) { +- if (strcmp(attr_loop->path, path) == 0) { +- dbg("found in cache '%s'", attr_loop->path); +- attr = attr_loop; +- } +- } +- if (!attr) { +- /* store attribute in cache */ +- dbg("new uncached attribute '%s'", path_full); +- attr = malloc(sizeof(struct sysfs_attr)); +- if (attr == NULL) +- return NULL; +- memset(attr, 0x00, sizeof(struct sysfs_attr)); +- strlcpy(attr->path, path, sizeof(attr->path)); +- dbg("add to cache '%s'", path_full); +- list_add(&attr->node, &attr_list); +- } else { +- /* clear old value */ +- if(attr->value) +- memset(attr->value, 0x00, sizeof(attr->value)); +- } ++ if (!attr_name || !value || !value_len) ++ return 0; + +- if (lstat(path_full, &statbuf) != 0) { +- dbg("stat '%s' failed: %s", path_full, strerror(errno)); ++ dbg("open '%s'/'%s'", devpath, attr_name); ++ sysfs_len = snprintf(path_full, PATH_SIZE, "%s%s/%s", sysfs_path, ++ devpath, attr_name); ++ if (sysfs_len >= PATH_SIZE || sysfs_len < 0) { ++ if (sysfs_len < 0) ++ dbg("cannot copy sysfs path %s%s/%s : %s", sysfs_path, ++ devpath, attr_name, strerror(errno)); ++ else ++ dbg("sysfs_path %s%s/%s too large", sysfs_path, ++ devpath, attr_name); + goto out; + } + +- if (S_ISLNK(statbuf.st_mode)) { +- /* links return the last element of the target path */ +- char link_target[PATH_SIZE]; +- int len; +- const char *pos; +- +- len = readlink(path_full, link_target, sizeof(link_target)); +- if (len > 0) { +- link_target[len] = '\0'; +- pos = strrchr(link_target, '/'); +- if (pos != NULL) { +- dbg("cache '%s' with link value '%s'", +- path_full, value); +- strlcpy(attr->value_local, &pos[1], +- sizeof(attr->value_local)); +- attr->value = attr->value_local; +- } +- } ++ if (stat(path_full, &statbuf) != 0) { ++ dbg("stat '%s' failed: %s", path_full, strerror(errno)); + goto out; + } + +@@ -487,35 +434,29 @@ char *sysfs_attr_get_value(const char *d + if (S_ISDIR(statbuf.st_mode)) + goto out; + +- /* skip non-readable files */ +- if ((statbuf.st_mode & S_IRUSR) == 0) ++ /* skip non-writeable files */ ++ if ((statbuf.st_mode & S_IWUSR) == 0) + goto out; + + /* read attribute value */ +- fd = open(path_full, O_RDONLY); ++ fd = open(path_full, O_WRONLY); + if (fd < 0) { + dbg("attribute '%s' can not be opened: %s", + path_full, strerror(errno)); + goto out; + } +- size = read(fd, value, sizeof(value)); +- close(fd); ++ size = write(fd, value, value_len); + if (size < 0) +- goto out; +- if (size == sizeof(value)) { +- dbg("overflow in attribute '%s', truncating", path_full); +- size--; ++ dbg("write to %s failed: %s", path_full, strerror(errno)); ++ else if (size < value_len) { ++ dbg("tried to write %d to %s. Wrote %d\n", value_len, ++ path_full, size); ++ size = -1; + } +- +- /* got a valid value, store and return it */ +- value[size] = '\0'; +- remove_trailing_chars(value, '\n'); +- dbg("cache '%s' with attribute value '%s'", path_full, value); +- strlcpy(attr->value_local, value, sizeof(attr->value_local)); +- attr->value = attr->value_local; ++ close(fd); + + out: +- return attr && attr->value && strlen(attr->value) ? attr->value : NULL; ++ return size; + } + + int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, +Index: b/libmultipath/sysfs.h +=================================================================== +--- a/libmultipath/sysfs.h ++++ b/libmultipath/sysfs.h +@@ -19,9 +19,10 @@ struct sysfs_device *sysfs_device_get(co + struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); + struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem); + void sysfs_device_put(struct sysfs_device *dev); +-char *sysfs_attr_get_value(const char *devpath, const char *attr_name); ++size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, ++ char *attr_value, int attr_len); ++ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, ++ const char *value, int value_len); + int sysfs_resolve_link(char *path, size_t size); + int sysfs_get_size (struct sysfs_device * dev, unsigned long long * size); +-int sysfs_attr_set_value(const char *devpath, const char *attr_name, +- const char *value); + #endif +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -223,18 +223,12 @@ int + ev_add_map (struct sysfs_device * dev, struct vectors * vecs) + { + char * alias; +- char *dev_t; + int major, minor; + char * refwwid; + struct multipath * mpp; + int map_present; + int r = 1; + +- dev_t = sysfs_attr_get_value(dev->devpath, "dev"); +- +- if (!dev_t || sscanf(dev_t, "%d:%d", &major, &minor) != 2) +- return 1; +- + alias = dm_mapname(major, minor); + + if (!alias) diff -Nru multipath-tools-0.4.9/debian/patches/0007-Move-setup_thread_attr-to-uevent.c.patch multipath-tools-0.4.9/debian/patches/0007-Move-setup_thread_attr-to-uevent.c.patch --- multipath-tools-0.4.9/debian/patches/0007-Move-setup_thread_attr-to-uevent.c.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0007-Move-setup_thread_attr-to-uevent.c.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,126 @@ +From 54496a355dde75fbd1069a8fc0fe274b4a68a079 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Tue, 3 May 2011 10:29:28 +0200 +Subject: [PATCH] Move setup_thread_attr() to uevent.c + +The function will be used by other instances, too, so move it +over to the library. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/uevent.c | 28 ++++++++++++++++++++++++++-- + libmultipath/uevent.h | 11 ++++++++++- + multipathd/main.c | 24 ------------------------ + 3 files changed, 36 insertions(+), 27 deletions(-) + +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + + #include "memory.h" +@@ -59,6 +60,30 @@ int is_uevent_busy(void) + return (uevqhp != NULL || servicing_uev); + } + ++void ++setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached) ++{ ++ if (pthread_attr_init(attr)) { ++ fprintf(stderr, "can't initialize thread attr: %s\n", ++ strerror(errno)); ++ exit(1); ++ } ++ if (stacksize < PTHREAD_STACK_MIN) ++ stacksize = PTHREAD_STACK_MIN; ++ ++ if (pthread_attr_setstacksize(attr, stacksize)) { ++ fprintf(stderr, "can't set thread stack size to %lu: %s\n", ++ (unsigned long)stacksize, strerror(errno)); ++ exit(1); ++ } ++ if (detached && pthread_attr_setdetachstate(attr, ++ PTHREAD_CREATE_DETACHED)) { ++ fprintf(stderr, "can't set thread to detached: %s\n", ++ strerror(errno)); ++ exit(1); ++ } ++} ++ + static struct uevent * alloc_uevent (void) + { + return (struct uevent *)MALLOC(sizeof(struct uevent)); +@@ -142,8 +167,7 @@ int uevent_listen(int (*uev_trigger)(str + pthread_mutex_init(uevc_lockp, NULL); + pthread_cond_init(uev_condp, NULL); + +- pthread_attr_init(&attr); +- pthread_attr_setstacksize(&attr, 64 * 1024); ++ setup_thread_attr(&attr, 64 * 1024, 0); + pthread_create(&uevq_thr, &attr, uevq_thread, NULL); + + /* +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -1,4 +1,10 @@ +-/* environment buffer, the kernel's size in lib/kobject_uevent.c should fit in */ ++#ifndef _UEVENT_H ++#define _UEVENT_H ++ ++/* ++ * buffer for environment variables, the kernel's size in ++ * lib/kobject_uevent.c should fit in ++*/ + #define HOTPLUG_BUFFER_SIZE 1024 + #define HOTPLUG_NUM_ENVP 32 + #define OBJECT_SIZE 512 +@@ -18,3 +24,6 @@ struct uevent { + int uevent_listen(int (*store_uev)(struct uevent *, void * trigger_data), + void * trigger_data); + int is_uevent_busy(void); ++void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached); ++ ++#endif /* _UEVENT_H */ +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1310,30 +1310,6 @@ set_oom_adj (int val) + fclose(fp); + } + +-void +-setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached) +-{ +- if (pthread_attr_init(attr)) { +- fprintf(stderr, "can't initialize thread attr: %s\n", +- strerror(errno)); +- exit(1); +- } +- if (stacksize < PTHREAD_STACK_MIN) +- stacksize = PTHREAD_STACK_MIN; +- +- if (pthread_attr_setstacksize(attr, stacksize)) { +- fprintf(stderr, "can't set thread stack size to %lu: %s\n", +- (unsigned long)stacksize, strerror(errno)); +- exit(1); +- } +- if (detached && pthread_attr_setdetachstate(attr, +- PTHREAD_CREATE_DETACHED)) { +- fprintf(stderr, "can't set thread to detached: %s\n", +- strerror(errno)); +- exit(1); +- } +-} +- + static int + child (void * param) + { diff -Nru multipath-tools-0.4.9/debian/patches/0008-Use-lists-for-uevent-processing.patch multipath-tools-0.4.9/debian/patches/0008-Use-lists-for-uevent-processing.patch --- multipath-tools-0.4.9/debian/patches/0008-Use-lists-for-uevent-processing.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0008-Use-lists-for-uevent-processing.patch 2015-07-28 19:22:43.000000000 +0000 @@ -0,0 +1,236 @@ +From 651847893a8efdc3ed4f24a610db4b307b0dcefd Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 25 Feb 2009 16:10:16 +0100 +Subject: [PATCH] Use lists for uevent processing + +We now have proper list definitions, so we might as well use them +for uevent processing. And we can clean up signalling, too; +the pthreads condition signalling is unreliable, as a condition +signal might be lost if we're in the middle of processing. So +we should rather check the queue status prior to wait for a +condition. +And we can introduce a pthread cleanup handler, as well. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/uevent.c | 117 +++++++++++++++++++++++++++----------------------- + libmultipath/uevent.h | 2 + 2 files changed, 66 insertions(+), 53 deletions(-) + +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -39,17 +39,18 @@ + #include + #include + #include ++#include + + #include "memory.h" + #include "debug.h" ++#include "list.h" + #include "uevent.h" + + typedef int (uev_trigger)(struct uevent *, void * trigger_data); + + pthread_t uevq_thr; +-struct uevent *uevqhp, *uevqtp; ++LIST_HEAD(uevq); + pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock; +-pthread_mutex_t uevc_lock, *uevc_lockp = &uevc_lock; + pthread_cond_t uev_cond, *uev_condp = &uev_cond; + uev_trigger *my_uev_trigger; + void * my_trigger_data; +@@ -57,7 +58,22 @@ int servicing_uev; + + int is_uevent_busy(void) + { +- return (uevqhp != NULL || servicing_uev); ++ int empty; ++ ++ pthread_mutex_lock(uevq_lockp); ++ empty = list_empty(&uevq); ++ pthread_mutex_unlock(uevq_lockp); ++ return (!empty || servicing_uev); ++} ++ ++struct uevent * alloc_uevent (void) ++{ ++ struct uevent *uev = MALLOC(sizeof(struct uevent)); ++ ++ if (uev) ++ INIT_LIST_HEAD(&uev->node); ++ ++ return uev; + } + + void +@@ -84,37 +100,31 @@ setup_thread_attr(pthread_attr_t *attr, + } + } + +-static struct uevent * alloc_uevent (void) +-{ +- return (struct uevent *)MALLOC(sizeof(struct uevent)); +-} +- ++/* ++ * Called with uevq_lockp held ++ */ + void +-service_uevq(void) ++service_uevq(struct list_head *tmpq) + { +- int empty; +- struct uevent *uev; ++ struct uevent *uev, *tmp; + +- do { +- pthread_mutex_lock(uevq_lockp); +- empty = (uevqhp == NULL); +- if (!empty) { +- uev = uevqhp; +- uevqhp = uev->next; +- if (uevqtp == uev) +- uevqtp = uev->next; +- pthread_mutex_unlock(uevq_lockp); +- +- if (my_uev_trigger && my_uev_trigger(uev, +- my_trigger_data)) +- condlog(0, "uevent trigger error"); ++ list_for_each_entry_safe(uev, tmp, tmpq, node) { ++ list_del_init(&uev->node); + +- FREE(uev); +- } +- else { +- pthread_mutex_unlock(uevq_lockp); +- } +- } while (empty == 0); ++ if (my_uev_trigger && my_uev_trigger(uev, my_trigger_data)) ++ condlog(0, "uevent trigger error"); ++ ++ FREE(uev); ++ } ++} ++ ++static void uevq_stop(void *arg) ++{ ++ condlog(3, "Stopping uev queue"); ++ pthread_mutex_lock(uevq_lockp); ++ my_uev_trigger = NULL; ++ pthread_cond_signal(uev_condp); ++ pthread_mutex_unlock(uevq_lockp); + } + + /* +@@ -126,13 +136,23 @@ uevq_thread(void * et) + mlockall(MCL_CURRENT | MCL_FUTURE); + + while (1) { +- pthread_mutex_lock(uevc_lockp); ++ LIST_HEAD(uevq_tmp); ++ ++ pthread_mutex_lock(uevq_lockp); + servicing_uev = 0; +- pthread_cond_wait(uev_condp, uevc_lockp); ++ /* ++ * Condition signals are unreliable, ++ * so make sure we only wait if we have to. ++ */ ++ if (list_empty(&uevq)) { ++ pthread_cond_wait(uev_condp, uevq_lockp); ++ } + servicing_uev = 1; +- pthread_mutex_unlock(uevc_lockp); +- +- service_uevq(); ++ list_splice_init(&uevq, &uevq_tmp); ++ pthread_mutex_unlock(uevq_lockp); ++ if (!my_uev_trigger) ++ break; ++ service_uevq(&uevq_tmp); + } + return NULL; + } +@@ -161,12 +181,12 @@ int uevent_listen(int (*uev_trigger)(str + * thereby not getting to empty the socket's receive buffer queue + * often enough. + */ +- uevqhp = uevqtp = NULL; ++ INIT_LIST_HEAD(&uevq); + + pthread_mutex_init(uevq_lockp, NULL); +- pthread_mutex_init(uevc_lockp, NULL); + pthread_cond_init(uev_condp, NULL); + ++ pthread_cleanup_push(uevq_stop, NULL); + setup_thread_attr(&attr, 64 * 1024, 0); + pthread_create(&uevq_thr, &attr, uevq_thread, NULL); + +@@ -267,7 +287,7 @@ int uevent_listen(int (*uev_trigger)(str + buflen = recvmsg(sock, &smsg, 0); + if (buflen < 0) { + if (errno != EINTR) +- condlog(0, "error receiving message"); ++ condlog(0, "error receiving message, errno %d", errno); + continue; + } + +@@ -295,6 +315,10 @@ int uevent_listen(int (*uev_trigger)(str + condlog(3, "unrecognized message header"); + continue; + } ++ if ((size_t)buflen > sizeof(buf)-1) { ++ condlog(2, "buffer overflow for received uevent"); ++ buflen = sizeof(buf)-1; ++ } + + uev = alloc_uevent(); + +@@ -351,28 +375,17 @@ int uevent_listen(int (*uev_trigger)(str + * Queue uevent and poke service pthread. + */ + pthread_mutex_lock(uevq_lockp); +- if (uevqtp) +- uevqtp->next = uev; +- else +- uevqhp = uev; +- uevqtp = uev; +- uev->next = NULL; +- pthread_mutex_unlock(uevq_lockp); +- +- pthread_mutex_lock(uevc_lockp); ++ list_add_tail(&uev->node, &uevq); + pthread_cond_signal(uev_condp); +- pthread_mutex_unlock(uevc_lockp); ++ pthread_mutex_unlock(uevq_lockp); + } + + exit: + close(sock); + +- pthread_mutex_lock(uevq_lockp); +- pthread_cancel(uevq_thr); +- pthread_mutex_unlock(uevq_lockp); ++ pthread_cleanup_pop(1); + + pthread_mutex_destroy(uevq_lockp); +- pthread_mutex_destroy(uevc_lockp); + pthread_cond_destroy(uev_condp); + + return 1; +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -14,7 +14,7 @@ + #endif + + struct uevent { +- void *next; ++ struct list_head node; + char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; + char *devpath; + char *action; diff -Nru multipath-tools-0.4.9/debian/patches/0009-Start-uevent-service-handler-from-main-thread.patch multipath-tools-0.4.9/debian/patches/0009-Start-uevent-service-handler-from-main-thread.patch --- multipath-tools-0.4.9/debian/patches/0009-Start-uevent-service-handler-from-main-thread.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0009-Start-uevent-service-handler-from-main-thread.patch 2015-07-28 19:22:39.000000000 +0000 @@ -0,0 +1,187 @@ +From 6b16726c299a7adc7d0d2b9a4da001928c04c341 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Tue, 30 Mar 2010 10:53:05 +0200 +Subject: [PATCH] Start uevent service handler from main thread + +We should start the uevent handler as early as possible so as +to not miss out any events. However, we cannot process these +events until after all paths have been discovered. So we +should be starting the uevent service routine only after +the discovery process. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/uevent.c | 19 ++++++++----------- + libmultipath/uevent.h | 6 ++++-- + multipathd/main.c | 45 +++++++++++++++++++++++++++++++++++++++------ + 3 files changed, 51 insertions(+), 19 deletions(-) + +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -130,9 +130,12 @@ static void uevq_stop(void *arg) + /* + * Service the uevent queue. + */ +-static void * +-uevq_thread(void * et) ++int uevent_dispatch(int (*uev_trigger)(struct uevent *, void * trigger_data), ++ void * trigger_data) + { ++ my_uev_trigger = uev_trigger; ++ my_trigger_data = trigger_data; ++ + mlockall(MCL_CURRENT | MCL_FUTURE); + + while (1) { +@@ -154,11 +157,11 @@ uevq_thread(void * et) + break; + service_uevq(&uevq_tmp); + } +- return NULL; ++ condlog(3, "Terminating uev service queue"); ++ return 0; + } + +-int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data), +- void * trigger_data) ++int uevent_listen(void) + { + int sock; + struct sockaddr_nl snl; +@@ -169,12 +172,8 @@ int uevent_listen(int (*uev_trigger)(str + int rcvsz = 0; + int rcvszsz = sizeof(rcvsz); + unsigned int *prcvszsz = (unsigned int *)&rcvszsz; +- pthread_attr_t attr; + const int feature_on = 1; + +- my_uev_trigger = uev_trigger; +- my_trigger_data = trigger_data; +- + /* + * Queue uevents for service by dedicated thread so that the uevent + * listening thread does not block on multipathd locks (vecs->lock) +@@ -187,8 +186,6 @@ int uevent_listen(int (*uev_trigger)(str + pthread_cond_init(uev_condp, NULL); + + pthread_cleanup_push(uevq_stop, NULL); +- setup_thread_attr(&attr, 64 * 1024, 0); +- pthread_create(&uevq_thr, &attr, uevq_thread, NULL); + + /* + * First check whether we have a udev socket +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -21,9 +21,11 @@ struct uevent { + char *envp[HOTPLUG_NUM_ENVP]; + }; + +-int uevent_listen(int (*store_uev)(struct uevent *, void * trigger_data), +- void * trigger_data); + int is_uevent_busy(void); + void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached); + ++int uevent_listen(void); ++int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), ++ void * trigger_data); ++ + #endif /* _UEVENT_H */ +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -735,13 +735,24 @@ ueventloop (void * ap) + block_signal(SIGUSR1, NULL); + block_signal(SIGHUP, NULL); + +- if (uevent_listen(&uev_trigger, ap)) +- fprintf(stderr, "error starting uevent listener"); ++ if (uevent_listen()) ++ condlog(0, "error starting uevent listener"); + + return NULL; + } + + static void * ++uevqloop (void * ap) ++{ ++ block_signal(SIGUSR1, NULL); ++ block_signal(SIGHUP, NULL); ++ ++ if (uevent_dispatch(&uev_trigger, ap)) ++ condlog(0, "error starting uevent dispatcher"); ++ ++ return NULL; ++} ++static void * + uxlsnrloop (void * ap) + { + block_signal(SIGUSR1, NULL); +@@ -1313,11 +1324,12 @@ set_oom_adj (int val) + static int + child (void * param) + { +- pthread_t check_thr, uevent_thr, uxlsnr_thr; ++ pthread_t check_thr, uevent_thr, uxlsnr_thr, uevq_thr; + pthread_attr_t log_attr, misc_attr; + struct vectors * vecs; + struct multipath * mpp; + int i; ++ int rc; + + mlockall(MCL_CURRENT | MCL_FUTURE); + +@@ -1386,18 +1398,38 @@ child (void * param) + conf->daemon = 1; + dm_udev_set_sync_support(0); + /* ++ * Start uevent listener early to catch events ++ */ ++ if ((rc = pthread_create(&uevent_thr, &misc_attr, ueventloop, vecs))) { ++ condlog(0, "failed to create uevent thread: %d", rc); ++ exit(1); ++ } ++ /* + * fetch and configure both paths and multipaths + */ ++ lock(vecs->lock); + if (configure(vecs, 1)) { ++ unlock(vecs->lock); + condlog(0, "failure during configuration"); + exit(1); + } ++ unlock(vecs->lock); ++ + /* + * start threads + */ +- pthread_create(&check_thr, &misc_attr, checkerloop, vecs); +- pthread_create(&uevent_thr, &misc_attr, ueventloop, vecs); +- pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs); ++ if ((rc = pthread_create(&check_thr, &misc_attr, checkerloop, vecs))) { ++ condlog(0,"failed to create checker loop thread: %d", rc); ++ exit(1); ++ } ++ if ((rc = pthread_create(&uxlsnr_thr, &misc_attr, uxlsnrloop, vecs))) { ++ condlog(0, "failed to create cli listener: %d", rc); ++ exit(1); ++ } ++ if ((rc = pthread_create(&uevq_thr, &misc_attr, uevqloop, vecs))) { ++ condlog(0, "failed to create uevent dispatcher: %d", rc); ++ exit(1); ++ } + pthread_attr_destroy(&misc_attr); + + pthread_mutex_lock(&exit_mutex); +@@ -1417,6 +1449,7 @@ child (void * param) + pthread_cancel(check_thr); + pthread_cancel(uevent_thr); + pthread_cancel(uxlsnr_thr); ++ pthread_cancel(uevq_thr); + + sysfs_cleanup(); + diff -Nru multipath-tools-0.4.9/debian/patches/0010-libmultipath-rework-sysfs-handling.patch multipath-tools-0.4.9/debian/patches/0010-libmultipath-rework-sysfs-handling.patch --- multipath-tools-0.4.9/debian/patches/0010-libmultipath-rework-sysfs-handling.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0010-libmultipath-rework-sysfs-handling.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,261 @@ +From e7b54e70bdd1d6020351a2af2e92dfb16724f2cd Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 27 May 2010 13:51:23 +0200 +Subject: [PATCH] libmultipath: rework sysfs handling + +sysfs_get_device() is called extremely often, so we need +to make sure to have that as streamlined as possible. +So remove all unused fields and use caching as often as +possible. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 17 +++---- + libmultipath/structs.h | 3 - + libmultipath/sysfs.c | 104 ++++++++--------------------------------------- + libmultipath/sysfs.h | 5 -- + 4 files changed, 28 insertions(+), 101 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -628,6 +628,9 @@ struct sysfs_device *sysfs_device_from_p + { + char sysdev[FILE_NAME_SIZE]; + ++ if (pp->sysdev && sysfs_device_verify(pp->sysdev)) ++ return pp->sysdev; ++ + strlcpy(sysdev,"/block/", FILE_NAME_SIZE); + strlcat(sysdev,pp->dev, FILE_NAME_SIZE); + +@@ -698,17 +701,13 @@ sysfs_pathinfo(struct path * pp) + return 1; + } + ++ pp->bus = SYSFS_BUS_UNDEF; + if (!strncmp(pp->dev,"cciss",5)) +- strcpy(parent->subsystem,"cciss"); +- +- condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem); +- +- if (!strncmp(parent->subsystem, "scsi",4)) +- pp->bus = SYSFS_BUS_SCSI; +- if (!strncmp(parent->subsystem, "ccw",3)) +- pp->bus = SYSFS_BUS_CCW; +- if (!strncmp(parent->subsystem,"cciss",5)) + pp->bus = SYSFS_BUS_CCISS; ++ if (!strncmp(pp->dev,"dasd", 4)) ++ pp->bus = SYSFS_BUS_CCW; ++ if (!strncmp(pp->dev,"sd", 2)) ++ pp->bus = SYSFS_BUS_SCSI; + + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; +Index: b/libmultipath/structs.h +=================================================================== +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -113,10 +113,7 @@ struct scsi_dev { + struct sysfs_device { + struct sysfs_device *parent; /* parent device */ + char devpath[PATH_SIZE]; +- char subsystem[NAME_SIZE]; /* $class, $bus, drivers, module */ + char kernel[NAME_SIZE]; /* device instance name */ +- char kernel_number[NAME_SIZE]; +- char driver[NAME_SIZE]; /* device driver name */ + }; + + struct path { +Index: b/libmultipath/sysfs.c +=================================================================== +--- a/libmultipath/sysfs.c ++++ b/libmultipath/sysfs.c +@@ -68,16 +68,11 @@ void sysfs_cleanup(void) + } + } + +-void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, +- const char *subsystem, const char *driver) ++void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath) + { + char *pos; + + strlcpy(dev->devpath, devpath, sizeof(dev->devpath)); +- if (subsystem != NULL) +- strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem)); +- if (driver != NULL) +- strlcpy(dev->driver, driver, sizeof(dev->driver)); + + /* set kernel name */ + pos = strrchr(dev->devpath, '/'); +@@ -93,13 +88,6 @@ void sysfs_device_set_values(struct sysf + pos[0] = '/'; + pos++; + } +- +- /* get kernel number */ +- pos = &dev->kernel[strlen(dev->kernel)]; +- while (isdigit(pos[-1])) +- pos--; +- strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number)); +- dbg("kernel_number='%s'", dev->kernel_number); + } + + int sysfs_resolve_link(char *devpath, size_t size) +@@ -134,6 +122,10 @@ int sysfs_resolve_link(char *devpath, si + return 0; + } + ++/* ++ * Caution: this routine is called extremely often. ++ * Should be as efficient as possible. ++ */ + struct sysfs_device *sysfs_device_get(const char *devpath) + { + char path[PATH_SIZE]; +@@ -141,22 +133,6 @@ struct sysfs_device *sysfs_device_get(co + struct sysfs_device *dev = NULL; + struct sysfs_dev *sysdev_loop, *sysdev; + struct stat statbuf; +- char link_path[PATH_SIZE]; +- char link_target[PATH_SIZE]; +- int len; +- char *pos; +- +- /* we handle only these devpathes */ +- if (devpath != NULL && +- strncmp(devpath, "/devices/", 9) != 0 && +- strncmp(devpath, "/subsystem/", 11) != 0 && +- strncmp(devpath, "/module/", 8) != 0 && +- strncmp(devpath, "/bus/", 5) != 0 && +- strncmp(devpath, "/class/", 7) != 0 && +- strncmp(devpath, "/block/", 7) != 0) { +- dbg("invalid devpath '%s'", devpath); +- return NULL; +- } + + dbg("open '%s'", devpath); + strlcpy(devpath_real, devpath, sizeof(devpath_real)); +@@ -203,53 +179,7 @@ struct sysfs_device *sysfs_device_get(co + dev = &sysdev->dev; + } + +- sysfs_device_set_values(dev, devpath_real, NULL, NULL); +- +- /* get subsystem name */ +- strlcpy(link_path, sysfs_path, sizeof(link_path)); +- strlcat(link_path, dev->devpath, sizeof(link_path)); +- strlcat(link_path, "/subsystem", sizeof(link_path)); +- len = readlink(link_path, link_target, sizeof(link_target)); +- if (len > 0) { +- /* get subsystem from "subsystem" link */ +- link_target[len] = '\0'; +- dbg("subsystem link '%s' points to '%s'", link_path, link_target); +- pos = strrchr(link_target, '/'); +- if (pos != NULL) +- strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem)); +- } else if (strstr(dev->devpath, "/drivers/") != NULL) { +- strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem)); +- } else if (strncmp(dev->devpath, "/module/", 8) == 0) { +- strlcpy(dev->subsystem, "module", sizeof(dev->subsystem)); +- } else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) { +- pos = strrchr(dev->devpath, '/'); +- if (pos == &dev->devpath[10]) +- strlcpy(dev->subsystem, "subsystem", +- sizeof(dev->subsystem)); +- } else if (strncmp(dev->devpath, "/class/", 7) == 0) { +- pos = strrchr(dev->devpath, '/'); +- if (pos == &dev->devpath[6]) +- strlcpy(dev->subsystem, "subsystem", +- sizeof(dev->subsystem)); +- } else if (strncmp(dev->devpath, "/bus/", 5) == 0) { +- pos = strrchr(dev->devpath, '/'); +- if (pos == &dev->devpath[4]) +- strlcpy(dev->subsystem, "subsystem", +- sizeof(dev->subsystem)); +- } +- +- /* get driver name */ +- strlcpy(link_path, sysfs_path, sizeof(link_path)); +- strlcat(link_path, dev->devpath, sizeof(link_path)); +- strlcat(link_path, "/driver", sizeof(link_path)); +- len = readlink(link_path, link_target, sizeof(link_target)); +- if (len > 0) { +- link_target[len] = '\0'; +- dbg("driver link '%s' points to '%s'", link_path, link_target); +- pos = strrchr(link_target, '/'); +- if (pos != NULL) +- strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); +- } ++ sysfs_device_set_values(dev, devpath_real); + + return dev; + } +@@ -306,16 +236,17 @@ device_link: + return dev->parent; + } + +-struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem) ++struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev) + { +- struct sysfs_device *dev_parent; ++ char path[PATH_SIZE]; ++ struct stat statbuf; ++ ++ strlcpy(path, sysfs_path, sizeof(path)); ++ strlcat(path, dev->devpath, sizeof(path)); ++ if (stat(dev->devpath, &statbuf) == 0 && ++ S_ISDIR(statbuf.st_mode)) ++ return dev; + +- dev_parent = sysfs_device_get_parent(dev); +- while (dev_parent != NULL) { +- if (strcmp(dev_parent->subsystem, subsystem) == 0) +- return dev_parent; +- dev_parent = sysfs_device_get_parent(dev_parent); +- } + return NULL; + } + +@@ -438,7 +369,7 @@ ssize_t sysfs_attr_set_value(const char + if ((statbuf.st_mode & S_IWUSR) == 0) + goto out; + +- /* read attribute value */ ++ /* write attribute value */ + fd = open(path_full, O_WRONLY); + if (fd < 0) { + dbg("attribute '%s' can not be opened: %s", +@@ -453,9 +384,10 @@ ssize_t sysfs_attr_set_value(const char + path_full, size); + size = -1; + } +- close(fd); + ++ close(fd); + out: ++ + return size; + } + +Index: b/libmultipath/sysfs.h +=================================================================== +--- a/libmultipath/sysfs.h ++++ b/libmultipath/sysfs.h +@@ -13,12 +13,11 @@ + + int sysfs_init(char *path, size_t len); + void sysfs_cleanup(void); +-void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, +- const char *subsystem, const char *driver); ++void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath); + struct sysfs_device *sysfs_device_get(const char *devpath); + struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); +-struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem); + void sysfs_device_put(struct sysfs_device *dev); ++struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev); + size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, + char *attr_value, int attr_len); + ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, diff -Nru multipath-tools-0.4.9/debian/patches/0011-Rework-sysfs-device-handling-in-multipathd.patch multipath-tools-0.4.9/debian/patches/0011-Rework-sysfs-device-handling-in-multipathd.patch --- multipath-tools-0.4.9/debian/patches/0011-Rework-sysfs-device-handling-in-multipathd.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0011-Rework-sysfs-device-handling-in-multipathd.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,572 @@ +From 5a947826b5f3cd4c0437ee6cacf7557cd6f5b410 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 20 Nov 2008 12:14:42 +0100 +Subject: [PATCH] Rework sysfs device handling in multipathd + +Relying on sysfs devices has the disadvantage that the device +might already been gone by the time we look at it. And we don't +actually need it for eg device-mapper events as we can get all +required information via the device-mapper ioctl. +So only access sysfs if we absolutely have to and try to get +the information from other places if possible. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/devmapper.c | 25 ++++++++ + libmultipath/devmapper.h | 1 + libmultipath/structs_vec.c | 3 - + libmultipath/structs_vec.h | 3 - + libmultipath/uevent.c | 62 +++++++++++++++++++++ + libmultipath/uevent.h | 4 + + multipathd/cli_handlers.c | 49 +++++++++++++--- + multipathd/main.c | 130 ++++++++++++++++++++++++++++----------------- + multipathd/main.h | 4 - + 9 files changed, 216 insertions(+), 65 deletions(-) + +Index: b/libmultipath/devmapper.c +=================================================================== +--- a/libmultipath/devmapper.c ++++ b/libmultipath/devmapper.c +@@ -517,6 +517,31 @@ out: + } + + int ++dm_get_major (char * mapname) ++{ ++ int r = -1; ++ struct dm_task *dmt; ++ struct dm_info info; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ return 0; ++ ++ if (!dm_task_set_name(dmt, mapname)) ++ goto out; ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info)) ++ goto out; ++ ++ r = info.major; ++out: ++ dm_task_destroy(dmt); ++ return r; ++} ++ ++int + dm_get_minor (char * mapname) + { + int r = -1; +Index: b/libmultipath/devmapper.h +=================================================================== +--- a/libmultipath/devmapper.h ++++ b/libmultipath/devmapper.h +@@ -31,6 +31,7 @@ int dm_enablegroup(char * mapname, int i + int dm_disablegroup(char * mapname, int index); + int dm_get_maps (vector mp); + int dm_geteventnr (char *name); ++int dm_get_major (char *name); + int dm_get_minor (char *name); + char * dm_mapname(int major, int minor); + int dm_remove_partmaps (const char * mapname, int need_sync); +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -377,8 +377,7 @@ out: + } + + extern struct multipath * +-add_map_without_path (struct vectors * vecs, +- int minor, char * alias) ++add_map_without_path (struct vectors * vecs, char * alias) + { + struct multipath * mpp = alloc_multipath(); + +Index: b/libmultipath/structs_vec.h +=================================================================== +--- a/libmultipath/structs_vec.h ++++ b/libmultipath/structs_vec.h +@@ -29,8 +29,7 @@ void remove_map_and_stop_waiter (struct + void remove_maps (struct vectors * vecs); + void remove_maps_and_stop_waiters (struct vectors * vecs); + +-struct multipath * add_map_without_path (struct vectors * vecs, +- int minor, char * alias); ++struct multipath * add_map_without_path (struct vectors * vecs, char * alias); + struct multipath * add_map_with_path (struct vectors * vecs, + struct path * pp, int add_vec); + int update_multipath (struct vectors *vecs, char *mapname); +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -363,10 +363,13 @@ int uevent_listen(void) + uev->envp[i] = NULL; + + condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath); ++ uev->kernel = strrchr(uev->devpath, '/'); ++ if (uev->kernel) ++ uev->kernel++; + + /* print payload environment */ + for (i = 0; uev->envp[i] != NULL; i++) +- condlog(3, "%s", uev->envp[i]); ++ condlog(5, "%s", uev->envp[i]); + + /* + * Queue uevent and poke service pthread. +@@ -387,3 +390,60 @@ exit: + + return 1; + } ++ ++extern int ++uevent_get_major(struct uevent *uev) ++{ ++ char *p, *q; ++ int i, major = -1; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "MAJOR", 5) && strlen(uev->envp[i]) > 6) { ++ p = uev->envp[i] + 6; ++ major = strtoul(p, &q, 10); ++ if (p == q) { ++ condlog(2, "invalid major '%s'", p); ++ major = -1; ++ } ++ break; ++ } ++ } ++ return major; ++} ++ ++extern int ++uevent_get_minor(struct uevent *uev) ++{ ++ char *p, *q; ++ int i, minor = -1; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "MINOR", 5) && strlen(uev->envp[i]) > 6) { ++ p = uev->envp[i] + 6; ++ minor = strtoul(p, &q, 10); ++ if (p == q) { ++ condlog(2, "invalid minor '%s'", p); ++ minor = -1; ++ } ++ break; ++ } ++ } ++ return minor; ++} ++ ++extern char * ++uevent_get_dm_name(struct uevent *uev) ++{ ++ char *p = NULL; ++ int i; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "DM_NAME", 6) && ++ strlen(uev->envp[i]) > 7) { ++ p = MALLOC(strlen(uev->envp[i] + 8) + 1); ++ strcpy(p, uev->envp[i] + 8); ++ break; ++ } ++ } ++ return p; ++} +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -18,6 +18,7 @@ struct uevent { + char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; + char *devpath; + char *action; ++ char *kernel; + char *envp[HOTPLUG_NUM_ENVP]; + }; + +@@ -27,5 +28,8 @@ void setup_thread_attr(pthread_attr_t *a + int uevent_listen(void); + int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), + void * trigger_data); ++int uevent_get_major(struct uevent *uev); ++int uevent_get_minor(struct uevent *uev); ++char *uevent_get_dm_name(struct uevent *uev); + + #endif /* _UEVENT_H */ +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -383,9 +383,10 @@ cli_add_map (void * v, char ** reply, in + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); +- int minor; ++ int major, minor; + char dev_path[PATH_SIZE]; +- struct sysfs_device *sysdev; ++ char *alias; ++ int rc; + + condlog(2, "%s: add map (operator)", param); + +@@ -400,13 +401,21 @@ cli_add_map (void * v, char ** reply, in + condlog(2, "%s: not a device mapper table", param); + return 0; + } +- sprintf(dev_path,"/block/dm-%d", minor); +- sysdev = sysfs_device_get(dev_path); +- if (!sysdev) { +- condlog(2, "%s: not found in sysfs", param); ++ major = dm_get_major(param); ++ if (major < 0) { ++ condlog(2, "%s: not a device mapper table", param); ++ return 0; ++ } ++ sprintf(dev_path,"dm-%d", minor); ++ alias = dm_mapname(major, minor); ++ if (!alias) { ++ condlog(2, "%s: mapname not found for %d:%d", ++ param, major, minor); + return 0; + } +- return ev_add_map(sysdev, vecs); ++ rc = ev_add_map(dev_path, alias, vecs); ++ FREE(alias); ++ return rc; + } + + int +@@ -414,10 +423,32 @@ cli_del_map (void * v, char ** reply, in + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); ++ int major, minor; ++ char dev_path[PATH_SIZE]; ++ char *alias; ++ int rc; + + condlog(2, "%s: remove map (operator)", param); +- +- return ev_remove_map(param, vecs); ++ minor = dm_get_minor(param); ++ if (minor < 0) { ++ condlog(2, "%s: not a device mapper table", param); ++ return 0; ++ } ++ major = dm_get_major(param); ++ if (major < 0) { ++ condlog(2, "%s: not a device mapper table", param); ++ return 0; ++ } ++ sprintf(dev_path,"dm-%d", minor); ++ alias = dm_mapname(major, minor); ++ if (!alias) { ++ condlog(2, "%s: mapname not found for %d:%d", ++ param, major, minor); ++ return 0; ++ } ++ rc = ev_remove_map(param, alias, minor, vecs); ++ FREE(alias); ++ return rc; + } + + int resize_map(struct multipath *mpp, unsigned long long size, +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -213,32 +213,41 @@ flush_map(struct multipath * mpp, struct + } + + static int +-uev_add_map (struct sysfs_device * dev, struct vectors * vecs) ++uev_add_map (struct uevent * uev, struct vectors * vecs) + { +- condlog(2, "%s: add map (uevent)", dev->kernel); +- return ev_add_map(dev, vecs); ++ char *alias; ++ int major = -1, minor = -1, rc; ++ ++ condlog(2, "%s: add map (uevent)", uev->kernel); ++ alias = uevent_get_dm_name(uev); ++ if (!alias) { ++ condlog(3, "%s: No DM_NAME in uevent", uev->kernel); ++ major = uevent_get_major(uev); ++ minor = uevent_get_minor(uev); ++ alias = dm_mapname(major, minor); ++ if (!alias) { ++ condlog(2, "%s: mapname not found for %d:%d", ++ uev->kernel, major, minor); ++ return 1; ++ } ++ } ++ rc = ev_add_map(uev->kernel, alias, vecs); ++ FREE(alias); ++ return rc; + } + + int +-ev_add_map (struct sysfs_device * dev, struct vectors * vecs) ++ev_add_map (char * dev, char * alias, struct vectors * vecs) + { +- char * alias; +- int major, minor; + char * refwwid; + struct multipath * mpp; + int map_present; + int r = 1; + +- alias = dm_mapname(major, minor); +- +- if (!alias) +- return 1; +- + map_present = dm_map_present(alias); + + if (map_present && dm_type(alias, TGT_MPATH) <= 0) { + condlog(4, "%s: not a multipath map", alias); +- FREE(alias); + return 0; + } + +@@ -250,21 +259,19 @@ ev_add_map (struct sysfs_device * dev, s + * if we create a multipath mapped device as a result + * of uev_add_path + */ +- condlog(0, "%s: devmap already registered", +- dev->kernel); +- FREE(alias); ++ condlog(0, "%s: devmap already registered", dev); + return 0; + } + + /* + * now we can register the map + */ +- if (map_present && (mpp = add_map_without_path(vecs, minor, alias))) { ++ if (map_present && (mpp = add_map_without_path(vecs, alias))) { + sync_map_state(mpp); +- condlog(2, "%s: devmap %s added", alias, dev->kernel); ++ condlog(2, "%s: devmap %s registered", alias, dev); + return 0; + } +- refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec); ++ refwwid = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec); + + if (refwwid) { + r = coalesce_paths(vecs, NULL, refwwid, 0); +@@ -272,47 +279,60 @@ ev_add_map (struct sysfs_device * dev, s + } + + if (!r) +- condlog(2, "%s: devmap %s added", alias, dev->kernel); ++ condlog(2, "%s: devmap %s added", alias, dev); + else +- condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel); ++ condlog(0, "%s: uev_add_map %s failed", alias, dev); + + FREE(refwwid); +- FREE(alias); + return r; + } + + static int +-uev_remove_map (struct sysfs_device * dev, struct vectors * vecs) ++uev_remove_map (struct uevent * uev, struct vectors * vecs) + { +- condlog(2, "%s: remove map (uevent)", dev->kernel); +- return ev_remove_map(dev->kernel, vecs); ++ char *alias; ++ int minor, rc; ++ ++ condlog(2, "%s: remove map (uevent)", uev->kernel); ++ alias = uevent_get_dm_name(uev); ++ if (!alias) { ++ condlog(3, "%s: No DM_NAME in uevent, ignoring", uev->kernel); ++ return 0; ++ } ++ minor = uevent_get_minor(uev); ++ rc = ev_remove_map(uev->kernel, alias, minor, vecs); ++ FREE(alias); ++ return rc; + } + + int +-ev_remove_map (char * devname, struct vectors * vecs) ++ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs) + { + struct multipath * mpp; + +- mpp = find_mp_by_str(vecs->mpvec, devname); ++ mpp = find_mp_by_minor(vecs->mpvec, minor); + + if (!mpp) { + condlog(2, "%s: devmap not registered, can't remove", + devname); + return 0; + } +- flush_map(mpp, vecs); +- +- return 0; ++ if (strcmp(mpp->alias, alias)) { ++ condlog(2, "%s: minor number mismatch (map %d, event %d)", ++ mpp->alias, mpp->dmi->minor, minor); ++ return 0; ++ } ++ return flush_map(mpp, vecs); + } + + static int +-uev_umount_map (struct sysfs_device * dev, struct vectors * vecs) ++uev_umount_map (struct uevent * uev, struct vectors * vecs) + { + struct multipath * mpp; + +- condlog(2, "%s: umount map (uevent)", dev->kernel); ++ condlog(2, "%s: umount map (uevent)", uev->kernel); + +- mpp = find_mp_by_str(vecs->mpvec, dev->kernel); ++ mpp = find_mp_by_str(vecs->mpvec, uev->kernel); + + if (!mpp) + return 0; +@@ -326,14 +346,21 @@ uev_umount_map (struct sysfs_device * de + return 0; + } + ++ + static int +-uev_add_path (struct sysfs_device * dev, struct vectors * vecs) ++uev_add_path (struct uevent *uev, struct vectors * vecs) + { ++ struct sysfs_device * dev; ++ ++ dev = sysfs_device_get(uev->devpath); ++ if (!dev) { ++ condlog(2, "%s: not found in sysfs", uev->devpath); ++ return 1; ++ } + condlog(2, "%s: add path (uevent)", dev->kernel); + return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1; + } + +- + /* + * returns: + * 0: added +@@ -485,12 +512,19 @@ out: + } + + static int +-uev_remove_path (struct sysfs_device * dev, struct vectors * vecs) ++uev_remove_path (struct uevent *uev, struct vectors * vecs) + { ++ struct sysfs_device * dev; + int retval; + +- condlog(2, "%s: remove path (uevent)", dev->kernel); +- retval = ev_remove_path(dev->kernel, vecs); ++ dev = sysfs_device_get(uev->devpath); ++ if (!dev) { ++ condlog(2, "%s: not found in sysfs", uev->devpath); ++ return 1; ++ } ++ condlog(2, "%s: remove path (uevent)", uev->kernel); ++ retval = ev_remove_path(uev->kernel, vecs); ++ + if (!retval) + sysfs_device_put(dev); + +@@ -673,7 +707,6 @@ int + uev_trigger (struct uevent * uev, void * trigger_data) + { + int r = 0; +- struct sysfs_device *sysdev; + struct vectors * vecs; + + vecs = (struct vectors *)trigger_data; +@@ -681,10 +714,6 @@ uev_trigger (struct uevent * uev, void * + if (uev_discard(uev->devpath)) + return 0; + +- sysdev = sysfs_device_get(uev->devpath); +- if(!sysdev) +- return 0; +- + lock(vecs->lock); + + /* +@@ -692,17 +721,17 @@ uev_trigger (struct uevent * uev, void * + * Add events are ignored here as the tables + * are not fully initialised then. + */ +- if (!strncmp(sysdev->kernel, "dm-", 3)) { ++ if (!strncmp(uev->kernel, "dm-", 3)) { + if (!strncmp(uev->action, "change", 6)) { +- r = uev_add_map(sysdev, vecs); ++ r = uev_add_map(uev, vecs); + goto out; + } + if (!strncmp(uev->action, "remove", 6)) { +- r = uev_remove_map(sysdev, vecs); ++ r = uev_remove_map(uev, vecs); + goto out; + } + if (!strncmp(uev->action, "umount", 6)) { +- r = uev_umount_map(sysdev, vecs); ++ r = uev_umount_map(uev, vecs); + goto out; + } + goto out; +@@ -712,15 +741,15 @@ uev_trigger (struct uevent * uev, void * + * path add/remove event + */ + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, +- sysdev->kernel) > 0) ++ uev->kernel) > 0) + goto out; + + if (!strncmp(uev->action, "add", 3)) { +- r = uev_add_path(sysdev, vecs); ++ r = uev_add_path(uev, vecs); + goto out; + } + if (!strncmp(uev->action, "remove", 6)) { +- r = uev_remove_path(sysdev, vecs); ++ r = uev_remove_path(uev, vecs); + goto out; + } + +@@ -1472,6 +1501,9 @@ child (void * param) + FREE(vecs); + vecs = NULL; + ++ cleanup_checkers(); ++ cleanup_prio(); ++ + condlog(2, "--------shut down-------"); + + if (logsink) +Index: b/multipathd/main.h +=================================================================== +--- a/multipathd/main.h ++++ b/multipathd/main.h +@@ -6,8 +6,8 @@ + int reconfigure (struct vectors *); + int ev_add_path (char *, struct vectors *); + int ev_remove_path (char *, struct vectors *); +-int ev_add_map (struct sysfs_device *, struct vectors *); +-int ev_remove_map (char *, struct vectors *); ++int ev_add_map (char *, char *, struct vectors *); ++int ev_remove_map (char *, char *, int, struct vectors *); + void sync_map_state (struct multipath *); + + #endif /* MAIN_H */ diff -Nru multipath-tools-0.4.9/debian/patches/0012-Only-check-offline-status-for-SCSI-devices.patch multipath-tools-0.4.9/debian/patches/0012-Only-check-offline-status-for-SCSI-devices.patch --- multipath-tools-0.4.9/debian/patches/0012-Only-check-offline-status-for-SCSI-devices.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0012-Only-check-offline-status-for-SCSI-devices.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,27 @@ +From cc2bec4f2be42f3fa106b6d6d53a82efa5dc3230 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 18 May 2011 09:32:15 +0200 +Subject: [PATCH] Only check offline status for SCSI devices + +Only SCSI devices can be checked for offline status, so we +should return PATH_UP for every other type. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -643,6 +643,9 @@ path_offline (struct path * pp) + struct sysfs_device * parent; + char buff[SCSI_STATE_SIZE]; + ++ if (pp->bus != SYSFS_BUS_SCSI) ++ return PATH_UP; ++ + pp->sysdev = sysfs_device_from_path(pp); + if (!pp->sysdev) { + condlog(1, "%s: failed to get sysfs information", pp->dev); diff -Nru multipath-tools-0.4.9/debian/patches/0013-Check-for-offline-path-in-get_prio.patch multipath-tools-0.4.9/debian/patches/0013-Check-for-offline-path-in-get_prio.patch --- multipath-tools-0.4.9/debian/patches/0013-Check-for-offline-path-in-get_prio.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0013-Check-for-offline-path-in-get_prio.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,30 @@ +From 16b8503510b11e690051a2a1c4f096505357d799 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 18 May 2011 09:35:34 +0200 +Subject: [PATCH] Check for offline path in get_prio() + +We need to check for an offline path in get_prio(), otherwise +the priority callout might stall. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -807,6 +807,12 @@ get_prio (struct path * pp) + if (!pp) + return 0; + ++ path_state = path_offline(pp); ++ if (path_state != PATH_UP) { ++ pp->priority = PRIO_UNDEF; ++ return 0; ++ } ++ + if (!pp->prio) { + select_prio(pp); + if (!pp->prio) { diff -Nru multipath-tools-0.4.9/debian/patches/0014-kpartx-long-path.patch multipath-tools-0.4.9/debian/patches/0014-kpartx-long-path.patch --- multipath-tools-0.4.9/debian/patches/0014-kpartx-long-path.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0014-kpartx-long-path.patch 2015-12-01 14:45:57.000000000 +0000 @@ -0,0 +1,41 @@ +From: Risto Kankkunen +Date: Mon, 29 Jun 2015 18:39:48 +0300 +Subject: Use image file device/inode to find the correct loop device in kpartx + +Previously kpartx used the "lo_name" field of struct loop_info to store +and match the image file name. That field is not intended to store path +names (it's not big enough). Therefore kpartx was unable to delete +mappings to file paths longer than 63 characters. It also didn't +properly handle relative file paths: two different files with identical +relative path names could not be mapped. Instead kpartx would modify +the existing mapping when seeing a new file with the same relative path. + +The "loopinfo" structure contains the image file device and inode +numbers. Use those to uniquely identify the correct loop device. + +--- a/kpartx/lopart.c ++++ b/kpartx/lopart.c +@@ -103,6 +103,14 @@ + int i, j, fd; + struct stat statbuf; + struct loop_info loopinfo; ++ dev_t file_dev; ++ ino_t file_ino; ++ ++ if (stat (filename, &statbuf) != 0) { ++ return NULL; ++ } ++ file_dev = statbuf.st_dev; ++ file_ino = statbuf.st_ino; + + for (j = 0; j < SIZE(loop_formats); j++) { + +@@ -123,7 +131,7 @@ + continue; + } + +- if (0 == strcmp(filename, loopinfo.lo_name)) { ++ if (loopinfo.lo_device == file_dev && loopinfo.lo_inode == file_ino) { + close (fd); + return xstrdup(dev); /*found */ + } diff -Nru multipath-tools-0.4.9/debian/patches/0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch multipath-tools-0.4.9/debian/patches/0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch --- multipath-tools-0.4.9/debian/patches/0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,125 @@ +From d982709f814bfb496f22b78b5951016957a00cf8 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 27 May 2010 13:53:43 +0200 +Subject: [PATCH] libmultipath: Remove duplicate calls to path_offline() + +When calling pathinfo() path_offline() is called several times +in a row, which is quite unnecessary. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 43 ++++++++++++++++++++++++------------------- + multipathd/main.c | 4 +++- + 2 files changed, 27 insertions(+), 20 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -784,11 +784,6 @@ get_state (struct path * pp, int daemon) + return PATH_UNCHECKED; + } + } +- state = path_offline(pp); +- if (state != PATH_UP) { +- condlog(3, "%s: path inaccessible", pp->dev); +- return state; +- } + if (daemon) + checker_set_async(c); + if (!conf->checker_timeout) +@@ -807,12 +802,6 @@ get_prio (struct path * pp) + if (!pp) + return 0; + +- path_state = path_offline(pp); +- if (path_state != PATH_UP) { +- pp->priority = PRIO_UNDEF; +- return 0; +- } +- + if (!pp->prio) { + select_prio(pp); + if (!pp->prio) { +@@ -862,6 +851,8 @@ get_uid (struct path * pp) + extern int + pathinfo (struct path *pp, vector hwtable, int mask) + { ++ int path_state; ++ + condlog(3, "%s: mask = 0x%x", pp->dev, mask); + + /* +@@ -870,6 +861,8 @@ pathinfo (struct path *pp, vector hwtabl + if (mask & DI_SYSFS && sysfs_pathinfo(pp)) + return 1; + ++ path_state = path_offline(pp); ++ + /* + * fetch info not available through sysfs + */ +@@ -882,7 +875,7 @@ pathinfo (struct path *pp, vector hwtabl + goto blank; + } + +- if (pp->bus == SYSFS_BUS_SCSI && ++ if (path_state == PATH_UP && pp->bus == SYSFS_BUS_SCSI && + scsi_ioctl_pathinfo(pp, mask)) + goto blank; + +@@ -891,20 +884,32 @@ pathinfo (struct path *pp, vector hwtabl + goto blank; + + if (mask & DI_CHECKER) { +- pp->state = get_state(pp, 0); +- if (pp->state == PATH_UNCHECKED || pp->state == PATH_WILD) +- goto blank; ++ if (path_state == PATH_UP) { ++ pp->state = get_state(pp, 0); ++ if (pp->state == PATH_UNCHECKED || ++ pp->state == PATH_WILD) ++ goto blank; ++ } else { ++ condlog(3, "%s: path inaccessible", pp->dev); ++ pp->state = path_state; ++ } + } + + /* + * Retrieve path priority, even for 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_PRIO) && path_state == PATH_UP) { ++ if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) { ++ if (!strlen(pp->wwid)) ++ get_uid(pp); ++ get_prio(pp); ++ } else { ++ pp->priority = PRIO_UNDEF; ++ } ++ } + +- if (mask & DI_WWID && !strlen(pp->wwid)) ++ if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid)) + get_uid(pp); + + return 0; +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -970,7 +970,9 @@ check_path (struct vectors * vecs, struc + */ + pp->tick = conf->checkint; + +- newstate = get_state(pp, 1); ++ newstate = path_offline(pp); ++ if (newstate == PATH_UP) ++ newstate = get_state(pp, 1); + + if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) { + condlog(2, "%s: unusable path", pp->dev); diff -Nru multipath-tools-0.4.9/debian/patches/0015-Update-dev_loss_tmo-for-no_path_retry.patch multipath-tools-0.4.9/debian/patches/0015-Update-dev_loss_tmo-for-no_path_retry.patch --- multipath-tools-0.4.9/debian/patches/0015-Update-dev_loss_tmo-for-no_path_retry.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0015-Update-dev_loss_tmo-for-no_path_retry.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,88 @@ +From 81520369cab8b4fe525b0f75f9107cebd74b455d Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Mon, 11 Jan 2010 15:06:08 +0100 +Subject: [PATCH] Update dev_loss_tmo for no_path_retry + +When 'no_path_retry' is active we have to update the dev_loss_tmo +setting accordingly to ensure that no devices are removed during +an all-paths-down scenario. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/defaults.h | 1 + + libmultipath/discovery.c | 23 +++++++++++++++++++++++ + libmultipath/structs_vec.c | 5 +++++ + 3 files changed, 29 insertions(+) + +Index: b/libmultipath/defaults.h +=================================================================== +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -16,6 +16,7 @@ + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) + ++#define MAX_DEV_LOSS_TMO 0x7FFFFFFF + #define DEFAULT_PIDFILE "/var/run/multipathd.pid" + #define DEFAULT_SOCKET "/var/run/multipathd.sock" + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -26,6 +26,7 @@ + #include "sysfs.h" + #include "discovery.h" + #include "prio.h" ++#include "defaults.h" + + struct path * + store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag) +@@ -273,9 +274,31 @@ sysfs_set_scsi_tmo (struct multipath *mp + int i; + char value[11]; + int rport_id; ++ int dev_loss_tmo = mpp->dev_loss; + ++ if (mpp->no_path_retry > 0) { ++ int no_path_retry_tmo = mpp->no_path_retry * conf->checkint; ++ ++ if (no_path_retry_tmo > MAX_DEV_LOSS_TMO) ++ no_path_retry_tmo = MAX_DEV_LOSS_TMO; ++ if (no_path_retry_tmo > dev_loss_tmo) ++ dev_loss_tmo = no_path_retry_tmo; ++ condlog(3, "%s: update dev_loss_tmo to %d\n", ++ mpp->alias, dev_loss_tmo); ++ } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) { ++ dev_loss_tmo = MAX_DEV_LOSS_TMO; ++ condlog(4, "%s: update dev_loss_tmo to %d\n", ++ mpp->alias, dev_loss_tmo); ++ } ++ mpp->dev_loss = dev_loss_tmo; ++ if (mpp->fast_io_fail > mpp->dev_loss) { ++ mpp->fast_io_fail = mpp->dev_loss; ++ condlog(3, "%s: update fast_io_fail to %d\n", ++ mpp->alias, mpp->fast_io_fail); ++ } + if (!mpp->dev_loss && !mpp->fast_io_fail) + return 0; ++ + vector_foreach_slot(mpp->paths, pp, i) { + rport_id = find_rport_id(pp); + if (rport_id < 0) { +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -451,6 +451,11 @@ verify_paths(struct multipath * mpp, str + if (!mpp) + return 0; + ++ select_features(mpp); ++ select_no_path_retry(mpp); ++ select_dev_loss(mpp); ++ sysfs_set_scsi_tmo(mpp); ++ + vector_foreach_slot (mpp->paths, pp, i) { + /* + * see if path is in sysfs diff -Nru multipath-tools-0.4.9/debian/patches/0016-Reload-map-for-device-read-only-setting-changes.patch multipath-tools-0.4.9/debian/patches/0016-Reload-map-for-device-read-only-setting-changes.patch --- multipath-tools-0.4.9/debian/patches/0016-Reload-map-for-device-read-only-setting-changes.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0016-Reload-map-for-device-read-only-setting-changes.patch 2015-07-28 19:22:42.000000000 +0000 @@ -0,0 +1,271 @@ +From 61f530a849ab720f3bf02a20be5658d484091f17 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 4 Dec 2008 14:20:06 +0100 +Subject: [PATCH] Reload map for device read-only setting changes + +Whenever the read-only setting for a device changes we have +to reload the map. This patch implements the required cli command +and also a uevent handler if a uevent with 'DISK_RO=' setting +has been received. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/configure.c | 35 +++++++++++++++++++++++++++++++++++ + libmultipath/configure.h | 1 + + libmultipath/uevent.c | 20 ++++++++++++++++++++ + libmultipath/uevent.h | 1 + + multipathd/cli.c | 2 ++ + multipathd/cli.h | 2 ++ + multipathd/cli_handlers.c | 22 ++++++++++++++++++++++ + multipathd/cli_handlers.h | 1 + + multipathd/main.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 9 files changed, 126 insertions(+) + +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -685,3 +685,38 @@ out: + return NULL; + } + ++extern int reload_map(struct vectors *vecs, struct multipath *mpp) ++{ ++ char params[PARAMS_SIZE]; ++ int r; ++ ++ update_mpp_paths(mpp, vecs->pathvec); ++ ++ params[0] = '\0'; ++ if (setup_map(mpp, params, PARAMS_SIZE)) { ++ condlog(0, "%s: failed to setup map", mpp->alias); ++ return 1; ++ } ++ select_action(mpp, vecs->mpvec, 1); ++ ++ r = domap(mpp, params); ++ if (r == DOMAP_FAIL || r == DOMAP_RETRY) { ++ condlog(3, "%s: domap (%u) failure " ++ "for reload map", mpp->alias, r); ++ return 1; ++ } ++ if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) { ++ if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) ++ dm_queue_if_no_path(mpp->alias, 0); ++ else ++ dm_queue_if_no_path(mpp->alias, 1); ++ } ++ if (mpp->pg_timeout != PGTIMEOUT_UNDEF) { ++ if (mpp->pg_timeout == -PGTIMEOUT_NONE) ++ dm_set_pg_timeout(mpp->alias, 0); ++ else ++ dm_set_pg_timeout(mpp->alias, mpp->pg_timeout); ++ } ++ ++ return 0; ++} +Index: b/libmultipath/configure.h +=================================================================== +--- a/libmultipath/configure.h ++++ b/libmultipath/configure.h +@@ -28,4 +28,5 @@ int domap (struct multipath * mpp, char + int reinstate_paths (struct multipath *mpp); + int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload); + char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec); ++int reload_map(struct vectors *vecs, struct multipath *mpp); + +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -431,6 +431,26 @@ uevent_get_minor(struct uevent *uev) + return minor; + } + ++extern int ++uevent_get_disk_ro(struct uevent *uev) ++{ ++ char *p, *q; ++ int i, ro = -1; ++ ++ for (i = 0; uev->envp[i] != NULL; i++) { ++ if (!strncmp(uev->envp[i], "DISK_RO", 6) && strlen(uev->envp[i]) > 7) { ++ p = uev->envp[i] + 8; ++ ro = strtoul(p, &q, 10); ++ if (p == q) { ++ condlog(2, "invalid read_only setting '%s'", p); ++ ro = -1; ++ } ++ break; ++ } ++ } ++ return ro; ++} ++ + extern char * + uevent_get_dm_name(struct uevent *uev) + { +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -30,6 +30,7 @@ int uevent_dispatch(int (*store_uev)(str + void * trigger_data); + int uevent_get_major(struct uevent *uev); + int uevent_get_minor(struct uevent *uev); ++int uevent_get_disk_ro(struct uevent *uev); + char *uevent_get_dm_name(struct uevent *uev); + + #endif /* _UEVENT_H */ +Index: b/multipathd/cli.c +=================================================================== +--- a/multipathd/cli.c ++++ b/multipathd/cli.c +@@ -156,6 +156,7 @@ load_keys (void) + r += add_key(keys, "reinstate", REINSTATE, 0); + r += add_key(keys, "fail", FAIL, 0); + r += add_key(keys, "resize", RESIZE, 0); ++ r += add_key(keys, "reload", RELOAD, 0); + r += add_key(keys, "disablequeueing", DISABLEQ, 0); + r += add_key(keys, "restorequeueing", RESTOREQ, 0); + r += add_key(keys, "paths", PATHS, 0); +@@ -437,6 +438,7 @@ cli_init (void) { + add_handler(SUSPEND+MAP, NULL); + add_handler(RESUME+MAP, NULL); + add_handler(RESIZE+MAP, NULL); ++ add_handler(RELOAD+MAP, NULL); + add_handler(DISABLEQ+MAP, NULL); + add_handler(RESTOREQ+MAP, NULL); + add_handler(DISABLEQ+MAPS, NULL); +Index: b/multipathd/cli.h +=================================================================== +--- a/multipathd/cli.h ++++ b/multipathd/cli.h +@@ -8,6 +8,7 @@ enum { + __REINSTATE, + __FAIL, + __RESIZE, ++ __RELOAD, + __DISABLEQ, + __RESTOREQ, + __PATHS, +@@ -36,6 +37,7 @@ enum { + #define REINSTATE (1 << __REINSTATE) + #define FAIL (1 << __FAIL) + #define RESIZE (1 << __RESIZE) ++#define RELOAD (1 << __RELOAD) + #define DISABLEQ (1 << __DISABLEQ) + #define RESTOREQ (1 << __RESTOREQ) + #define PATHS (1 << __PATHS) +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -451,6 +451,28 @@ cli_del_map (void * v, char ** reply, in + return rc; + } + ++int ++cli_reload(void *v, char **reply, int *len, void *data) ++{ ++ struct vectors * vecs = (struct vectors *)data; ++ char * mapname = get_keyparam(v, MAP); ++ struct multipath *mpp; ++ int minor; ++ ++ condlog(2, "%s: reload map (operator)", mapname); ++ if (sscanf(mapname, "dm-%d", &minor) == 1) ++ mpp = find_mp_by_minor(vecs->mpvec, minor); ++ else ++ mpp = find_mp_by_alias(vecs->mpvec, mapname); ++ ++ if (!mpp) { ++ condlog(0, "%s: invalid map name. cannot reload", mapname); ++ return 1; ++ } ++ ++ return reload_map(vecs, mpp); ++} ++ + int resize_map(struct multipath *mpp, unsigned long long size, + struct vectors * vecs) + { +Index: b/multipathd/cli_handlers.h +=================================================================== +--- a/multipathd/cli_handlers.h ++++ b/multipathd/cli_handlers.h +@@ -18,6 +18,7 @@ int cli_del_map (void * v, char ** reply + int cli_switch_group(void * v, char ** reply, int * len, void * data); + int cli_reconfigure(void * v, char ** reply, int * len, void * data); + int cli_resize(void * v, char ** reply, int * len, void * data); ++int cli_reload(void * v, char ** reply, int * len, void * data); + int cli_disable_queueing(void * v, char ** reply, int * len, void * data); + int cli_disable_all_queueing(void * v, char ** reply, int * len, void * data); + int cli_restore_queueing(void * v, char ** reply, int * len, void * data); +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -635,6 +635,43 @@ fail: + } + + static int ++uev_update_path (struct uevent *uev, struct vectors * vecs) ++{ ++ struct sysfs_device * dev; ++ int retval, ro; ++ ++ dev = sysfs_device_get(uev->devpath); ++ if (!dev) { ++ condlog(2, "%s: not found in sysfs", uev->devpath); ++ return 1; ++ } ++ ro = uevent_get_disk_ro(uev); ++ ++ if (ro >= 0) { ++ struct path * pp; ++ ++ condlog(2, "%s: update path write_protect to '%d' (uevent)", ++ uev->kernel, ro); ++ pp = find_path_by_dev(vecs->pathvec, uev->kernel); ++ if (!pp) { ++ condlog(0, "%s: spurious uevent, path not found", ++ uev->kernel); ++ return 1; ++ } ++ if (pp->mpp) ++ retval = reload_map(vecs, pp->mpp); ++ ++ condlog(2, "%s: map %s reloaded (retval %d)", ++ uev->kernel, pp->mpp->alias, retval); ++ ++ } ++ ++ sysfs_device_put(dev); ++ ++ return retval; ++} ++ ++static int + map_discovery (struct vectors * vecs) + { + struct multipath * mpp; +@@ -752,6 +789,10 @@ uev_trigger (struct uevent * uev, void * + r = uev_remove_path(uev, vecs); + goto out; + } ++ if (!strncmp(uev->action, "change", 6)) { ++ r = uev_update_path(uev, vecs); ++ goto out; ++ } + + out: + unlock(vecs->lock); +@@ -813,6 +854,7 @@ uxlsnrloop (void * ap) + set_handler_callback(SUSPEND+MAP, cli_suspend); + set_handler_callback(RESUME+MAP, cli_resume); + set_handler_callback(RESIZE+MAP, cli_resize); ++ set_handler_callback(RELOAD+MAP, cli_reload); + set_handler_callback(REINSTATE+PATH, cli_reinstate); + set_handler_callback(FAIL+PATH, cli_fail); + set_handler_callback(DISABLEQ+MAP, cli_disable_queueing); diff -Nru multipath-tools-0.4.9/debian/patches/0017-multipath-get-right-sysfs-value-for-checker_timeout.patch multipath-tools-0.4.9/debian/patches/0017-multipath-get-right-sysfs-value-for-checker_timeout.patch --- multipath-tools-0.4.9/debian/patches/0017-multipath-get-right-sysfs-value-for-checker_timeout.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0017-multipath-get-right-sysfs-value-for-checker_timeout.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,27 @@ +From ce1c220981bb42ab4a4e8a53251867188ef8861e Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 4 Oct 2011 23:15:05 -0500 +Subject: [PATCH] multipath: get right sysfs value for checker_timeout + +sysfs_get_timeout() wasn't looking in the correct directory for the +checker timeout value. It was looking at .../block//timeout, +instead of .../block//device/timeout + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -166,7 +166,7 @@ sysfs_get_timeout(struct sysfs_device *d + if (safe_sprintf(attr_path, "%s/device", dev->devpath)) + return 1; + +- len = sysfs_attr_get_value(dev->devpath, "timeout", attr, NAME_SIZE); ++ len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE); + if (!len) { + condlog(3, "%s: No timeout value in sysfs", dev->devpath); + return 1; diff -Nru multipath-tools-0.4.9/debian/patches/0018-multipath-handle-offlined-paths.patch multipath-tools-0.4.9/debian/patches/0018-multipath-handle-offlined-paths.patch --- multipath-tools-0.4.9/debian/patches/0018-multipath-handle-offlined-paths.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0018-multipath-handle-offlined-paths.patch 2015-07-28 19:22:43.000000000 +0000 @@ -0,0 +1,103 @@ +From 3641d566526370f9f9a76948c4ad45286220e84a Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 17 Oct 2011 16:16:02 -0500 +Subject: [PATCH] multipath: handle offlined paths + +The kernel does not allow multipath to load tables containing offline +devices. Because of this, if you try add a path to a multipath device with +an offline path, the multipathd will continually, retry and fail to reload +the table. I've limited the retries to three to avoid livelocking. + +Also, if you map included a offline path, multipath was crashing because +it couldn't get the required sysfs information before calling get_state(). +It now checks for this in multipath, like it does in multipathd + +Lastly, multipathd would keep reprinting the last checker message for +offlined paths, instead of something useful. It now prints a "path offline" +message. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 9 +++++++-- + multipathd/main.c | 22 +++++++++++++++++----- + 2 files changed, 24 insertions(+), 7 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -794,8 +794,13 @@ get_state (struct path * pp, int daemon) + condlog(3, "%s: get_state", pp->dev); + + if (!checker_selected(c)) { +- if (daemon) +- pathinfo(pp, conf->hwtable, DI_SYSFS); ++ if (daemon || pp->sysdev == NULL) { ++ if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) { ++ condlog(3, "%s: couldn't get sysfs pathinfo", ++ pp->dev); ++ return PATH_UNCHECKED; ++ } ++ } + select_checker(pp); + if (!checker_selected(c)) { + condlog(3, "%s: No checker selected", pp->dev); +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -60,8 +60,13 @@ + #define FILE_NAME_SIZE 256 + #define CMDSIZE 160 + +-#define LOG_MSG(a,b) \ +- if (strlen(b)) condlog(a, "%s: %s - %s", pp->mpp->alias, pp->dev, b); ++#define LOG_MSG(a, b) \ ++do { \ ++ if (pp->offline) \ ++ condlog(a, "%s: %s - path offline", pp->mpp->alias, pp->dev); \ ++ else if (strlen(b)) \ ++ condlog(a, "%s: %s - %s", pp->mpp->alias, pp->dev, b); \ ++} while(0) + + pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER; +@@ -374,6 +379,7 @@ ev_add_path (char * devname, struct vect + struct path * pp; + char empty_buff[WWID_SIZE] = {0}; + char params[PARAMS_SIZE] = {0}; ++ int retries = 3; + + if (strstr(devname, "..") != NULL) { + /* +@@ -480,12 +486,14 @@ rescan: + /* + * deal with asynchronous uevents :(( + */ +- if (mpp->action == ACT_RELOAD) { ++ if (mpp->action == ACT_RELOAD && retries-- > 0) { + condlog(0, "%s: uev_add_path sleep", mpp->alias); + sleep(1); + update_mpp_paths(mpp, vecs->pathvec); + goto rescan; + } ++ else if (mpp->action == ACT_RELOAD) ++ condlog(0, "%s: giving up reload", mpp->alias); + else + goto out; + } +@@ -503,8 +511,12 @@ rescan: + start_waiter_thread(mpp, vecs)) + goto out; + +- condlog(2, "%s path added to devmap %s", devname, mpp->alias); +- return 0; ++ if (retries >= 0) { ++ condlog(2, "%s path added to devmap %s", devname, mpp->alias); ++ return 0; ++ } ++ else ++ return 1; + + out: + remove_map(mpp, vecs, 1); diff -Nru multipath-tools-0.4.9/debian/patches/0019-multipath-fix-scsi-timeout-code.patch multipath-tools-0.4.9/debian/patches/0019-multipath-fix-scsi-timeout-code.patch --- multipath-tools-0.4.9/debian/patches/0019-multipath-fix-scsi-timeout-code.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0019-multipath-fix-scsi-timeout-code.patch 2015-07-28 19:22:39.000000000 +0000 @@ -0,0 +1,458 @@ +From bb817e4b8c2eef12fb831a17cf935db8a1677d06 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 19 Dec 2011 16:19:56 -0600 +Subject: [PATCH] multipath: fix scsi timeout code + +sysfs_attr_set_value() returns the amount written on on success, or -1 on +failure. sysfs_setc_scsi_tmo() was checking if the return was nonzero, and +failing if it was. This meant that it always failed out silently after writing +the first value. I've changed the check, and added some error messages. I also +made sysfs_attr_set_value return -1 for all errors. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 4 + libmultipath/sysfs.c | 375 +++++------------------------------------------ + 2 files changed, 49 insertions(+), 330 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -316,7 +316,7 @@ sysfs_set_scsi_tmo (struct multipath *mp + if (mpp->dev_loss){ + snprintf(value, 11, "%u", mpp->dev_loss); + if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", +- value, 11)) { ++ value, 11) < 0) { + condlog(0, "%s failed to set %s/dev_loss_tmo", + mpp->alias, attr_path); + return 1; +@@ -328,7 +328,7 @@ sysfs_set_scsi_tmo (struct multipath *mp + else + snprintf(value, 11, "%u", mpp->fast_io_fail); + if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo", +- value, 11)) { ++ value, 11) < 0) { + condlog(0, + "%s failed to set %s/fast_io_fail_tmo", + mpp->alias, attr_path); +Index: b/libmultipath/sysfs.c +=================================================================== +--- a/libmultipath/sysfs.c ++++ b/libmultipath/sysfs.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -35,360 +36,78 @@ + #include "util.h" + #include "debug.h" + +-char sysfs_path[PATH_SIZE]; +- +-/* list of sysfs devices */ +-static LIST_HEAD(sysfs_dev_list); +-struct sysfs_dev { +- struct list_head node; +- struct sysfs_device dev; +-}; +- +-int sysfs_init(char *path, size_t len) +-{ +- if (path) { +- strlcpy(sysfs_path, path, len); +- remove_trailing_chars(sysfs_path, '/'); +- } else +- strlcpy(sysfs_path, "/sys", sizeof(sysfs_path)); +- dbg("sysfs_path='%s'", sysfs_path); +- +- INIT_LIST_HEAD(&sysfs_dev_list); +- return 0; +-} +- +-void sysfs_cleanup(void) +-{ +- struct sysfs_dev *sysdev_loop; +- struct sysfs_dev *sysdev_temp; +- +- list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) { +- list_del(&sysdev_loop->node); +- free(sysdev_loop); +- } +-} +- +-void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath) +-{ +- char *pos; +- +- strlcpy(dev->devpath, devpath, sizeof(dev->devpath)); +- +- /* set kernel name */ +- pos = strrchr(dev->devpath, '/'); +- if (pos == NULL) +- return; +- strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); +- dbg("kernel='%s'", dev->kernel); +- +- /* some devices have '!' in their name, change that to '/' */ +- pos = dev->kernel; +- while (pos[0] != '\0') { +- if (pos[0] == '!') +- pos[0] = '/'; +- pos++; +- } +-} +- +-int sysfs_resolve_link(char *devpath, size_t size) +-{ +- char link_path[PATH_SIZE]; +- char link_target[PATH_SIZE]; +- int len; +- int i; +- int back; +- +- strlcpy(link_path, sysfs_path, sizeof(link_path)); +- strlcat(link_path, devpath, sizeof(link_path)); +- len = readlink(link_path, link_target, sizeof(link_target)); +- if (len <= 0) +- return -1; +- link_target[len] = '\0'; +- dbg("path link '%s' points to '%s'", devpath, link_target); +- +- for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) +- ; +- dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back); +- for (i = 0; i <= back; i++) { +- char *pos = strrchr(devpath, '/'); +- +- if (pos == NULL) +- return -1; +- pos[0] = '\0'; +- } +- dbg("after moving back '%s'", devpath); +- strlcat(devpath, "/", size); +- strlcat(devpath, &link_target[back * 3], size); +- return 0; +-} +- +-/* +- * Caution: this routine is called extremely often. +- * Should be as efficient as possible. +- */ +-struct sysfs_device *sysfs_device_get(const char *devpath) +-{ +- char path[PATH_SIZE]; +- char devpath_real[PATH_SIZE]; +- struct sysfs_device *dev = NULL; +- struct sysfs_dev *sysdev_loop, *sysdev; +- struct stat statbuf; +- +- dbg("open '%s'", devpath); +- strlcpy(devpath_real, devpath, sizeof(devpath_real)); +- remove_trailing_chars(devpath_real, '/'); +- if (devpath[0] == '\0' ) +- return NULL; +- +- /* if we got a link, resolve it to the real device */ +- strlcpy(path, sysfs_path, sizeof(path)); +- strlcat(path, devpath_real, sizeof(path)); +- if (lstat(path, &statbuf) != 0) { +- /* if stat fails look in the cache */ +- dbg("stat '%s' failed: %s", path, strerror(errno)); +- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { +- if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { +- dbg("found vanished dev in cache '%s'", +- sysdev_loop->dev.devpath); +- return &sysdev_loop->dev; +- } +- } +- return NULL; +- } +- +- if (S_ISLNK(statbuf.st_mode)) { +- if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0) +- return NULL; +- } +- +- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { +- if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { +- dbg("found dev in cache '%s'", sysdev_loop->dev.devpath); +- dev = &sysdev_loop->dev; +- } +- } +- +- if(!dev) { +- /* it is a new device */ +- dbg("new device '%s'", devpath_real); +- sysdev = malloc(sizeof(struct sysfs_dev)); +- if (sysdev == NULL) +- return NULL; +- memset(sysdev, 0x00, sizeof(struct sysfs_dev)); +- list_add(&sysdev->node, &sysfs_dev_list); +- dev = &sysdev->dev; +- } +- +- sysfs_device_set_values(dev, devpath_real); +- +- return dev; +-} +- +-struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) +-{ +- char parent_devpath[PATH_SIZE]; +- char *pos; +- +- dbg("open '%s'", dev->devpath); +- +- /* look if we already know the parent */ +- if (dev->parent != NULL) +- return dev->parent; +- +- strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); +- dbg("'%s'", parent_devpath); +- +- /* strip last element */ +- pos = strrchr(parent_devpath, '/'); +- if (pos == NULL || pos == parent_devpath) +- return NULL; +- pos[0] = '\0'; +- +- if (strncmp(parent_devpath, "/class", 6) == 0) { +- pos = strrchr(parent_devpath, '/'); +- if (pos == &parent_devpath[6] || pos == parent_devpath) { +- dbg("/class top level, look for device link"); +- goto device_link; +- } +- } +- if (strcmp(parent_devpath, "/block") == 0) { +- dbg("/block top level, look for device link"); +- goto device_link; +- } +- +- /* are we at the top level? */ +- pos = strrchr(parent_devpath, '/'); +- if (pos == NULL || pos == parent_devpath) +- return NULL; +- +- /* get parent and remember it */ +- dev->parent = sysfs_device_get(parent_devpath); +- return dev->parent; +- +-device_link: +- strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); +- strlcat(parent_devpath, "/device", sizeof(parent_devpath)); +- if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0) +- return NULL; +- +- /* get parent and remember it */ +- dev->parent = sysfs_device_get(parent_devpath); +- return dev->parent; +-} +- +-struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev) ++ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, ++ char * value, size_t value_len) + { +- char path[PATH_SIZE]; +- struct stat statbuf; +- +- strlcpy(path, sysfs_path, sizeof(path)); +- strlcat(path, dev->devpath, sizeof(path)); +- if (stat(dev->devpath, &statbuf) == 0 && +- S_ISDIR(statbuf.st_mode)) +- return dev; +- +- return NULL; +-} +- +-void sysfs_device_put(struct sysfs_device *dev) +-{ +- struct sysfs_dev *sysdev_loop; +- +- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { +- if (&sysdev_loop->dev == dev) { +- dbg("removed dev '%s' from cache", +- sysdev_loop->dev.devpath); +- list_del(&sysdev_loop->node); +- free(sysdev_loop); +- return; +- } +- } +- dbg("dev '%s' not found in cache", +- sysdev_loop->dev.devpath); +- +- return; +-} +- +-size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, +- char *attr_value, int attr_len) +-{ +- char path_full[PATH_SIZE]; ++ const char *devpath; + const char *path; + struct stat statbuf; + int fd; +- ssize_t size; +- size_t sysfs_len; ++ ssize_t size = -1; + +- if (!attr_value || !attr_len) ++ if (!dev || !attr_name || !value) + return 0; + +- attr_value[0] = '\0'; +- size = 0; +- +- dbg("open '%s'/'%s'", devpath, attr_name); +- sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); +- if(sysfs_len >= sizeof(path_full)) +- sysfs_len = sizeof(path_full) - 1; +- path = &path_full[sysfs_len]; +- strlcat(path_full, devpath, sizeof(path_full)); +- strlcat(path_full, "/", sizeof(path_full)); +- strlcat(path_full, attr_name, sizeof(path_full)); +- +- if (stat(path_full, &statbuf) != 0) { +- dbg("stat '%s' failed: %s", path_full, strerror(errno)); +- goto out; +- } ++ devpath = udev_device_get_syspath(dev); ++ condlog(4, "open '%s'/'%s'", devpath, attr_name); ++ if (stat(devpath, &statbuf) != 0) { ++ condlog(4, "stat '%s' failed: %s", devpath, strerror(errno)); ++ return 0; ++ } + + /* skip directories */ + if (S_ISDIR(statbuf.st_mode)) +- goto out; ++ return 0; + +- /* skip non-readable files */ +- if ((statbuf.st_mode & S_IRUSR) == 0) +- goto out; ++ /* skip non-writeable files */ ++ if ((statbuf.st_mode & S_IWUSR) == 0) ++ return 0; + +- /* read attribute value */ +- fd = open(path_full, O_RDONLY); ++ /* write attribute value */ ++ fd = open(devpath, O_WRONLY); + if (fd < 0) { +- dbg("attribute '%s' can not be opened: %s", +- path_full, strerror(errno)); +- goto out; +- } +- size = read(fd, attr_value, attr_len); +- close(fd); +- if (size < 0) +- goto out; +- if (size == attr_len) { +- dbg("overflow in attribute '%s', truncating", path_full); +- size--; ++ condlog(4, "attribute '%s' can not be opened: %s", ++ devpath, strerror(errno)); ++ return 0; + } ++ size = write(fd, value, value_len); ++ if (size < 0) { ++ condlog(4, "write to %s failed: %s", devpath, strerror(errno)); ++ size = 0; ++ } else if (size < value_len) { ++ condlog(4, "tried to write %ld to %s. Wrote %ld\n", ++ (long)value_len, devpath, (long)size); ++ size = 0; ++ } + +- /* got a valid value, store and return it */ +- attr_value[size] = '\0'; +- remove_trailing_chars(attr_value, '\n'); +- +-out: ++ close(fd); + return size; + } + +-ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, +- const char *value, int value_len) ++int ++sysfs_get_size (struct path *pp, unsigned long long * size) + { +- char path_full[PATH_SIZE]; +- struct stat statbuf; +- int fd; +- ssize_t size = 0; +- size_t sysfs_len; ++ const char * attr; ++ int r; + +- if (!attr_name || !value || !value_len) +- return 0; +- +- dbg("open '%s'/'%s'", devpath, attr_name); +- sysfs_len = snprintf(path_full, PATH_SIZE, "%s%s/%s", sysfs_path, +- devpath, attr_name); +- if (sysfs_len >= PATH_SIZE || sysfs_len < 0) { +- if (sysfs_len < 0) +- dbg("cannot copy sysfs path %s%s/%s : %s", sysfs_path, +- devpath, attr_name, strerror(errno)); +- else +- dbg("sysfs_path %s%s/%s too large", sysfs_path, +- devpath, attr_name); +- goto out; +- } ++ if (!pp->udev) ++ return 1; + +- if (stat(path_full, &statbuf) != 0) { +- dbg("stat '%s' failed: %s", path_full, strerror(errno)); +- goto out; ++ attr = udev_device_get_sysattr_value(pp->udev, "size"); ++ if (!attr) { ++ condlog(3, "%s: No size attribute in sysfs", pp->dev); ++ return 1; + } + +- /* skip directories */ +- if (S_ISDIR(statbuf.st_mode)) +- goto out; +- +- /* skip non-writeable files */ +- if ((statbuf.st_mode & S_IWUSR) == 0) +- goto out; ++ r = sscanf(attr, "%llu\n", size); + +- /* write attribute value */ +- fd = open(path_full, O_WRONLY); +- if (fd < 0) { +- dbg("attribute '%s' can not be opened: %s", +- path_full, strerror(errno)); +- goto out; ++ if (r != 1) { ++ condlog(3, "%s: Cannot parse size attribute '%s'", ++ pp->dev, attr); ++ return 1; + } +- size = write(fd, value, value_len); +- if (size < 0) +- dbg("write to %s failed: %s", path_full, strerror(errno)); +- else if (size < value_len) { +- dbg("tried to write %d to %s. Wrote %d\n", value_len, +- path_full, size); +- size = -1; +- } +- +- close(fd); +-out: + +- return size; ++ return 0; + } + + int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, diff -Nru multipath-tools-0.4.9/debian/patches/0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch multipath-tools-0.4.9/debian/patches/0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch --- multipath-tools-0.4.9/debian/patches/0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,77 @@ +From d49d4d7c0666c0a0bcac2c72c8402d1c1e9c3c8c Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 12 Jan 2012 22:14:56 -0600 +Subject: [PATCH] multipath: make tgt_node_name work for iscsi devices + +tgt_node_name wasn't displaying anything for iscsi devices. With this +change, if multipath can't get the node_name, it will check +sys/devices/platform/hostX/sessionY/iscsi_session/sessionY/targetname +and if this is available, it will get the node name from there. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 20 ++++++++++++++++++-- + libmultipath/structs.h | 2 +- + 2 files changed, 19 insertions(+), 3 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -210,10 +210,11 @@ sysfs_get_size (struct sysfs_device * de + } + + int +-sysfs_get_fc_nodename (struct sysfs_device * dev, char * node, ++sysfs_get_tgt_nodename (struct sysfs_device * dev, char * node, + unsigned int host, unsigned int channel, + unsigned int target) + { ++ unsigned int checkhost, session; + char attr_path[SYSFS_PATH_SIZE]; + size_t len; + +@@ -225,6 +226,21 @@ sysfs_get_fc_nodename (struct sysfs_devi + } + + len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE); ++ if (len) ++ return 0; ++ ++ if (sscanf(dev->devpath, "/devices/platform/host%u/session%u/", ++ &checkhost, &session) != 2) ++ return 1; ++ if (checkhost != host) ++ return 1; ++ if (safe_sprintf(attr_path, "/devices/platform/host%u/session%u/iscsi_session/session%u", host, session, session)) { ++ condlog(0, "attr_path too small"); ++ return 1; ++ } ++ ++ len = sysfs_attr_get_value(attr_path, "targetname", node, ++ NODE_NAME_SIZE); + if (!len) + return 1; + +@@ -544,7 +560,7 @@ scsi_sysfs_pathinfo (struct path * pp, s + /* + * target node name + */ +- if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name, ++ if(!sysfs_get_tgt_nodename(parent, pp->tgt_node_name, + pp->sg_id.host_no, + pp->sg_id.channel, + pp->sg_id.scsi_id)) { +Index: b/libmultipath/structs.h +=================================================================== +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -5,7 +5,7 @@ + + #define WWID_SIZE 128 + #define SERIAL_SIZE 65 +-#define NODE_NAME_SIZE 65 ++#define NODE_NAME_SIZE 224 + #define PATH_STR_SIZE 16 + #define PARAMS_SIZE 1024 + #define FILE_NAME_SIZE 256 diff -Nru multipath-tools-0.4.9/debian/patches/0021-multipath-cleanup-dev_loss_tmo-issues.patch multipath-tools-0.4.9/debian/patches/0021-multipath-cleanup-dev_loss_tmo-issues.patch --- multipath-tools-0.4.9/debian/patches/0021-multipath-cleanup-dev_loss_tmo-issues.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0021-multipath-cleanup-dev_loss_tmo-issues.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,86 @@ +From a8b432d1d32b2a59a67aa848d54c374bb3487f6f Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 10 Feb 2012 12:11:37 -0600 +Subject: [PATCH] multipath: cleanup dev_loss_tmo issues + +There are a couple of issues with the dev_loss_tmo code. First, the +comparison between fast_io_fail and dev_loss was failing for +fast_io_fail = -1. Second, if fast_io_fail_tmo was set to off, and +dev_loss was greater than 600, dev_loss_tmo would not be set. Finally, +verify_paths was calling sysfs_set_scsi_tmo without ever calling +select_fast_io_fail. However, this hasn't be causing problems since +setup_map is always called immediately after verify_paths, and it calls +all the select_ functions correctly. This patch fixes all these. Now, +if setting dev_loss_tmo fails, and fast_io_fail is set to off, it will +retry will dev_loss_tmo set to 600. Also, the calls that are duplicated +between verify_paths and setup_map have been removed. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 22 +++++++++++++++------- + libmultipath/structs_vec.c | 5 ----- + 2 files changed, 15 insertions(+), 12 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -299,17 +299,17 @@ sysfs_set_scsi_tmo (struct multipath *mp + no_path_retry_tmo = MAX_DEV_LOSS_TMO; + if (no_path_retry_tmo > dev_loss_tmo) + dev_loss_tmo = no_path_retry_tmo; +- condlog(3, "%s: update dev_loss_tmo to %d\n", ++ condlog(3, "%s: update dev_loss_tmo to %d", + mpp->alias, dev_loss_tmo); + } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) { + dev_loss_tmo = MAX_DEV_LOSS_TMO; +- condlog(4, "%s: update dev_loss_tmo to %d\n", ++ condlog(3, "%s: update dev_loss_tmo to %d", + mpp->alias, dev_loss_tmo); + } + mpp->dev_loss = dev_loss_tmo; +- if (mpp->fast_io_fail > mpp->dev_loss) { ++ if (mpp->fast_io_fail > (int)mpp->dev_loss) { + mpp->fast_io_fail = mpp->dev_loss; +- condlog(3, "%s: update fast_io_fail to %d\n", ++ condlog(3, "%s: update fast_io_fail to %d", + mpp->alias, mpp->fast_io_fail); + } + if (!mpp->dev_loss && !mpp->fast_io_fail) +@@ -333,9 +333,17 @@ sysfs_set_scsi_tmo (struct multipath *mp + snprintf(value, 11, "%u", mpp->dev_loss); + if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", + value, 11) < 0) { +- condlog(0, "%s failed to set %s/dev_loss_tmo", +- mpp->alias, attr_path); +- return 1; ++ int err = 1; ++ if (mpp->fast_io_fail <= 0 && mpp->dev_loss > 600) { ++ strncpy(value, "600", 4); ++ condlog(3, "%s: limiting dev_loss_tmo to 600, since fast_io_fail is not set", mpp->alias); ++ if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", value, 11) >= 0) ++ err = 0; ++ } ++ if (err) { ++ condlog(0, "%s failed to set %s/dev_loss_tmo", mpp->alias, attr_path); ++ return 1; ++ } + } + } + if (mpp->fast_io_fail){ +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -451,11 +451,6 @@ verify_paths(struct multipath * mpp, str + if (!mpp) + return 0; + +- select_features(mpp); +- select_no_path_retry(mpp); +- select_dev_loss(mpp); +- sysfs_set_scsi_tmo(mpp); +- + vector_foreach_slot (mpp->paths, pp, i) { + /* + * see if path is in sysfs diff -Nru multipath-tools-0.4.9/debian/patches/0022-Fix-for-setting-0-to-fast_io_fail.patch multipath-tools-0.4.9/debian/patches/0022-Fix-for-setting-0-to-fast_io_fail.patch --- multipath-tools-0.4.9/debian/patches/0022-Fix-for-setting-0-to-fast_io_fail.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0022-Fix-for-setting-0-to-fast_io_fail.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,154 @@ +From f49221abb9f97bd14f1cdee6206cbd068249396a Mon Sep 17 00:00:00 2001 +From: Jun'ichi Nomura +Date: Mon, 12 Mar 2012 20:43:55 +0900 +Subject: [PATCH] Fix for setting '0' to fast_io_fail + +Hi Christophe, + +In kernel, '0' is valid value for fast_io_fail, meaning immediate +termination of ios on rport delete. +However, '0' is treated as 'not-configured' in various places of +multipath-tools and it is not possible to set 0 to fast_io_fail. + +Attached patch fixes that by introducing MP_FAST_IO_FAIL_ZERO +as internal representation of zero value. + +-- +Jun'ichi Nomura, NEC Corporation +--- + libmultipath/config.h | 7 +++++++ + libmultipath/dict.c | 20 ++++++++++++++------ + libmultipath/discovery.c | 6 ++++-- + libmultipath/propsel.c | 10 ++++++---- + 4 files changed, 31 insertions(+), 12 deletions(-) + +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -7,6 +7,13 @@ + #define ORIGIN_DEFAULT 0 + #define ORIGIN_CONFIG 1 + ++/* ++ * In kernel, fast_io_fail == 0 means immediate failure on rport delete. ++ * OTOH '0' means not-configured in various places in multipath-tools. ++ */ ++#define MP_FAST_IO_FAIL_OFF (-1) ++#define MP_FAST_IO_FAIL_ZERO (-2) ++ + enum devtypes { + DEV_NONE, + DEV_DEVT, +Index: b/libmultipath/dict.c +=================================================================== +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -43,10 +43,12 @@ def_fast_io_fail_handler(vector strvec) + + buff = set_value(strvec); + if (strlen(buff) == 3 && !strcmp(buff, "off")) +- conf->fast_io_fail = -1; ++ conf->fast_io_fail = MP_FAST_IO_FAIL_OFF; + else if (sscanf(buff, "%d", &conf->fast_io_fail) != 1 || +- conf->fast_io_fail < -1) ++ conf->fast_io_fail < MP_FAST_IO_FAIL_ZERO) + conf->fast_io_fail = 0; ++ else if (conf->fast_io_fail == 0) ++ conf->fast_io_fail = MP_FAST_IO_FAIL_ZERO; + + FREE(buff); + return 0; +@@ -716,10 +718,12 @@ hw_fast_io_fail_handler(vector strvec) + + buff = set_value(strvec); + if (strlen(buff) == 3 && !strcmp(buff, "off")) +- hwe->fast_io_fail = -1; ++ hwe->fast_io_fail = MP_FAST_IO_FAIL_OFF; + else if (sscanf(buff, "%d", &hwe->fast_io_fail) != 1 || +- hwe->fast_io_fail < -1) ++ hwe->fast_io_fail < MP_FAST_IO_FAIL_ZERO) + hwe->fast_io_fail = 0; ++ else if (hwe->fast_io_fail == 0) ++ hwe->fast_io_fail = MP_FAST_IO_FAIL_ZERO; + + FREE(buff); + return 0; +@@ -1523,8 +1527,10 @@ snprint_hw_fast_io_fail(char * buff, int + struct hwentry * hwe = (struct hwentry *)data; + if (!hwe->fast_io_fail) + return 0; +- if (hwe->fast_io_fail == -1) ++ if (hwe->fast_io_fail == MP_FAST_IO_FAIL_OFF) + return snprintf(buff, len, "off"); ++ if (hwe->fast_io_fail == MP_FAST_IO_FAIL_ZERO) ++ return snprintf(buff, len, "0"); + return snprintf(buff, len, "%d", hwe->fast_io_fail); + } + +@@ -1810,8 +1816,10 @@ snprint_def_fast_io_fail(char * buff, in + { + if (!conf->fast_io_fail) + return 0; +- if (conf->fast_io_fail == -1) ++ if (conf->fast_io_fail == MP_FAST_IO_FAIL_OFF) + return snprintf(buff, len, "off"); ++ if (conf->fast_io_fail == MP_FAST_IO_FAIL_ZERO) ++ return snprintf(buff, len, "0"); + return snprintf(buff, len, "%d", conf->fast_io_fail); + } + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -334,7 +334,7 @@ sysfs_set_scsi_tmo (struct multipath *mp + if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", + value, 11) < 0) { + int err = 1; +- if (mpp->fast_io_fail <= 0 && mpp->dev_loss > 600) { ++ if ((!mpp->fast_io_fail || mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) && mpp->dev_loss > 600) { + strncpy(value, "600", 4); + condlog(3, "%s: limiting dev_loss_tmo to 600, since fast_io_fail is not set", mpp->alias); + if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", value, 11) >= 0) +@@ -347,8 +347,10 @@ sysfs_set_scsi_tmo (struct multipath *mp + } + } + if (mpp->fast_io_fail){ +- if (mpp->fast_io_fail == -1) ++ if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) + sprintf(value, "off"); ++ else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) ++ sprintf(value, "0"); + else + snprintf(value, 11, "%u", mpp->fast_io_fail); + if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo", +Index: b/libmultipath/propsel.c +=================================================================== +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -474,18 +474,20 @@ select_fast_io_fail(struct multipath *mp + { + if (mp->hwe && mp->hwe->fast_io_fail) { + mp->fast_io_fail = mp->hwe->fast_io_fail; +- if (mp->fast_io_fail == -1) ++ if (mp->fast_io_fail == MP_FAST_IO_FAIL_OFF) + condlog(3, "%s: fast_io_fail_tmo = off (controller default)", mp->alias); + else +- condlog(3, "%s: fast_io_fail_tmo = %d (controller default)", mp->alias, mp->fast_io_fail); ++ condlog(3, "%s: fast_io_fail_tmo = %d (controller default)", mp->alias, ++ mp->fast_io_fail == MP_FAST_IO_FAIL_ZERO ? 0 : mp->fast_io_fail); + return 0; + } + if (conf->fast_io_fail) { + mp->fast_io_fail = conf->fast_io_fail; +- if (mp->fast_io_fail == -1) ++ if (mp->fast_io_fail == MP_FAST_IO_FAIL_OFF) + condlog(3, "%s: fast_io_fail_tmo = off (config file default)", mp->alias); + else +- condlog(3, "%s: fast_io_fail_tmo = %d (config file default)", mp->alias, mp->fast_io_fail); ++ condlog(3, "%s: fast_io_fail_tmo = %d (config file default)", mp->alias, ++ mp->fast_io_fail == MP_FAST_IO_FAIL_ZERO ? 0 : mp->fast_io_fail); + return 0; + } + mp->fast_io_fail = 0; diff -Nru multipath-tools-0.4.9/debian/patches/0023-Fix-fast_io_fail-capping.patch multipath-tools-0.4.9/debian/patches/0023-Fix-fast_io_fail-capping.patch --- multipath-tools-0.4.9/debian/patches/0023-Fix-fast_io_fail-capping.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0023-Fix-fast_io_fail-capping.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,40 @@ +From c75d521c3642c16ad32532205560e10b0b0cb8df Mon Sep 17 00:00:00 2001 +From: Jun'ichi Nomura +Date: Mon, 12 Mar 2012 20:56:52 +0900 +Subject: [PATCH] Fix fast_io_fail capping + +Hi Christophe, + +fast_io_fail is only meaningful if it is smaller than dev_loss_tmo. +Setting dev_loss_tmo value to fast_io_fail ends up with -EINVAL. +If the fast_io_fail is not configured properly, turning it off +seems to be the right behavior. + +MP_FAST_IO_FAIL_OFF is -1, defined in the following patch: + [PATCH] Fix for setting '0' to fast_io_fail + http://www.redhat.com/archives/dm-devel/2012-March/msg00047.html + +-- +Jun'ichi Nomura, NEC Corporation +--- + libmultipath/discovery.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -307,10 +307,10 @@ sysfs_set_scsi_tmo (struct multipath *mp + mpp->alias, dev_loss_tmo); + } + mpp->dev_loss = dev_loss_tmo; +- if (mpp->fast_io_fail > (int)mpp->dev_loss) { +- mpp->fast_io_fail = mpp->dev_loss; +- condlog(3, "%s: update fast_io_fail to %d", ++ if (mpp->dev_loss && mpp->fast_io_fail >= (int)mpp->dev_loss) { ++ condlog(3, "%s: turning off fast_io_fail (%d is not smaller than dev_loss_tmo)", + mpp->alias, mpp->fast_io_fail); ++ mpp->fast_io_fail = MP_FAST_IO_FAIL_OFF; + } + if (!mpp->dev_loss && !mpp->fast_io_fail) + return 0; diff -Nru multipath-tools-0.4.9/debian/patches/0024-multipath-enable-getting-uevents-through-libudev.patch multipath-tools-0.4.9/debian/patches/0024-multipath-enable-getting-uevents-through-libudev.patch --- multipath-tools-0.4.9/debian/patches/0024-multipath-enable-getting-uevents-through-libudev.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0024-multipath-enable-getting-uevents-through-libudev.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,221 @@ +From 970c9f4d4b25329dd524f19ad14c65cac1c711c5 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 9 Apr 2012 23:01:54 -0500 +Subject: [PATCH] multipath: enable getting uevents through libudev + +udev is removing support for RUN+="socket:..." rules. For now, I've kept +all the existing uevent code, but I've added a new method for getting the +uevent information using libudev that will be tried first. + +This version includes more error checking. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 2 + libmultipath/uevent.c | 155 ++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 138 insertions(+), 19 deletions(-) + +Index: b/libmultipath/Makefile +=================================================================== +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -7,7 +7,7 @@ include ../Makefile.inc + SONAME=0 + DEVLIB = libmultipath.so + LIBS = $(DEVLIB).$(SONAME) +-LIBDEPS = -lpthread -ldl -ldevmapper ++LIBDEPS = -lpthread -ldl -ldevmapper -ludev + + OBJS = memory.o parser.o vector.o devmapper.o callout.o \ + hwtable.o blacklist.o util.o dmparser.o config.o \ +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + + #include "memory.h" +@@ -161,7 +162,7 @@ int uevent_dispatch(int (*uev_trigger)(s + return 0; + } + +-int uevent_listen(void) ++int failback_listen(void) + { + int sock; + struct sockaddr_nl snl; +@@ -173,20 +174,6 @@ int uevent_listen(void) + int rcvszsz = sizeof(rcvsz); + unsigned int *prcvszsz = (unsigned int *)&rcvszsz; + const int feature_on = 1; +- +- /* +- * Queue uevents for service by dedicated thread so that the uevent +- * listening thread does not block on multipathd locks (vecs->lock) +- * thereby not getting to empty the socket's receive buffer queue +- * often enough. +- */ +- INIT_LIST_HEAD(&uevq); +- +- pthread_mutex_init(uevq_lockp, NULL); +- pthread_cond_init(uev_condp, NULL); +- +- pthread_cleanup_push(uevq_stop, NULL); +- + /* + * First check whether we have a udev socket + */ +@@ -382,13 +369,145 @@ int uevent_listen(void) + + exit: + close(sock); ++ return 1; ++} + +- pthread_cleanup_pop(1); ++int uevent_listen(void) ++{ ++ int err; ++ struct udev *udev = NULL; ++ struct udev_monitor *monitor = NULL; ++ int fd, socket_flags; ++ int need_failback = 1; ++ /* ++ * Queue uevents for service by dedicated thread so that the uevent ++ * listening thread does not block on multipathd locks (vecs->lock) ++ * thereby not getting to empty the socket's receive buffer queue ++ * often enough. ++ */ ++ INIT_LIST_HEAD(&uevq); + ++ pthread_mutex_init(uevq_lockp, NULL); ++ pthread_cond_init(uev_condp, NULL); ++ pthread_cleanup_push(uevq_stop, NULL); ++ ++ udev = udev_new(); ++ if (!udev) { ++ condlog(2, "failed to create udev context"); ++ goto out; ++ } ++ monitor = udev_monitor_new_from_netlink(udev, "udev"); ++ if (!monitor) { ++ condlog(2, "failed to create udev monitor"); ++ goto out; ++ } ++ if (udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024)) ++ condlog(2, "failed to increase buffer size"); ++ fd = udev_monitor_get_fd(monitor); ++ if (fd < 0) { ++ condlog(2, "failed to get monitor fd"); ++ goto out; ++ } ++ socket_flags = fcntl(fd, F_GETFL); ++ if (socket_flags < 0) { ++ condlog(2, "failed to get monitor socket flags : %s", ++ strerror(errno)); ++ goto out; ++ } ++ if (fcntl(fd, F_SETFL, socket_flags & ~O_NONBLOCK) < 0) { ++ condlog(2, "failed to set monitor socket flags : %s", ++ strerror(errno)); ++ goto out; ++ } ++ err = udev_monitor_filter_add_match_subsystem_devtype(monitor, "block", ++ NULL); ++ if (err) ++ condlog(2, "failed to create filter : %s\n", strerror(-err)); ++ err = udev_monitor_enable_receiving(monitor); ++ if (err) { ++ condlog(2, "failed to enable receiving : %s\n", strerror(-err)); ++ goto out; ++ } ++ while (1) { ++ int i = 0; ++ char *pos, *end; ++ struct uevent *uev; ++ struct udev_device *dev; ++ struct udev_list_entry *list_entry; ++ ++ dev = udev_monitor_receive_device(monitor); ++ if (!dev) { ++ condlog(0, "failed getting udev device"); ++ continue; ++ } ++ ++ uev = alloc_uevent(); ++ if (!uev) { ++ condlog(1, "lost uevent, oom"); ++ continue; ++ } ++ pos = uev->buffer; ++ end = pos + HOTPLUG_BUFFER_SIZE + OBJECT_SIZE - 1; ++ udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev)) { ++ const char *name, *value; ++ int bytes; ++ ++ name = udev_list_entry_get_name(list_entry); ++ if (!name) ++ name = "(null)"; ++ value = udev_list_entry_get_value(list_entry); ++ if (!value) ++ value = "(null)"; ++ bytes = snprintf(pos, end - pos, "%s=%s", name, ++ value); ++ if (pos + bytes >= end) { ++ condlog(2, "buffer overflow for uevent"); ++ break; ++ } ++ uev->envp[i] = pos; ++ pos += bytes; ++ *pos = '\0'; ++ pos++; ++ if (strcmp(name, "DEVPATH") == 0) ++ uev->devpath = uev->envp[i] + 8; ++ if (strcmp(name, "ACTION") == 0) ++ uev->action = uev->envp[i] + 7; ++ i++; ++ if (i == HOTPLUG_NUM_ENVP - 1) ++ break; ++ } ++ udev_device_unref(dev); ++ uev->envp[i] = NULL; ++ ++ condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath); ++ uev->kernel = strrchr(uev->devpath, '/'); ++ if (uev->kernel) ++ uev->kernel++; ++ ++ /* print payload environment */ ++ for (i = 0; uev->envp[i] != NULL; i++) ++ condlog(5, "%s", uev->envp[i]); ++ ++ /* ++ * Queue uevent and poke service pthread. ++ */ ++ pthread_mutex_lock(uevq_lockp); ++ list_add_tail(&uev->node, &uevq); ++ pthread_cond_signal(uev_condp); ++ pthread_mutex_unlock(uevq_lockp); ++ } ++ need_failback = 0; ++out: ++ if (monitor) ++ udev_monitor_unref(monitor); ++ if (udev) ++ udev_unref(udev); ++ if (need_failback) ++ err = failback_listen(); ++ pthread_cleanup_pop(1); + pthread_mutex_destroy(uevq_lockp); + pthread_cond_destroy(uev_condp); +- +- return 1; ++ return err; + } + + extern int diff -Nru multipath-tools-0.4.9/debian/patches/0025-Use-devpath-as-argument-for-sysfs-functions.patch multipath-tools-0.4.9/debian/patches/0025-Use-devpath-as-argument-for-sysfs-functions.patch --- multipath-tools-0.4.9/debian/patches/0025-Use-devpath-as-argument-for-sysfs-functions.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0025-Use-devpath-as-argument-for-sysfs-functions.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,371 @@ +From 44217d3b6ceec8bbc434b33702693676d9ce2738 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:08:55 +0200 +Subject: [PATCH] Use devpath as argument for sysfs functions + +Whenever we pass in a sysfs structure to functions we're only +ever interested in the devpath. So we can as well pass in the +device path directly, without reference to the sysfs structure. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 67 +++++++++++++++++++++++---------------------- + libmultipath/discovery.h | 4 +- + libmultipath/propsel.c | 2 - + libmultipath/structs_vec.c | 2 - + libmultipath/sysfs.h | 2 - + libmultipath/util.c | 6 ++-- + libmultipath/util.h | 2 - + multipathd/cli_handlers.c | 2 - + 8 files changed, 45 insertions(+), 42 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -128,19 +128,19 @@ path_discovery (vector pathvec, struct c + + #define declare_sysfs_get_str(fname) \ + extern int \ +-sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \ ++sysfs_get_##fname (const char * devpath, char * buff, size_t len) \ + { \ + int size; \ + \ +- size = sysfs_attr_get_value(dev->devpath, #fname, buff, len); \ ++ size = sysfs_attr_get_value(devpath, #fname, buff, len); \ + if (!size) { \ + condlog(3, "%s: attribute %s not found in sysfs", \ +- dev->kernel, #fname); \ ++ devpath, #fname); \ + return 1; \ + } \ + if (size == len) { \ + condlog(3, "%s: overflow in attribute %s", \ +- dev->kernel, #fname); \ ++ devpath, #fname); \ + return 2; \ + } \ + strchop(buff); \ +@@ -156,19 +156,22 @@ declare_sysfs_get_str(state); + declare_sysfs_get_str(dev); + + int +-sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout) ++sysfs_get_timeout(const char *devpath, unsigned int *timeout) + { + char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE]; + size_t len; + int r; + unsigned int t; + +- if (safe_sprintf(attr_path, "%s/device", dev->devpath)) ++ if (!devpath) ++ return 1; ++ ++ if (safe_sprintf(attr_path, "%s/device", devpath)) + return 1; + + len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE); + if (!len) { +- condlog(3, "%s: No timeout value in sysfs", dev->devpath); ++ condlog(3, "%s: No timeout value in sysfs", devpath); + return 1; + } + +@@ -176,7 +179,7 @@ sysfs_get_timeout(struct sysfs_device *d + + if (r != 1) { + condlog(3, "%s: Cannot parse timeout attribute '%s'", +- dev->devpath, attr); ++ devpath, attr); + return 1; + } + +@@ -186,15 +189,15 @@ sysfs_get_timeout(struct sysfs_device *d + } + + int +-sysfs_get_size (struct sysfs_device * dev, unsigned long long * size) ++sysfs_get_size (const char * devpath, unsigned long long * size) + { + char attr[NAME_SIZE]; + size_t len; + int r; + +- len = sysfs_attr_get_value(dev->devpath, "size", attr, NAME_SIZE); ++ len = sysfs_attr_get_value(devpath, "size", attr, NAME_SIZE); + if (!len) { +- condlog(3, "%s: No size attribute in sysfs", dev->devpath); ++ condlog(3, "%s: No size attribute in sysfs", devpath); + return 1; + } + +@@ -202,7 +205,7 @@ sysfs_get_size (struct sysfs_device * de + + if (r != 1) { + condlog(3, "%s: Cannot parse size attribute '%s'", +- dev->devpath, attr); ++ devpath, attr); + return 1; + } + +@@ -210,7 +213,7 @@ sysfs_get_size (struct sysfs_device * de + } + + int +-sysfs_get_tgt_nodename (struct sysfs_device * dev, char * node, ++sysfs_get_tgt_nodename (const char * devpath, char * node, + unsigned int host, unsigned int channel, + unsigned int target) + { +@@ -229,8 +232,8 @@ sysfs_get_tgt_nodename (struct sysfs_dev + if (len) + return 0; + +- if (sscanf(dev->devpath, "/devices/platform/host%u/session%u/", +- &checkhost, &session) != 2) ++ if (sscanf(devpath, "/devices/platform/host%u/session%u/", ++ &checkhost, &session) != 2) + return 1; + if (checkhost != host) + return 1; +@@ -526,7 +529,7 @@ get_inq (char * dev, char * vendor, char + } + + static int +-scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) ++scsi_sysfs_pathinfo (struct path * pp, const char * parent) + { + char attr_path[FILE_NAME_SIZE]; + +@@ -553,7 +556,7 @@ scsi_sysfs_pathinfo (struct path * pp, s + /* + * host / bus / target / lun + */ +- basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE); ++ basenamecpy(parent, attr_path, FILE_NAME_SIZE); + + sscanf(attr_path, "%i:%i:%i:%i", + &pp->sg_id.host_no, +@@ -582,7 +585,7 @@ scsi_sysfs_pathinfo (struct path * pp, s + } + + static int +-ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) ++ccw_sysfs_pathinfo (struct path * pp, const char * parent) + { + char attr_path[FILE_NAME_SIZE]; + char attr_buff[FILE_NAME_SIZE]; +@@ -612,7 +615,7 @@ ccw_sysfs_pathinfo (struct path * pp, st + /* + * host / bus / target / lun + */ +- basenamecpy(parent->devpath, attr_path, FILE_NAME_SIZE); ++ basenamecpy(parent, attr_path, FILE_NAME_SIZE); + pp->sg_id.lun = 0; + sscanf(attr_path, "%i.%i.%x", + &pp->sg_id.host_no, +@@ -629,14 +632,14 @@ ccw_sysfs_pathinfo (struct path * pp, st + } + + static int +-cciss_sysfs_pathinfo (struct path * pp, struct sysfs_device * dev) ++cciss_sysfs_pathinfo (struct path * pp, const char * devpath) + { + char attr_path[FILE_NAME_SIZE]; + + /* + * host / bus / target / lun + */ +- basenamecpy(dev->devpath, attr_path, FILE_NAME_SIZE); ++ basenamecpy(devpath, attr_path, FILE_NAME_SIZE); + pp->sg_id.lun = 0; + pp->sg_id.channel = 0; + sscanf(attr_path, "cciss!c%id%i", +@@ -652,12 +655,12 @@ cciss_sysfs_pathinfo (struct path * pp, + } + + static int +-common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev) ++common_sysfs_pathinfo (struct path * pp, const char * devpath) + { + size_t len; + +- len = sysfs_attr_get_value(dev->devpath, "dev", +- pp->dev_t, BLK_DEV_SIZE); ++ len = sysfs_attr_get_value(devpath, "dev", ++ pp->dev_t, BLK_DEV_SIZE); + if (!len) { + condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); + return 1; +@@ -665,7 +668,7 @@ common_sysfs_pathinfo (struct path * pp, + + condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); + +- if (sysfs_get_size(dev, &pp->size)) ++ if (sysfs_get_size(devpath, &pp->size)) + return 1; + + condlog(3, "%s: size = %llu", pp->dev, pp->size); +@@ -711,7 +714,7 @@ path_offline (struct path * pp) + return PATH_WILD; + } + +- if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE)) ++ if (sysfs_get_state(parent->devpath, buff, SCSI_STATE_SIZE)) + return PATH_WILD; + + condlog(3, "%s: state = %s", pp->dev, buff); +@@ -740,7 +743,7 @@ sysfs_pathinfo(struct path * pp) + return 1; + } + +- if (common_sysfs_pathinfo(pp, pp->sysdev)) ++ if (common_sysfs_pathinfo(pp, pp->sysdev->devpath)) + return 1; + + parent = sysfs_device_get_parent(pp->sysdev); +@@ -764,13 +767,13 @@ sysfs_pathinfo(struct path * pp) + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; + else if (pp->bus == SYSFS_BUS_SCSI) { +- if (scsi_sysfs_pathinfo(pp, parent)) ++ if (scsi_sysfs_pathinfo(pp, parent->devpath)) + return 1; + } else if (pp->bus == SYSFS_BUS_CCW) { +- if (ccw_sysfs_pathinfo(pp, parent)) ++ if (ccw_sysfs_pathinfo(pp, parent->devpath)) + return 1; + } else if (pp->bus == SYSFS_BUS_CCISS) { +- if (cciss_sysfs_pathinfo(pp, pp->sysdev)) ++ if (cciss_sysfs_pathinfo(pp, pp->sysdev->devpath)) + return 1; + } + return 0; +@@ -840,8 +843,8 @@ get_state (struct path * pp, int daemon) + } + if (daemon) + checker_set_async(c); +- if (!conf->checker_timeout) +- sysfs_get_timeout(pp->sysdev, &(c->timeout)); ++ if (!conf->checker_timeout && pp->sysdev) ++ sysfs_get_timeout(pp->sysdev->devpath, &(c->timeout)); + state = checker_check(c); + condlog(3, "%s: state = %i", pp->dev, state); + if (state == PATH_DOWN && strlen(checker_message(c))) +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -24,7 +24,7 @@ + #define SCSI_COMMAND_TERMINATED 0x22 + #define SG_ERR_DRIVER_SENSE 0x08 + +-int sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len); ++int sysfs_get_dev (const char * dev, char * buff, size_t len); + int path_discovery (vector pathvec, struct config * conf, int flag); + + int do_tur (char *); +@@ -34,7 +34,7 @@ int pathinfo (struct path *, vector hwta + struct path * store_pathinfo (vector pathvec, vector hwtable, + char * devname, int flag); + int sysfs_set_scsi_tmo (struct multipath *mpp); +-int sysfs_get_timeout(struct sysfs_device *dev, unsigned int *timeout); ++int sysfs_get_timeout(const char * devpath, unsigned int *timeout); + + /* + * discovery bitmask +Index: b/libmultipath/propsel.c +=================================================================== +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -310,7 +310,7 @@ out: + condlog(3, "%s: checker timeout = %u ms (config file default)", + pp->dev, c->timeout); + } +- else if (sysfs_get_timeout(pp->sysdev, &c->timeout) == 0) ++ else if (pp->sysdev && sysfs_get_timeout(pp->sysdev->devpath, &c->timeout) == 0) + condlog(3, "%s: checker timeout = %u ms (sysfs setting)", + pp->dev, c->timeout); + else { +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -455,7 +455,7 @@ verify_paths(struct multipath * mpp, str + /* + * see if path is in sysfs + */ +- if (!pp->sysdev || sysfs_get_dev(pp->sysdev, ++ if (!pp->sysdev || sysfs_get_dev(pp->sysdev->devpath, + pp->dev_t, BLK_DEV_SIZE)) { + condlog(0, "%s: failed to access path %s", mpp->alias, + pp->sysdev ? pp->sysdev->devpath : pp->dev_t); +Index: b/libmultipath/sysfs.h +=================================================================== +--- a/libmultipath/sysfs.h ++++ b/libmultipath/sysfs.h +@@ -23,5 +23,5 @@ size_t sysfs_attr_get_value(const char * + ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, + const char *value, int value_len); + int sysfs_resolve_link(char *path, size_t size); +-int sysfs_get_size (struct sysfs_device * dev, unsigned long long * size); ++int sysfs_get_size(const char * devpath, unsigned long long * size); + #endif +Index: b/libmultipath/util.c +=================================================================== +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -40,7 +40,7 @@ strchop(char *str) + } + + int +-basenamecpy (char * str1, char * str2, int str2len) ++basenamecpy (const char * str1, char * str2, int str2len) + { + char *p; + +@@ -53,7 +53,7 @@ basenamecpy (char * str1, char * str2, i + if (!str2) + return 0; + +- p = str1 + (strlen(str1) - 1); ++ p = (char *)str1 + (strlen(str1) - 1); + + while (*--p != '/' && p != str1) + continue; +@@ -248,6 +248,6 @@ devt2devname (char *devname, int devname + condlog(0, "sysfs entry %s is not a directory\n", block_path); + return 1; + } +- basenamecpy(block_path, devname, devname_len); ++ basenamecpy((const char *)block_path, devname, devname_len); + return 0; + } +Index: b/libmultipath/util.h +=================================================================== +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -3,7 +3,7 @@ + + int strcmp_chomp(char *, char *); + void strchop(char *); +-int basenamecpy (char * src, char * dst, int); ++int basenamecpy (const char * src, char * dst, int); + int filepresent (char * run); + int get_word (char * sentence, char ** word); + size_t strlcpy(char *dst, const char *src, size_t size); +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -514,7 +514,7 @@ cli_resize(void *v, char **reply, int *l + + pgp = VECTOR_SLOT(mpp->pg, 0); + pp = VECTOR_SLOT(pgp->paths, 0); +- if (sysfs_get_size(pp->sysdev, &size)) { ++ if (!pp->sysdev || sysfs_get_size(pp->sysdev->devpath, &size)) { + condlog(0, "%s: couldn't get size for sysfs. cannot resize", + mapname); + return 1; diff -Nru multipath-tools-0.4.9/debian/patches/0026-multipathd-remove-references-to-sysfs_device.patch multipath-tools-0.4.9/debian/patches/0026-multipathd-remove-references-to-sysfs_device.patch --- multipath-tools-0.4.9/debian/patches/0026-multipathd-remove-references-to-sysfs_device.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0026-multipathd-remove-references-to-sysfs_device.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,80 @@ +From 0fd247cb8819ef938c6f98123c141dda43b70af6 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:08:56 +0200 +Subject: [PATCH] multipathd: remove references to sysfs_device + +When processing events we don't need to take a reference to the +sysfs_device; it will be done later on during pathinfo. + +Signed-off-by: Hannes Reinecke +--- + multipathd/main.c | 30 ++---------------------------- + 1 file changed, 2 insertions(+), 28 deletions(-) + +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -355,14 +355,7 @@ uev_umount_map (struct uevent * uev, str + static int + uev_add_path (struct uevent *uev, struct vectors * vecs) + { +- struct sysfs_device * dev; +- +- dev = sysfs_device_get(uev->devpath); +- if (!dev) { +- condlog(2, "%s: not found in sysfs", uev->devpath); +- return 1; +- } +- condlog(2, "%s: add path (uevent)", dev->kernel); ++ condlog(2, "%s: add path (uevent)", uev->kernel); + return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1; + } + +@@ -526,21 +519,10 @@ out: + static int + uev_remove_path (struct uevent *uev, struct vectors * vecs) + { +- struct sysfs_device * dev; + int retval; + +- dev = sysfs_device_get(uev->devpath); +- if (!dev) { +- condlog(2, "%s: not found in sysfs", uev->devpath); +- return 1; +- } + condlog(2, "%s: remove path (uevent)", uev->kernel); +- retval = ev_remove_path(uev->kernel, vecs); +- +- if (!retval) +- sysfs_device_put(dev); +- +- return retval; ++ return ev_remove_path(uev->kernel, vecs); + } + + int +@@ -649,14 +631,8 @@ fail: + static int + uev_update_path (struct uevent *uev, struct vectors * vecs) + { +- struct sysfs_device * dev; + int retval, ro; + +- dev = sysfs_device_get(uev->devpath); +- if (!dev) { +- condlog(2, "%s: not found in sysfs", uev->devpath); +- return 1; +- } + ro = uevent_get_disk_ro(uev); + + if (ro >= 0) { +@@ -678,8 +654,6 @@ uev_update_path (struct uevent *uev, str + + } + +- sysfs_device_put(dev); +- + return retval; + } + diff -Nru multipath-tools-0.4.9/debian/patches/0027-multipathd-use-struct-path-as-argument-for-event-pro.patch multipath-tools-0.4.9/debian/patches/0027-multipathd-use-struct-path-as-argument-for-event-pro.patch --- multipath-tools-0.4.9/debian/patches/0027-multipathd-use-struct-path-as-argument-for-event-pro.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0027-multipathd-use-struct-path-as-argument-for-event-pro.patch 2015-07-28 19:22:39.000000000 +0000 @@ -0,0 +1,327 @@ +From df676380c83f9b87540c2769a5950335ac783ca1 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:08:57 +0200 +Subject: [PATCH] multipathd: use struct path as argument for event processing + +ev_add/remove_path should be using struct path as the argument, +this makes transitioning to use libudev easier. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.h | 2 + multipathd/cli_handlers.c | 39 ++++++++++++++---- + multipathd/main.c | 99 ++++++++++++++++++++++------------------------ + multipathd/main.h | 4 - + 4 files changed, 85 insertions(+), 59 deletions(-) + +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -24,6 +24,8 @@ + #define SCSI_COMMAND_TERMINATED 0x22 + #define SG_ERR_DRIVER_SENSE 0x08 + ++struct config; ++ + int sysfs_get_dev (const char * dev, char * buff, size_t len); + int path_discovery (vector pathvec, struct config * conf, int flag); + +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -353,18 +354,37 @@ cli_add_path (void * v, char ** reply, i + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, PATH); ++ struct path *pp; + int r; + + condlog(2, "%s: add path (operator)", param); + + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, +- param) > 0 || (r = ev_add_path(param, vecs)) == 2) { +- *reply = strdup("blacklisted\n"); +- *len = strlen(*reply) + 1; +- condlog(2, "%s: path blacklisted", param); +- return 0; ++ param) > 0) ++ goto blacklisted; ++ ++ pp = find_path_by_dev(vecs->pathvec, param); ++ if (pp) { ++ condlog(2, "%s: path already in pathvec", param); ++ if (pp->mpp) ++ return 0; ++ } else { ++ pp = store_pathinfo(vecs->pathvec, conf->hwtable, ++ param, DI_ALL); ++ if (!pp) { ++ condlog(0, "%s: failed to store path info", param); ++ return 1; ++ } + } ++ r = ev_add_path(pp, vecs); ++ if (r == 2) ++ goto blacklisted; + return r; ++blacklisted: ++ *reply = strdup("blacklisted\n"); ++ *len = strlen(*reply) + 1; ++ condlog(2, "%s: path blacklisted", param); ++ return 0; + } + + int +@@ -372,10 +392,15 @@ cli_del_path (void * v, char ** reply, i + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, PATH); ++ struct path *pp; + + condlog(2, "%s: remove path (operator)", param); +- +- return ev_remove_path(param, vecs); ++ pp = find_path_by_dev(vecs->pathvec, param); ++ if (!pp) { ++ condlog(0, "%s: path already removed", param); ++ return 0; ++ } ++ return ev_remove_path(pp, vecs); + } + + int +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -355,58 +355,59 @@ uev_umount_map (struct uevent * uev, str + static int + uev_add_path (struct uevent *uev, struct vectors * vecs) + { +- condlog(2, "%s: add path (uevent)", uev->kernel); +- return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1; +-} ++ struct path *pp; + +-/* +- * returns: +- * 0: added +- * 1: error +- * 2: blacklisted +- */ +-int +-ev_add_path (char * devname, struct vectors * vecs) +-{ +- struct multipath * mpp; +- struct path * pp; +- char empty_buff[WWID_SIZE] = {0}; +- char params[PARAMS_SIZE] = {0}; +- int retries = 3; +- +- if (strstr(devname, "..") != NULL) { ++ condlog(2, "%s: add path (uevent)", uev->kernel); ++ if (strstr(uev->kernel, "..") != NULL) { + /* + * Don't allow relative device names in the pathvec + */ +- condlog(0, "%s: path name is invalid", devname); ++ condlog(0, "%s: path name is invalid", uev->kernel); + return 1; + } + +- pp = find_path_by_dev(vecs->pathvec, devname); +- ++ pp = find_path_by_dev(vecs->pathvec, uev->kernel); + if (pp) { + condlog(0, "%s: spurious uevent, path already in pathvec", +- devname); ++ uev->kernel); + if (pp->mpp) + return 0; +- } +- else { ++ } else { + /* + * get path vital state + */ + if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- devname, DI_ALL))) { +- condlog(0, "%s: failed to store path info", devname); ++ uev->kernel, DI_ALL))) { ++ condlog(0, "%s: failed to store path info", ++ uev->kernel); + return 1; + } + pp->checkint = conf->checkint; + } + ++ return (ev_add_path(pp, vecs) != 1)? 0 : 1; ++} ++ ++/* ++ * returns: ++ * 0: added ++ * 1: error ++ * 2: blacklisted ++ */ ++int ++ev_add_path (struct path * pp, struct vectors * vecs) ++{ ++ struct multipath * mpp; ++ char empty_buff[WWID_SIZE] = {0}; ++ char params[PARAMS_SIZE] = {0}; ++ int retries = 3; ++ int start_waiter = 0; ++ + /* + * need path UID to go any further + */ + if (memcmp(empty_buff, pp->wwid, WWID_SIZE) == 0) { +- condlog(0, "%s: failed to get path uid", devname); ++ condlog(0, "%s: failed to get path uid", pp->dev); + return 1; /* leave path added to pathvec */ + } + if (filter_path(conf, pp) > 0){ +@@ -423,11 +424,11 @@ rescan: + if (!pp->size) + condlog(0, "%s: failed to add new path %s, " + "device size is 0", +- devname, pp->dev); ++ mpp->alias, pp->dev); + else + condlog(0, "%s: failed to add new path %s, " + "device size mismatch", +- devname, pp->dev); ++ mpp->alias, pp->dev); + int i = find_slot(vecs->pathvec, (void *)pp); + if (i != -1) + vector_del_slot(vecs->pathvec, i); +@@ -447,7 +448,7 @@ rescan: + else { + if (!pp->size) { + condlog(0, "%s: failed to create new map," +- " %s device size is 0 ", devname, pp->dev); ++ " device size is 0 ", pp->dev); + int i = find_slot(vecs->pathvec, (void *)pp); + if (i != -1) + vector_del_slot(vecs->pathvec, i); +@@ -467,7 +468,7 @@ rescan: + */ + if (setup_map(mpp, params, PARAMS_SIZE)) { + condlog(0, "%s: failed to setup map for addition of new " +- "path %s", mpp->alias, devname); ++ "path %s", mpp->alias, pp->dev); + goto out; + } + /* +@@ -475,7 +476,7 @@ rescan: + */ + if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed in domap for addition of new " +- "path %s", mpp->alias, devname); ++ "path %s", mpp->alias, pp->dev); + /* + * deal with asynchronous uevents :(( + */ +@@ -505,7 +506,7 @@ rescan: + goto out; + + if (retries >= 0) { +- condlog(2, "%s path added to devmap %s", devname, mpp->alias); ++ condlog(2, "%s path added to devmap %s", pp->dev, mpp->alias); + return 0; + } + else +@@ -519,28 +520,27 @@ out: + static int + uev_remove_path (struct uevent *uev, struct vectors * vecs) + { +- int retval; ++ struct path *pp; + + condlog(2, "%s: remove path (uevent)", uev->kernel); +- return ev_remove_path(uev->kernel, vecs); ++ pp = find_path_by_dev(vecs->pathvec, uev->kernel); ++ ++ if (!pp) { ++ /* Not an error; path might have been purged earlier */ ++ condlog(0, "%s: path already removed", uev->kernel); ++ return 0; ++ } ++ ++ return ev_remove_path(pp, vecs); + } + + int +-ev_remove_path (char * devname, struct vectors * vecs) ++ev_remove_path (struct path *pp, struct vectors * vecs) + { + struct multipath * mpp; +- struct path * pp; + int i, retval = 0; + char params[PARAMS_SIZE] = {0}; + +- pp = find_path_by_dev(vecs->pathvec, devname); +- +- if (!pp) { +- /* Not an error; path might have been purged earlier */ +- condlog(0, "%s: path already removed", devname); +- return 0; +- } +- + /* + * avoid referring to the map of an orphaned path + */ +@@ -588,8 +588,7 @@ ev_remove_path (char * devname, struct v + + if (setup_map(mpp, params, PARAMS_SIZE)) { + condlog(0, "%s: failed to setup map for" +- " removal of path %s", mpp->alias, +- devname); ++ " removal of path %s", mpp->alias, pp->dev); + goto fail; + } + /* +@@ -599,7 +598,7 @@ ev_remove_path (char * devname, struct v + if (domap(mpp, params) <= 0) { + condlog(0, "%s: failed in domap for " + "removal of path %s", +- mpp->alias, devname); ++ mpp->alias, pp->dev); + retval = 1; + } else { + /* +@@ -611,7 +610,7 @@ ev_remove_path (char * devname, struct v + sync_map_state(mpp); + + condlog(2, "%s: path removed from map %s", +- devname, mpp->alias); ++ pp->dev, mpp->alias); + } + } + +Index: b/multipathd/main.h +=================================================================== +--- a/multipathd/main.h ++++ b/multipathd/main.h +@@ -4,8 +4,8 @@ + #define MAPGCINT 5 + + int reconfigure (struct vectors *); +-int ev_add_path (char *, struct vectors *); +-int ev_remove_path (char *, struct vectors *); ++int ev_add_path (struct path *, struct vectors *); ++int ev_remove_path (struct path *, struct vectors *); + int ev_add_map (char *, char *, struct vectors *); + int ev_remove_map (char *, char *, int, struct vectors *); + void sync_map_state (struct multipath *); diff -Nru multipath-tools-0.4.9/debian/patches/0028-Add-global-udev-reference-pointer-to-config.patch multipath-tools-0.4.9/debian/patches/0028-Add-global-udev-reference-pointer-to-config.patch --- multipath-tools-0.4.9/debian/patches/0028-Add-global-udev-reference-pointer-to-config.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0028-Add-global-udev-reference-pointer-to-config.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,101 @@ +From 7007dbe906d34c8ee2d4ba4dedb4b2308c3a7933 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:08:58 +0200 +Subject: [PATCH] Add global udev reference pointer to config + +Instead of using a local reference to udev we should be moving it +to the global config structure. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/config.c | 5 +++++ + libmultipath/config.h | 1 + + libmultipath/uevent.c | 12 +++--------- + 3 files changed, 9 insertions(+), 9 deletions(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -5,6 +5,7 @@ + */ + #include + #include ++#include + + #include "checkers.h" + #include "memory.h" +@@ -417,6 +418,9 @@ free_config (struct config * conf) + if (conf->dev) + FREE(conf->dev); + ++ if (conf->udev) ++ udev_unref(conf->udev); ++ + if (conf->udev_dir) + FREE(conf->udev_dir); + +@@ -473,6 +477,7 @@ load_config (char * file) + if (!conf->verbosity) + conf->verbosity = DEFAULT_VERBOSITY; + ++ conf->udev = udev_new(); + conf->dev_type = DEV_NONE; + conf->minio = 1000; + conf->max_fds = 0; +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -96,6 +96,7 @@ struct config { + uint32_t cookie; + + char * dev; ++ struct udev * udev; + char * sysfs_dir; + char * udev_dir; + char * multipath_dir; +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -46,6 +46,8 @@ + #include "debug.h" + #include "list.h" + #include "uevent.h" ++#include "vector.h" ++#include "config.h" + + typedef int (uev_trigger)(struct uevent *, void * trigger_data); + +@@ -375,7 +377,6 @@ exit: + int uevent_listen(void) + { + int err; +- struct udev *udev = NULL; + struct udev_monitor *monitor = NULL; + int fd, socket_flags; + int need_failback = 1; +@@ -391,12 +392,7 @@ int uevent_listen(void) + pthread_cond_init(uev_condp, NULL); + pthread_cleanup_push(uevq_stop, NULL); + +- udev = udev_new(); +- if (!udev) { +- condlog(2, "failed to create udev context"); +- goto out; +- } +- monitor = udev_monitor_new_from_netlink(udev, "udev"); ++ monitor = udev_monitor_new_from_netlink(conf->udev, "udev"); + if (!monitor) { + condlog(2, "failed to create udev monitor"); + goto out; +@@ -500,8 +496,6 @@ int uevent_listen(void) + out: + if (monitor) + udev_monitor_unref(monitor); +- if (udev) +- udev_unref(udev); + if (need_failback) + err = failback_listen(); + pthread_cleanup_pop(1); diff -Nru multipath-tools-0.4.9/debian/patches/0029-Use-udev-enumeration-during-discovery.patch multipath-tools-0.4.9/debian/patches/0029-Use-udev-enumeration-during-discovery.patch --- multipath-tools-0.4.9/debian/patches/0029-Use-udev-enumeration-during-discovery.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0029-Use-udev-enumeration-during-discovery.patch 2015-07-28 19:22:42.000000000 +0000 @@ -0,0 +1,83 @@ +From 185b60240fd1a827075b780bb8d497170dcfc00b Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:08:59 +0200 +Subject: [PATCH] Use udev enumeration during discovery + +Instead of scanning /sys/block by hand we should be using enumeration +provided by udev. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 40 ++++++++++++++++++---------------------- + 1 file changed, 18 insertions(+), 22 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index 426c511..d68324b 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -91,37 +92,32 @@ path_discover (vector pathvec, struct config * conf, char * devname, int flag) + int + path_discovery (vector pathvec, struct config * conf, int flag) + { +- DIR *blkdir; +- struct dirent *blkdev; +- struct stat statbuf; +- char devpath[PATH_MAX]; ++ struct udev_enumerate *udev_iter; ++ struct udev_list_entry *entry; ++ char *devpath; + char *devptr; + int r = 0; + +- if (!(blkdir = opendir("/sys/block"))) ++ udev_iter = udev_enumerate_new(conf->udev); ++ if (!udev_iter) + return 1; + +- strcpy(devpath,"/sys/block"); +- while ((blkdev = readdir(blkdir)) != NULL) { +- if ((strcmp(blkdev->d_name,".") == 0) || +- (strcmp(blkdev->d_name,"..") == 0)) +- continue; +- +- devptr = devpath + 10; +- *devptr = '\0'; +- strcat(devptr,"/"); +- strcat(devptr,blkdev->d_name); +- if (stat(devpath, &statbuf) < 0) +- continue; +- +- if (S_ISDIR(statbuf.st_mode) == 0) +- continue; ++ udev_enumerate_add_match_subsystem(udev_iter, "block"); ++ udev_enumerate_scan_devices(udev_iter); + ++ udev_list_entry_foreach(entry, ++ udev_enumerate_get_list_entry(udev_iter)) { ++ devpath = udev_list_entry_get_name(entry); + condlog(4, "Discover device %s", devpath); ++ devptr = strrchr(devpath, '/'); ++ if (devptr) ++ devptr++; ++ else ++ devptr = devpath; + +- r += path_discover(pathvec, conf, blkdev->d_name, flag); ++ r += path_discover(pathvec, conf, devptr, flag); + } +- closedir(blkdir); ++ udev_enumerate_unref(udev_iter); + condlog(4, "Discovery status %d", r); + return r; + } +-- +2.1.4 + diff -Nru multipath-tools-0.4.9/debian/patches/0030-use-struct-udev_device-during-discovery.patch multipath-tools-0.4.9/debian/patches/0030-use-struct-udev_device-during-discovery.patch --- multipath-tools-0.4.9/debian/patches/0030-use-struct-udev_device-during-discovery.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0030-use-struct-udev_device-during-discovery.patch 2015-07-28 19:22:43.000000000 +0000 @@ -0,0 +1,95 @@ +From 931be6984ac16823307604a5c2d41943cef39b48 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:09:00 +0200 +Subject: [PATCH] use struct udev_device during discovery + +We can save quite some parsing etc. by just using struct udev_device. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 44 ++++++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c +index d68324b..fd0f827 100644 +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -56,34 +56,24 @@ out: + } + + static int +-path_discover (vector pathvec, struct config * conf, char * devname, int flag) ++path_discover (vector pathvec, struct config * conf, ++ struct udev_device *udevice, int flag) + { +- char path[FILE_NAME_SIZE]; + struct path * pp; ++ const char * devname; + ++ devname = udev_device_get_sysname(udevice); + if (!devname) + return 0; + + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, +- devname) > 0) ++ (char *)devname) > 0) + return 0; + +- if(safe_sprintf(path, "%s/block/%s/device", sysfs_path, +- devname)) { +- condlog(0, "path too small"); +- return 1; +- } +- +- if (strncmp(devname,"cciss",5) && !filepresent(path)) { +- condlog(4, "path %s not present", path); +- return 0; +- } +- +- pp = find_path_by_dev(pathvec, devname); +- ++ pp = find_path_by_dev(pathvec, (char *)devname); + if (!pp) { + pp = store_pathinfo(pathvec, conf->hwtable, +- devname, flag); ++ (char *)devname, flag); + return (pp ? 0 : 1); + } + return pathinfo(pp, conf->hwtable, flag); +@@ -94,8 +84,8 @@ path_discovery (vector pathvec, struct config * conf, int flag) + { + struct udev_enumerate *udev_iter; + struct udev_list_entry *entry; +- char *devpath; +- char *devptr; ++ struct udev_device *udevice; ++ const char *devpath; + int r = 0; + + udev_iter = udev_enumerate_new(conf->udev); +@@ -109,13 +99,15 @@ path_discovery (vector pathvec, struct config * conf, int flag) + udev_enumerate_get_list_entry(udev_iter)) { + devpath = udev_list_entry_get_name(entry); + condlog(4, "Discover device %s", devpath); +- devptr = strrchr(devpath, '/'); +- if (devptr) +- devptr++; +- else +- devptr = devpath; +- +- r += path_discover(pathvec, conf, devptr, flag); ++ udevice = udev_device_new_from_syspath(conf->udev, devpath); ++ if (!udevice) { ++ condlog(4, "%s: no udev information", devpath); ++ r++; ++ continue; ++ } ++ if(!strncmp(udev_device_get_devtype(udevice), "disk", 4)) ++ r += path_discover(pathvec, conf, udevice, flag); ++ udev_device_unref(udevice); + } + udev_enumerate_unref(udev_iter); + condlog(4, "Discovery status %d", r); +-- +2.1.4 + diff -Nru multipath-tools-0.4.9/debian/patches/0031-More-debugging-output-when-synchronizing-path-states.patch multipath-tools-0.4.9/debian/patches/0031-More-debugging-output-when-synchronizing-path-states.patch --- multipath-tools-0.4.9/debian/patches/0031-More-debugging-output-when-synchronizing-path-states.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0031-More-debugging-output-when-synchronizing-path-states.patch 2015-07-28 19:22:39.000000000 +0000 @@ -0,0 +1,36 @@ +From 6df6f4fb158132d90a9a228ac5b47f3571a7f14d Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 21 Jan 2009 15:01:38 +0100 +Subject: [PATCH] More debugging output when synchronizing path states + +When synchronizing path state we might end up removing a path. +However, if this path is not in state PATH_DOWN there is an +error somewhere. So modify the messages accordingly. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/structs_vec.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -457,8 +457,15 @@ verify_paths(struct multipath * mpp, str + */ + if (!pp->sysdev || sysfs_get_dev(pp->sysdev->devpath, + pp->dev_t, BLK_DEV_SIZE)) { +- condlog(0, "%s: failed to access path %s", mpp->alias, +- pp->sysdev ? pp->sysdev->devpath : pp->dev_t); ++ if (pp->state != PATH_DOWN) { ++ condlog(1, "%s: removing valid path %s in state %d", ++ mpp->alias, ++ pp->sysdev?pp->sysdev->devpath:pp->dev_t, pp->state); ++ } else { ++ condlog(3, "%s: failed to access path %s", ++ mpp->alias, ++ pp->sysdev ? pp->sysdev->devpath : pp->dev_t); ++ } + count++; + vector_del_slot(mpp->paths, i); + i--; diff -Nru multipath-tools-0.4.9/debian/patches/0032-Use-struct-udev_device-instead-of-sysdev.patch multipath-tools-0.4.9/debian/patches/0032-Use-struct-udev_device-instead-of-sysdev.patch --- multipath-tools-0.4.9/debian/patches/0032-Use-struct-udev_device-instead-of-sysdev.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0032-Use-struct-udev_device-instead-of-sysdev.patch 2015-07-28 19:22:41.000000000 +0000 @@ -0,0 +1,816 @@ +From 058a0044cb2ab7cac6f7c3e2e17b16e00b5e57fa Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:09:02 +0200 +Subject: [PATCH] Use struct udev_device instead of sysdev + +Remove hand-crafted sysdev and use struct udev_device instead. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 279 ++++++++++++++++++++++++--------------------- + libmultipath/discovery.h | 6 + libmultipath/propsel.c | 2 + libmultipath/structs.c | 6 + libmultipath/structs.h | 8 - + libmultipath/structs_vec.c | 10 - + libmultipath/sysfs.h | 3 + libmultipath/uevent.c | 4 + libmultipath/uevent.h | 1 + libmultipath/util.c | 10 + + libmultipath/util.h | 1 + multipath/main.c | 1 + multipathd/Makefile | 2 + multipathd/cli_handlers.c | 11 + + multipathd/main.c | 9 - + 15 files changed, 196 insertions(+), 157 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -30,9 +30,15 @@ + #include "defaults.h" + + struct path * +-store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag) ++store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice, ++ int flag) + { + struct path * pp; ++ const char * devname; ++ ++ devname = udev_device_get_sysname(udevice); ++ if (!devname) ++ return NULL; + + pp = alloc_path(); + +@@ -43,6 +49,7 @@ store_pathinfo (vector pathvec, vector h + condlog(0, "pp->dev too small"); + goto out; + } ++ pp->udev = udev_device_ref(udevice); + if (pathinfo(pp, hwtable, flag)) + goto out; + +@@ -73,7 +80,7 @@ path_discover (vector pathvec, struct co + pp = find_path_by_dev(pathvec, (char *)devname); + if (!pp) { + pp = store_pathinfo(pathvec, conf->hwtable, +- (char *)devname, flag); ++ udevice, flag); + return (pp ? 0 : 1); + } + return pathinfo(pp, conf->hwtable, flag); +@@ -114,24 +121,27 @@ path_discovery (vector pathvec, struct c + return r; + } + +-#define declare_sysfs_get_str(fname) \ +-extern int \ +-sysfs_get_##fname (const char * devpath, char * buff, size_t len) \ +-{ \ +- int size; \ +- \ +- size = sysfs_attr_get_value(devpath, #fname, buff, len); \ +- if (!size) { \ ++#define declare_sysfs_get_str(fname) \ ++extern int \ ++sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len) \ ++{ \ ++ const char * attr; \ ++ const char * devname; \ ++ \ ++ devname = udev_device_get_sysname(udev); \ ++ \ ++ attr = udev_device_get_sysattr_value(udev, #fname); \ ++ if (!attr) { \ + condlog(3, "%s: attribute %s not found in sysfs", \ +- devpath, #fname); \ ++ devname, #fname); \ + return 1; \ + } \ +- if (size == len) { \ ++ if (strlen(attr) > len) { \ + condlog(3, "%s: overflow in attribute %s", \ +- devpath, #fname); \ ++ devname, #fname); \ + return 2; \ + } \ +- strchop(buff); \ ++ strlcpy(buff, attr, len); \ + return 0; \ + } + +@@ -144,22 +154,27 @@ declare_sysfs_get_str(state); + declare_sysfs_get_str(dev); + + int +-sysfs_get_timeout(const char *devpath, unsigned int *timeout) ++sysfs_get_timeout(struct path *pp, unsigned int *timeout) + { +- char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE]; +- size_t len; ++ const char *attr = NULL; ++ const char *subsys; ++ struct udev_device *parent; + int r; + unsigned int t; + +- if (!devpath) +- return 1; +- +- if (safe_sprintf(attr_path, "%s/device", devpath)) ++ if (!pp->udev) + return 1; + +- len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE); +- if (!len) { +- condlog(3, "%s: No timeout value in sysfs", devpath); ++ parent = pp->udev; ++ while (parent) { ++ subsys = udev_device_get_subsystem(parent); ++ attr = udev_device_get_sysattr_value(parent, "timeout"); ++ if (subsys && attr) ++ break; ++ parent = udev_device_get_parent(parent); ++ } ++ if (!attr) { ++ condlog(3, "%s: No timeout value in sysfs", pp->dev); + return 1; + } + +@@ -167,7 +182,7 @@ sysfs_get_timeout(const char *devpath, u + + if (r != 1) { + condlog(3, "%s: Cannot parse timeout attribute '%s'", +- devpath, attr); ++ pp->dev, attr); + return 1; + } + +@@ -177,15 +192,17 @@ sysfs_get_timeout(const char *devpath, u + } + + int +-sysfs_get_size (const char * devpath, unsigned long long * size) ++sysfs_get_size (struct path *pp, unsigned long long * size) + { +- char attr[NAME_SIZE]; +- size_t len; ++ const char * attr; + int r; + +- len = sysfs_attr_get_value(devpath, "size", attr, NAME_SIZE); +- if (!len) { +- condlog(3, "%s: No size attribute in sysfs", devpath); ++ if (!pp->udev) ++ return 1; ++ ++ attr = udev_device_get_sysattr_value(pp->udev, "size"); ++ if (!attr) { ++ condlog(3, "%s: No size attribute in sysfs", pp->dev); + return 1; + } + +@@ -193,7 +210,7 @@ sysfs_get_size (const char * devpath, un + + if (r != 1) { + condlog(3, "%s: Cannot parse size attribute '%s'", +- devpath, attr); ++ pp->dev, attr); + return 1; + } + +@@ -201,41 +218,56 @@ sysfs_get_size (const char * devpath, un + } + + int +-sysfs_get_tgt_nodename (const char * devpath, char * node, +- unsigned int host, unsigned int channel, +- unsigned int target) ++sysfs_get_tgt_nodename (struct path *pp, char * node) + { +- unsigned int checkhost, session; ++ const char * targetid; ++ struct udev_device *parent; + char attr_path[SYSFS_PATH_SIZE]; + size_t len; + ++ parent = pp->udev; ++ while (parent) { ++ targetid = udev_device_get_sysname(parent); ++ if (!strncmp(targetid , "target", 6)) ++ break; ++ parent = udev_device_get_parent(parent); ++ } ++ /* 'target' needs to exist */ ++ if (!parent || !targetid) ++ return 1; ++ /* Check if it's FibreChannel */ + if (safe_sprintf(attr_path, +- "/class/fc_transport/target%i:%i:%i", +- host, channel, target)) { ++ "/class/fc_transport/%s", targetid)) { + condlog(0, "attr_path too small"); + return 1; + } + +- len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE); ++ len = sysfs_attr_get_value(attr_path, "node_name", ++ node, NODE_NAME_SIZE); + if (len) + return 0; + +- if (sscanf(devpath, "/devices/platform/host%u/session%u/", +- &checkhost, &session) != 2) +- return 1; +- if (checkhost != host) +- return 1; +- if (safe_sprintf(attr_path, "/devices/platform/host%u/session%u/iscsi_session/session%u", host, session, session)) { +- condlog(0, "attr_path too small"); +- return 1; ++ /* Check for iSCSI */ ++ parent = pp->udev; ++ while (parent) { ++ targetid = udev_device_get_sysname(parent); ++ if (!strncmp(targetid , "session", 6)) ++ break; ++ parent = udev_device_get_parent(parent); ++ } ++ if (parent) { ++ if (safe_sprintf(attr_path, "/class/iscsi_session/%s", ++ targetid)) { ++ condlog(0, "attr_path too small"); ++ return 1; ++ } ++ len = sysfs_attr_get_value(attr_path, "targetname", node, ++ NODE_NAME_SIZE); ++ if (len) ++ return 0; + } + +- len = sysfs_attr_get_value(attr_path, "targetname", node, +- NODE_NAME_SIZE); +- if (!len) +- return 1; +- +- return 0; ++ return 1; + } + + static int +@@ -517,9 +549,28 @@ get_inq (char * dev, char * vendor, char + } + + static int +-scsi_sysfs_pathinfo (struct path * pp, const char * parent) ++scsi_sysfs_pathinfo (struct path * pp) + { +- char attr_path[FILE_NAME_SIZE]; ++ struct udev_device *parent; ++ const char *attr_path = NULL; ++ ++ parent = pp->udev; ++ while (parent) { ++ if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) { ++ attr_path = udev_device_get_sysname(parent); ++ if (!attr_path) ++ break; ++ if (sscanf(attr_path, "%i:%i:%i:%i", ++ &pp->sg_id.host_no, ++ &pp->sg_id.channel, ++ &pp->sg_id.scsi_id, ++ &pp->sg_id.lun) == 4) ++ break; ++ } ++ parent = udev_device_get_parent(parent); ++ } ++ if (!attr_path || pp->sg_id.host_no == -1) ++ return 1; + + if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE)) + return 1; +@@ -544,13 +595,6 @@ scsi_sysfs_pathinfo (struct path * pp, c + /* + * host / bus / target / lun + */ +- basenamecpy(parent, attr_path, FILE_NAME_SIZE); +- +- sscanf(attr_path, "%i:%i:%i:%i", +- &pp->sg_id.host_no, +- &pp->sg_id.channel, +- &pp->sg_id.scsi_id, +- &pp->sg_id.lun); + condlog(3, "%s: h:b:t:l = %i:%i:%i:%i", + pp->dev, + pp->sg_id.host_no, +@@ -561,10 +605,7 @@ scsi_sysfs_pathinfo (struct path * pp, c + /* + * target node name + */ +- if(!sysfs_get_tgt_nodename(parent, pp->tgt_node_name, +- pp->sg_id.host_no, +- pp->sg_id.channel, +- pp->sg_id.scsi_id)) { ++ if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) { + condlog(3, "%s: tgt_node_name = %s", + pp->dev, pp->tgt_node_name); + } +@@ -573,10 +614,20 @@ scsi_sysfs_pathinfo (struct path * pp, c + } + + static int +-ccw_sysfs_pathinfo (struct path * pp, const char * parent) ++ccw_sysfs_pathinfo (struct path * pp) + { +- char attr_path[FILE_NAME_SIZE]; +- char attr_buff[FILE_NAME_SIZE]; ++ struct udev_device *parent; ++ char attr_buff[NAME_SIZE]; ++ const char *attr_path; ++ ++ parent = pp->udev; ++ while (parent) { ++ if (!strncmp(udev_device_get_subsystem(parent), "ccw", 3)) ++ break; ++ parent = udev_device_get_parent(parent); ++ } ++ if (!parent) ++ return 1; + + sprintf(pp->vendor_id, "IBM"); + +@@ -603,7 +654,7 @@ ccw_sysfs_pathinfo (struct path * pp, co + /* + * host / bus / target / lun + */ +- basenamecpy(parent, attr_path, FILE_NAME_SIZE); ++ attr_path = udev_device_get_sysname(parent); + pp->sg_id.lun = 0; + sscanf(attr_path, "%i.%i.%x", + &pp->sg_id.host_no, +@@ -620,14 +671,17 @@ ccw_sysfs_pathinfo (struct path * pp, co + } + + static int +-cciss_sysfs_pathinfo (struct path * pp, const char * devpath) ++cciss_sysfs_pathinfo (struct path * pp) + { +- char attr_path[FILE_NAME_SIZE]; ++ const char * attr_path; + + /* + * host / bus / target / lun + */ +- basenamecpy(devpath, attr_path, FILE_NAME_SIZE); ++ attr_path = udev_device_get_devpath(pp->udev); ++ if (!attr_path) ++ return 1; ++ + pp->sg_id.lun = 0; + pp->sg_id.channel = 0; + sscanf(attr_path, "cciss!c%id%i", +@@ -643,20 +697,20 @@ cciss_sysfs_pathinfo (struct path * pp, + } + + static int +-common_sysfs_pathinfo (struct path * pp, const char * devpath) ++common_sysfs_pathinfo (struct path * pp) + { +- size_t len; +- +- len = sysfs_attr_get_value(devpath, "dev", +- pp->dev_t, BLK_DEV_SIZE); +- if (!len) { ++ if (!pp->udev) { ++ condlog(4, "%s: udev not initialised", pp->dev); ++ return 1; ++ } ++ if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) { + condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); + return 1; + } + + condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); + +- if (sysfs_get_size(devpath, &pp->size)) ++ if (sysfs_get_size(pp, &pp->size)) + return 1; + + condlog(3, "%s: size = %llu", pp->dev, pp->size); +@@ -664,45 +718,28 @@ common_sysfs_pathinfo (struct path * pp, + return 0; + } + +-struct sysfs_device *sysfs_device_from_path(struct path *pp) +-{ +- char sysdev[FILE_NAME_SIZE]; +- +- if (pp->sysdev && sysfs_device_verify(pp->sysdev)) +- return pp->sysdev; +- +- strlcpy(sysdev,"/block/", FILE_NAME_SIZE); +- strlcat(sysdev,pp->dev, FILE_NAME_SIZE); +- +- return sysfs_device_get(sysdev); +-} +- + int + path_offline (struct path * pp) + { +- struct sysfs_device * parent; ++ struct udev_device * parent; + char buff[SCSI_STATE_SIZE]; + + if (pp->bus != SYSFS_BUS_SCSI) + return PATH_UP; + +- pp->sysdev = sysfs_device_from_path(pp); +- if (!pp->sysdev) { +- condlog(1, "%s: failed to get sysfs information", pp->dev); +- return PATH_WILD; ++ parent = pp->udev; ++ while (parent) { ++ if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) ++ break; ++ parent = udev_device_get_parent(parent); + } + +- parent = sysfs_device_get_parent(pp->sysdev); +- if (!parent) +- parent = pp->sysdev; +- if (parent && !strncmp(parent->kernel, "block",5)) +- parent = sysfs_device_get_parent(parent); + if (!parent) { +- condlog(1, "%s: failed to get parent", pp->dev); ++ condlog(1, "%s: failed to get sysfs information", pp->dev); + return PATH_WILD; + } + +- if (sysfs_get_state(parent->devpath, buff, SCSI_STATE_SIZE)) ++ if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE)) + return PATH_WILD; + + condlog(3, "%s: state = %s", pp->dev, buff); +@@ -723,26 +760,8 @@ path_offline (struct path * pp) + extern int + sysfs_pathinfo(struct path * pp) + { +- struct sysfs_device *parent; +- +- pp->sysdev = sysfs_device_from_path(pp); +- if (!pp->sysdev) { +- condlog(1, "%s: failed to get sysfs information", pp->dev); ++ if (common_sysfs_pathinfo(pp)) + return 1; +- } +- +- if (common_sysfs_pathinfo(pp, pp->sysdev->devpath)) +- return 1; +- +- parent = sysfs_device_get_parent(pp->sysdev); +- if (!parent) +- parent = pp->sysdev; +- if (parent && !strncmp(parent->kernel, "block",5)) +- parent = sysfs_device_get_parent(parent); +- if (!parent) { +- condlog(1, "%s: failed to get parent", pp->dev); +- return 1; +- } + + pp->bus = SYSFS_BUS_UNDEF; + if (!strncmp(pp->dev,"cciss",5)) +@@ -755,13 +774,13 @@ sysfs_pathinfo(struct path * pp) + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; + else if (pp->bus == SYSFS_BUS_SCSI) { +- if (scsi_sysfs_pathinfo(pp, parent->devpath)) ++ if (scsi_sysfs_pathinfo(pp)) + return 1; + } else if (pp->bus == SYSFS_BUS_CCW) { +- if (ccw_sysfs_pathinfo(pp, parent->devpath)) ++ if (ccw_sysfs_pathinfo(pp)) + return 1; + } else if (pp->bus == SYSFS_BUS_CCISS) { +- if (cciss_sysfs_pathinfo(pp, pp->sysdev->devpath)) ++ if (cciss_sysfs_pathinfo(pp)) + return 1; + } + return 0; +@@ -811,7 +830,7 @@ get_state (struct path * pp, int daemon) + condlog(3, "%s: get_state", pp->dev); + + if (!checker_selected(c)) { +- if (daemon || pp->sysdev == NULL) { ++ if (daemon) { + if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) { + condlog(3, "%s: couldn't get sysfs pathinfo", + pp->dev); +@@ -831,8 +850,8 @@ get_state (struct path * pp, int daemon) + } + if (daemon) + checker_set_async(c); +- if (!conf->checker_timeout && pp->sysdev) +- sysfs_get_timeout(pp->sysdev->devpath, &(c->timeout)); ++ if (!conf->checker_timeout) ++ sysfs_get_timeout(pp, &(c->timeout)); + state = checker_check(c); + condlog(3, "%s: state = %i", pp->dev, state); + if (state == PATH_DOWN && strlen(checker_message(c))) +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -26,7 +26,7 @@ + + struct config; + +-int sysfs_get_dev (const char * dev, char * buff, size_t len); ++int sysfs_get_dev (struct udev_device *udev, char * buff, size_t len); + int path_discovery (vector pathvec, struct config * conf, int flag); + + int do_tur (char *); +@@ -34,9 +34,9 @@ int path_offline (struct path *); + int get_state (struct path * pp, int daemon); + int pathinfo (struct path *, vector hwtable, int mask); + struct path * store_pathinfo (vector pathvec, vector hwtable, +- char * devname, int flag); ++ struct udev_device *udevice, int flag); + int sysfs_set_scsi_tmo (struct multipath *mpp); +-int sysfs_get_timeout(const char * devpath, unsigned int *timeout); ++int sysfs_get_timeout(struct path *pp, unsigned int *timeout); + + /* + * discovery bitmask +Index: b/libmultipath/propsel.c +=================================================================== +--- a/libmultipath/propsel.c ++++ b/libmultipath/propsel.c +@@ -310,7 +310,7 @@ out: + condlog(3, "%s: checker timeout = %u ms (config file default)", + pp->dev, c->timeout); + } +- else if (pp->sysdev && sysfs_get_timeout(pp->sysdev->devpath, &c->timeout) == 0) ++ else if (pp->udev && sysfs_get_timeout(pp, &c->timeout) == 0) + condlog(3, "%s: checker timeout = %u ms (sysfs setting)", + pp->dev, c->timeout); + else { +Index: b/libmultipath/structs.c +=================================================================== +--- a/libmultipath/structs.c ++++ b/libmultipath/structs.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "memory.h" +@@ -47,6 +48,11 @@ free_path (struct path * pp) + if (pp->fd >= 0) + close(pp->fd); + ++ if (pp->udev) { ++ udev_device_unref(pp->udev); ++ pp->udev = NULL; ++ } ++ + FREE(pp); + } + +Index: b/libmultipath/structs.h +=================================================================== +--- a/libmultipath/structs.h ++++ b/libmultipath/structs.h +@@ -110,16 +110,10 @@ struct scsi_dev { + int host_no; + }; + +-struct sysfs_device { +- struct sysfs_device *parent; /* parent device */ +- char devpath[PATH_SIZE]; +- char kernel[NAME_SIZE]; /* device instance name */ +-}; +- + struct path { + char dev[FILE_NAME_SIZE]; + char dev_t[BLK_DEV_SIZE]; +- struct sysfs_device *sysdev; ++ struct udev_device *udev; + struct scsi_idlun scsi_id; + struct sg_id sg_id; + char wwid[WWID_SIZE]; +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -455,16 +455,14 @@ verify_paths(struct multipath * mpp, str + /* + * see if path is in sysfs + */ +- if (!pp->sysdev || sysfs_get_dev(pp->sysdev->devpath, +- pp->dev_t, BLK_DEV_SIZE)) { ++ if (!pp->udev || sysfs_get_dev(pp->udev, pp->dev_t, ++ BLK_DEV_SIZE)) { + if (pp->state != PATH_DOWN) { + condlog(1, "%s: removing valid path %s in state %d", +- mpp->alias, +- pp->sysdev?pp->sysdev->devpath:pp->dev_t, pp->state); ++ mpp->alias, pp->dev, pp->state); + } else { + condlog(3, "%s: failed to access path %s", +- mpp->alias, +- pp->sysdev ? pp->sysdev->devpath : pp->dev_t); ++ mpp->alias, pp->dev); + } + count++; + vector_del_slot(mpp->paths, i); +Index: b/libmultipath/sysfs.h +=================================================================== +--- a/libmultipath/sysfs.h ++++ b/libmultipath/sysfs.h +@@ -13,7 +13,6 @@ + + int sysfs_init(char *path, size_t len); + void sysfs_cleanup(void); +-void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath); + struct sysfs_device *sysfs_device_get(const char *devpath); + struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); + void sysfs_device_put(struct sysfs_device *dev); +@@ -23,5 +22,5 @@ size_t sysfs_attr_get_value(const char * + ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, + const char *value, int value_len); + int sysfs_resolve_link(char *path, size_t size); +-int sysfs_get_size(const char * devpath, unsigned long long * size); ++int sysfs_get_size(struct path *pp, unsigned long long * size); + #endif +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -117,6 +117,8 @@ service_uevq(struct list_head *tmpq) + if (my_uev_trigger && my_uev_trigger(uev, my_trigger_data)) + condlog(0, "uevent trigger error"); + ++ if (uev->udev) ++ udev_device_unref(uev->udev); + FREE(uev); + } + } +@@ -472,7 +474,7 @@ int uevent_listen(void) + if (i == HOTPLUG_NUM_ENVP - 1) + break; + } +- udev_device_unref(dev); ++ uev->udev = dev; + uev->envp[i] = NULL; + + condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath); +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -15,6 +15,7 @@ + + struct uevent { + struct list_head node; ++ struct udev_device *udev; + char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; + char *devpath; + char *action; +Index: b/libmultipath/util.c +=================================================================== +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -251,3 +251,13 @@ devt2devname (char *devname, int devname + basenamecpy((const char *)block_path, devname, devname_len); + return 0; + } ++ ++dev_t parse_devt(const char *dev_t) ++{ ++ int maj, min; ++ ++ if (sscanf(dev_t,"%d:%d", &maj, &min) != 2) ++ return 0; ++ ++ return makedev(maj, min); ++} +Index: b/libmultipath/util.h +=================================================================== +--- a/libmultipath/util.h ++++ b/libmultipath/util.h +@@ -10,6 +10,7 @@ size_t strlcpy(char *dst, const char *sr + size_t strlcat(char *dst, const char *src, size_t size); + void remove_trailing_chars(char *path, char c); + int devt2devname (char *, int, char *); ++dev_t parse_devt(const char *dev_t); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -459,7 +459,6 @@ main (int argc, char *argv[]) + out: + dm_udev_wait(conf->cookie); + +- sysfs_cleanup(); + dm_lib_release(); + dm_lib_exit(); + +Index: b/multipathd/Makefile +=================================================================== +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -6,7 +6,7 @@ include ../Makefile.inc + # basic flags setting + # + CFLAGS += -I$(multipathdir) +-LDFLAGS += -lpthread -ldevmapper -lreadline -ldl \ ++LDFLAGS += -lpthread -ldevmapper -lreadline -ldl -ludev \ + -lmultipath -L$(multipathdir) + + # +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + + #include "main.h" + #include "cli.h" +@@ -369,10 +371,15 @@ cli_add_path (void * v, char ** reply, i + if (pp->mpp) + return 0; + } else { ++ struct udev_device *udevice; ++ ++ udevice = udev_device_new_from_devnum(conf->udev, 'b', ++ parse_devt(pp->dev_t)); + pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- param, DI_ALL); ++ udevice, DI_ALL); + if (!pp) { + condlog(0, "%s: failed to store path info", param); ++ udev_device_unref(udevice); + return 1; + } + } +@@ -539,7 +546,7 @@ cli_resize(void *v, char **reply, int *l + + pgp = VECTOR_SLOT(mpp->pg, 0); + pp = VECTOR_SLOT(pgp->paths, 0); +- if (!pp->sysdev || sysfs_get_size(pp->sysdev->devpath, &size)) { ++ if (!pp->udev || sysfs_get_size(pp, &size)) { + condlog(0, "%s: couldn't get size for sysfs. cannot resize", + mapname); + return 1; +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -373,13 +374,17 @@ uev_add_path (struct uevent *uev, struct + if (pp->mpp) + return 0; + } else { ++ struct udev_device *udevice; ++ + /* + * get path vital state + */ ++ udevice = udev_device_ref(uev->udev); + if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- uev->kernel, DI_ALL))) { ++ udevice, DI_ALL))) { + condlog(0, "%s: failed to store path info", + uev->kernel); ++ udev_device_unref(udevice); + return 1; + } + pp->checkint = conf->checkint; +@@ -1509,8 +1514,6 @@ child (void * param) + pthread_cancel(uxlsnr_thr); + pthread_cancel(uevq_thr); + +- sysfs_cleanup(); +- + free_keys(keys); + keys = NULL; + free_handlers(handlers); diff -Nru multipath-tools-0.4.9/debian/patches/0033-discovery-Fixup-cciss-discovery.patch multipath-tools-0.4.9/debian/patches/0033-discovery-Fixup-cciss-discovery.patch --- multipath-tools-0.4.9/debian/patches/0033-discovery-Fixup-cciss-discovery.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0033-discovery-Fixup-cciss-discovery.patch 2015-07-28 19:22:40.000000000 +0000 @@ -0,0 +1,122 @@ +From ecf8e26d9a35e19727304fbe4d79b19d86cd059d Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:09:03 +0200 +Subject: [PATCH] discovery: Fixup cciss discovery + +We can get the sysfs attributes directly from the parent. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 78 ++++++++++++++++++++++++++++------------------- + 1 file changed, 47 insertions(+), 31 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -162,7 +162,7 @@ sysfs_get_timeout(struct path *pp, unsig + int r; + unsigned int t; + +- if (!pp->udev) ++ if (!pp->udev || pp->bus != SYSFS_BUS_SCSI) + return 1; + + parent = pp->udev; +@@ -673,26 +673,56 @@ ccw_sysfs_pathinfo (struct path * pp) + static int + cciss_sysfs_pathinfo (struct path * pp) + { +- const char * attr_path; ++ const char * attr_path = NULL; ++ struct udev_device *parent; ++ ++ parent = pp->udev; ++ while (parent) { ++ if (!strncmp(udev_device_get_subsystem(parent), "cciss", 5)) { ++ attr_path = udev_device_get_sysname(parent); ++ if (!attr_path) ++ break; ++ if (sscanf(attr_path, "c%id%i", ++ &pp->sg_id.host_no, ++ &pp->sg_id.scsi_id) == 2) ++ break; ++ } ++ parent = udev_device_get_parent(parent); ++ } ++ if (!attr_path || pp->sg_id.host_no == -1) ++ return 1; ++ ++ if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE)) ++ return 1; ++ ++ condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); ++ ++ if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE)) ++ return 1; ++ ++ condlog(3, "%s: product = %s", pp->dev, pp->product_id); ++ ++ if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE)) ++ return 1; ++ ++ condlog(3, "%s: rev = %s", pp->dev, pp->rev); + + /* +- * host / bus / target / lun ++ * set the hwe configlet pointer + */ +- attr_path = udev_device_get_devpath(pp->udev); +- if (!attr_path) +- return 1; ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev); + ++ /* ++ * host / bus / target / lun ++ */ + pp->sg_id.lun = 0; + pp->sg_id.channel = 0; +- sscanf(attr_path, "cciss!c%id%i", +- &pp->sg_id.host_no, +- &pp->sg_id.scsi_id); + condlog(3, "%s: h:b:t:l = %i:%i:%i:%i", +- pp->dev, +- pp->sg_id.host_no, +- pp->sg_id.channel, +- pp->sg_id.scsi_id, +- pp->sg_id.lun); ++ pp->dev, ++ pp->sg_id.host_no, ++ pp->sg_id.channel, ++ pp->sg_id.scsi_id, ++ pp->sg_id.lun); + return 0; + } + +@@ -800,23 +830,9 @@ scsi_ioctl_pathinfo (struct path * pp, i + static int + cciss_ioctl_pathinfo (struct path * pp, int mask) + { +- int ret; +- +- if (mask & DI_SYSFS) { +- ret = get_inq(pp->dev, pp->vendor_id, pp->product_id, +- pp->rev, pp->fd); +- if (ret) +- return ret; +- +- condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); +- condlog(3, "%s: product = %s", pp->dev, pp->product_id); +- condlog(3, "%s: revision = %s", pp->dev, pp->rev); +- /* +- * set the hwe configlet pointer +- */ +- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, +- pp->product_id, pp->rev); +- ++ if (mask & DI_SERIAL) { ++ get_serial(pp->serial, SERIAL_SIZE, pp->fd); ++ condlog(3, "%s: serial = %s", pp->dev, pp->serial); + } + return 0; + } diff -Nru multipath-tools-0.4.9/debian/patches/0035-Use-udev-devices-during-discovery.patch multipath-tools-0.4.9/debian/patches/0035-Use-udev-devices-during-discovery.patch --- multipath-tools-0.4.9/debian/patches/0035-Use-udev-devices-during-discovery.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0035-Use-udev-devices-during-discovery.patch 2015-07-28 20:48:19.000000000 +0000 @@ -0,0 +1,391 @@ +From a84042277d92bf2f999f19ad22c762306b252e83 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:09:05 +0200 +Subject: [PATCH] Use udev devices during discovery + +Remove all hand-crafted sysfs access code and replace it with +libudev functions. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/discovery.c | 309 +++++++++++++---------------------------------- + 1 file changed, 89 insertions(+), 220 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -192,127 +192,126 @@ sysfs_get_timeout(struct path *pp, unsig + } + + int +-sysfs_get_size (struct path *pp, unsigned long long * size) ++sysfs_get_tgt_nodename (struct path *pp, char * node) + { +- const char * attr; +- int r; +- +- if (!pp->udev) +- return 1; +- +- attr = udev_device_get_sysattr_value(pp->udev, "size"); +- if (!attr) { +- condlog(3, "%s: No size attribute in sysfs", pp->dev); +- return 1; +- } +- +- r = sscanf(attr, "%llu\n", size); ++ const char *targetid, *value; ++ struct udev_device *parent, *tgtdev; + +- if (r != 1) { +- condlog(3, "%s: Cannot parse size attribute '%s'", +- pp->dev, attr); ++ parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_device"); ++ if (!parent) + return 1; ++ /* Check for SAS */ ++ value = udev_device_get_sysattr_value(parent, "sas_address"); ++ if (value) { ++ strncpy(node, value, NODE_NAME_SIZE); ++ return 0; + } + +- return 0; +-} +- +-int +-sysfs_get_tgt_nodename (struct path *pp, char * node) +-{ +- const char * targetid; +- struct udev_device *parent; +- char attr_path[SYSFS_PATH_SIZE]; +- size_t len; +- +- parent = pp->udev; +- while (parent) { +- targetid = udev_device_get_sysname(parent); +- if (!strncmp(targetid , "target", 6)) +- break; +- parent = udev_device_get_parent(parent); +- } +- /* 'target' needs to exist */ +- if (!parent || !targetid) ++ parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target"); ++ if (!parent) + return 1; ++ tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_transport", udev_device_get_sysname(parent)); + /* Check if it's FibreChannel */ +- if (safe_sprintf(attr_path, +- "/class/fc_transport/%s", targetid)) { +- condlog(0, "attr_path too small"); +- return 1; +- } ++ if (tgtdev) { ++ const char *value; + +- len = sysfs_attr_get_value(attr_path, "node_name", +- node, NODE_NAME_SIZE); +- if (len) +- return 0; ++ value = udev_device_get_sysattr_value(tgtdev, "node_name"); ++ if (value) { ++ strncpy(node, value, NODE_NAME_SIZE); ++ return 0; ++ } ++ udev_device_unref(tgtdev); ++ } + + /* Check for iSCSI */ + parent = pp->udev; ++ targetid = NULL; + while (parent) { + targetid = udev_device_get_sysname(parent); + if (!strncmp(targetid , "session", 6)) + break; + parent = udev_device_get_parent(parent); ++ targetid = NULL; + } + if (parent) { +- if (safe_sprintf(attr_path, "/class/iscsi_session/%s", +- targetid)) { +- condlog(0, "attr_path too small"); +- return 1; ++ tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "iscsi_session", targetid); ++ if (node) { ++ const char *value; ++ ++ value = udev_device_get_sysattr_value(tgtdev, "targetname"); ++ if (value) { ++ strncpy(node, value, NODE_NAME_SIZE); ++ return 0; ++ } ++ udev_device_unref(tgtdev); + } +- len = sysfs_attr_get_value(attr_path, "targetname", node, +- NODE_NAME_SIZE); +- if (len) +- return 0; + } +- + return 1; + } + +-static int +-find_rport_id(struct path *pp) ++static void ++sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) + { +- char attr_path[SYSFS_PATH_SIZE]; +- char *dir, *base; +- int host, channel, rport_id = -1; +- +- if (safe_sprintf(attr_path, +- "/class/fc_transport/target%i:%i:%i", +- pp->sg_id.host_no, pp->sg_id.channel, +- pp->sg_id.scsi_id)) { +- condlog(0, "attr_path too small for target"); +- return 1; +- } +- +- if (sysfs_resolve_link(attr_path, SYSFS_PATH_SIZE)) +- return -1; +- +- condlog(4, "target%d:%d:%d -> path %s", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id, attr_path); +- dir = attr_path; +- do { +- base = basename(dir); +- dir = dirname(dir); ++ struct udev_device *parent = pp->udev; ++ struct udev_device *rport_dev = NULL; ++ char value[11]; ++ const char *rport_id = NULL; + +- if (sscanf((const char *)base, "rport-%d:%d-%d", &host, &channel, &rport_id) == 3) ++ while (parent) { ++ rport_id = udev_device_get_sysname(parent); ++ if (!strncmp(rport_id, "rport-", 6)) + break; +- } while (strcmp((const char *)dir, "/")); +- +- if (rport_id < 0) +- return -1; +- +- condlog(4, "target%d:%d:%d -> rport_id %d", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id, rport_id); +- return rport_id; ++ parent = udev_device_get_parent(parent); ++ rport_id = NULL; ++ } ++ if (!parent || !rport_id) { ++ condlog(0, "%s: rport id not found", pp->dev); ++ return; ++ } ++ rport_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_remote_ports", rport_id); ++ if (!rport_dev) { ++ condlog(3, "%s: No fc_remote_port device for '%s'", pp->dev, ++ rport_id); ++ return; ++ } ++ condlog(4, "target%d:%d:%d -> %s", pp->sg_id.host_no, ++ pp->sg_id.channel, pp->sg_id.scsi_id, rport_id); ++ ++ snprintf(value, 11, "%u", mpp->dev_loss); ++ if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo", value, 11) < 0) { ++ if ((!mpp->fast_io_fail || ++ mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) ++ && mpp->dev_loss > 600) { ++ condlog(3, "%s: limiting dev_loss_tmo to 600, since " ++ "fast_io_fail is not set", mpp->alias); ++ snprintf(value, 11, "%u", 600); ++ if (sysfs_attr_set_value(rport_dev, "dev_loss_tmo", ++ value, 11) < 0) ++ condlog(0, "%s failed to set dev_loss_tmo", ++ mpp->alias); ++ return; ++ } ++ } ++ if (mpp->fast_io_fail){ ++ if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) ++ sprintf(value, "off"); ++ else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) ++ sprintf(value, "0"); ++ else ++ snprintf(value, 11, "%u", mpp->fast_io_fail); ++ if (sysfs_attr_set_value(rport_dev, "fast_io_fail_tmo", ++ value, 11) < 0) { ++ condlog(0, "%s failed to set fast_io_fail_tmo", ++ mpp->alias); ++ } ++ } + } + + int + sysfs_set_scsi_tmo (struct multipath *mpp) + { +- char attr_path[SYSFS_PATH_SIZE]; + struct path *pp; + int i; +- char value[11]; +- int rport_id; + int dev_loss_tmo = mpp->dev_loss; + + if (mpp->no_path_retry > 0) { +@@ -339,75 +338,11 @@ sysfs_set_scsi_tmo (struct multipath *mp + return 0; + + vector_foreach_slot(mpp->paths, pp, i) { +- rport_id = find_rport_id(pp); +- if (rport_id < 0) { +- condlog(0, "failed to find rport_id for target%d:%d:%d", pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id); +- return 1; +- } +- +- if (safe_snprintf(attr_path, SYSFS_PATH_SIZE, +- "/class/fc_remote_ports/rport-%d:%d-%d", +- pp->sg_id.host_no, pp->sg_id.channel, +- rport_id)) { +- condlog(0, "attr_path '/class/fc_remote_ports/rport-%d:%d-%d' too large", pp->sg_id.host_no, pp->sg_id.channel, rport_id); +- return 1; +- } +- if (mpp->dev_loss){ +- snprintf(value, 11, "%u", mpp->dev_loss); +- if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", +- value, 11) < 0) { +- int err = 1; +- if ((!mpp->fast_io_fail || mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) && mpp->dev_loss > 600) { +- strncpy(value, "600", 4); +- condlog(3, "%s: limiting dev_loss_tmo to 600, since fast_io_fail is not set", mpp->alias); +- if (sysfs_attr_set_value(attr_path, "dev_loss_tmo", value, 11) >= 0) +- err = 0; +- } +- if (err) { +- condlog(0, "%s failed to set %s/dev_loss_tmo", mpp->alias, attr_path); +- return 1; +- } +- } +- } +- if (mpp->fast_io_fail){ +- if (mpp->fast_io_fail == MP_FAST_IO_FAIL_OFF) +- sprintf(value, "off"); +- else if (mpp->fast_io_fail == MP_FAST_IO_FAIL_ZERO) +- sprintf(value, "0"); +- else +- snprintf(value, 11, "%u", mpp->fast_io_fail); +- if (sysfs_attr_set_value(attr_path, "fast_io_fail_tmo", +- value, 11) < 0) { +- condlog(0, +- "%s failed to set %s/fast_io_fail_tmo", +- mpp->alias, attr_path); +- return 1; +- } +- } ++ sysfs_set_rport_tmo(mpp, pp); + } + return 0; + } + +-static int +-opennode (char * dev, int mode) +-{ +- char devpath[FILE_NAME_SIZE], *ptr; +- +- if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) { +- condlog(0, "devpath too small"); +- return -1; +- } +- /* +- * Translate '!' into '/' +- */ +- ptr = devpath; +- while ((ptr = strchr(ptr, '!'))) { +- *ptr = '/'; +- ptr++; +- } +- return open(devpath, mode); +-} +- + int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len) +@@ -483,72 +418,6 @@ get_serial (char * str, int maxlen, int + } + + static int +-get_inq (char * dev, char * vendor, char * product, char * rev, int fd) +-{ +- unsigned char buff[MX_ALLOC_LEN + 1] = {0}; +- int len; +- +- if (fd < 0) +- return 1; +- +- if (0 != do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN)) +- return 1; +- +- /* Check peripheral qualifier */ +- if ((buff[0] >> 5) != 0) { +- int pqual = (buff[0] >> 5); +- switch (pqual) { +- case 1: +- condlog(3, "%s: INQUIRY failed, LU not connected", dev); +- break; +- case 3: +- condlog(3, "%s: INQUIRY failed, LU not supported", dev); +- break; +- default: +- condlog(3, "%s: INQUIRY failed, Invalid PQ %x", +- dev, pqual); +- break; +- } +- +- return 1; +- } +- +- len = buff[4] + 4; +- +- if (len < 8) { +- condlog(3, "%s: INQUIRY response too short (len %d)", +- dev, len); +- return 1; +- } +- +- len -= 8; +- memset(vendor, 0x0, 8); +- memcpy(vendor, buff + 8, len > 8 ? 8 : len); +- vendor[8] = '\0'; +- strchop(vendor); +- if (len <= 8) +- return 0; +- +- len -= 8; +- +- memset(product, 0x0, 16); +- memcpy(product, buff + 16, len > 16 ? 16 : len); +- product[16] = '\0'; +- strchop(product); +- if (len <= 16) +- return 0; +- +- len -= 16; +- +- memset(rev, 0x0, 4); +- memcpy(rev, buff + 32, 4); +- rev[4] = '\0'; +- strchop(rev); +- +- return 0; +-} +- +-static int + scsi_sysfs_pathinfo (struct path * pp) + { + struct udev_device *parent; +@@ -947,7 +816,7 @@ pathinfo (struct path *pp, vector hwtabl + * fetch info not available through sysfs + */ + if (pp->fd < 0) +- pp->fd = opennode(pp->dev, O_RDONLY); ++ pp->fd = open(udev_device_get_devnode(pp->udev), O_RDWR); + + if (pp->fd < 0) { + condlog(4, "Couldn't open node for %s: %s", diff -Nru multipath-tools-0.4.9/debian/patches/0036-Remove-all-references-to-hand-craftes-sysfs-code.patch multipath-tools-0.4.9/debian/patches/0036-Remove-all-references-to-hand-craftes-sysfs-code.patch --- multipath-tools-0.4.9/debian/patches/0036-Remove-all-references-to-hand-craftes-sysfs-code.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0036-Remove-all-references-to-hand-craftes-sysfs-code.patch 2015-07-28 20:48:24.000000000 +0000 @@ -0,0 +1,308 @@ +From 4a0b1d0f58c620173f902ed19c0a82c8818dff00 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 19 Apr 2012 11:09:06 +0200 +Subject: [PATCH] Remove all references to hand-craftes sysfs code + +We've now converted everything to libudev, so we can get rid +of all the variables etc. + +Signed-off-by: Hannes Reinecke +--- + libmultipath/config.c | 7 --- + libmultipath/config.h | 3 - + libmultipath/dict.c | 26 ------------ + libmultipath/structs_vec.c | 1 + libmultipath/sysfs.c | 92 --------------------------------------------- + libmultipath/sysfs.h | 21 +--------- + multipath/main.c | 4 - + multipath/multipath.conf.5 | 4 - + multipathd/main.c | 4 - + 9 files changed, 5 insertions(+), 157 deletions(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -421,9 +421,6 @@ free_config (struct config * conf) + if (conf->udev) + udev_unref(conf->udev); + +- if (conf->udev_dir) +- FREE(conf->udev_dir); +- + if (conf->multipath_dir) + FREE(conf->multipath_dir); + +@@ -571,10 +568,8 @@ load_config (char * file) + if (!conf->mptable) + goto out; + } +- if (conf->udev_dir == NULL) +- conf->udev_dir = set_default(DEFAULT_UDEVDIR); + +- if (!conf->udev_dir || !conf->multipath_dir) ++ if (!conf->multipath_dir) + goto out; + + return 0; +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -69,7 +69,6 @@ struct config { + int dry_run; + int list; + int pgpolicy_flag; +- int with_sysfs; + int pgpolicy; + enum devtypes dev_type; + int minio; +@@ -97,8 +96,6 @@ struct config { + + char * dev; + struct udev * udev; +- char * sysfs_dir; +- char * udev_dir; + char * multipath_dir; + char * selector; + char * getuid; +Index: b/libmultipath/dict.c +=================================================================== +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -79,17 +79,6 @@ verbosity_handler(vector strvec) + } + + static int +-udev_dir_handler(vector strvec) +-{ +- conf->udev_dir = set_value(strvec); +- +- if (!conf->udev_dir) +- return 1; +- +- return 0; +-} +- +-static int + multipath_dir_handler(vector strvec) + { + conf->multipath_dir = set_value(strvec); +@@ -1840,21 +1829,9 @@ snprint_def_verbosity (char * buff, int + } + + static int +-snprint_def_udev_dir (char * buff, int len, void * data) +-{ +- if (!conf->udev_dir) +- return 0; +- if (strlen(DEFAULT_UDEVDIR) == strlen(conf->udev_dir) && +- !strcmp(conf->udev_dir, DEFAULT_UDEVDIR)) +- return 0; +- +- return snprintf(buff, len, "\"%s\"", conf->udev_dir); +-} +- +-static int + snprint_def_multipath_dir (char * buff, int len, void * data) + { +- if (!conf->udev_dir) ++ if (!conf->multipath_dir) + return 0; + if (strlen(DEFAULT_MULTIPATHDIR) == strlen(conf->multipath_dir) && + !strcmp(conf->multipath_dir, DEFAULT_MULTIPATHDIR)) +@@ -2143,7 +2120,6 @@ init_keywords(void) + install_keyword_root("defaults", NULL); + install_keyword("verbosity", &verbosity_handler, &snprint_def_verbosity); + install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval); +- install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir); + install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir); + install_keyword("selector", &def_selector_handler, &snprint_def_selector); + install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy); +Index: b/libmultipath/structs_vec.c +=================================================================== +--- a/libmultipath/structs_vec.c ++++ b/libmultipath/structs_vec.c +@@ -13,7 +13,6 @@ + #include "dmparser.h" + #include "config.h" + #include "propsel.h" +-#include "sysfs.h" + #include "discovery.h" + #include "prio.h" + +Index: b/libmultipath/sysfs.h +=================================================================== +--- a/libmultipath/sysfs.h ++++ b/libmultipath/sysfs.h +@@ -5,22 +5,7 @@ + #ifndef _LIBMULTIPATH_SYSFS_H + #define _LIBMULTIPATH_SYSFS_H + +-#ifdef DEBUG +-# define dbg(format, args...) condlog(4, format, ##args) +-#else +-# define dbg(format, args...) do {} while (0) +-#endif +- +-int sysfs_init(char *path, size_t len); +-void sysfs_cleanup(void); +-struct sysfs_device *sysfs_device_get(const char *devpath); +-struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); +-void sysfs_device_put(struct sysfs_device *dev); +-struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev); +-size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, +- char *attr_value, int attr_len); +-ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, +- const char *value, int value_len); +-int sysfs_resolve_link(char *path, size_t size); +-int sysfs_get_size(struct path *pp, unsigned long long * size); ++ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, ++ char * value, size_t value_len); ++int sysfs_get_size (struct path *pp, unsigned long long * size); + #endif +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -349,10 +349,6 @@ main (int argc, char *argv[]) + condlog(0, "failed to initialize prioritizers"); + exit(1); + } +- if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { +- condlog(0, "multipath tools need sysfs mounted"); +- exit(1); +- } + while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:r")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); +Index: b/multipath/multipath.conf.5 +=================================================================== +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -72,10 +72,6 @@ the interval between checks will gradual + default is + .I 5 + .TP +-.B udev_dir +-directory where udev creates its device nodes; default is +-.I /dev +-.TP + .B verbosity + default verbosity. Higher values increase the verbosity level. Valid + levels are between 0 and 6; default is +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -1454,10 +1454,6 @@ child (void * param) + if (!vecs) + exit(1); + +- if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { +- condlog(0, "can not find sysfs mount point"); +- exit(1); +- } + conf->daemon = 1; + dm_udev_set_sync_support(0); + /* +Index: b/libmultipath/sysfs.c +=================================================================== +--- a/libmultipath/sysfs.c ++++ b/libmultipath/sysfs.c +@@ -109,95 +109,3 @@ sysfs_get_size (struct path *pp, unsigne + + return 0; + } +- +-int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, +- const char *subsystem, const char *id) +-{ +- size_t sysfs_len; +- char path_full[PATH_SIZE]; +- char *path; +- struct stat statbuf; +- +- sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); +- path = &path_full[sysfs_len]; +- +- if (strcmp(subsystem, "subsystem") == 0) { +- strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- +- strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- goto out; +- +- strlcpy(path, "/class/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- } +- +- if (strcmp(subsystem, "module") == 0) { +- strlcpy(path, "/module/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- goto out; +- } +- +- if (strcmp(subsystem, "drivers") == 0) { +- char subsys[NAME_SIZE]; +- char *driver; +- +- strlcpy(subsys, id, sizeof(subsys)); +- driver = strchr(subsys, ':'); +- if (driver != NULL) { +- driver[0] = '\0'; +- driver = &driver[1]; +- strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); +- strlcat(path, subsys, sizeof(path_full) - sysfs_len); +- strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len); +- strlcat(path, driver, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- +- strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); +- strlcat(path, subsys, sizeof(path_full) - sysfs_len); +- strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len); +- strlcat(path, driver, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- } +- goto out; +- } +- +- strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); +- strlcat(path, subsystem, sizeof(path_full) - sysfs_len); +- strlcat(path, "/devices/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- +- strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); +- strlcat(path, subsystem, sizeof(path_full) - sysfs_len); +- strlcat(path, "/devices/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +- +- strlcpy(path, "/class/", sizeof(path_full) - sysfs_len); +- strlcat(path, subsystem, sizeof(path_full) - sysfs_len); +- strlcat(path, "/", sizeof(path_full) - sysfs_len); +- strlcat(path, id, sizeof(path_full) - sysfs_len); +- if (stat(path_full, &statbuf) == 0) +- goto found; +-out: +- return 0; +-found: +- if (S_ISLNK(statbuf.st_mode)) +- sysfs_resolve_link(path, sizeof(path_full) - sysfs_len); +- strlcpy(devpath_full, path, len); +- return 1; +-} diff -Nru multipath-tools-0.4.9/debian/patches/0037-multipath-libudev-cleanup-and-bugfixes.patch multipath-tools-0.4.9/debian/patches/0037-multipath-libudev-cleanup-and-bugfixes.patch --- multipath-tools-0.4.9/debian/patches/0037-multipath-libudev-cleanup-and-bugfixes.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0037-multipath-libudev-cleanup-and-bugfixes.patch 2015-07-29 20:31:30.000000000 +0000 @@ -0,0 +1,492 @@ +From a00088a0162fe96d647c42902a9f86c4950b907f Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Tue, 5 Jun 2012 18:04:36 -0500 +Subject: [PATCH] multipath: libudev cleanup and bugfixes + +get_refwwid wasn't working anymore, since it wasn't setting the path's udevice. +Also, cli_add_path was dereferencing a NULL pointer (pp). Finally, there were +a number of places where udev devices weren't getting dereferenced when they +should have been, causing memory leaks. This patch cleans these up. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 9 +++------ + libmultipath/config.h | 2 +- + libmultipath/configure.c | 42 +++++++++++++++++++----------------------- + libmultipath/discovery.c | 10 ++++++---- + libmultipath/uevent.c | 29 +++++++++++++++++------------ + libmultipath/uevent.h | 4 +++- + multipath/Makefile | 2 +- + multipath/main.c | 12 +++++++++--- + multipathd/cli_handlers.c | 8 +++++--- + multipathd/main.c | 22 +++++++++++++--------- + 10 files changed, 77 insertions(+), 63 deletions(-) + +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "checkers.h" + #include "vector.h" +@@ -608,18 +609,17 @@ get_refwwid (char * dev, enum devtypes d + + pp = find_path_by_dev(pathvec, buff); + if (!pp) { +- pp = alloc_path(); ++ struct udev_device *udevice = udev_device_new_from_subsystem_sysname(conf->udev, "block", buff); + +- if (!pp) ++ if (!udevice) { ++ condlog(2, "%s: can't get udev device", buff); + return NULL; +- +- strncpy(pp->dev, buff, FILE_NAME_SIZE); +- +- if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID)) +- return NULL; +- +- if (store_path(pathvec, pp)) { +- free_path(pp); ++ } ++ pp = store_pathinfo(pathvec, conf->hwtable, udevice, ++ DI_SYSFS | DI_WWID); ++ udev_device_unref(udevice); ++ if (!pp) { ++ condlog(0, "%s can't store path info", buff); + return NULL; + } + } +@@ -630,21 +630,17 @@ get_refwwid (char * dev, enum devtypes d + if (dev_type == DEV_DEVT) { + pp = find_path_by_devt(pathvec, dev); + if (!pp) { +- if (devt2devname(buff, FILE_NAME_SIZE, dev)) +- return NULL; ++ struct udev_device *udevice = udev_device_new_from_devnum(conf->udev, 'b', parse_devt(dev)); + +- pp = alloc_path(); +- +- if (!pp) +- return NULL; +- +- strncpy(pp->dev, buff, FILE_NAME_SIZE); +- +- if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID)) ++ if (!udevice) { ++ condlog(2, "%s: can't get udev device", dev); + return NULL; +- +- if (store_path(pathvec, pp)) { +- free_path(pp); ++ } ++ pp = store_pathinfo(pathvec, conf->hwtable, udevice, ++ DI_SYSFS | DI_WWID); ++ udev_device_unref(udevice); ++ if (!pp) { ++ condlog(0, "%s can't store path info", buff); + return NULL; + } + } +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -216,11 +216,11 @@ sysfs_get_tgt_nodename (struct path *pp, + const char *value; + + value = udev_device_get_sysattr_value(tgtdev, "node_name"); ++ udev_device_unref(tgtdev); + if (value) { + strncpy(node, value, NODE_NAME_SIZE); + return 0; + } +- udev_device_unref(tgtdev); + } + + /* Check for iSCSI */ +@@ -235,15 +235,15 @@ sysfs_get_tgt_nodename (struct path *pp, + } + if (parent) { + tgtdev = udev_device_new_from_subsystem_sysname(conf->udev, "iscsi_session", targetid); +- if (node) { ++ if (tgtdev) { + const char *value; + + value = udev_device_get_sysattr_value(tgtdev, "targetname"); ++ udev_device_unref(tgtdev); + if (value) { + strncpy(node, value, NODE_NAME_SIZE); + return 0; + } +- udev_device_unref(tgtdev); + } + } + return 1; +@@ -289,7 +289,7 @@ sysfs_set_rport_tmo(struct multipath *mp + value, 11) < 0) + condlog(0, "%s failed to set dev_loss_tmo", + mpp->alias); +- return; ++ goto out; + } + } + if (mpp->fast_io_fail){ +@@ -305,6 +305,8 @@ sysfs_set_rport_tmo(struct multipath *mp + mpp->alias); + } + } ++out: ++ udev_device_unref(rport_dev); + } + + int +Index: b/libmultipath/uevent.c +=================================================================== +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -47,14 +47,15 @@ + #include "list.h" + #include "uevent.h" + #include "vector.h" +-#include "config.h" + + typedef int (uev_trigger)(struct uevent *, void * trigger_data); + + pthread_t uevq_thr; + LIST_HEAD(uevq); +-pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock; +-pthread_cond_t uev_cond, *uev_condp = &uev_cond; ++pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER; ++pthread_mutex_t *uevq_lockp = &uevq_lock; ++pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER; ++pthread_cond_t *uev_condp = &uev_cond; + uev_trigger *my_uev_trigger; + void * my_trigger_data; + int servicing_uev; +@@ -125,11 +126,14 @@ service_uevq(struct list_head *tmpq) + + static void uevq_stop(void *arg) + { ++ struct udev *udev = arg; ++ + condlog(3, "Stopping uev queue"); + pthread_mutex_lock(uevq_lockp); + my_uev_trigger = NULL; + pthread_cond_signal(uev_condp); + pthread_mutex_unlock(uevq_lockp); ++ udev_unref(udev); + } + + /* +@@ -376,7 +380,7 @@ exit: + return 1; + } + +-int uevent_listen(void) ++int uevent_listen(struct udev *udev) + { + int err; + struct udev_monitor *monitor = NULL; +@@ -388,15 +392,17 @@ int uevent_listen(void) + * thereby not getting to empty the socket's receive buffer queue + * often enough. + */ +- INIT_LIST_HEAD(&uevq); +- +- pthread_mutex_init(uevq_lockp, NULL); +- pthread_cond_init(uev_condp, NULL); +- pthread_cleanup_push(uevq_stop, NULL); ++ if (!udev) { ++ condlog(1, "no udev context"); ++ return 1; ++ } ++ udev_ref(udev); ++ pthread_cleanup_push(uevq_stop, udev); + +- monitor = udev_monitor_new_from_netlink(conf->udev, "udev"); ++ monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!monitor) { + condlog(2, "failed to create udev monitor"); ++ err = 2; + goto out; + } + if (udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024)) +@@ -441,6 +447,7 @@ int uevent_listen(void) + + uev = alloc_uevent(); + if (!uev) { ++ udev_device_unref(dev); + condlog(1, "lost uevent, oom"); + continue; + } +@@ -501,8 +508,6 @@ out: + if (need_failback) + err = failback_listen(); + pthread_cleanup_pop(1); +- pthread_mutex_destroy(uevq_lockp); +- pthread_cond_destroy(uev_condp); + return err; + } + +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -373,15 +373,17 @@ cli_add_path (void * v, char ** reply, i + } else { + struct udev_device *udevice; + +- udevice = udev_device_new_from_devnum(conf->udev, 'b', +- parse_devt(pp->dev_t)); ++ udevice = udev_device_new_from_subsystem_sysname(conf->udev, ++ "block", ++ param); + pp = store_pathinfo(vecs->pathvec, conf->hwtable, + udevice, DI_ALL); ++ udev_device_unref(udevice); + if (!pp) { + condlog(0, "%s: failed to store path info", param); +- udev_device_unref(udevice); + return 1; + } ++ pp->checkint = conf->checkint; + } + r = ev_add_path(pp, vecs); + if (r == 2) +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -79,6 +79,8 @@ int logsink; + */ + struct vectors * gvecs; + ++struct udev * udev; ++ + static int + need_switch_pathgroup (struct multipath * mpp, int refresh) + { +@@ -374,17 +376,13 @@ uev_add_path (struct uevent *uev, struct + if (pp->mpp) + return 0; + } else { +- struct udev_device *udevice; +- + /* + * get path vital state + */ +- udevice = udev_device_ref(uev->udev); + if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- udevice, DI_ALL))) { ++ uev->udev, DI_ALL))) { + condlog(0, "%s: failed to store path info", + uev->kernel); +- udev_device_unref(udevice); + return 1; + } + pp->checkint = conf->checkint; +@@ -792,10 +790,12 @@ out: + static void * + ueventloop (void * ap) + { ++ struct udev *udev = ap; ++ + block_signal(SIGUSR1, NULL); + block_signal(SIGHUP, NULL); + +- if (uevent_listen()) ++ if (uevent_listen(udev)) + condlog(0, "error starting uevent listener"); + + return NULL; +@@ -1258,7 +1258,7 @@ reconfigure (struct vectors * vecs) + vecs->pathvec = NULL; + conf = NULL; + +- if (load_config(DEFAULT_CONFIGFILE)) ++ if (load_config(DEFAULT_CONFIGFILE, udev)) + return 1; + + conf->verbosity = old->verbosity; +@@ -1396,6 +1396,8 @@ child (void * param) + + mlockall(MCL_CURRENT | MCL_FUTURE); + ++ udev = udev_new(); ++ + setup_thread_attr(&misc_attr, 64 * 1024, 1); + setup_thread_attr(&waiter_attr, 32 * 1024, 1); + +@@ -1408,7 +1410,7 @@ child (void * param) + condlog(2, "--------start up--------"); + condlog(2, "read " DEFAULT_CONFIGFILE); + +- if (load_config(DEFAULT_CONFIGFILE)) ++ if (load_config(DEFAULT_CONFIGFILE, udev)) + exit(1); + + if (init_checkers()) { +@@ -1459,7 +1461,7 @@ child (void * param) + /* + * Start uevent listener early to catch events + */ +- if ((rc = pthread_create(&uevent_thr, &misc_attr, ueventloop, vecs))) { ++ if ((rc = pthread_create(&uevent_thr, &misc_attr, ueventloop, udev))) { + condlog(0, "failed to create uevent thread: %d", rc); + exit(1); + } +@@ -1550,6 +1552,8 @@ child (void * param) + free_config(conf); + conf = NULL; + ++ udev_unref(udev); ++ udev = NULL; + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +Index: b/libmultipath/uevent.h +=================================================================== +--- a/libmultipath/uevent.h ++++ b/libmultipath/uevent.h +@@ -13,6 +13,8 @@ + #define NETLINK_KOBJECT_UEVENT 15 + #endif + ++struct udev; ++ + struct uevent { + struct list_head node; + struct udev_device *udev; +@@ -26,7 +28,7 @@ struct uevent { + int is_uevent_busy(void); + void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached); + +-int uevent_listen(void); ++int uevent_listen(struct udev *udev); + int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), + void * trigger_data); + int uevent_get_major(struct uevent *uev); +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -418,9 +418,6 @@ free_config (struct config * conf) + if (conf->dev) + FREE(conf->dev); + +- if (conf->udev) +- udev_unref(conf->udev); +- + if (conf->multipath_dir) + FREE(conf->multipath_dir); + +@@ -460,12 +457,12 @@ free_config (struct config * conf) + } + + int +-load_config (char * file) ++load_config (char * file, struct udev *udev) + { + if (!conf) + conf = alloc_config(); + +- if (!conf) ++ if (!conf || !udev) + return 1; + + /* +@@ -474,7 +471,7 @@ load_config (char * file) + if (!conf->verbosity) + conf->verbosity = DEFAULT_VERBOSITY; + +- conf->udev = udev_new(); ++ conf->udev = udev; + conf->dev_type = DEV_NONE; + conf->minio = 1000; + conf->max_fds = 0; +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -134,7 +134,7 @@ void free_mptable (vector mptable); + + int store_hwe (vector hwtable, struct hwentry *); + +-int load_config (char * file); ++int load_config (char * file, struct udev * udev); + struct config * alloc_config (void); + void free_config (struct config * conf); + +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -325,6 +326,7 @@ out: + int + main (int argc, char *argv[]) + { ++ struct udev *udev; + int arg; + extern char *optarg; + extern int optind; +@@ -335,19 +337,21 @@ main (int argc, char *argv[]) + exit(1); + } + ++ udev = udev_new(); ++ + if (dm_prereq()) + exit(1); + +- if (load_config(DEFAULT_CONFIGFILE)) ++ if (load_config(DEFAULT_CONFIGFILE, udev)) + exit(1); + + if (init_checkers()) { + condlog(0, "failed to initialize checkers"); +- exit(1); ++ goto out; + } + if (init_prio()) { + condlog(0, "failed to initialize prioritizers"); +- exit(1); ++ goto out; + } + while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:r")) != EOF ) { + switch(arg) { +@@ -468,6 +472,8 @@ out: + free_config(conf); + conf = NULL; + ++ udev_unref(udev); ++ + #ifdef _DEBUG_ + dbg_free_final(NULL); + #endif +Index: b/multipath/Makefile +=================================================================== +--- a/multipath/Makefile ++++ b/multipath/Makefile +@@ -7,7 +7,7 @@ include ../Makefile.inc + OBJS = main.o + + CFLAGS += -I$(multipathdir) +-LDFLAGS += -lpthread -ldevmapper -ldl -lmultipath -L$(multipathdir) ++LDFLAGS += -lpthread -ldevmapper -ldl -ludev -lmultipath -L$(multipathdir) + + EXEC = multipath + diff -Nru multipath-tools-0.4.9/debian/patches/0038-multipath-check-if-a-device-belongs-to-multipath.patch multipath-tools-0.4.9/debian/patches/0038-multipath-check-if-a-device-belongs-to-multipath.patch --- multipath-tools-0.4.9/debian/patches/0038-multipath-check-if-a-device-belongs-to-multipath.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0038-multipath-check-if-a-device-belongs-to-multipath.patch 2015-07-29 20:19:28.000000000 +0000 @@ -0,0 +1,756 @@ +From 374ad934a915767b1fee81a9362e3522833a5fa8 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 27 Jul 2012 15:55:24 -0500 +Subject: [PATCH] multipath: check if a device belongs to multipath + +This patch adds a new multipath option "-c", which checks if a device +belongs to multipath. This can be done during the add uevent for the +device, before the multipath device has even been created. This allows +udev to be able to handle multipath path devices differently. To do +this multipath now keeps track of the wwids of all previously created +multipath devices in /etc/multipath/wwids. The file creating and +editting code from alias.[ch] has been split out into file.[ch]. When a +device is checked to see if it's a multipath path, it's wwid is +compared against the ones in the wwids file. Also, since the +uid_attribute may not have been added to the udev database entry for +the device if this is called in a udev rule, when using the "-c" option, +get_uid will now also check the process' envirionment variables for the +uid_attribute. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/Makefile | 2 + libmultipath/alias.c | 152 --------------------------------------- + libmultipath/alias.h | 1 + libmultipath/configure.c | 3 + libmultipath/defaults.h | 1 + libmultipath/file.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/file.h | 11 ++ + libmultipath/wwids.c | 139 ++++++++++++++++++++++++++++++++++++ + libmultipath/wwids.h | 18 ++++ + multipath/main.c | 36 ++++++++- + 10 files changed, 387 insertions(+), 156 deletions(-) + create mode 100644 libmultipath/file.c + create mode 100644 libmultipath/file.h + create mode 100644 libmultipath/wwids.c + create mode 100644 libmultipath/wwids.h + +Index: b/libmultipath/Makefile +=================================================================== +--- a/libmultipath/Makefile ++++ b/libmultipath/Makefile +@@ -15,7 +15,7 @@ OBJS = memory.o parser.o vector.o devmap + pgpolicies.o debug.o regex.o defaults.o uevent.o \ + switchgroup.o uxsock.o print.o alias.o log_pthread.o \ + log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \ +- lock.o waiter.o ++ lock.o waiter.o file.o wwids.o + + LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h) + +Index: b/libmultipath/alias.c +=================================================================== +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -3,19 +3,16 @@ + * Copyright (c) 2005 Benjamin Marzinski, Redhat + */ + #include +-#include +-#include +-#include + #include + #include + #include + #include + #include +-#include + + #include "debug.h" + #include "uxsock.h" + #include "alias.h" ++#include "file.h" + + + /* +@@ -37,149 +34,6 @@ + */ + + static int +-ensure_directories_exist(char *str, mode_t dir_mode) +-{ +- char *pathname; +- char *end; +- int err; +- +- pathname = strdup(str); +- if (!pathname){ +- condlog(0, "Cannot copy bindings file pathname : %s", +- strerror(errno)); +- return -1; +- } +- end = pathname; +- /* skip leading slashes */ +- while (end && *end && (*end == '/')) +- end++; +- +- while ((end = strchr(end, '/'))) { +- /* if there is another slash, make the dir. */ +- *end = '\0'; +- err = mkdir(pathname, dir_mode); +- if (err && errno != EEXIST) { +- condlog(0, "Cannot make directory [%s] : %s", +- pathname, strerror(errno)); +- free(pathname); +- return -1; +- } +- if (!err) +- condlog(3, "Created dir [%s]", pathname); +- *end = '/'; +- end++; +- } +- free(pathname); +- return 0; +-} +- +-static void +-sigalrm(int sig) +-{ +- /* do nothing */ +-} +- +-static int +-lock_bindings_file(int fd) +-{ +- struct sigaction act, oldact; +- sigset_t set, oldset; +- struct flock lock; +- int err; +- +- memset(&lock, 0, sizeof(lock)); +- lock.l_type = F_WRLCK; +- lock.l_whence = SEEK_SET; +- +- act.sa_handler = sigalrm; +- sigemptyset(&act.sa_mask); +- act.sa_flags = 0; +- sigemptyset(&set); +- sigaddset(&set, SIGALRM); +- +- sigaction(SIGALRM, &act, &oldact); +- sigprocmask(SIG_UNBLOCK, &set, &oldset); +- +- alarm(BINDINGS_FILE_TIMEOUT); +- err = fcntl(fd, F_SETLKW, &lock); +- alarm(0); +- +- if (err) { +- if (errno != EINTR) +- condlog(0, "Cannot lock bindings file : %s", +- strerror(errno)); +- else +- condlog(0, "Bindings file is locked. Giving up."); +- } +- +- sigprocmask(SIG_SETMASK, &oldset, NULL); +- sigaction(SIGALRM, &oldact, NULL); +- return err; +- +-} +- +- +-static int +-open_bindings_file(char *file, int *can_write) +-{ +- int fd; +- struct stat s; +- +- if (ensure_directories_exist(file, 0700)) +- return -1; +- *can_write = 1; +- fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); +- if (fd < 0) { +- if (errno == EROFS) { +- *can_write = 0; +- condlog(3, "Cannot open bindings file [%s] read/write. " +- " trying readonly", file); +- fd = open(file, O_RDONLY); +- if (fd < 0) { +- condlog(0, "Cannot open bindings file [%s] " +- "readonly : %s", file, strerror(errno)); +- return -1; +- } +- } +- else { +- condlog(0, "Cannot open bindings file [%s] : %s", file, +- strerror(errno)); +- return -1; +- } +- } +- if (*can_write && lock_bindings_file(fd) < 0) +- goto fail; +- +- memset(&s, 0, sizeof(s)); +- if (fstat(fd, &s) < 0){ +- condlog(0, "Cannot stat bindings file : %s", strerror(errno)); +- goto fail; +- } +- if (s.st_size == 0) { +- if (*can_write == 0) +- goto fail; +- /* If bindings file is empty, write the header */ +- size_t len = strlen(BINDINGS_FILE_HEADER); +- if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) { +- condlog(0, +- "Cannot write header to bindings file : %s", +- strerror(errno)); +- /* cleanup partially written header */ +- ftruncate(fd, 0); +- goto fail; +- } +- fsync(fd); +- condlog(3, "Initialized new bindings file [%s]", file); +- } +- +- return fd; +- +-fail: +- close(fd); +- return -1; +-} +- +-static int + format_devname(char *name, int id, int len) + { + int pos; +@@ -346,7 +200,7 @@ get_user_friendly_alias(char *wwid, char + return NULL; + } + +- fd = open_bindings_file(file, &can_write); ++ fd = open_file(file, &can_write, BINDINGS_FILE_HEADER); + if (fd < 0) + return NULL; + +@@ -396,7 +250,7 @@ get_user_friendly_wwid(char *alias, char + return NULL; + } + +- fd = open_bindings_file(file, &unused); ++ fd = open_file(file, &unused, BINDINGS_FILE_HEADER); + if (fd < 0) + return NULL; + +Index: b/libmultipath/alias.h +=================================================================== +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -1,4 +1,3 @@ +-#define BINDINGS_FILE_TIMEOUT 30 + #define BINDINGS_FILE_HEADER \ + "# Multipath bindings, Version : 1.0\n" \ + "# NOTE: this file is automatically maintained by the multipath program.\n" \ +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -36,6 +36,7 @@ + #include "alias.h" + #include "prio.h" + #include "util.h" ++#include "wwids.h" + + extern int + setup_map (struct multipath * mpp, char * params, int params_size) +@@ -390,6 +391,8 @@ domap (struct multipath * mpp, char * pa + * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD + * succeeded + */ ++ if (mpp->action == ACT_CREATE) ++ remember_wwid(mpp->wwid); + if (!conf->daemon) { + /* multipath client mode */ + dm_switchgroup(mpp->alias, mpp->bestpg); +Index: b/libmultipath/defaults.h +=================================================================== +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -21,5 +21,6 @@ + #define DEFAULT_SOCKET "/var/run/multipathd.sock" + #define DEFAULT_CONFIGFILE "/etc/multipath.conf" + #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" ++#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" + + char * set_default (char * str); +Index: b/libmultipath/file.c +=================================================================== +--- /dev/null ++++ b/libmultipath/file.c +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (c) 2005 Christophe Varoqui ++ * Copyright (c) 2005 Benjamin Marzinski, Redhat ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "file.h" ++#include "debug.h" ++#include "uxsock.h" ++ ++ ++/* ++ * significant parts of this file were taken from iscsi-bindings.c of the ++ * linux-iscsi project. ++ * Copyright (C) 2002 Cisco Systems, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++static int ++ensure_directories_exist(char *str, mode_t dir_mode) ++{ ++ char *pathname; ++ char *end; ++ int err; ++ ++ pathname = strdup(str); ++ if (!pathname){ ++ condlog(0, "Cannot copy file pathname %s : %s", ++ str, strerror(errno)); ++ return -1; ++ } ++ end = pathname; ++ /* skip leading slashes */ ++ while (end && *end && (*end == '/')) ++ end++; ++ ++ while ((end = strchr(end, '/'))) { ++ /* if there is another slash, make the dir. */ ++ *end = '\0'; ++ err = mkdir(pathname, dir_mode); ++ if (err && errno != EEXIST) { ++ condlog(0, "Cannot make directory [%s] : %s", ++ pathname, strerror(errno)); ++ free(pathname); ++ return -1; ++ } ++ if (!err) ++ condlog(3, "Created dir [%s]", pathname); ++ *end = '/'; ++ end++; ++ } ++ free(pathname); ++ return 0; ++} ++ ++static void ++sigalrm(int sig) ++{ ++ /* do nothing */ ++} ++ ++static int ++lock_file(int fd, char *file_name) ++{ ++ struct sigaction act, oldact; ++ sigset_t set, oldset; ++ struct flock lock; ++ int err; ++ ++ memset(&lock, 0, sizeof(lock)); ++ lock.l_type = F_WRLCK; ++ lock.l_whence = SEEK_SET; ++ ++ act.sa_handler = sigalrm; ++ sigemptyset(&act.sa_mask); ++ act.sa_flags = 0; ++ sigemptyset(&set); ++ sigaddset(&set, SIGALRM); ++ ++ sigaction(SIGALRM, &act, &oldact); ++ sigprocmask(SIG_UNBLOCK, &set, &oldset); ++ ++ alarm(FILE_TIMEOUT); ++ err = fcntl(fd, F_SETLKW, &lock); ++ alarm(0); ++ ++ if (err) { ++ if (errno != EINTR) ++ condlog(0, "Cannot lock %s : %s", file_name, ++ strerror(errno)); ++ else ++ condlog(0, "%s is locked. Giving up.", file_name); ++ } ++ ++ sigprocmask(SIG_SETMASK, &oldset, NULL); ++ sigaction(SIGALRM, &oldact, NULL); ++ return err; ++} ++ ++int ++open_file(char *file, int *can_write, char *header) ++{ ++ int fd; ++ struct stat s; ++ ++ if (ensure_directories_exist(file, 0700)) ++ return -1; ++ *can_write = 1; ++ fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); ++ if (fd < 0) { ++ if (errno == EROFS) { ++ *can_write = 0; ++ condlog(3, "Cannot open file [%s] read/write. " ++ " trying readonly", file); ++ fd = open(file, O_RDONLY); ++ if (fd < 0) { ++ condlog(0, "Cannot open file [%s] " ++ "readonly : %s", file, strerror(errno)); ++ return -1; ++ } ++ } ++ else { ++ condlog(0, "Cannot open file [%s] : %s", file, ++ strerror(errno)); ++ return -1; ++ } ++ } ++ if (*can_write && lock_file(fd, file) < 0) ++ goto fail; ++ ++ memset(&s, 0, sizeof(s)); ++ if (fstat(fd, &s) < 0){ ++ condlog(0, "Cannot stat file %s : %s", file, strerror(errno)); ++ goto fail; ++ } ++ if (s.st_size == 0) { ++ if (*can_write == 0) ++ goto fail; ++ /* If file is empty, write the header */ ++ size_t len = strlen(header); ++ if (write_all(fd, header, len) != len) { ++ condlog(0, ++ "Cannot write header to file %s : %s", file, ++ strerror(errno)); ++ /* cleanup partially written header */ ++ if (ftruncate(fd, 0)) ++ condlog(0, "Cannot truncate header : %s", ++ strerror(errno)); ++ goto fail; ++ } ++ fsync(fd); ++ condlog(3, "Initialized new file [%s]", file); ++ } ++ ++ return fd; ++ ++fail: ++ close(fd); ++ return -1; ++} +Index: b/libmultipath/file.h +=================================================================== +--- /dev/null ++++ b/libmultipath/file.h +@@ -0,0 +1,11 @@ ++/* ++ * Copyright (c) 2010 Benjamin Marzinski, Redhat ++ */ ++ ++#ifndef _FILE_H ++#define _FILE_H ++ ++#define FILE_TIMEOUT 30 ++int open_file(char *file, int *can_write, char *header); ++ ++#endif /* _FILE_H */ +Index: b/libmultipath/wwids.c +=================================================================== +--- /dev/null ++++ b/libmultipath/wwids.c +@@ -0,0 +1,139 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "checkers.h" ++#include "vector.h" ++#include "structs.h" ++#include "debug.h" ++#include "uxsock.h" ++#include "file.h" ++#include "wwids.h" ++#include "defaults.h" ++ ++/* ++ * Copyright (c) 2010 Benjamin Marzinski, Redhat ++ */ ++ ++static int ++lookup_wwid(FILE *f, char *wwid) { ++ int c; ++ char buf[LINE_MAX]; ++ int count; ++ ++ while ((c = fgetc(f)) != EOF){ ++ if (c != '/') { ++ if (fgets(buf, LINE_MAX, f) == NULL) ++ return 0; ++ else ++ continue; ++ } ++ count = 0; ++ while ((c = fgetc(f)) != '/') { ++ if (c == EOF) ++ return 0; ++ if (count >= WWID_SIZE - 1) ++ goto next; ++ if (wwid[count] == '\0') ++ goto next; ++ if (c != wwid[count++]) ++ goto next; ++ } ++ if (wwid[count] == '\0') ++ return 1; ++next: ++ if (fgets(buf, LINE_MAX, f) == NULL) ++ return 0; ++ } ++ return 0; ++} ++ ++static int ++write_out_wwid(int fd, char *wwid) { ++ int ret; ++ off_t offset; ++ char buf[WWID_SIZE + 3]; ++ ++ ret = snprintf(buf, WWID_SIZE + 3, "/%s/\n", wwid); ++ if (ret >= (WWID_SIZE + 3) || ret < 0){ ++ condlog(0, "can't format wwid for writing (%d) : %s", ++ ret, strerror(errno)); ++ return -1; ++ } ++ offset = lseek(fd, 0, SEEK_END); ++ if (offset < 0) { ++ condlog(0, "can't seek to the end of wwids file : %s", ++ strerror(errno)); ++ return -1; ++ } ++ if (write_all(fd, buf, strlen(buf)) != strlen(buf)) { ++ condlog(0, "cannot write wwid to wwids file : %s", ++ strerror(errno)); ++ if (ftruncate(fd, offset)) ++ condlog(0, "cannot truncate failed wwid write : %s", ++ strerror(errno)); ++ return -1; ++ } ++ return 1; ++} ++ ++int ++check_wwids_file(char *wwid, int write_wwid) ++{ ++ int fd, can_write, found, ret; ++ FILE *f; ++ fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER); ++ if (fd < 0) ++ return -1; ++ ++ f = fdopen(fd, "r"); ++ if (!f) { ++ condlog(0,"can't fdopen wwids file : %s", strerror(errno)); ++ close(fd); ++ return -1; ++ } ++ found = lookup_wwid(f, wwid); ++ if (found) { ++ ret = 0; ++ goto out; ++ } ++ if (!write_wwid) { ++ ret = -1; ++ goto out; ++ } ++ if (!can_write) { ++ condlog(0, "wwids file is read-only. Can't write wwid"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (fflush(f) != 0) { ++ condlog(0, "cannot fflush wwids file stream : %s", ++ strerror(errno)); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = write_out_wwid(fd, wwid); ++out: ++ fclose(f); ++ return ret; ++} ++ ++int ++remember_wwid(char *wwid) ++{ ++ int ret = check_wwids_file(wwid, 1); ++ if (ret < 0){ ++ condlog(3, "failed writing wwid %s to wwids file", wwid); ++ return -1; ++ } ++ if (ret == 1) ++ condlog(3, "wrote wwid %s to wwids file", wwid); ++ else ++ condlog(4, "wwid %s already in wwids file", wwid); ++ return 0; ++} +Index: b/libmultipath/wwids.h +=================================================================== +--- /dev/null ++++ b/libmultipath/wwids.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (c) 2010 Benjamin Marzinski, Redhat ++ */ ++ ++#ifndef _WWIDS_H ++#define _WWIDS_H ++ ++#define WWIDS_FILE_HEADER \ ++"# Multipath wwids, Version : 1.0\n" \ ++"# NOTE: This file is automatically maintained by multipath and multipathd.\n" \ ++"# You should not need to edit this file in normal circumstances.\n" \ ++"#\n" \ ++"# Valid WWIDs:\n" ++ ++int remember_wwid(char *wwid); ++int check_wwids_file(char *wwid, int write_wwid); ++ ++#endif /* _WWIDS_H */ +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + int logsink; + +@@ -80,7 +81,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname); ++ fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -h\n", progname); +@@ -92,6 +93,7 @@ usage (char * progname) + " -ll show multipath topology (maximum info)\n" \ + " -f flush a multipath device map\n" \ + " -F flush all multipath device maps\n" \ ++ " -c check if a device should be a path in a multipath device\n" \ + " -d dry run, do not create or update devmaps\n" \ + " -r force devmap reload\n" \ + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ +@@ -204,6 +206,7 @@ get_dm_mpvec (vector curmp, vector pathv + + if (!conf->dry_run) + reinstate_paths(mpp); ++ remember_wwid(mpp->wwid); + } + return 0; + } +@@ -254,8 +257,13 @@ configure (void) + * if we have a blacklisted device parameter, exit early + */ + if (dev && +- (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0)) +- goto out; ++ (filter_devnode(conf->blist_devnode, ++ conf->elist_devnode, dev) > 0)) { ++ if (conf->dry_run == 2) ++ printf("%s is not a valid multipath device path\n", ++ conf->dev); ++ goto out; ++ } + + /* + * scope limiting must be translated into a wwid +@@ -272,6 +280,15 @@ configure (void) + if (filter_wwid(conf->blist_wwid, conf->elist_wwid, + refwwid) > 0) + goto out; ++ if (conf->dry_run == 2) { ++ if (check_wwids_file(refwwid, 0) == 0){ ++ printf("%s is a valid multipath device path\n", conf->dev); ++ r = 0; ++ } ++ else ++ printf("%s is not a valid multipath device path\n", conf->dev); ++ goto out; ++ } + } + + /* +@@ -353,7 +370,7 @@ main (int argc, char *argv[]) + condlog(0, "failed to initialize prioritizers"); + goto out; + } +- while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:r")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:r")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -367,8 +384,12 @@ main (int argc, char *argv[]) + case 'b': + conf->bindings_file = optarg; + break; ++ case 'c': ++ conf->dry_run = 2; ++ break; + case 'd': +- conf->dry_run = 1; ++ if (!conf->dry_run) ++ conf->dry_run = 1; + break; + case 'f': + conf->remove = FLUSH_ONE; +@@ -441,6 +462,11 @@ main (int argc, char *argv[]) + + dm_init(); + ++ if (conf->dry_run == 2 && ++ (!conf->dev || conf->dev_type == DEV_DEVMAP)) { ++ condlog(0, "the -c option requires a path to check"); ++ goto out; ++ } + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) + r = dm_flush_map(conf->dev); diff -Nru multipath-tools-0.4.9/debian/patches/0039-multipath-and-wwids_file-multipath.conf-option.patch multipath-tools-0.4.9/debian/patches/0039-multipath-and-wwids_file-multipath.conf-option.patch --- multipath-tools-0.4.9/debian/patches/0039-multipath-and-wwids_file-multipath.conf-option.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0039-multipath-and-wwids_file-multipath.conf-option.patch 2015-07-29 20:19:31.000000000 +0000 @@ -0,0 +1,145 @@ +From 1dafbbc353472536ba1ab5b1495048006a680752 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Mon, 20 Aug 2012 17:19:26 -0500 +Subject: [PATCH] multipath: and wwids_file multipath.conf option + +This patch adds a wwids_file multipath.conf option, so that users can +move the wwids file from its default location at /etc/multipath/wwids. +It also corrects the default bindings file location in the multipath.conf +manpage and makes the bindings_file value always print out when you +display the configuration, like is done with the other default values. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 5 ++++- + libmultipath/config.h | 1 + + libmultipath/dict.c | 20 ++++++++++++++++++++ + libmultipath/wwids.c | 3 ++- + multipath/multipath.conf.5 | 6 ++++++ + 5 files changed, 33 insertions(+), 2 deletions(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -433,6 +433,8 @@ free_config (struct config * conf) + if (conf->hwhandler) + FREE(conf->hwhandler); + ++ if (conf->wwids_file) ++ FREE(conf->wwids_file); + if (conf->prio_name) + FREE(conf->prio_name); + +@@ -477,6 +479,7 @@ load_config (char * file, struct udev *u + conf->max_fds = 0; + conf->bindings_file = DEFAULT_BINDINGS_FILE; + conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR); ++ conf->wwids_file = set_default(DEFAULT_WWIDS_FILE); + conf->flush_on_last_del = 0; + conf->attribute_flags = 0; + +@@ -566,7 +569,7 @@ load_config (char * file, struct udev *u + goto out; + } + +- if (!conf->multipath_dir) ++ if (!conf->multipath_dir || !conf->wwids_file) + goto out; + + return 0; +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -102,6 +102,7 @@ struct config { + char * features; + char * hwhandler; + char * bindings_file; ++ char * wwids_file; + char * prio_name; + char * prio_args; + char * checker_name; +Index: b/libmultipath/dict.c +=================================================================== +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -473,6 +473,17 @@ names_handler(vector strvec) + return 0; + } + ++static int ++wwids_file_handler(vector strvec) ++{ ++ conf->wwids_file = set_value(strvec); ++ ++ if (!conf->wwids_file) ++ return 1; ++ ++ return 0; ++} ++ + /* + * blacklist block handlers + */ +@@ -1793,6 +1804,14 @@ snprint_hw_path_checker (char * buff, in + } + + static int ++snprint_def_wwids_file (char * buff, int len, void * data) ++{ ++ if (conf->wwids_file == NULL) ++ return 0; ++ return snprintf(buff, len, "%s", conf->wwids_file); ++} ++ ++static int + snprint_def_polling_interval (char * buff, int len, void * data) + { + if (conf->checkint == DEFAULT_CHECKINT) +@@ -2121,6 +2140,7 @@ init_keywords(void) + install_keyword("verbosity", &verbosity_handler, &snprint_def_verbosity); + install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval); + install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir); ++ install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file); + install_keyword("selector", &def_selector_handler, &snprint_def_selector); + install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy); + install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout); +Index: b/libmultipath/wwids.c +=================================================================== +--- a/libmultipath/wwids.c ++++ b/libmultipath/wwids.c +@@ -13,6 +13,7 @@ + #include "file.h" + #include "wwids.h" + #include "defaults.h" ++#include "config.h" + + /* + * Copyright (c) 2010 Benjamin Marzinski, Redhat +@@ -85,7 +86,7 @@ check_wwids_file(char *wwid, int write_w + { + int fd, can_write, found, ret; + FILE *f; +- fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER); ++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); + if (fd < 0) + return -1; + +Index: b/multipath/multipath.conf.5 +=================================================================== +--- a/multipath/multipath.conf.5 ++++ b/multipath/multipath.conf.5 +@@ -229,6 +229,12 @@ be overridden by any specific aliases in + Default is + .I no + .TP ++.B wwids_file ++The full pathname of the wwids file, which is used by multipath to keep track ++of the wwids for LUNs it has created multipath devices on in the past. ++Defaults to ++.I /etc/multipath/wwids ++.TP + .B max_fds + Specify the maximum number of file descriptors that can be opened by multipath + and multipathd. This is equivalent to ulimit \-n. A value of \fImax\fR will set diff -Nru multipath-tools-0.4.9/debian/patches/0040-multipath-Check-blacklists-as-soon-as-possible.patch multipath-tools-0.4.9/debian/patches/0040-multipath-Check-blacklists-as-soon-as-possible.patch --- multipath-tools-0.4.9/debian/patches/0040-multipath-Check-blacklists-as-soon-as-possible.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0040-multipath-Check-blacklists-as-soon-as-possible.patch 2015-07-29 20:19:33.000000000 +0000 @@ -0,0 +1,598 @@ +From 881c56fe7b7b324e9239e3cf0944d92af336653f Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Sat, 12 Jan 2013 00:04:53 -0600 +Subject: [PATCH] multipath: Check blacklists as soon as possible + +Multipath does a lot of unnecessary work on devices blacklisted by device +type or wwid before ignoring them. When dealing with a large number of +devices blacklisted this way, multipath can take long time to complete. +The patch makes sure that multipath is checking the blacklists as soon +as it has the necessary information to do so. To do this, pathinfo() now +takes another flag DI_BLACKLIST, which is only used by store_pathinfo(), +that tells it to check if the device should be blacklisted. Doing this +cleanly also required changing how store_pathinfo() and rlookup_binding() +are called. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/alias.c | 49 +++++++++++++++++--------------- + libmultipath/alias.h | 2 - + libmultipath/configure.c | 70 ++++++++++++++++++++++++++++++---------------- + libmultipath/configure.h | 2 - + libmultipath/discovery.c | 47 +++++++++++++++++++++++------- + libmultipath/discovery.h | 11 ++++--- + libmultipath/util.c | 2 - + multipath/main.c | 14 ++++----- + multipathd/cli_handlers.c | 11 +++---- + multipathd/main.c | 22 ++++++-------- + 10 files changed, 141 insertions(+), 89 deletions(-) + +Index: b/libmultipath/alias.c +=================================================================== +--- a/libmultipath/alias.c ++++ b/libmultipath/alias.c +@@ -13,6 +13,9 @@ + #include "uxsock.h" + #include "alias.h" + #include "file.h" ++#include "vector.h" ++#include "checkers.h" ++#include "structs.h" + + + /* +@@ -101,23 +104,23 @@ lookup_binding(FILE *f, char *map_wwid, + } + + static int +-rlookup_binding(FILE *f, char **map_wwid, char *map_alias) ++rlookup_binding(FILE *f, char *buff, char *map_alias) + { +- char buf[LINE_MAX]; ++ char line[LINE_MAX]; + unsigned int line_nr = 0; + int id = 0; + +- *map_wwid = NULL; ++ buff[0] = '\0'; + +- while (fgets(buf, LINE_MAX, f)) { ++ while (fgets(line, LINE_MAX, f)) { + char *c, *alias, *wwid; + int curr_id; + + line_nr++; +- c = strpbrk(buf, "#\n\r"); ++ c = strpbrk(line, "#\n\r"); + if (c) + *c = '\0'; +- alias = strtok(buf, " \t"); ++ alias = strtok(line, " \t"); + if (!alias) /* blank line */ + continue; + curr_id = scan_devname(alias); +@@ -130,13 +133,16 @@ rlookup_binding(FILE *f, char **map_wwid + line_nr); + continue; + } ++ if (strlen(wwid) > WWID_SIZE - 1) { ++ condlog(3, ++ "Ignoring too large wwid at %u in bindings file", line_nr); ++ continue; ++ } + if (strcmp(alias, map_alias) == 0){ + condlog(3, "Found matching alias [%s] in bindings file." + "\nSetting wwid to %s", alias, wwid); +- *map_wwid = strdup(wwid); +- if (*map_wwid == NULL) +- condlog(0, "Cannot copy alias from bindings " +- "file : %s", strerror(errno)); ++ strncpy(buff, wwid, WWID_SIZE); ++ buff[WWID_SIZE - 1] = '\0'; + return id; + } + } +@@ -238,28 +244,27 @@ get_user_friendly_alias(char *wwid, char + return alias; + } + +-char * +-get_user_friendly_wwid(char *alias, char *file) ++int ++get_user_friendly_wwid(char *alias, char *buff, char *file) + { +- char *wwid; +- int fd, scan_fd, id, unused; ++ int fd, scan_fd, unused; + FILE *f; + + if (!alias || *alias == '\0') { + condlog(3, "Cannot find binding for empty alias"); +- return NULL; ++ return -1; + } + + fd = open_file(file, &unused, BINDINGS_FILE_HEADER); + if (fd < 0) +- return NULL; ++ return -1; + + scan_fd = dup(fd); + if (scan_fd < 0) { + condlog(0, "Cannot dup bindings file descriptor : %s", + strerror(errno)); + close(fd); +- return NULL; ++ return -1; + } + + f = fdopen(scan_fd, "r"); +@@ -268,19 +273,19 @@ get_user_friendly_wwid(char *alias, char + strerror(errno)); + close(scan_fd); + close(fd); +- return NULL; ++ return -1; + } + +- id = rlookup_binding(f, &wwid, alias); +- if (id < 0) { ++ rlookup_binding(f, buff, alias); ++ if (!strlen(buff)) { + fclose(f); + close(scan_fd); + close(fd); +- return NULL; ++ return -1; + } + + fclose(f); + close(scan_fd); + close(fd); +- return wwid; ++ return 0; + } +Index: b/libmultipath/alias.h +=================================================================== +--- a/libmultipath/alias.h ++++ b/libmultipath/alias.h +@@ -8,4 +8,4 @@ + "#\n" + + char *get_user_friendly_alias(char *wwid, char *file); +-char *get_user_friendly_wwid(char *alias, char *file); ++int get_user_friendly_wwid(char *alias, char *buff, char *file); +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -593,21 +593,32 @@ coalesce_paths (struct vectors * vecs, v + return 0; + } + +-extern char * +-get_refwwid (char * dev, enum devtypes dev_type, vector pathvec) ++/* ++ * returns: ++ * 0 - success ++ * 1 - failure ++ * 2 - blacklist ++ */ ++extern int ++get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid) + { ++ int ret = 1; + struct path * pp; + char buff[FILE_NAME_SIZE]; + char * refwwid = NULL, tmpwwid[WWID_SIZE]; + ++ if (!wwid) ++ return 1; ++ *wwid = NULL; ++ + if (dev_type == DEV_NONE) +- return NULL; ++ return 1; + + if (dev_type == DEV_DEVNODE) { + if (basenamecpy(dev, buff, FILE_NAME_SIZE) == 0) { + condlog(1, "basename failed for '%s' (%s)", + dev, buff); +- return NULL; ++ return 1; + } + + pp = find_path_by_dev(pathvec, buff); +@@ -616,14 +627,16 @@ get_refwwid (char * dev, enum devtypes d + + if (!udevice) { + condlog(2, "%s: can't get udev device", buff); +- return NULL; ++ return 1; + } +- pp = store_pathinfo(pathvec, conf->hwtable, udevice, +- DI_SYSFS | DI_WWID); ++ ret = store_pathinfo(pathvec, conf->hwtable, udevice, ++ DI_SYSFS | DI_WWID, &pp); + udev_device_unref(udevice); + if (!pp) { +- condlog(0, "%s can't store path info", buff); +- return NULL; ++ if (ret == 1) ++ condlog(0, "%s can't store path info", ++ buff); ++ return ret; + } + } + refwwid = pp->wwid; +@@ -637,14 +650,16 @@ get_refwwid (char * dev, enum devtypes d + + if (!udevice) { + condlog(2, "%s: can't get udev device", dev); +- return NULL; ++ return 1; + } +- pp = store_pathinfo(pathvec, conf->hwtable, udevice, +- DI_SYSFS | DI_WWID); ++ ret = store_pathinfo(pathvec, conf->hwtable, udevice, ++ DI_SYSFS | DI_WWID, &pp); + udev_device_unref(udevice); + if (!pp) { +- condlog(0, "%s can't store path info", buff); +- return NULL; ++ if (ret == 1) ++ condlog(0, "%s can't store path info", ++ buff); ++ return ret; + } + } + refwwid = pp->wwid; +@@ -654,17 +669,17 @@ get_refwwid (char * dev, enum devtypes d + + if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) { + refwwid = tmpwwid; +- goto out; ++ goto check; + } + + /* + * may be a binding + */ +- refwwid = get_user_friendly_wwid(dev, +- conf->bindings_file); +- +- if (refwwid) +- return refwwid; ++ if (get_user_friendly_wwid(dev, tmpwwid, ++ conf->bindings_file) == 0) { ++ refwwid = tmpwwid; ++ goto check; ++ } + + /* + * or may be an alias +@@ -676,12 +691,21 @@ get_refwwid (char * dev, enum devtypes d + */ + if (!refwwid) + refwwid = dev; ++ ++check: ++ if (refwwid && strlen(refwwid)) { ++ if (filter_wwid(conf->blist_wwid, conf->elist_wwid, ++ refwwid) > 0) ++ return 2; ++ } + } + out: +- if (refwwid && strlen(refwwid)) +- return STRDUP(refwwid); ++ if (refwwid && strlen(refwwid)) { ++ *wwid = STRDUP(refwwid); ++ return 0; ++ } + +- return NULL; ++ return 1; + } + + extern int reload_map(struct vectors *vecs, struct multipath *mpp) +Index: b/libmultipath/configure.h +=================================================================== +--- a/libmultipath/configure.h ++++ b/libmultipath/configure.h +@@ -27,6 +27,6 @@ int setup_map (struct multipath * mpp, c + int domap (struct multipath * mpp, char * params); + int reinstate_paths (struct multipath *mpp); + int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload); +-char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec); ++int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid); + int reload_map(struct vectors *vecs, struct multipath *mpp); + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -29,37 +29,45 @@ + #include "prio.h" + #include "defaults.h" + +-struct path * ++int + store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice, +- int flag) ++ int flag, struct path **pp_ptr) + { ++ int err = 1; + struct path * pp; + const char * devname; + ++ if (pp_ptr) ++ *pp_ptr = NULL; ++ + devname = udev_device_get_sysname(udevice); + if (!devname) +- return NULL; ++ return 1; + + pp = alloc_path(); + + if (!pp) +- return NULL; ++ return 1; + + if(safe_sprintf(pp->dev, "%s", devname)) { + condlog(0, "pp->dev too small"); + goto out; + } + pp->udev = udev_device_ref(udevice); +- if (pathinfo(pp, hwtable, flag)) ++ err = pathinfo(pp, hwtable, flag | DI_BLACKLIST); ++ if (err) + goto out; + +- if (store_path(pathvec, pp)) ++ err = store_path(pathvec, pp); ++ if (err) + goto out; + +- return pp; + out: +- free_path(pp); +- return NULL; ++ if (err) ++ free_path(pp); ++ else if (pp_ptr) ++ *pp_ptr = pp; ++ return err; + } + + static int +@@ -79,9 +87,11 @@ path_discover (vector pathvec, struct co + + pp = find_path_by_dev(pathvec, (char *)devname); + if (!pp) { +- pp = store_pathinfo(pathvec, conf->hwtable, +- udevice, flag); +- return (pp ? 0 : 1); ++ if (store_pathinfo(pathvec, conf->hwtable, ++ udevice, flag, NULL) != 1) ++ return 0; ++ else ++ return 1; + } + return pathinfo(pp, conf->hwtable, flag); + } +@@ -812,6 +822,13 @@ pathinfo (struct path *pp, vector hwtabl + if (mask & DI_SYSFS && sysfs_pathinfo(pp)) + return 1; + ++ if (mask & DI_BLACKLIST && mask & DI_SYSFS) { ++ if (filter_device(conf->blist_device, conf->elist_device, ++ pp->vendor_id, pp->product_id) > 0) { ++ return 2; ++ } ++ } ++ + path_state = path_offline(pp); + + /* +@@ -862,6 +879,12 @@ pathinfo (struct path *pp, vector hwtabl + + if (path_state == PATH_UP && (mask & DI_WWID) && !strlen(pp->wwid)) + get_uid(pp); ++ if (mask & DI_BLACKLIST && mask & DI_WWID) { ++ if (filter_wwid(conf->blist_wwid, conf->elist_wwid, ++ pp->wwid) > 0) { ++ return 2; ++ } ++ } + + return 0; + +Index: b/libmultipath/discovery.h +=================================================================== +--- a/libmultipath/discovery.h ++++ b/libmultipath/discovery.h +@@ -33,8 +33,9 @@ int do_tur (char *); + int path_offline (struct path *); + int get_state (struct path * pp, int daemon); + int pathinfo (struct path *, vector hwtable, int mask); +-struct path * store_pathinfo (vector pathvec, vector hwtable, +- struct udev_device *udevice, int flag); ++int store_pathinfo (vector pathvec, vector hwtable, ++ struct udev_device *udevice, int flag, ++ struct path **pp_ptr); + int sysfs_set_scsi_tmo (struct multipath *mpp); + int sysfs_get_timeout(struct path *pp, unsigned int *timeout); + +@@ -46,14 +47,16 @@ enum discovery_mode { + __DI_SERIAL, + __DI_CHECKER, + __DI_PRIO, +- __DI_WWID ++ __DI_WWID, ++ __DI_BLACKLIST, + }; + + #define DI_SYSFS (1 << __DI_SYSFS) + #define DI_SERIAL (1 << __DI_SERIAL) + #define DI_CHECKER (1 << __DI_CHECKER) + #define DI_PRIO (1 << __DI_PRIO) +-#define DI_WWID (1 << __DI_WWID) ++#define DI_WWID (1 << __DI_WWID) ++#define DI_BLACKLIST (1 << __DI_BLACKLIST) + + #define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CHECKER | DI_PRIO | \ + DI_WWID) +Index: b/libmultipath/util.c +=================================================================== +--- a/libmultipath/util.c ++++ b/libmultipath/util.c +@@ -47,7 +47,7 @@ basenamecpy (const char * str1, char * s + if (!str1 || !strlen(str1)) + return 0; + +- if (strlen(str1) > str2len) ++ if (strlen(str1) >= str2len) + return 0; + + if (!str2) +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -256,7 +256,7 @@ configure (void) + /* + * if we have a blacklisted device parameter, exit early + */ +- if (dev && ++ if (dev && conf->dev_type == DEV_DEVNODE && + (filter_devnode(conf->blist_devnode, + conf->elist_devnode, dev) > 0)) { + if (conf->dry_run == 2) +@@ -270,16 +270,16 @@ configure (void) + * failing the translation is fatal (by policy) + */ + if (conf->dev) { +- refwwid = get_refwwid(conf->dev, conf->dev_type, pathvec); +- ++ int failed = get_refwwid(conf->dev, conf->dev_type, pathvec, ++ &refwwid); + if (!refwwid) { +- condlog(3, "scope is nul"); ++ if (failed == 2 && conf->dry_run == 2) ++ printf("%s is not a valid multipath device path\n", conf->dev); ++ else ++ condlog(3, "scope is nul"); + goto out; + } + condlog(3, "scope limited to %s", refwwid); +- if (filter_wwid(conf->blist_wwid, conf->elist_wwid, +- refwwid) > 0) +- goto out; + if (conf->dry_run == 2) { + if (check_wwids_file(refwwid, 0) == 0){ + printf("%s is a valid multipath device path\n", conf->dev); +Index: b/multipathd/cli_handlers.c +=================================================================== +--- a/multipathd/cli_handlers.c ++++ b/multipathd/cli_handlers.c +@@ -376,19 +376,18 @@ cli_add_path (void * v, char ** reply, i + udevice = udev_device_new_from_subsystem_sysname(conf->udev, + "block", + param); +- pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- udevice, DI_ALL); ++ r = store_pathinfo(vecs->pathvec, conf->hwtable, ++ udevice, DI_ALL, &pp); + udev_device_unref(udevice); + if (!pp) { ++ if (r == 2) ++ goto blacklisted; + condlog(0, "%s: failed to store path info", param); + return 1; + } + pp->checkint = conf->checkint; + } +- r = ev_add_path(pp, vecs); +- if (r == 2) +- goto blacklisted; +- return r; ++ return ev_add_path(pp, vecs); + blacklisted: + *reply = strdup("blacklisted\n"); + *len = strlen(*reply) + 1; +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -279,7 +279,7 @@ ev_add_map (char * dev, char * alias, st + condlog(2, "%s: devmap %s registered", alias, dev); + return 0; + } +- refwwid = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec); ++ r = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec, &refwwid); + + if (refwwid) { + r = coalesce_paths(vecs, NULL, refwwid, 0); +@@ -288,6 +288,8 @@ ev_add_map (char * dev, char * alias, st + + if (!r) + condlog(2, "%s: devmap %s added", alias, dev); ++ else if (r == 2) ++ condlog(2, "%s: uev_add_map %s blacklisted", alias, dev); + else + condlog(0, "%s: uev_add_map %s failed", alias, dev); + +@@ -359,6 +361,7 @@ static int + uev_add_path (struct uevent *uev, struct vectors * vecs) + { + struct path *pp; ++ int ret; + + condlog(2, "%s: add path (uevent)", uev->kernel); + if (strstr(uev->kernel, "..") != NULL) { +@@ -379,8 +382,11 @@ uev_add_path (struct uevent *uev, struct + /* + * get path vital state + */ +- if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, +- uev->udev, DI_ALL))) { ++ ret = store_pathinfo(vecs->pathvec, conf->hwtable, ++ uev->udev, DI_ALL, &pp); ++ if (!pp) { ++ if (ret == 2) ++ return 0; + condlog(0, "%s: failed to store path info", + uev->kernel); + return 1; +@@ -388,14 +394,13 @@ uev_add_path (struct uevent *uev, struct + pp->checkint = conf->checkint; + } + +- return (ev_add_path(pp, vecs) != 1)? 0 : 1; ++ return ev_add_path(pp, vecs); + } + + /* + * returns: + * 0: added + * 1: error +- * 2: blacklisted + */ + int + ev_add_path (struct path * pp, struct vectors * vecs) +@@ -413,13 +418,6 @@ ev_add_path (struct path * pp, struct ve + condlog(0, "%s: failed to get path uid", pp->dev); + return 1; /* leave path added to pathvec */ + } +- if (filter_path(conf, pp) > 0){ +- int i = find_slot(vecs->pathvec, (void *)pp); +- if (i != -1) +- vector_del_slot(vecs->pathvec, i); +- free_path(pp); +- return 2; +- } + mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); + rescan: + if (mpp) { diff -Nru multipath-tools-0.4.9/debian/patches/0041-add-wwids-file-cleanup-options.patch multipath-tools-0.4.9/debian/patches/0041-add-wwids-file-cleanup-options.patch --- multipath-tools-0.4.9/debian/patches/0041-add-wwids-file-cleanup-options.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0041-add-wwids-file-cleanup-options.patch 2015-07-29 20:19:36.000000000 +0000 @@ -0,0 +1,323 @@ +From 9b67d685855b214a87761c2934de2daa7fb0a612 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 2 May 2013 16:46:31 -0500 +Subject: [PATCH] add wwids file cleanup options + +This patch adds the "-w " and "-W" options to multipath. They +allow users to either remove a specified device from the wwids file, or +reset the wwids file to only include the wwids for their current +multipath devices. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/discovery.c | 3 - + libmultipath/wwids.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ + libmultipath/wwids.h | 2 + multipath/main.c | 51 ++++++++++++++++-- + multipath/multipath.8 | 8 ++ + 5 files changed, 188 insertions(+), 6 deletions(-) + +Index: b/libmultipath/discovery.c +=================================================================== +--- a/libmultipath/discovery.c ++++ b/libmultipath/discovery.c +@@ -54,7 +54,8 @@ store_pathinfo (vector pathvec, vector h + goto out; + } + pp->udev = udev_device_ref(udevice); +- err = pathinfo(pp, hwtable, flag | DI_BLACKLIST); ++ err = pathinfo(pp, hwtable, ++ (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST)); + if (err) + goto out; + +Index: b/libmultipath/wwids.c +=================================================================== +--- a/libmultipath/wwids.c ++++ b/libmultipath/wwids.c +@@ -82,6 +82,136 @@ write_out_wwid(int fd, char *wwid) { + } + + int ++replace_wwids(vector mp) ++{ ++ int i, fd, can_write; ++ struct multipath * mpp; ++ size_t len; ++ int ret = -1; ++ ++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ if (!can_write) { ++ condlog(0, "cannot replace wwids. wwids file is read-only"); ++ goto out_file; ++ } ++ if (ftruncate(fd, 0) < 0) { ++ condlog(0, "cannot truncate wwids file : %s", strerror(errno)); ++ goto out_file; ++ } ++ len = strlen(WWIDS_FILE_HEADER); ++ if (write_all(fd, WWIDS_FILE_HEADER, len) != len) { ++ condlog(0, "Can't write wwid file header : %s", ++ strerror(errno)); ++ /* cleanup partially written header */ ++ if (ftruncate(fd, 0) < 0) ++ condlog(0, "Cannot truncate header : %s", ++ strerror(errno)); ++ goto out_file; ++ } ++ if (!mp || !mp->allocated) { ++ ret = 0; ++ goto out_file; ++ } ++ vector_foreach_slot(mp, mpp, i) { ++ if (write_out_wwid(fd, mpp->wwid) < 0) ++ goto out_file; ++ } ++ ret = 0; ++out_file: ++ close(fd); ++out: ++ return ret; ++} ++ ++int ++do_remove_wwid(int fd, char *str) { ++ char buf[4097]; ++ char *ptr; ++ off_t start = 0; ++ int bytes; ++ ++ while (1) { ++ if (lseek(fd, start, SEEK_SET) < 0) { ++ condlog(0, "wwid file read lseek failed : %s", ++ strerror(errno)); ++ return -1; ++ } ++ bytes = read(fd, buf, 4096); ++ if (bytes < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ condlog(0, "failed to read from wwids file : %s", ++ strerror(errno)); ++ return -1; ++ } ++ if (!bytes) /* didn't find wwid to remove */ ++ return 1; ++ buf[bytes] = '\0'; ++ ptr = strstr(buf, str); ++ if (ptr != NULL) { ++ condlog(3, "found '%s'", str); ++ if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) { ++ condlog(0, "write lseek failed : %s", ++ strerror(errno)); ++ return -1; ++ } ++ while (1) { ++ if (write(fd, "#", 1) < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ condlog(0, "failed to write to wwids file : %s", strerror(errno)); ++ return -1; ++ } ++ return 0; ++ } ++ } ++ ptr = strrchr(buf, '\n'); ++ if (ptr == NULL) { /* shouldn't happen, assume it is EOF */ ++ condlog(4, "couldn't find newline, assuming end of file"); ++ return 1; ++ } ++ start = start + (ptr - buf) + 1; ++ } ++} ++ ++ ++int ++remove_wwid(char *wwid) { ++ int fd, len, can_write; ++ char *str; ++ int ret = -1; ++ ++ len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */ ++ str = malloc(len); ++ if (str == NULL) { ++ condlog(0, "can't allocate memory to remove wwid : %s", ++ strerror(errno)); ++ return -1; ++ } ++ if (snprintf(str, len, "/%s/\n", wwid) >= len) { ++ condlog(0, "string overflow trying to remove wwid"); ++ goto out; ++ } ++ condlog(3, "removing line '%s' from wwids file", str); ++ fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); ++ if (fd < 0) ++ goto out; ++ if (!can_write) { ++ condlog(0, "cannot remove wwid. wwids file is read-only"); ++ goto out_file; ++ } ++ ret = do_remove_wwid(fd, str); ++ ++out_file: ++ close(fd); ++out: ++ free(str); ++ return ret; ++} ++ ++int + check_wwids_file(char *wwid, int write_wwid) + { + int fd, can_write, found, ret; +Index: b/libmultipath/wwids.h +=================================================================== +--- a/libmultipath/wwids.h ++++ b/libmultipath/wwids.h +@@ -14,5 +14,7 @@ + + int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); ++int remove_wwid(char *wwid); ++int replace_wwids(vector mp); + + #endif /* _WWIDS_H */ +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -81,7 +81,7 @@ usage (char * progname) + { + fprintf (stderr, VERSION_STRING); + fprintf (stderr, "Usage:\n"); +- fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname); ++ fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); + fprintf (stderr, " %s -F [-v lvl]\n", progname); + fprintf (stderr, " %s -h\n", progname); +@@ -98,6 +98,8 @@ usage (char * progname) + " -r force devmap reload\n" \ + " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ + " -b fil bindings file location\n" \ ++ " -w remove a device from the wwids file\n" \ ++ " -W reset the wwids file include only the current devices\n" \ + " -p pol force all maps to specified path grouping policy :\n" \ + " . failover one path per priority group\n" \ + " . multibus all paths in one priority group\n" \ +@@ -206,7 +208,6 @@ get_dm_mpvec (vector curmp, vector pathv + + if (!conf->dry_run) + reinstate_paths(mpp); +- remember_wwid(mpp->wwid); + } + return 0; + } +@@ -256,7 +257,7 @@ configure (void) + /* + * if we have a blacklisted device parameter, exit early + */ +- if (dev && conf->dev_type == DEV_DEVNODE && ++ if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 && + (filter_devnode(conf->blist_devnode, + conf->elist_devnode, dev) > 0)) { + if (conf->dry_run == 2) +@@ -279,6 +280,17 @@ configure (void) + condlog(3, "scope is nul"); + goto out; + } ++ if (conf->dry_run == 3) { ++ r = remove_wwid(refwwid); ++ if (r == 0) ++ printf("wwid '%s' removed\n", refwwid); ++ else if (r == 1) { ++ printf("wwid '%s' not in wwids file\n", ++ refwwid); ++ r = 0; ++ } ++ goto out; ++ } + condlog(3, "scope limited to %s", refwwid); + if (conf->dry_run == 2) { + if (check_wwids_file(refwwid, 0) == 0){ +@@ -370,7 +382,7 @@ main (int argc, char *argv[]) + condlog(0, "failed to initialize prioritizers"); + goto out; + } +- while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:r")) != EOF ) { ++ while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:rwW")) != EOF ) { + switch(arg) { + case 1: printf("optarg : %s\n",optarg); + break; +@@ -422,6 +434,12 @@ main (int argc, char *argv[]) + break; + case 'h': + usage(argv[0]); ++ case 'w': ++ conf->dry_run = 3; ++ break; ++ case 'W': ++ conf->dry_run = 4; ++ break; + case ':': + fprintf(stderr, "Missing option argument\n"); + usage(argv[0]); +@@ -467,6 +485,31 @@ main (int argc, char *argv[]) + condlog(0, "the -c option requires a path to check"); + goto out; + } ++ if (conf->dry_run == 3 && !conf->dev) { ++ condlog(0, "the -w option requires a device"); ++ goto out; ++ } ++ if (conf->dry_run == 4) { ++ struct multipath * mpp; ++ int i; ++ vector curmp; ++ ++ curmp = vector_alloc(); ++ if (!curmp) { ++ condlog(0, "can't allocate memory for mp list"); ++ goto out; ++ } ++ if (dm_get_maps(curmp) == 0) ++ r = replace_wwids(curmp); ++ if (r == 0) ++ printf("successfully reset wwids\n"); ++ vector_foreach_slot_backwards(curmp, mpp, i) { ++ vector_del_slot(curmp, i); ++ free_multipath(mpp, KEEP_PATHS); ++ } ++ vector_free(curmp); ++ goto out; ++ } + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) + r = dm_flush_map(conf->dev); +Index: b/multipath/multipath.8 +=================================================================== +--- a/multipath/multipath.8 ++++ b/multipath/multipath.8 +@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco + .RB [\| \-v\ \c + .IR verbosity \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-F \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-F | \-w | \-W \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -47,6 +47,12 @@ flush a multipath device map specified a + .B \-F + flush all unused multipath device maps + .TP ++.B \-w ++remove the wwid for the specified device from the wwids file ++.TP ++.B \-W ++reset the wwids file to only include the current multipath devices ++.TP + .BI \-p " policy" + force maps to specified policy: + .RS 1.2i diff -Nru multipath-tools-0.4.9/debian/patches/0042-add-find_multipaths-option.patch multipath-tools-0.4.9/debian/patches/0042-add-find_multipaths-option.patch --- multipath-tools-0.4.9/debian/patches/0042-add-find_multipaths-option.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0042-add-find_multipaths-option.patch 2015-07-29 20:19:39.000000000 +0000 @@ -0,0 +1,263 @@ +From 1e4224725dffa248630a150e5ae6f98b2fbfad7c Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Fri, 13 Mar 2015 13:27:25 -0500 +Subject: [PATCH] add find_multipaths option + +This patch adds a new option (find_multipaths) to the defaults section +of multipath.conf. This is used to keep multipath from simply creating +multipath devices on top of any non-blacklisted device. When this is +set to "yes", multipath will only create multipath devices when there +are actually multiple paths to the storage. This means that in most +setups where find_multipaths is set, users don't need to bother with the +editting the blacklist, because multipath will do the work for them. +The only case where blacklisting is still necessary is if user want to +disable multipathing on LUNs that actually have multiple paths. + +One of the issues with only grabbing devices with multiple paths is that +multipath can't know when it first sees a path device whether a second +path device will appear. This could be a problem, because if multipath +doesn't claim the device, something else might. For instance, a +filesystem could be automounted on a path device before the second path +device appeared. + +Multipath deals with this by using the /etc/multipaths/wwids file. If +the device wwid is listed in this file, multipath knows that it is a +path device, and can create a multipath device on it as soon as it +appears. This means that after multipath has created a multipath device +once, it will automatically create it in the future as soon as the first +path is discovered. + +In general, there are three conditions for find_multipaths to allow the +creation of a device. After passing all the checks that multipath +currently does to allow device creation, one of these three conditions +must also be true for device creation, if find_multipaths is enabled. + +1. There are at least two non-blacklisted paths with the same wwid +2. The creation was manually forced, by specifying the device with the + multipath command +3. The path's wwid is in the wwids file, which means that multipath has + previously created a multipath device with that wwid. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/config.c | 1 + + libmultipath/config.h | 1 + + libmultipath/configure.c | 11 +++++++++++ + libmultipath/defaults.h | 1 + + libmultipath/dict.c | 34 ++++++++++++++++++++++++++++++++++ + libmultipath/wwids.c | 26 ++++++++++++++++++++++++++ + libmultipath/wwids.h | 1 + + multipath/main.c | 2 +- + multipathd/main.c | 6 ++++++ + 9 files changed, 82 insertions(+), 1 deletion(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -482,6 +482,7 @@ load_config (char * file, struct udev *u + conf->wwids_file = set_default(DEFAULT_WWIDS_FILE); + conf->flush_on_last_del = 0; + conf->attribute_flags = 0; ++ conf->find_multipaths = DEFAULT_FIND_MULTIPATHS; + + /* + * preload default hwtable +Index: b/libmultipath/configure.c +=================================================================== +--- a/libmultipath/configure.c ++++ b/libmultipath/configure.c +@@ -453,6 +453,10 @@ coalesce_paths (struct vectors * vecs, v + + memset(empty_buff, 0, WWID_SIZE); + ++ /* ignore refwwid if it's empty */ ++ if (refwwid && !strlen(refwwid)) ++ refwwid = NULL; ++ + if (force_reload) { + vector_foreach_slot (pathvec, pp1, k) { + pp1->mpp = NULL; +@@ -478,6 +482,13 @@ coalesce_paths (struct vectors * vecs, v + if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE)) + continue; + ++ /* If find_multipaths was selected check if the path is valid */ ++ if (conf->find_multipaths && !refwwid && ++ !should_multipath(pp1, pathvec)) { ++ orphan_path(pp1); ++ continue; ++ } ++ + /* + * at this point, we know we really got a new mp + */ +Index: b/libmultipath/defaults.h +=================================================================== +--- a/libmultipath/defaults.h ++++ b/libmultipath/defaults.h +@@ -12,6 +12,7 @@ + #define DEFAULT_PGTIMEOUT -PGTIMEOUT_NONE + #define DEFAULT_USER_FRIENDLY_NAMES 0 + #define DEFAULT_VERBOSITY 2 ++#define DEFAULT_FIND_MULTIPATHS 1 + + #define DEFAULT_CHECKINT 5 + #define MAX_CHECKINT(a) (a << 2) +Index: b/libmultipath/dict.c +=================================================================== +--- a/libmultipath/dict.c ++++ b/libmultipath/dict.c +@@ -37,6 +37,27 @@ polling_interval_handler(vector strvec) + } + + static int ++def_find_multipaths_handler(vector strvec) ++{ ++ char * buff; ++ ++ buff = set_value(strvec); ++ ++ if (!buff) ++ return 1; ++ ++ if ((strlen(buff) == 2 && !strcmp(buff, "no")) || ++ (strlen(buff) == 1 && !strcmp(buff, "0"))) ++ conf->find_multipaths = 0; ++ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || ++ (strlen(buff) == 1 && !strcmp(buff, "1"))) ++ conf->find_multipaths = 1; ++ ++ FREE(buff); ++ return 0; ++} ++ ++static int + def_fast_io_fail_handler(vector strvec) + { + char * buff; +@@ -2097,6 +2118,18 @@ snprint_def_flush_on_last_del (char * bu + } + + static int ++snprint_def_find_multipaths (char * buff, int len, void * data) ++{ ++ if (conf->find_multipaths == DEFAULT_FIND_MULTIPATHS) ++ return 0; ++ if (!conf->find_multipaths) ++ return snprintf(buff, len, "no"); ++ ++ return snprintf(buff, len, "yes"); ++} ++ ++ ++static int + snprint_def_user_friendly_names (char * buff, int len, void * data) + { + if (conf->user_friendly_names == DEFAULT_USER_FRIENDLY_NAMES) +@@ -2164,6 +2197,7 @@ init_keywords(void) + install_keyword("gid", &def_gid_handler, &snprint_def_gid); + install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail); + install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss); ++ install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths); + __deprecated install_keyword("default_selector", &def_selector_handler, NULL); + __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL); + __deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL); +Index: b/libmultipath/wwids.c +=================================================================== +--- a/libmultipath/wwids.c ++++ b/libmultipath/wwids.c +@@ -255,6 +255,32 @@ out: + } + + int ++should_multipath(struct path *pp1, vector pathvec) ++{ ++ int i; ++ struct path *pp2; ++ ++ condlog(4, "checking if %s should be multipathed", pp1->dev); ++ vector_foreach_slot(pathvec, pp2, i) { ++ if (pp1->dev == pp2->dev) ++ continue; ++ if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) { ++ condlog(3, "found multiple paths with wwid %s, " ++ "multipathing %s", pp1->wwid, pp1->dev); ++ return 1; ++ } ++ } ++ if (check_wwids_file(pp1->wwid, 0) < 0) { ++ condlog(3, "wwid %s not in wwids file, skipping %s", ++ pp1->wwid, pp1->dev); ++ return 0; ++ } ++ condlog(3, "found wwid %s in wwids file, multipathing %s", pp1->wwid, ++ pp1->dev); ++ return 1; ++} ++ ++int + remember_wwid(char *wwid) + { + int ret = check_wwids_file(wwid, 1); +Index: b/libmultipath/wwids.h +=================================================================== +--- a/libmultipath/wwids.h ++++ b/libmultipath/wwids.h +@@ -12,6 +12,7 @@ + "#\n" \ + "# Valid WWIDs:\n" + ++int should_multipath(struct path *pp, vector pathvec); + int remember_wwid(char *wwid); + int check_wwids_file(char *wwid, int write_wwid); + int remove_wwid(char *wwid); +Index: b/multipath/main.c +=================================================================== +--- a/multipath/main.c ++++ b/multipath/main.c +@@ -340,7 +340,7 @@ configure (void) + /* + * core logic entry point + */ +- r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload); ++ r = coalesce_paths(&vecs, NULL, refwwid, conf->force_reload); + + out: + if (refwwid) +Index: b/multipathd/main.c +=================================================================== +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "pidfile.h" +@@ -457,6 +458,11 @@ rescan: + return 1; + } + ++ if (conf->find_multipaths && ++ !should_multipath(pp, vecs->pathvec)) { ++ orphan_path(pp); ++ return 0; ++ } + condlog(4,"%s: creating new map", pp->dev); + if ((mpp = add_map_with_path(vecs, pp, 1))) + mpp->action = ACT_CREATE; +Index: b/libmultipath/config.h +=================================================================== +--- a/libmultipath/config.h ++++ b/libmultipath/config.h +@@ -89,6 +89,7 @@ struct config { + int attribute_flags; + int fast_io_fail; + unsigned int dev_loss; ++ int find_multipaths; + uid_t uid; + gid_t gid; + mode_t mode; diff -Nru multipath-tools-0.4.9/debian/patches/0043-alloc-keywords.patch multipath-tools-0.4.9/debian/patches/0043-alloc-keywords.patch --- multipath-tools-0.4.9/debian/patches/0043-alloc-keywords.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/0043-alloc-keywords.patch 2015-10-07 02:13:51.000000000 +0000 @@ -0,0 +1,79 @@ +From: Hannes Reinecke +Subject: Properly allocate keywords structure + +This patch is a subset of the changes in the commit: +ace982abd6cfe76fab3f89067db52e9f103972f5 +(multipath: add '-t' option to dump internal hwtable) + +It correctly initializes the vector for keywords in the case where there is no +multipath.conf file present when multipath-tools starts, and is effectively +no change for the case where the file is present (only moves vector +initialization outside of init_data() so that it can be used when we don't +want to call init_data()). + +The full contents of the commit are not included because it would be a new +feature, and we've already added enough of those by SRU (see the other +forty-some patches backported from 0.5.0). This one would have been for +convenience only, not critical to a properly functioning multipath +setup. ~cyphermox + +--- + libmultipath/config.c | 1 + + libmultipath/parser.c | 19 +++++++++++++------ + 2 files changed, 14 insertions(+), 6 deletions(-) + +Index: b/libmultipath/config.c +=================================================================== +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -500,6 +500,7 @@ load_config (char * file, struct udev *u + * read the config file + */ + set_current_keywords(&conf->keywords); ++ alloc_keywords(); + if (filepresent(file)) { + int builtin_hwtable_size; + +Index: b/libmultipath/parser.c +=================================================================== +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -24,8 +24,8 @@ + + /* local vars */ + static int sublevel = 0; +-vector keywords = NULL; +-vector *keywords_addr = NULL; ++static vector keywords = NULL; ++static vector *keywords_addr = NULL; + + void set_current_keywords (vector *k) + { +@@ -471,16 +471,23 @@ process_stream(vector keywords) + return r; + } + ++int alloc_keywords(void) ++{ ++ if (!keywords) ++ keywords = vector_alloc(); ++ ++ if (!keywords) ++ return 1; ++ ++ return 0; ++} ++ + /* Data initialization */ + int + init_data(char *conf_file, void (*init_keywords) (void)) + { + int r; + +- if (!keywords) +- keywords = vector_alloc(); +- if (!keywords) +- return 1; + stream = fopen(conf_file, "r"); + if (!stream) { + syslog(LOG_WARNING, "Configuration file open problem"); diff -Nru multipath-tools-0.4.9/debian/patches/series multipath-tools-0.4.9/debian/patches/series --- multipath-tools-0.4.9/debian/patches/series 2015-07-14 16:12:35.000000000 +0000 +++ multipath-tools-0.4.9/debian/patches/series 2015-12-01 15:11:07.000000000 +0000 @@ -23,4 +23,46 @@ 0021-fc-timeout-attrs-multipath-make-sure-all-the-hwe-attributes-get-merged.patch 0022-fc-timeout-attrs-multipath-fix-scsi-timeout-code.patch 0023-fc-timeout-attrs-multipath-make-sure-we-store-all-the-hwentry-attributes.patch -0024-ignore-usb.patch +0001-multipath-add-checker_timeout-default-config-option.patch +0002-Make-params-variable-local.patch +0003-libmultipath-Fix-possible-string-overflow.patch +0004-Update-hwtable-factorization.patch +0005-Fixup-strip-trailing-whitespaces-for-getuid-return-v.patch +0006-Remove-sysfs_attr-cache.patch +0007-Move-setup_thread_attr-to-uevent.c.patch +0008-Use-lists-for-uevent-processing.patch +0009-Start-uevent-service-handler-from-main-thread.patch +0010-libmultipath-rework-sysfs-handling.patch +0011-Rework-sysfs-device-handling-in-multipathd.patch +0012-Only-check-offline-status-for-SCSI-devices.patch +0013-Check-for-offline-path-in-get_prio.patch +0014-libmultipath-Remove-duplicate-calls-to-path_offline.patch +0015-Update-dev_loss_tmo-for-no_path_retry.patch +0016-Reload-map-for-device-read-only-setting-changes.patch +0017-multipath-get-right-sysfs-value-for-checker_timeout.patch +0018-multipath-handle-offlined-paths.patch +0019-multipath-fix-scsi-timeout-code.patch +0020-multipath-make-tgt_node_name-work-for-iscsi-devices.patch +0021-multipath-cleanup-dev_loss_tmo-issues.patch +0022-Fix-for-setting-0-to-fast_io_fail.patch +0023-Fix-fast_io_fail-capping.patch +0024-multipath-enable-getting-uevents-through-libudev.patch +0025-Use-devpath-as-argument-for-sysfs-functions.patch +0026-multipathd-remove-references-to-sysfs_device.patch +0027-multipathd-use-struct-path-as-argument-for-event-pro.patch +0028-Add-global-udev-reference-pointer-to-config.patch +0029-Use-udev-enumeration-during-discovery.patch +0030-use-struct-udev_device-during-discovery.patch +0031-More-debugging-output-when-synchronizing-path-states.patch +0032-Use-struct-udev_device-instead-of-sysdev.patch +0033-discovery-Fixup-cciss-discovery.patch +0035-Use-udev-devices-during-discovery.patch +0036-Remove-all-references-to-hand-craftes-sysfs-code.patch +0037-multipath-libudev-cleanup-and-bugfixes.patch +0038-multipath-check-if-a-device-belongs-to-multipath.patch +0039-multipath-and-wwids_file-multipath.conf-option.patch +0040-multipath-Check-blacklists-as-soon-as-possible.patch +0041-add-wwids-file-cleanup-options.patch +0042-add-find_multipaths-option.patch +0043-alloc-keywords.patch +0014-kpartx-long-path.patch diff -Nru multipath-tools-0.4.9/debian/rules multipath-tools-0.4.9/debian/rules --- multipath-tools-0.4.9/debian/rules 2015-07-13 18:31:31.000000000 +0000 +++ multipath-tools-0.4.9/debian/rules 2015-12-01 15:20:23.000000000 +0000 @@ -69,7 +69,6 @@ dh_installinit -pmultipath-tools dh_installinit -pmultipath-tools --name=multipath-tools-boot --no-start -- start 21 S . dh_installudev -pkpartx --priority=95 - dh_installudev -pmultipath-tools --name=multipath --priority=95 dh_installdebconf -pmultipath-tools-boot dh_installman dh_makeshlibs --add-udeb=multipath-udeb