Imported Upstream version 0.6.0 upstream/0.6.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:14 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:14 +0000 (13:50 +0900)
100 files changed:
COPYING
Makefile
Makefile.inc
kpartx/devmapper.c
kpartx/devmapper.h
kpartx/dos.c
kpartx/kpartx.c
kpartx/kpartx.rules
kpartx/lopart.c
kpartx/sun.c
libmpathcmd/Makefile [new file with mode: 0644]
libmpathcmd/mpath_cmd.c [new file with mode: 0644]
libmpathcmd/mpath_cmd.h [new file with mode: 0644]
libmpathpersist/Makefile
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_updatepr.c
libmpathpersist/mpathpr.h
libmultipath/Makefile
libmultipath/alias.c
libmultipath/alias.h
libmultipath/blacklist.c
libmultipath/blacklist.h
libmultipath/callout.c
libmultipath/checkers.c
libmultipath/checkers.h
libmultipath/checkers/rdac.c
libmultipath/config.c
libmultipath/config.h
libmultipath/configure.c
libmultipath/configure.h
libmultipath/defaults.h
libmultipath/devmapper.c
libmultipath/devmapper.h
libmultipath/dict.c
libmultipath/dict.h
libmultipath/discovery.c
libmultipath/discovery.h
libmultipath/dmparser.c
libmultipath/hwtable.c
libmultipath/list.h
libmultipath/log_pthread.c
libmultipath/parser.c
libmultipath/parser.h
libmultipath/pgpolicies.c
libmultipath/print.c
libmultipath/print.h
libmultipath/prio.c
libmultipath/prio.h
libmultipath/prioritizers/alua.c
libmultipath/prioritizers/alua_rtpg.c
libmultipath/prioritizers/alua_rtpg.h
libmultipath/prioritizers/emc.c
libmultipath/prioritizers/hds.c
libmultipath/prioritizers/hp_sw.c
libmultipath/prioritizers/iet.c
libmultipath/prioritizers/ontap.c
libmultipath/prioritizers/rdac.c
libmultipath/prioritizers/weightedpath.c
libmultipath/prioritizers/weightedpath.h
libmultipath/propsel.c
libmultipath/propsel.h
libmultipath/structs.c
libmultipath/structs.h
libmultipath/structs_vec.c
libmultipath/structs_vec.h
libmultipath/sysfs.c
libmultipath/sysfs.h
libmultipath/uevent.c
libmultipath/util.c
libmultipath/uxsock.c
libmultipath/uxsock.h
libmultipath/version.h
libmultipath/wwids.c
libmultipath/wwids.h
mpathpersist/Makefile
multipath.conf.annotated
multipath.conf.defaults
multipath.conf.synthetic
multipath/11-dm-mpath.rules [new file with mode: 0644]
multipath/Makefile
multipath/dev_t.h [deleted file]
multipath/main.c
multipath/multipath.8
multipath/multipath.conf.5
multipath/multipath.rules [new file with mode: 0644]
multipathd/Makefile
multipathd/cli.c
multipathd/cli.h
multipathd/cli_handlers.c
multipathd/cli_handlers.h
multipathd/main.c
multipathd/main.h
multipathd/multipathd.8
multipathd/multipathd.init.suse
multipathd/multipathd.service
multipathd/multipathd.socket
multipathd/uxclnt.c
multipathd/uxclnt.h
multipathd/uxlsnr.c
multipathd/uxlsnr.h

diff --git a/COPYING b/COPYING
index 9e31bbf0b336985f8ef7bff1d2dc73aaacd101dd..0ade0e91cf624693d7c3751b341b00333f154d36 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -3,7 +3,7 @@
                       Version 2, June 1991
 
  Copyright (C) 1991 Free Software Foundation, Inc.
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
index baf775314c13145bb08bae80dc5c8dc8981870c8..06f50c82b77d3c9f8b1d4c3c3148b67daf2e8223 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,7 @@ export KRNLSRC
 export KRNLOBJ
 
 BUILDDIRS = \
+       libmpathcmd \
        libmultipath \
        libmultipath/prioritizers \
        libmultipath/checkers \
index f4451602b371b29bdc397c52e376a7d65c115fe0..ecc20eff41a9121c90fdb4e459d22a0d18bd0902 100644 (file)
@@ -21,35 +21,50 @@ ifndef LIB
        endif
 endif
 
+ifndef RUN
+       ifeq ($(shell test -L /var/run -o ! -d /var/run && echo 1),1)
+               RUN=run
+       else
+               RUN=var/run
+       endif
+endif
+
 ifndef SYSTEMD
        ifeq ($(shell systemctl --version > /dev/null 2>&1 && echo 1), 1)
                SYSTEMD = $(shell systemctl --version 2> /dev/null |  sed -n 's/systemd \([0-9]*\)/\1/p')
        endif
 endif
 
+ifndef SYSTEMDPATH
+       SYSTEMDPATH=usr/lib
+endif
+
 prefix      = 
 exec_prefix = $(prefix)
 bindir      = $(exec_prefix)/sbin
-libudevdir  = ${prefix}/lib/udev
+libudevdir  = $(prefix)/$(SYSTEMDPATH)/udev
+udevrulesdir = $(libudevdir)/rules.d
 multipathdir = $(TOPDIR)/libmultipath
 mandir      = $(prefix)/usr/share/man/man8
 man5dir     = $(prefix)/usr/share/man/man5
 man3dir      = $(prefix)/usr/share/man/man3
 rcdir      = $(prefix)/etc/init.d
 syslibdir   = $(prefix)/$(LIB)
+incdir      = $(prefix)/usr/include
 libdir     = $(prefix)/$(LIB)/multipath
-unitdir     = $(prefix)/usr/lib/systemd/system
+unitdir     = $(prefix)/$(SYSTEMDPATH)/systemd/system
 mpathpersistdir = $(TOPDIR)/libmpathpersist
+mpathcmddir = $(TOPDIR)/libmpathcmd
 
 GZIP        = gzip -9 -c
 INSTALL_PROGRAM = install
 
 ifndef RPM_OPT_FLAGS
-       RPM_OPT_FLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
+       RPM_OPT_FLAGS = -O2 -g -pipe -Wformat-security -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
 endif
 
 OPTFLAGS     = $(RPM_OPT_FLAGS) -Wunused -Wstrict-prototypes
-CFLAGS      = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\"
+CFLAGS      = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
 SHARED_FLAGS = -shared
 
 %.o:   %.c
index 24a43ee8bb863d2f861cfa91c17c156f64ba7ef7..e006bc32f532eb7f717dc25c4b58c4013dfc73de 100644 (file)
 #define MAX_PREFIX_LEN 8
 #define PARAMS_SIZE 1024
 
-#ifndef LIBDM_API_COOKIE
-static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a)
-{
-       return 1;
-}
-#endif
-
 extern int
 dm_prereq (char * str, int x, int y, int z)
 {
@@ -60,10 +53,13 @@ dm_prereq (char * str, int x, int y, int z)
 }
 
 extern int
-dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) {
+dm_simplecmd (int task, const char *name, int no_flush, uint16_t udev_flags) {
        int r = 0;
        int udev_wait_flag = (task == DM_DEVICE_RESUME ||
                              task == DM_DEVICE_REMOVE);
+#ifdef LIBDM_API_COOKIE
+       uint32_t cookie = 0;
+#endif
        struct dm_task *dmt;
 
        if (!(dmt = dm_task_create(task)))
@@ -78,10 +74,23 @@ dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) {
        if (no_flush)
                dm_task_no_flush(dmt);
 
-       if (udev_wait_flag && !dm_task_set_cookie(dmt, cookie, (udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK))
+#ifdef LIBDM_API_COOKIE
+       if (!udev_sync)
+               udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
+       if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) {
+               dm_udev_complete(cookie);
                goto out;
+       }
+#endif
        r = dm_task_run(dmt);
-
+#ifdef LIBDM_API_COOKIE
+       if (udev_wait_flag) {
+               if (!r)
+                       dm_udev_complete(cookie);
+               else
+                       dm_udev_wait(cookie);
+       }
+#endif
        out:
        dm_task_destroy(dmt);
        return r;
@@ -90,10 +99,14 @@ dm_simplecmd (int task, const char *name, int no_flush, uint32_t *cookie) {
 extern int
 dm_addmap (int task, const char *name, const char *target,
           const char *params, uint64_t size, int ro, const char *uuid, int part,
-          mode_t mode, uid_t uid, gid_t gid, uint32_t *cookie) {
+          mode_t mode, uid_t uid, gid_t gid) {
        int r = 0;
        struct dm_task *dmt;
        char *prefixed_uuid = NULL;
+#ifdef LIBDM_API_COOKIE
+       uint32_t cookie = 0;
+       uint16_t udev_flags = 0;
+#endif
 
        if (!(dmt = dm_task_create (task)))
                return 0;
@@ -128,23 +141,42 @@ dm_addmap (int task, const char *name, const char *target,
 
        dm_task_no_open_count(dmt);
 
-       if (task == DM_DEVICE_CREATE && !dm_task_set_cookie(dmt, cookie, (udev_sync)? 0 : DM_UDEV_DISABLE_LIBRARY_FALLBACK))
+#ifdef LIBDM_API_COOKIE
+       if (!udev_sync)
+               udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
+       if (task == DM_DEVICE_CREATE &&
+           !dm_task_set_cookie(dmt, &cookie, udev_flags)) {
+               dm_udev_complete(cookie);
                goto addout;
+       }
+#endif
        r = dm_task_run (dmt);
-
-       addout:
+#ifdef LIBDM_API_COOKIE
+       if (task == DM_DEVICE_CREATE) {
+               if (!r)
+                       dm_udev_complete(cookie);
+               else
+                       dm_udev_wait(cookie);
+       }
+#endif
+addout:
        dm_task_destroy (dmt);
+       free(prefixed_uuid);
 
        return r;
 }
 
 extern int
-dm_map_present (char * str)
+dm_map_present (char * str, char **uuid)
 {
        int r = 0;
        struct dm_task *dmt;
+       const char *uuidtmp;
        struct dm_info info;
 
+       if (uuid)
+               *uuid = NULL;
+
        if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
                return 0;
 
@@ -159,8 +191,15 @@ dm_map_present (char * str)
        if (!dm_task_get_info(dmt, &info))
                goto out;
 
-       if (info.exists)
-               r = 1;
+       if (!info.exists)
+               goto out;
+
+       r = 1;
+       if (uuid) {
+               uuidtmp = dm_task_get_uuid(dmt);
+               if (uuidtmp && strlen(uuidtmp))
+                       *uuid = strdup(uuidtmp);
+       }
 out:
        dm_task_destroy(dmt);
        return r;
index 0edc063a9e11961ede0c3e4c16e32e18f98d9122..436efe11c9913de8dadcbe412fd1a36505b6fd6d 100644 (file)
@@ -1,16 +1,23 @@
-#define MAJOR(dev)      ((dev & 0xfff00) >> 8)
-#define MINOR(dev)      ((dev & 0xff) | ((dev >> 12) & 0xfff00))
-#define MKDEV(ma,mi)    ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
+#ifndef _KPARTX_DEVMAPPER_H
+#define _KPARTX_DEVMAPPER_H
+
+#ifdef DM_SUBSYSTEM_UDEV_FLAG0
+#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0
+#else
+#define MPATH_UDEV_RELOAD_FLAG 0
+#endif
 
 extern int udev_sync;
 
 int dm_prereq (char *, int, int, int);
-int dm_simplecmd (int, const char *, int, uint32_t *);
+int dm_simplecmd (int, const char *, int, uint16_t);
 int dm_addmap (int, const char *, const char *, const char *, uint64_t,
-              int, const char *, int, mode_t, uid_t, gid_t, uint32_t *);
-int dm_map_present (char *);
+              int, const char *, int, mode_t, uid_t, gid_t);
+int dm_map_present (char *, char **);
 char * dm_mapname(int major, int minor);
 dev_t dm_get_first_dep(char *devname);
 char * dm_mapuuid(int major, int minor);
 int dm_devn (char * mapname, int *major, int *minor);
 int dm_no_partitions(int major, int minor);
+
+#endif /* _KPARTX_DEVMAPPER_H */
index 0e57f0e2d55a2032fd96e76f5efc6abdd31953d0..90ad3bd0e04a50dc13b574553696f0bee623a7b3 100644 (file)
@@ -101,8 +101,12 @@ read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
                        break;
                }
                if (is_extended(p.sys_type)) {
-                       sp[i].size = sector_size_mul * 2; /* extended partitions only get two
-                                          sectors mapped for LILO to install */
+                       /* extended partitions only get one or
+                          two sectors mapped for LILO to install,
+                          whichever is needed to have 1kb of space */
+                       if (sector_size_mul == 1)
+                               sp[i].size = 2;
+                       else sp[i].size = sector_size_mul;
                        n += read_extended_partition(fd, &p, i, sp+n, ns-n);
                }
        }
index 9a9a5eb20b560ca17ad1775c5b1368393bda0962..e8c35d436472a667a2af3762abd356a5202113a8 100644 (file)
@@ -168,8 +168,8 @@ get_hotplug_device(void)
        if (stat(devname, &buf))
                return NULL;
 
-       major = (unsigned int)MAJOR(buf.st_rdev);
-       minor = (unsigned int)MINOR(buf.st_rdev);
+       major = major(buf.st_rdev);
+       minor = minor(buf.st_rdev);
 
        if (!(mapname = dm_mapname(major, minor))) /* Not dm device. */
                return NULL;
@@ -191,6 +191,21 @@ get_hotplug_device(void)
        return device;
 }
 
+static int
+check_uuid(char *uuid, char *part_uuid, char **err_msg) {
+       char *map_uuid = strchr(part_uuid, '-');
+       if (!map_uuid || strncmp(part_uuid, "part", 4) != 0) {
+               *err_msg = "not a kpartx partition";
+               return -1;
+       }
+       map_uuid++;
+       if (strcmp(uuid, map_uuid) != 0) {
+               *err_msg = "a partition of a different device";
+               return -1;
+       }
+       return 0;
+}
+
 int
 main(int argc, char **argv){
        int i, j, m, n, op, off, arg, c, d, ro=0;
@@ -208,7 +223,6 @@ main(int argc, char **argv){
        int hotplug = 0;
        int loopcreated = 0;
        struct stat buf;
-       uint32_t cookie = 0;
 
        initpts();
        init_crc32();
@@ -281,6 +295,8 @@ main(int argc, char **argv){
 #ifdef LIBDM_API_COOKIE
        if (!udev_sync)
                dm_udev_set_sync_support(0);
+       else
+               dm_udev_set_sync_support(1);
 #endif
 
        if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE || what == UPDATE)) {
@@ -322,15 +338,18 @@ main(int argc, char **argv){
                        loopcreated = 1;
                }
                device = loopdev;
+
+               if (stat(device, &buf)) {
+                       printf("failed to stat() %s\n", device);
+                       exit (1);
+               }
        }
 
        off = find_devname_offset(device);
 
        if (!loopdev) {
-               uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
-                                 (unsigned int)MINOR(buf.st_rdev));
-               mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev),
-                                    (unsigned int)MINOR(buf.st_rdev));
+               uuid = dm_mapuuid(major(buf.st_rdev), minor(buf.st_rdev));
+               mapname = dm_mapname(major(buf.st_rdev), minor(buf.st_rdev));
        }
 
        if (!uuid)
@@ -339,8 +358,7 @@ main(int argc, char **argv){
        if (!mapname)
                mapname = device + off;
        else if (!force_devmap &&
-                dm_no_partitions((unsigned int)MAJOR(buf.st_rdev),
-                                 (unsigned int)MINOR(buf.st_rdev))) {
+                dm_no_partitions(major(buf.st_rdev), minor(buf.st_rdev))) {
                /* Feature 'no_partitions' is set, return */
                return 0;
        }
@@ -428,7 +446,9 @@ main(int argc, char **argv){
                        break;
 
                case DELETE:
-                       for (j = n-1; j >= 0; j--) {
+                       for (j = MAXSLICES-1; j >= 0; j--) {
+                               char *part_uuid, *reason;
+
                                if (safe_sprintf(partname, "%s%s%d",
                                             mapname, delim, j+1)) {
                                        fprintf(stderr, "partname too small\n");
@@ -436,11 +456,20 @@ main(int argc, char **argv){
                                }
                                strip_slash(partname);
 
-                               if (!slices[j].size || !dm_map_present(partname))
+                               if (!dm_map_present(partname, &part_uuid))
                                        continue;
 
+                               if (part_uuid && uuid) {
+                                       if (check_uuid(uuid, part_uuid, &reason) != 0) {
+                                               fprintf(stderr, "%s is %s. Not removing\n", partname, reason);
+                                               free(part_uuid);
+                                               continue;
+                                       }
+                                       free(part_uuid);
+                               }
+
                                if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
-                                                 0, &cookie)) {
+                                                 0, 0)) {
                                        r++;
                                        continue;
                                }
@@ -463,6 +492,8 @@ main(int argc, char **argv){
                case UPDATE:
                        /* ADD and UPDATE share the same code that adds new partitions. */
                        for (j = 0, c = 0; j < n; j++) {
+                               char *part_uuid, *reason;
+
                                if (slices[j].size == 0)
                                        continue;
 
@@ -479,30 +510,43 @@ main(int argc, char **argv){
                                }
                                strip_slash(partname);
 
-                               if (safe_sprintf(params, "%s %" PRIu64 ,
-                                                device, slices[j].start)) {
+                               if (safe_sprintf(params, "%d:%d %" PRIu64 ,
+                                                major(buf.st_rdev), minor(buf.st_rdev), slices[j].start)) {
                                        fprintf(stderr, "params too small\n");
                                        exit(1);
                                }
 
-                               op = (dm_map_present(partname) ?
+                               op = (dm_map_present(partname, &part_uuid) ?
                                        DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
 
+                               if (part_uuid && uuid) {
+                                       if (check_uuid(uuid, part_uuid, &reason) != 0) {
+                                               fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
+                                               r++;
+                                               free(part_uuid);
+                                               continue;
+                                       }
+                                       free(part_uuid);
+                               }
+
                                if (!dm_addmap(op, partname, DM_TARGET, params,
                                               slices[j].size, ro, uuid, j+1,
                                               buf.st_mode & 0777, buf.st_uid,
-                                              buf.st_gid, &cookie)) {
+                                              buf.st_gid)) {
                                        fprintf(stderr, "create/reload failed on %s\n",
                                                partname);
                                        r++;
+                                       continue;
                                }
                                if (op == DM_DEVICE_RELOAD &&
                                    !dm_simplecmd(DM_DEVICE_RESUME, partname,
-                                                 1, &cookie)) {
+                                                 1, MPATH_UDEV_RELOAD_FLAG)) {
                                        fprintf(stderr, "resume failed on %s\n",
                                                partname);
                                        r++;
+                                       continue;
                                }
+
                                dm_devn(partname, &slices[j].major,
                                        &slices[j].minor);
 
@@ -516,6 +560,7 @@ main(int argc, char **argv){
                        d = c;
                        while (c) {
                                for (j = 0; j < n; j++) {
+                                       char *part_uuid, *reason;
                                        int k = slices[j].container - 1;
 
                                        if (slices[j].size == 0)
@@ -541,33 +586,41 @@ main(int argc, char **argv){
                                        }
                                        strip_slash(partname);
 
-                                       if (safe_sprintf(params, "%s %" PRIu64,
-                                                        device,
+                                       if (safe_sprintf(params, "%d:%d %" PRIu64,
+                                                        major(buf.st_rdev), minor(buf.st_rdev),
                                                         slices[j].start)) {
                                                fprintf(stderr, "params too small\n");
                                                exit(1);
                                        }
 
-                                       op = (dm_map_present(partname) ?
+                                       op = (dm_map_present(partname,
+                                                            &part_uuid) ?
                                              DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
 
+                                       if (part_uuid && uuid) {
+                                               if (check_uuid(uuid, part_uuid, &reason) != 0) {
+                                                       fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
+                                                       free(part_uuid);
+                                                       continue;
+                                               }
+                                               free(part_uuid);
+                                       }
+
                                        dm_addmap(op, partname, DM_TARGET, params,
                                                  slices[j].size, ro, uuid, j+1,
                                                  buf.st_mode & 0777,
-                                                 buf.st_uid, buf.st_gid,
-                                                 &cookie);
+                                                 buf.st_uid, buf.st_gid);
 
                                        if (op == DM_DEVICE_RELOAD)
                                                dm_simplecmd(DM_DEVICE_RESUME,
                                                             partname, 1,
-                                                            &cookie);
-
+                                                            MPATH_UDEV_RELOAD_FLAG);
                                        dm_devn(partname, &slices[j].major,
                                                &slices[j].minor);
 
                                        if (verbose)
-                                               printf("add map %s : 0 %" PRIu64 " %s %s\n",
-                                                      partname, slices[j].size,
+                                               printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
+                                                      partname, slices[j].major, slices[j].minor, slices[j].size,
                                                       DM_TARGET, params);
                                        c--;
                                }
@@ -582,6 +635,7 @@ main(int argc, char **argv){
                        }
 
                        for (j = MAXSLICES-1; j >= 0; j--) {
+                               char *part_uuid, *reason;
                                if (safe_sprintf(partname, "%s%s%d",
                                             mapname, delim, j+1)) {
                                        fprintf(stderr, "partname too small\n");
@@ -589,11 +643,21 @@ main(int argc, char **argv){
                                }
                                strip_slash(partname);
 
-                               if (slices[j].size || !dm_map_present(partname))
+                               if (slices[j].size ||
+                                   !dm_map_present(partname, &part_uuid))
                                        continue;
 
+                               if (part_uuid && uuid) {
+                                       if (check_uuid(uuid, part_uuid, &reason) != 0) {
+                                               fprintf(stderr, "%s is %s. Not removing\n", partname, reason);
+                                               free(part_uuid);
+                                               continue;
+                                       }
+                                       free(part_uuid);
+                               }
+
                                if (!dm_simplecmd(DM_DEVICE_REMOVE,
-                                                 partname, 1, &cookie)) {
+                                                 partname, 1, 0)) {
                                        r++;
                                        continue;
                                }
@@ -619,9 +683,7 @@ main(int argc, char **argv){
                }
                printf("loop deleted : %s\n", device);
        }
-#ifdef LIBDM_API_COOKIE
-       dm_udev_wait(cookie);
-#endif
+
        dm_lib_release();
        dm_lib_exit();
 
index 5c0d0ff7ee2e5d29df2eacb302cf31a551ac61f9..022361f907e873ac16fc75459b88af34b27576e5 100644 (file)
@@ -12,12 +12,6 @@ ENV{DM_DEPS}=="0", GOTO="kpartx_end"
 
 ENV{DM_UUID}=="?*", IMPORT{program}=="kpartx_id %M %m $env{DM_UUID}"
 
-ENV{DM_ACTION}=="PATH_FAILED", ENV{DM_NR_VALID_PATHS}=="0", \
-       GOTO="blkid_end"
-ENV{DM_UUID}=="mpath-*", IMPORT{program}="/sbin/blkid -o udev -p $tempnode"
-ENV{DM_PART}=="?*", IMPORT{program}="/sbin/blkid -o udev -p $tempnode"
-LABEL="blkid_end"
-
 OPTIONS="link_priority=50"
 
 # Create persistent links for multipath tables
@@ -46,8 +40,8 @@ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", \
        SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
 
 # Create dm tables for partitions
-ENV{DM_ACTION}=="PATH_FAILED", ENV{DM_NR_VALID_PATHS}=="0", \
-       GOTO="kpartx_end"
+ENV{DM_ACTION}=="PATH_FAILED|PATH_REINSTATED", GOTO="kpartx_end"
+ENV{DM_NR_VALID_PATHS}=="0", GOTO="kpartx_end"
 ENV{DM_STATE}!="SUSPENDED", ENV{DM_UUID}=="mpath-*", \
         RUN+="/sbin/kpartx -u -p -part /dev/$name"
 
index 6f83048ddd44b62f2251ec695f48f31c58fdf185..26f30111ff2df443668e03d4ffb0f9dabfc32530 100644 (file)
@@ -103,6 +103,14 @@ find_loop_by_file (const char * filename)
        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 @@ find_loop_by_file (const char * filename)
                                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 */
                        }
index 3d88b2150ce457cd509f177c8924e630083fa989..b8c023b18120f5f0a9e3e6cb7c6bcebe4bef45b9 100644 (file)
@@ -82,8 +82,6 @@ read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
        for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
                s = &l->partitions[i];
 
-               if (s->num_sectors == 0)
-                       continue;
                if (n < ns) {
                        sp[n].start = offset +
                                be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
diff --git a/libmpathcmd/Makefile b/libmpathcmd/Makefile
new file mode 100644 (file)
index 0000000..0304ecc
--- /dev/null
@@ -0,0 +1,30 @@
+# Makefile
+#
+include ../Makefile.inc
+
+SONAME=0
+DEVLIB = libmpathcmd.so
+LIBS = $(DEVLIB).$(SONAME)
+
+OBJS = mpath_cmd.o
+
+all: $(LIBS)
+
+$(LIBS): $(OBJS)
+       $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS)
+       ln -sf $@ $(DEVLIB)
+
+install: $(LIBS)
+       $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
+       $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
+       ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+       $(INSTALL_PROGRAM) -d $(DESTDIR)$(incdir)
+       $(INSTALL_PROGRAM) -m 755 mpath_cmd.h $(DESTDIR)$(incdir)
+
+uninstall:
+       rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
+       rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB)
+       rm -f $(DESTDIR)$(incdir)/mpath_cmd.h
+
+clean:
+       rm -f core *.a *.o *.gz *.so *.so.*
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
new file mode 100644 (file)
index 0000000..1aaf5ea
--- /dev/null
@@ -0,0 +1,178 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <string.h>
+#include <errno.h>
+
+#include "mpath_cmd.h"
+
+/*
+ * keep reading until its all read
+ */
+static ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout)
+{
+       size_t total = 0;
+       ssize_t n;
+       int ret;
+       struct pollfd pfd;
+
+       while (len) {
+               pfd.fd = fd;
+               pfd.events = POLLIN;
+               ret = poll(&pfd, 1, timeout);
+               if (!ret) {
+                       errno = ETIMEDOUT;
+                       return -1;
+               } else if (ret < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return -1;
+               } else if (!pfd.revents & POLLIN)
+                       continue;
+               n = read(fd, buf, len);
+               if (n < 0) {
+                       if ((errno == EINTR) || (errno == EAGAIN))
+                               continue;
+                       return -1;
+               }
+               if (!n)
+                       return total;
+               buf = n + (char *)buf;
+               len -= n;
+               total += n;
+       }
+       return total;
+}
+
+/*
+ * keep writing until it's all sent
+ */
+static size_t write_all(int fd, const void *buf, size_t len)
+{
+       size_t total = 0;
+
+       while (len) {
+               ssize_t n = write(fd, buf, len);
+               if (n < 0) {
+                       if ((errno == EINTR) || (errno == EAGAIN))
+                               continue;
+                       return total;
+               }
+               if (!n)
+                       return total;
+               buf = n + (char *)buf;
+               len -= n;
+               total += n;
+       }
+       return total;
+}
+
+/*
+ * connect to a unix domain socket
+ */
+int mpath_connect(void)
+{
+       int fd, len;
+       struct sockaddr_un addr;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_LOCAL;
+       addr.sun_path[0] = '\0';
+       len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t);
+       strncpy(&addr.sun_path[1], DEFAULT_SOCKET, len);
+
+       fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (fd == -1)
+               return -1;
+
+       if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+int mpath_disconnect(int fd)
+{
+       return close(fd);
+}
+
+ssize_t mpath_recv_reply_len(int fd, unsigned int timeout)
+{
+       size_t len;
+       ssize_t ret;
+
+       ret = read_all(fd, &len, sizeof(len), timeout);
+       if (ret < 0)
+               return ret;
+       if (ret != sizeof(len)) {
+               errno = EIO;
+               return ret;
+       }
+       return len;
+}
+
+int mpath_recv_reply_data(int fd, char *reply, size_t len,
+                         unsigned int timeout)
+{
+       ssize_t ret;
+
+       ret = read_all(fd, reply, len, timeout);
+       if (ret < 0)
+               return ret;
+       if (ret != len) {
+               errno = EIO;
+               return -1;
+       }
+       reply[len - 1] = '\0';
+       return 0;
+}
+
+int mpath_recv_reply(int fd, char **reply, unsigned int timeout)
+{
+       int err;
+       ssize_t len;
+
+       *reply = NULL;
+       len = mpath_recv_reply_len(fd, timeout);
+       if (len <= 0)
+               return len;
+       *reply = malloc(len);
+       if (!*reply)
+               return -1;
+       err = mpath_recv_reply_data(fd, *reply, len, timeout);
+       if (err) {
+               free(*reply);
+               *reply = NULL;
+               return err;
+       }
+       return 0;
+}
+
+int mpath_send_cmd(int fd, const char *cmd)
+{
+       size_t len;
+
+       if (cmd != NULL)
+               len = strlen(cmd) + 1;
+       else
+               len = 0;
+       if (write_all(fd, &len, sizeof(len)) != sizeof(len))
+               return -1;
+       if (len && write_all(fd, cmd, len) != len)
+               return -1;
+       return 0;
+}
+
+int mpath_process_cmd(int fd, const char *cmd, char **reply,
+                     unsigned int timeout)
+{
+       if (mpath_send_cmd(fd, cmd) != 0)
+               return -1;
+       return mpath_recv_reply(fd, reply, timeout);
+}
diff --git a/libmpathcmd/mpath_cmd.h b/libmpathcmd/mpath_cmd.h
new file mode 100644 (file)
index 0000000..6d80a2f
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * This file is part of the device-mapper multipath userspace tools.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef LIB_MPATH_CMD_H
+#define LIB_MPATH_CMD_H
+
+#ifdef __cpluscplus
+extern "C" {
+#endif
+
+#define DEFAULT_SOCKET         "/org/kernel/linux/storage/multipathd"
+#define DEFAULT_REPLY_TIMEOUT  1000
+
+
+/*
+ * DESCRIPTION:
+ *     Connect to the running multipathd daemon. On systems with the
+ *     multipathd.socket systemd unit file installed, this command will
+ *     start multipathd if it is not already running. This function
+ *     must be run before any of the others in this library
+ *
+ * RETURNS:
+ *     A file descriptor on success. -1 on failure (with errno set).
+ */
+int mpath_connect(void);
+
+
+/*
+ * DESCRIPTION:
+ *     Disconnect from the multipathd daemon. This function must be
+ *     run after after processing all the multipath commands.
+ *
+ * RETURNS:
+ *     0 on success. -1 on failure (with errno set).
+ */
+int mpath_disconnect(int fd);
+
+
+/*
+ * DESCRIPTION
+ *     Send multipathd a command and return the reply. This function
+ *     does the same as calling mpath_send_cmd() and then
+ *     mpath_recv_reply()
+ *
+ * RETURNS:
+ *     0 on successs, and reply will either be NULL (if there was no
+ *     reply data), or point to the reply string, which must be freed by
+ *     the caller. -1 on failure (with errno set).
+ */
+int mpath_process_cmd(int fd, const char *cmd, char **reply,
+                     unsigned int timeout);
+
+
+/*
+ * DESCRIPTION:
+ *     Send a command to multipathd
+ *
+ * RETURNS:
+ *     0 on success. -1 on failure (with errno set)
+ */
+int mpath_send_cmd(int fd, const char *cmd);
+
+
+/*
+ * DESCRIPTION:
+ *     Return a reply from multipathd for a previously sent command.
+ *     This is equivalent to calling mpath_recv_reply_len(), allocating
+ *     a buffer of the appropriate size, and then calling
+ *     mpath_recv_reply_data() with that buffer.
+ *
+ * RETURNS:
+ *     0 on success, and reply will either be NULL (if there was no
+ *     reply data), or point to the reply string, which must be freed by
+ *     the caller, -1 on failure (with errno set).
+ */
+int mpath_recv_reply(int fd, char **reply, unsigned int timeout);
+
+
+/*
+ * DESCRIPTION:
+ *     Return the size of the upcoming reply data from the sent multipath
+ *     command. This must be called before calling mpath_recv_reply_data().
+ *
+ * RETURNS:
+ *     The required size of the reply data buffer on success. -1 on
+ *     failure (with errno set).
+ */
+ssize_t mpath_recv_reply_len(int fd, unsigned int timeout);
+
+
+/*
+ * DESCRIPTION:
+ *     Return the reply data from the sent multipath command.
+ *     mpath_recv_reply_len must be called first. reply must point to a
+ *     buffer of len size.
+ *
+ * RETURNS:
+ *     0 on success, and reply will contain the reply data string. -1
+ *     on failure (with errno set).
+ */
+int mpath_recv_reply_data(int fd, char *reply, size_t len,
+                         unsigned int timeout);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIB_MPATH_CMD_H */
index c4ec1c540462716f001eacf1a447f2ace1f01d6a..e49cdb99bc63eaa64cebd9a90fe2368133795fe2 100644 (file)
@@ -10,8 +10,9 @@ DEVLIB = libmpathpersist.so
 LIBS = $(DEVLIB).$(SONAME)
 
 
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) 
-LIBDEPS +=  -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) 
+LIBDEPS +=  -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \
+       -L$(mpathcmddir) -lmpathcmd
 
 OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o 
 
@@ -30,17 +31,17 @@ install: $(LIBS)
        $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
        $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir)
        $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir)
-       $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/include/
+       $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(incdir)
        $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/share/doc/mpathpersist/
        ln -sf $(DESTDIR)$(syslibdir)/$(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
        install -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir)    
        install -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir)   
-       install -m 644 mpath_persist.h $(DESTDIR)/usr/include/
+       install -m 644 mpath_persist.h $(DESTDIR)$(incdir)
 
 uninstall:
        rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
-       rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_in.3.gz 
-       rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_out.3.gz        
+       rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz        
+       rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz       
 
 clean:
        rm -f core *.a *.o 
index bd301250e185b23e839b971b08097eb19eb264c7..b23e116031e37a8a0daa481d24236756a064b653 100644 (file)
@@ -1,7 +1,7 @@
 #include <libdevmapper.h>
 #include <defaults.h>
 #include <sys/stat.h>
-#include <linux/kdev_t.h>
+#include <sys/types.h>
 #include <fcntl.h>
 #include <vector.h>
 #include <checkers.h>
@@ -19,6 +19,7 @@
 #include <dmparser.h>
 #include <ctype.h>
 #include <propsel.h>
+#include <util.h>
 
 #include "mpath_persist.h"
 #include "mpathpr.h"
@@ -28,6 +29,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
+#include <sys/resource.h>
 
 #define __STDC_FORMAT_MACROS 1
 
@@ -40,6 +43,16 @@ mpath_lib_init (struct udev *udev)
                return 1;
        }
 
+       if (conf->max_fds) {
+               struct rlimit fd_limit;
+
+               fd_limit.rlim_cur = conf->max_fds;
+               fd_limit.rlim_max = conf->max_fds;
+               if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
+                       condlog(0, "can't set open fds limit to %d : %s",
+                                  conf->max_fds, strerror(errno));
+       }
+
        return 0;
 }
 
@@ -71,7 +84,8 @@ updatepaths (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, PATH_SIZE,
+                                                pp->dev_t)){
                                        /*
                                         * path is not in sysfs anymore
                                         */
@@ -94,7 +108,7 @@ updatepaths (struct multipath * mpp)
        return 0;
 }
 
-int 
+int
 mpath_prin_activepath (struct multipath *mpp, int rq_servact,
        struct prin_resp * resp, int noisy)
 {
@@ -104,14 +118,19 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
 
        vector_foreach_slot (mpp->pg, pgp, j){
                vector_foreach_slot (pgp->paths, pp, i){
-                       if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
-                               condlog(2, "%s: %s not available. Skip.", mpp->wwid, pp->dev);
-                               condlog(3, "%s: status = %d.", mpp->wwid, pp->state);
+                       if (!((pp->state == PATH_UP) ||
+                             (pp->state == PATH_GHOST))){
+                               condlog(2, "%s: %s not available. Skip.",
+                                       mpp->wwid, pp->dev);
+                               condlog(3, "%s: status = %d.",
+                                       mpp->wwid, pp->state);
                                continue;
                        }
 
-                       condlog(3, "%s: sending pr in command to %s ", mpp->wwid, pp->dev);
-                       ret = mpath_send_prin_activepath(pp->dev, rq_servact, resp, noisy);
+                       condlog(3, "%s: sending pr in command to %s ",
+                               mpp->wwid, pp->dev);
+                       ret = mpath_send_prin_activepath(pp->dev, rq_servact,
+                                                        resp, noisy);
                        switch(ret)
                        {
                                case MPATH_PR_SUCCESS:
@@ -122,10 +141,11 @@ mpath_prin_activepath (struct multipath *mpp, int rq_servact,
                        }
                }
        }
-       return ret;     
+       return ret;
 }
 
-int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)
+int mpath_persistent_reserve_in (int fd, int rq_servact,
+       struct prin_resp *resp, int noisy, int verbose)
 {
        struct stat info;
        vector curmp = NULL;
@@ -141,14 +161,14 @@ int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp,
        if (fstat( fd, &info) != 0){
                condlog(0, "stat error %d", fd);
                return MPATH_PR_FILE_ERROR;
-       } 
+       }
        if(!S_ISBLK(info.st_mode)){
                condlog(0, "Failed to get major:minor. fd = %d", fd);
                return MPATH_PR_FILE_ERROR;
        }
 
-       major = (int)MAJOR(info.st_rdev);
-       minor = (int)MINOR(info.st_rdev);       
+       major = major(info.st_rdev);
+       minor = minor(info.st_rdev);
        condlog(4, "Device %d:%d:  ", major, minor);
 
        /* get alias from major:minor*/
@@ -160,7 +180,7 @@ int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp,
 
        condlog(3, "alias = %s", alias);
        map_present = dm_map_present(alias);
-       if (map_present && dm_type(alias, TGT_MPATH) <= 0){
+       if (map_present && !dm_is_mpath(alias)){
                condlog( 0, "%s: not a multipath device.", alias);
                ret = MPATH_PR_DMMP_ERROR;
                goto out;
@@ -178,7 +198,7 @@ int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp,
                goto out;
        }
 
-       if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER)) {
+       if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
                ret = MPATH_PR_DMMP_ERROR;
                goto out1;
        }
@@ -201,14 +221,14 @@ int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp,
 
 out1:
        free_multipathvec(curmp, KEEP_PATHS);
-       free_pathvec(pathvec, FREE_PATHS);      
+       free_pathvec(pathvec, FREE_PATHS);
 out:
        FREE(alias);
-       return ret;                                             
+       return ret;
 }
 
 int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
-               unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
+       unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
 {
 
        struct stat info;
@@ -223,7 +243,7 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
        int ret;
        int j;
        unsigned char *keyp;
-       uint64_t prkey;         
+       uint64_t prkey;
 
        conf->verbosity = verbose;
 
@@ -234,11 +254,11 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
 
        if(!S_ISBLK(info.st_mode)){
                condlog(3, "Failed to get major:minor. fd=%d", fd);
-               return MPATH_PR_FILE_ERROR;     
-       }       
+               return MPATH_PR_FILE_ERROR;
+       }
 
-       major = (int)MAJOR(info.st_rdev);
-       minor = (int)MINOR(info.st_rdev);
+       major = major(info.st_rdev);
+       minor = minor(info.st_rdev);
        condlog(4, "Device  %d:%d", major, minor);
 
        /* get WWN of the device from major:minor*/
@@ -250,7 +270,7 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
        condlog(3, "alias = %s", alias);
        map_present = dm_map_present(alias);
 
-       if (map_present && dm_type(alias, TGT_MPATH) <= 0){
+       if (map_present && !dm_is_mpath(alias)){
                condlog(3, "%s: not a multipath device.", alias);
                ret = MPATH_PR_DMMP_ERROR;
                goto out;
@@ -262,13 +282,13 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
        curmp = vector_alloc ();
        pathvec = vector_alloc ();
 
-        if (!curmp || !pathvec){
-                condlog (0, "%s: vector allocation failed.", alias);
-                ret = MPATH_PR_DMMP_ERROR;
-                goto out;
-        }
+       if (!curmp || !pathvec){
+               condlog (0, "%s: vector allocation failed.", alias);
+               ret = MPATH_PR_DMMP_ERROR;
+               goto out;
+       }
 
-       if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER)) {
+       if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
                ret = MPATH_PR_DMMP_ERROR;
                goto out1;
        }
@@ -292,22 +312,22 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
 
        switch(rq_servact)
        {
-               case MPATH_PROUT_REG_SA: 
-               case MPATH_PROUT_REG_IGN_SA:  
-                       ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-                       break;
-               case MPATH_PROUT_RES_SA :  
-               case MPATH_PROUT_PREE_SA :  
-               case MPATH_PROUT_PREE_AB_SA :  
-               case MPATH_PROUT_CLEAR_SA:  
-                       ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-                       break;
-               case MPATH_PROUT_REL_SA:
-                       ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
-                       break;
-               default:
-                       ret = MPATH_PR_OTHER;
-                       goto out1;
+       case MPATH_PROUT_REG_SA:
+       case MPATH_PROUT_REG_IGN_SA:
+               ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       case MPATH_PROUT_RES_SA :
+       case MPATH_PROUT_PREE_SA :
+       case MPATH_PROUT_PREE_AB_SA :
+       case MPATH_PROUT_CLEAR_SA:
+               ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       case MPATH_PROUT_REL_SA:
+               ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+               break;
+       default:
+               ret = MPATH_PR_OTHER;
+               goto out1;
        }
 
        if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
@@ -326,7 +346,7 @@ int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
                else
                        update_prflag(alias, "set", noisy);
        } else {
-               if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) || 
+               if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) ||
                                        (rq_servact == MPATH_PROUT_PREE_AB_SA ))){
                        update_prflag(alias, "unset", noisy);
                }
@@ -337,7 +357,7 @@ out1:
 
 out:
        FREE(alias);
-       return ret; 
+       return ret;
 }
 
 int
@@ -365,9 +385,9 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid)
                dm_get_map(mpp->alias, &mpp->size, params);
                condlog(3, "params = %s", params);
                dm_get_status(mpp->alias, status);
-                condlog(3, "status = %s", status);
+               condlog(3, "status = %s", status);
                disassemble_map (pathvec, params, mpp);
-               
+
                /*
                 * disassemble_map() can add new paths to pathvec.
                 * If not in "fast list mode", we need to fetch information
@@ -386,18 +406,20 @@ void * mpath_prin_pthread_fn (void *p)
        int ret;
        struct prin_param * pparam = (struct prin_param *)p;
 
-       ret = prin_do_scsi_ioctl(pparam->dev, pparam->rq_servact, pparam->resp,  pparam->noisy);
-       pparam->status = ret;   
-       pthread_exit(NULL);     
+       ret = prin_do_scsi_ioctl(pparam->dev, pparam->rq_servact,
+                                pparam->resp,  pparam->noisy);
+       pparam->status = ret;
+       pthread_exit(NULL);
 }
 
-int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy)
+int mpath_send_prin_activepath (char * dev, int rq_servact,
+                               struct prin_resp * resp, int noisy)
 {
 
        int rc;
 
        rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
-       
+
        return (rc);
 }
 
@@ -409,14 +431,14 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
        struct pathgroup *pgp = NULL;
        struct path *pp = NULL;
        int rollback = 0;
-       int active_pathcount=0; 
+       int active_pathcount=0;
        int rc;
        int count=0;
        int status = MPATH_PR_SUCCESS;
        uint64_t sa_key = 0;
 
        if (!mpp)
-               return MPATH_PR_DMMP_ERROR; 
+               return MPATH_PR_DMMP_ERROR;
 
        active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
 
@@ -444,12 +466,13 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
 
                condlog (3, "THRED ID [%d] INFO]", i);
                condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
-               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope); 
-               condlog (3, "rq_type=%d ", thread[i].param.rq_type);  
-               condlog (3, "rkey="); 
-               condlog (3, "paramp->sa_flags =%02x ", thread[i].param.paramp->sa_flags); 
-               condlog (3, "noisy=%d ", thread[i].param.noisy); 
-               condlog (3, "status=%d ", thread[i].param.status); 
+               condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
+               condlog (3, "rq_type=%d ", thread[i].param.rq_type);
+               condlog (3, "rkey=");
+               condlog (3, "paramp->sa_flags =%02x ",
+                        thread[i].param.paramp->sa_flags);
+               condlog (3, "noisy=%d ", thread[i].param.noisy);
+               condlog (3, "status=%d ", thread[i].param.status);
        }
 
        pthread_attr_t attr;
@@ -508,7 +531,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                                memset(&thread[i].param.paramp->sa_key, 0, 8);
                                thread[i].param.status = MPATH_PR_SUCCESS;
                                rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, 
-                                               (void *)(&thread[count].param));
+                                               (void *)(&thread[i].param));
                                if (rc){
                                        condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
                                }
@@ -539,7 +562,7 @@ void * mpath_prout_pthread_fn(void *p)
 }
 
 int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
-        unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
+       unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
 {
        int i,j, ret;
        struct pathgroup *pgp = NULL;
@@ -548,13 +571,15 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
        vector_foreach_slot (mpp->pg, pgp, j){
                vector_foreach_slot (pgp->paths, pp, i){
                        if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
-                               condlog (1, "%s: %s path not up. Skip", mpp->wwid, pp->dev); 
+                               condlog (1, "%s: %s path not up. Skip",
+                                        mpp->wwid, pp->dev);
                                continue;
                        }
 
                        condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
-                       ret = send_prout_activepath(pp->dev, rq_servact, rq_scope, rq_type, 
-                                       paramp, noisy); 
+                       ret = send_prout_activepath(pp->dev, rq_servact,
+                                                   rq_scope, rq_type,
+                                                   paramp, noisy);
                        return ret ;
                }
        }
@@ -585,7 +610,7 @@ int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
        rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
        if (rc){
                condlog (3, "%s: failed to create thread %d", dev, rc);
-               exit(-1);
+               return MPATH_PR_OTHER;
        }
        /* Free attribute and wait for the other threads */
        pthread_attr_destroy(&attr);
@@ -595,7 +620,7 @@ int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
 }
 
 int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
-        unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
+       unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
 {
        int i, j;
        int num = 0;
@@ -610,7 +635,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
        struct prout_param_descriptor *pamp;
        struct prin_resp *pr_buff;
        int length;
-       struct transportid *pptr;       
+       struct transportid *pptr;
 
        if (!mpp)
                return MPATH_PR_DMMP_ERROR;
@@ -644,7 +669,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
                                condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
                                continue;
                        }
-                       
+
                        strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
                        condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
                        rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
@@ -681,13 +706,13 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
        num = resp.prin_descriptor.prin_readresv.additional_length / 8;
        if (num == 0){
                condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
-               return MPATH_PR_SUCCESS;        
+               return MPATH_PR_SUCCESS;
        }
        condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
 
        pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
        if (!pr_buff){
-               condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);  
+               condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);
                return MPATH_PR_OTHER;
        }
 
@@ -723,16 +748,21 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
                condlog (3, "%s: reservation key set.", mpp->wwid);
        }
 
-       mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA, rq_scope, rq_type, pamp,
-                       noisy);
+       status = mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA,
+                                    rq_scope, rq_type, pamp, noisy);
+
+       if (status) {
+               condlog(0, "%s: failed to send CLEAR_SA", mpp->wwid);
+               goto out1;
+       }
 
        pamp->num_transportid = 1;
        pptr=pamp->trnptid_list[0];
 
        for (i = 0; i < num; i++){
-               if (mpp->reservation_key && 
+               if (mpp->reservation_key &&
                        memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
-                       mpp->reservation_key, 8)){      
+                              mpp->reservation_key, 8)){
                        /*register with tarnsport id*/
                        memset(pamp, 0, length);
                        pamp->trnptid_list[0] = pptr;
@@ -768,7 +798,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
                memset (pamp, 0, length);
                memcpy (pamp->sa_key, mpp->reservation_key, 8);
                memset (pamp->key, 0, 8);
-               status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);      
+               status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);
        }
 
 
@@ -802,7 +832,7 @@ void * mpath_alloc_prin_response(int prin_sa)
                        memset(ptr, 0, size);
                        break;
                case MPATH_PRIN_RFSTAT_SA:
-                       size = sizeof(struct print_fulldescr_list) + 
+                       size = sizeof(struct print_fulldescr_list) +
                                sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
                        ptr = malloc(size);
                        memset(ptr, 0, size);
@@ -822,7 +852,7 @@ int update_map_pr(struct multipath *mpp)
        if (!mpp->reservation_key)
        {
                /* Nothing to do. Assuming pr mgmt feature is disabled*/
-               condlog(3, "%s: reservation_key not set in multiapth.conf", mpp->alias);
+               condlog(3, "%s: reservation_key not set in multipath.conf", mpp->alias);
                return MPATH_PR_SUCCESS;
        }
 
index 8597d40501afe237c5a5a3fd601308ee37e24e17..bda8991389641815fa1bb9b9ba9510b9a6b2151a 100644 (file)
@@ -12,9 +12,9 @@
 #include <sys/poll.h>
 #include <errno.h>
 #include <debug.h>
+#include <mpath_cmd.h>
+#include <uxsock.h>
 #include "memory.h"
-#include "../libmultipath/uxsock.h"
-#include "../libmultipath/defaults.h"
 
 unsigned long mem_allocated;    /* Total memory used in Bytes */
 
@@ -23,10 +23,9 @@ int update_prflag(char * arg1, char * arg2, int noisy)
        int fd;
        char str[64];
        char *reply;
-       size_t len;
        int ret = 0;
 
-       fd = ux_socket_connect(DEFAULT_SOCKET);
+       fd = mpath_connect();
        if (fd == -1) {
                condlog (0, "ux socket connect error");
                return 1 ;
@@ -34,18 +33,23 @@ int update_prflag(char * arg1, char * arg2, int noisy)
 
        snprintf(str,sizeof(str),"map %s %s", arg1, arg2);
        condlog (2, "%s: pr flag message=%s", arg1, str);
-       send_packet(fd, str, strlen(str) + 1);
-       recv_packet(fd, &reply, &len);
-
-       condlog (2, "%s: message=%s reply=%s", arg1, str, reply);
-       if (!reply || strncmp(reply,"ok", 2) == 0)
-               ret = -1;
-       else if (strncmp(reply, "fail", 4) == 0)
+       send_packet(fd, str);
+       ret = recv_packet(fd, &reply, DEFAULT_REPLY_TIMEOUT);
+       if (ret < 0) {
+               condlog(2, "%s: message=%s error=%d", arg1, str, errno);
                ret = -2;
-       else{
-               ret = atoi(reply);
+       } else {
+               condlog (2, "%s: message=%s reply=%s", arg1, str, reply);
+               if (!reply || strncmp(reply,"ok", 2) == 0)
+                       ret = -1;
+               else if (strncmp(reply, "fail", 4) == 0)
+                       ret = -2;
+               else{
+                       ret = atoi(reply);
+               }
        }
 
        free(reply);
+       mpath_disconnect(fd);
        return ret;
 }
index 54dfb3e805f88c3b064a635dc9a98603bf6a6d58..d69a73249ad60c6bcda92953330974ed8f1bfc91 100644 (file)
@@ -50,6 +50,5 @@ int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
 int update_prflag(char * arg1, char * arg2, int noisy);
 void * mpath_alloc_prin_response(int prin_sa);
 int update_map_pr(struct multipath *mpp);
-int devt2devname (char *devname, char *devt);
 
-#endif  
+#endif
index 636436425c8179127157524a19b30fae3f1a2b06..1ee968ec15c267c7621809547682cd462a181b59 100644 (file)
@@ -7,9 +7,14 @@ include ../Makefile.inc
 SONAME=0
 DEVLIB = libmultipath.so
 LIBS = $(DEVLIB).$(SONAME)
-LIBDEPS = -lpthread -ldl -ldevmapper -ludev
+CFLAGS += -I$(mpathcmddir)
+LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd
 ifdef SYSTEMD
-       LIBDEPS += -lsystemd-daemon
+       ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1)
+               LIBDEPS += -lsystemd
+       else
+               LIBDEPS += -lsystemd-daemon
+       endif
 endif
 
 OBJS = memory.o parser.o vector.o devmapper.o callout.o \
@@ -32,7 +37,7 @@ ifneq ($(strip $(LIBDM_API_COOKIE)),0)
        CFLAGS += -DLIBDM_API_COOKIE
 endif
 
-LIBUDEV_API_RECVBUF = $(shell grep -Ecs '^[a-z]*[[:space:]]+udev_monitor_set_resolve_buffer_size' /usr/include/libudev.h)
+LIBUDEV_API_RECVBUF = $(shell grep -Ecs '^[a-z]*[[:space:]]+udev_monitor_set_receive_buffer_size' /usr/include/libudev.h)
 
 ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0)
        CFLAGS += -DLIBUDEV_API_RECVBUF
@@ -42,6 +47,12 @@ ifdef SYSTEMD
        CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
 endif
 
+LIBDM_API_DEFERRED = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_deferred_remove' /usr/include/libdevmapper.h)
+
+ifneq ($(strip $(LIBDM_API_DEFERRED)),0)
+       CFLAGS += -DLIBDM_API_DEFERRED
+endif
+
 all: $(LIBS)
 
 $(LIBS): $(OBJS)
index ab151857dadddfc254b37d153dabf9d1d252d620..7d12a0c2e54562d6680c1f91cad3fc6d5fdca42e 100644 (file)
@@ -67,7 +67,7 @@ scan_devname(char *alias, char *prefix)
                return -1;
 
        if (strlen(alias) == strlen(prefix))
-               return -1;      
+               return -1;
 
        if (strlen(alias) > strlen(prefix) + 7)
                /* id of 'aaaaaaaa' overflows int */
@@ -145,17 +145,15 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias, char *prefix)
 }
 
 static int
-rlookup_binding(FILE *f, char *buff, char *map_alias)
+rlookup_binding(FILE *f, char *buff, char *map_alias, char *prefix)
 {
        char line[LINE_MAX];
        unsigned int line_nr = 0;
-       int id = 0;
 
        buff[0] = '\0';
 
        while (fgets(line, LINE_MAX, f)) {
                char *c, *alias, *wwid;
-               int curr_id;
 
                line_nr++;
                c = strpbrk(line, "#\n\r");
@@ -164,9 +162,6 @@ rlookup_binding(FILE *f, char *buff, char *map_alias)
                alias = strtok(line, " \t");
                if (!alias) /* blank line */
                        continue;
-               curr_id = scan_devname(alias, NULL); /* TBD: Why this call? */
-               if (curr_id >= id)
-                       id = curr_id + 1;
                wwid = strtok(NULL, " \t");
                if (!wwid){
                        condlog(3,
@@ -184,11 +179,12 @@ rlookup_binding(FILE *f, char *buff, char *map_alias)
                                "\nSetting wwid to %s", alias, wwid);
                        strncpy(buff, wwid, WWID_SIZE);
                        buff[WWID_SIZE - 1] = '\0';
-                       return id;
+                       return 0;
                }
        }
        condlog(3, "No matching alias [%s] in bindings file.", map_alias);
-       return id;
+
+       return -1;
 }
 
 static char *
@@ -236,6 +232,67 @@ allocate_binding(int fd, char *wwid, int id, char *prefix)
        return alias;
 }
 
+char *
+use_existing_alias (char *wwid, char *file, char *alias_old,
+               char *prefix, int bindings_read_only)
+{
+       char *alias = NULL;
+       int id = 0;
+       int fd, can_write;
+       char buff[WWID_SIZE];
+       FILE *f;
+
+       fd = open_file(file, &can_write, BINDINGS_FILE_HEADER);
+       if (fd < 0)
+               return NULL;
+
+       f = fdopen(fd, "r");
+       if (!f) {
+               condlog(0, "cannot fdopen on bindings file descriptor");
+               close(fd);
+               return NULL;
+       }
+       /* lookup the binding. if it exsists, the wwid will be in buff
+        * either way, id contains the id for the alias
+        */
+       rlookup_binding(f, buff, alias_old, prefix);
+
+       if (strlen(buff) > 0) {
+               /* if buff is our wwid, it's already
+                * allocated correctly
+                */
+               if (strcmp(buff, wwid) == 0)
+                       alias = STRDUP(alias_old);
+               else {
+                       alias = NULL;
+                       condlog(0, "alias %s already bound to wwid %s, cannot reuse",
+                               alias_old, buff);
+               }
+               goto out;
+       }
+
+       /* allocate the existing alias in the bindings file */
+       id = scan_devname(alias_old, prefix);
+       if (id <= 0)
+               goto out;
+
+       if (fflush(f) != 0) {
+               condlog(0, "cannot fflush bindings file stream : %s",
+                       strerror(errno));
+               goto out;
+       }
+
+       if (can_write && !bindings_read_only) {
+               alias = allocate_binding(fd, wwid, id, prefix);
+               condlog(0, "Allocated existing binding [%s] for WWID [%s]",
+                       alias, wwid);
+       }
+
+out:
+       fclose(f);
+       return alias;
+}
+
 char *
 get_user_friendly_alias(char *wwid, char *file, char *prefix,
                        int bindings_read_only)
@@ -271,6 +328,7 @@ get_user_friendly_alias(char *wwid, char *file, char *prefix,
        if (fflush(f) != 0) {
                condlog(0, "cannot fflush bindings file stream : %s",
                        strerror(errno));
+               free(alias);
                fclose(f);
                return NULL;
        }
@@ -305,7 +363,7 @@ get_user_friendly_wwid(char *alias, char *buff, char *file)
                return -1;
        }
 
-       rlookup_binding(f, buff, alias);
+       rlookup_binding(f, buff, alias, NULL);
        if (!strlen(buff)) {
                fclose(f);
                return -1;
index 8ddd0b54e1148a84a4fdfd712fc15f1a556fb1fc..9cb3e8f57ae4d60f069a5488b3c4258f81455c86 100644 (file)
@@ -10,3 +10,5 @@
 char *get_user_friendly_alias(char *wwid, char *file, char *prefix,
                              int bindings_readonly);
 int get_user_friendly_wwid(char *alias, char *buff, char *file);
+char *use_existing_alias (char *wwid, char *file, char *alias_old,
+               char *prefix, int bindings_read_only);
index 79ddcde1879604fdafb52c893a0a7aaf5a7ce5c0..2400eda1044147d19cb7f0e95a1dd09b8c5e031c 100644 (file)
@@ -80,6 +80,8 @@ set_ble_device (vector blist, char * vendor, char * product, int origin)
                if (regcomp(&ble->vendor_reg, vendor,
                            REG_EXTENDED|REG_NOSUB)) {
                        FREE(vendor);
+                       if (product)
+                               FREE(product);
                        return 1;
                }
                ble->vendor = vendor;
@@ -88,6 +90,10 @@ set_ble_device (vector blist, char * vendor, char * product, int origin)
                if (regcomp(&ble->product_reg, product,
                            REG_EXTENDED|REG_NOSUB)) {
                        FREE(product);
+                       if (vendor) {
+                               ble->vendor = NULL;
+                               FREE(vendor);
+                       }
                        return 1;
                }
                ble->product = product;
@@ -129,8 +135,12 @@ _blacklist_exceptions_device(vector elist, char * vendor, char * product)
        struct blentry_device * ble;
 
        vector_foreach_slot (elist, ble, i) {
-               if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
-                   !regexec(&ble->product_reg, product, 0, NULL, 0))
+               if (!ble->vendor && !ble->product)
+                       continue;
+               if ((!ble->vendor ||
+                    !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
+                   (!ble->product ||
+                    !regexec(&ble->product_reg, product, 0, NULL, 0)))
                        return 1;
        }
        return 0;
@@ -143,8 +153,12 @@ _blacklist_device (vector blist, char * vendor, char * product)
        struct blentry_device * ble;
 
        vector_foreach_slot (blist, ble, i) {
-               if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
-                   !regexec(&ble->product_reg, product, 0, NULL, 0))
+               if (!ble->vendor && !ble->product)
+                       continue;
+               if ((!ble->vendor ||
+                    !regexec(&ble->vendor_reg, vendor, 0, NULL, 0)) &&
+                   (!ble->product ||
+                    !regexec(&ble->product_reg, product, 0, NULL, 0)))
                        return 1;
        }
        return 0;
@@ -164,7 +178,7 @@ setup_default_blist (struct config * conf)
        if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
                return 1;
 
-       str = STRDUP("^(td|hd)[a-z]");
+       str = STRDUP("^(td|hd|vd)[a-z]");
        if (!str)
                return 1;
        if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
@@ -176,7 +190,13 @@ setup_default_blist (struct config * conf)
        if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
                return 1;
 
-       str = STRDUP("(ID_SCSI_VPD|ID_WWN)");
+       str = STRDUP("^nvme.*");
+       if (!str)
+               return 1;
+       if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
+               return 1;
+
+       str = STRDUP("(SCSI_IDENT_.*|ID_WWN)");
        if (!str)
                return 1;
        if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
@@ -196,6 +216,7 @@ setup_default_blist (struct config * conf)
                                           STRDUP(hwe->bl_product),
                                           ORIGIN_DEFAULT)) {
                                FREE(ble);
+                               vector_del_slot(conf->blist_device, VECTOR_SIZE(conf->blist_device) - 1);
                                return 1;
                        }
                }
@@ -207,6 +228,8 @@ setup_default_blist (struct config * conf)
        if (vendor && product)                                          \
                condlog(3, "%s: (%s:%s) %s %s",                         \
                        dev, vendor, product, (M), (S));                \
+       else if (wwid && !dev)                                          \
+               condlog(3, "%s: %s %s", wwid, (M), (S));                \
        else if (wwid)                                                  \
                condlog(3, "%s: %s %s %s", dev, (M), wwid, (S));        \
        else if (env)                                                   \
@@ -307,10 +330,10 @@ _filter_wwid (vector blist, vector elist, char * wwid)
 }
 
 int
-filter_wwid (vector blist, vector elist, char * wwid)
+filter_wwid (vector blist, vector elist, char * wwid, char * dev)
 {
        int r = _filter_wwid(blist, elist, wwid);
-       log_filter(NULL, NULL, NULL, wwid, NULL, r);
+       log_filter(dev, NULL, NULL, wwid, NULL, r);
        return r;
 }
 
index 0e90e9a4107277391d458fc6b88d79d5f8398c74..24a5fa524208698fc3dc62dd8212420ff039cb2e 100644 (file)
@@ -32,7 +32,7 @@ struct blentry_device {
 int setup_default_blist (struct config *);
 int alloc_ble_device (vector);
 int filter_devnode (vector, vector, char *);
-int filter_wwid (vector, vector, char *);
+int filter_wwid (vector, vector, char *, char *);
 int filter_device (vector, vector, char *, char *);
 int filter_path (struct config *, struct path *);
 int filter_property(struct config *, struct udev_device *);
index c35c7c008ca642ee17d1083520e08b88d564b55d..4cbbd06970f8e754d6ebb6c896e128cf217e76db 100644 (file)
@@ -125,7 +125,7 @@ int execute_program(char *path, char *value, int len)
                        if (status == 0)
                                retval = 0;
                        else
-                               condlog(0, "%s exitted with %d", argv[0], status);
+                               condlog(0, "%s exited with %d", argv[0], status);
                }
                else if (WIFSIGNALED(status))
                        condlog(0, "%s was terminated by signal %d", argv[0], WTERMSIG(status));
index 4a4cd7ccd74fee89bbf802564936324f1358a2df..ef1d09975f13f7b1930acde316f5d77b21a17eaa 100644 (file)
@@ -19,6 +19,7 @@ char *checker_state_names[] = {
       "pending",
       "timeout",
       "removed",
+      "delayed",
 };
 
 static LIST_HEAD(checkers);
@@ -194,7 +195,7 @@ void checker_put (struct checker * dst)
 {
        struct checker * src;
 
-       if (!dst)
+       if (!dst || !dst->check)
                return;
        src = checker_lookup(dst->name);
        if (dst->free)
index e62b52f10c279780a436c12a27a545d4d82f3464..a935b3f73e719491f0db20c84571a590d9a83320 100644 (file)
  * PATH REMOVED:
  * - Use: All checkers
  * - Description: Device has been removed from the system
+ *
+ * PATH_DELAYED:
+ * - Use: None of the checkers (returned if the path is being delayed before
+ *   reintegration.
+ * - Description: If a path fails after being up for less than
+ *   delay_watch_checks checks, when it comes back up again, it will not
+ *   be marked as up until it has been up for delay_wait_checks checks.
+ *   During this time, it is marked as "delayed"
  */
 enum path_check_state {
        PATH_WILD,
@@ -65,6 +73,7 @@ enum path_check_state {
        PATH_PENDING,
        PATH_TIMEOUT,
        PATH_REMOVED,
+       PATH_DELAYED,
        PATH_MAX_STATE
 };
 
index e0b2ea41db3301b4eb96b54b1c11835d6ead1e11..00e3c44cabb2838cab0a05958796b44192066ecb 100644 (file)
@@ -308,7 +308,7 @@ libcheck_check (struct checker * c)
 done:
        switch (ret) {
        case PATH_DOWN:
-               MSG(c, (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
+               MSG(c, "%s", (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
                        checker_msg_string(&inq));
                break;
        case PATH_UP:
index e13c3079a15dd444b426a85733aa0a9506936551..8b9e770a81715bb40cedb00ddc48c9f93415a277 100644 (file)
@@ -6,6 +6,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <libudev.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "checkers.h"
 #include "memory.h"
@@ -21,6 +24,7 @@
 #include "defaults.h"
 #include "prio.h"
 #include "devmapper.h"
+#include "mpath_cmd.h"
 
 static int
 hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
@@ -340,6 +344,9 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
        merge_num(user_friendly_names);
        merge_num(retain_hwhandler);
        merge_num(detect_prio);
+       merge_num(deferred_remove);
+       merge_num(delay_watch_checks);
+       merge_num(delay_wait_checks);
 
        /*
         * Make sure features is consistent with
@@ -412,6 +419,7 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
        hwe->user_friendly_names = dhwe->user_friendly_names;
        hwe->retain_hwhandler = dhwe->retain_hwhandler;
        hwe->detect_prio = dhwe->detect_prio;
+       conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
 
        if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
                goto out;
@@ -497,17 +505,24 @@ free_config (struct config * conf)
 
        if (conf->wwids_file)
                FREE(conf->wwids_file);
+
        if (conf->prio_name)
                FREE(conf->prio_name);
 
        if (conf->alias_prefix)
                FREE(conf->alias_prefix);
+       if (conf->partition_delim)
+               FREE(conf->partition_delim);
 
        if (conf->prio_args)
                FREE(conf->prio_args);
 
        if (conf->checker_name)
                FREE(conf->checker_name);
+
+       if (conf->config_dir)
+               FREE(conf->config_dir);
+
        if (conf->reservation_key)
                FREE(conf->reservation_key);
 
@@ -523,10 +538,48 @@ free_config (struct config * conf)
 
        free_mptable(conf->mptable);
        free_hwtable(conf->hwtable);
+       free_hwe(conf->overrides);
        free_keywords(conf->keywords);
        FREE(conf);
 }
 
+/* if multipath fails to process the config directory, it should continue,
+ * with just a warning message */
+static void
+process_config_dir(vector keywords, char *dir)
+{
+       struct dirent **namelist;
+       int i, n;
+       char path[LINE_MAX];
+       int old_hwtable_size;
+
+       if (dir[0] != '/') {
+               condlog(1, "config_dir '%s' must be a fully qualified path",
+                       dir);
+               return;
+       }
+       n = scandir(dir, &namelist, NULL, alphasort);
+       if (n < 0) {
+               if (errno == ENOENT)
+                       condlog(3, "No configuration dir '%s'", dir);
+               else
+                       condlog(0, "couldn't open configuration dir '%s': %s",
+                               dir, strerror(errno));
+               return;
+       }
+       for (i = 0; i < n; i++) {
+               if (!strstr(namelist[i]->d_name, ".conf"))
+                       continue;
+               old_hwtable_size = VECTOR_SIZE(conf->hwtable);
+               snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
+               path[LINE_MAX-1] = '\0';
+               process_file(path);
+               if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
+                       factorize_hwtable(conf->hwtable, old_hwtable_size);
+
+       }
+}
+
 int
 load_config (char * file, struct udev *udev)
 {
@@ -549,18 +602,26 @@ load_config (char * file, struct udev *udev)
        get_sys_max_fds(&conf->max_fds);
        conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
        conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
-       conf->bindings_read_only = 0;
        conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
        conf->features = set_default(DEFAULT_FEATURES);
        conf->flush_on_last_del = 0;
        conf->attribute_flags = 0;
        conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
        conf->checkint = DEFAULT_CHECKINT;
-       conf->max_checkint = MAX_CHECKINT(conf->checkint);
+       conf->max_checkint = 0;
        conf->pgfailback = DEFAULT_FAILBACK;
        conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
        conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
        conf->detect_prio = DEFAULT_DETECT_PRIO;
+       conf->force_sync = 0;
+       conf->partition_delim = NULL;
+       conf->processed_main_config = 0;
+       conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
+       conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
+       conf->uid_attribute = set_default(DEFAULT_UID_ATTRIBUTE);
+       conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
+       conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
+       conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
 
        /*
         * preload default hwtable
@@ -579,11 +640,12 @@ load_config (char * file, struct udev *udev)
         */
        set_current_keywords(&conf->keywords);
        alloc_keywords();
+       init_keywords();
        if (filepresent(file)) {
                int builtin_hwtable_size;
 
                builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
-               if (init_data(file, init_keywords)) {
+               if (process_file(file)) {
                        condlog(0, "error parsing config file");
                        goto out;
                }
@@ -595,13 +657,19 @@ load_config (char * file, struct udev *udev)
                        factorize_hwtable(conf->hwtable, builtin_hwtable_size);
                }
 
-       } else {
-               init_keywords();
        }
 
+       conf->processed_main_config = 1;
+       if (conf->config_dir == NULL)
+               conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
+       if (conf->config_dir && conf->config_dir[0] != '\0')
+               process_config_dir(conf->keywords, conf->config_dir);
+
        /*
         * fill the voids left in the config file
         */
+       if (conf->max_checkint == 0)
+               conf->max_checkint = MAX_CHECKINT(conf->checkint);
        if (conf->blist_devnode == NULL) {
                conf->blist_devnode = vector_alloc();
 
index 445525b174414a99f188fdc75a7b481b3cbe31a1..e9828ea241ad043ad2df9826bc562dbff5408c0c 100644 (file)
@@ -19,7 +19,19 @@ enum devtypes {
        DEV_NONE,
        DEV_DEVT,
        DEV_DEVNODE,
-       DEV_DEVMAP
+       DEV_DEVMAP,
+       DEV_UEVENT
+};
+
+enum mpath_cmds {
+       CMD_CREATE,
+       CMD_DRY_RUN,
+       CMD_LIST_SHORT,
+       CMD_LIST_LONG,
+       CMD_VALID_PATH,
+       CMD_REMOVE_WWID,
+       CMD_RESET_WWIDS,
+       CMD_ADD_WWID,
 };
 
 struct hwentry {
@@ -48,6 +60,9 @@ struct hwentry {
        int user_friendly_names;
        int retain_hwhandler;
        int detect_prio;
+       int deferred_remove;
+       int delay_watch_checks;
+       int delay_wait_checks;
        char * bl_product;
 };
 
@@ -71,6 +86,9 @@ struct mpentry {
        int flush_on_last_del;
        int attribute_flags;
        int user_friendly_names;
+       int deferred_remove;
+       int delay_watch_checks;
+       int delay_wait_checks;
        uid_t uid;
        gid_t gid;
        mode_t mode;
@@ -78,8 +96,7 @@ struct mpentry {
 
 struct config {
        int verbosity;
-       int dry_run;
-       int list;
+       enum mpath_cmds cmd;
        int pgpolicy_flag;
        int pgpolicy;
        enum devtypes dev_type;
@@ -96,24 +113,33 @@ struct config {
        int max_fds;
        int force_reload;
        int queue_without_daemon;
+       int ignore_wwids;
        int checker_timeout;
        int daemon;
-#ifdef USE_SYSTEMD
-       int watchdog;
-#endif
        int flush_on_last_del;
        int attribute_flags;
        int fast_io_fail;
        unsigned int dev_loss;
        int log_checker_err;
        int allow_queueing;
+       int find_multipaths;
        uid_t uid;
        gid_t gid;
        mode_t mode;
-       uint32_t cookie;
        int reassign_maps;
        int retain_hwhandler;
        int detect_prio;
+       int force_sync;
+       int deferred_remove;
+       int processed_main_config;
+       int delay_watch_checks;
+       int delay_wait_checks;
+       int uxsock_timeout;
+       int retrigger_tries;
+       int retrigger_delay;
+       int ignore_new_devs;
+       int delayed_reconfig;
+       int uev_wait_timeout;
        unsigned int version[3];
 
        char * dev;
@@ -130,11 +156,14 @@ struct config {
        char * prio_args;
        char * checker_name;
        char * alias_prefix;
+       char * partition_delim;
+       char * config_dir;
        unsigned char * reservation_key;
 
        vector keywords;
        vector mptable;
        vector hwtable;
+       struct hwentry *overrides;
 
        vector blist_devnode;
        vector blist_wwid;
index 8c09791bc037a1b059f59ddceab9ecd145576e72..30c7259921b0787efd5002af1398f180eaee3c16 100644 (file)
@@ -14,6 +14,7 @@
 #include <errno.h>
 #include <libdevmapper.h>
 #include <libudev.h>
+#include <mpath_cmd.h>
 
 #include "checkers.h"
 #include "vector.h"
 #include "uxsock.h"
 #include "wwids.h"
 
+/* group paths in pg by host adapter
+ */
+int group_by_host_adapter(struct pathgroup *pgp, vector adapters)
+{
+       struct adapter_group *agp;
+       struct host_group *hgp;
+       struct path *pp, *pp1;
+       char adapter_name1[SLOT_NAME_SIZE];
+       char adapter_name2[SLOT_NAME_SIZE];
+       int i, j;
+       int found_hostgroup = 0;
+
+       while (VECTOR_SIZE(pgp->paths) > 0) {
+
+               pp = VECTOR_SLOT(pgp->paths, 0);
+
+               if (sysfs_get_host_adapter_name(pp, adapter_name1))
+                       goto out;
+               /* create a new host adapter group
+                */
+               agp = alloc_adaptergroup();
+               if (!agp)
+                       goto out;
+               agp->pgp = pgp;
+
+               strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE);
+               store_adaptergroup(adapters, agp);
+
+               /* create a new host port group
+                */
+               hgp = alloc_hostgroup();
+               if (!hgp)
+                       goto out;
+               if (store_hostgroup(agp->host_groups, hgp))
+                       goto out;
+
+               hgp->host_no = pp->sg_id.host_no;
+               agp->num_hosts++;
+               if (store_path(hgp->paths, pp))
+                       goto out;
+
+               hgp->num_paths++;
+               /* delete path from path group
+                */
+               vector_del_slot(pgp->paths, 0);
+
+               /* add all paths belonging to same host adapter
+                */
+               vector_foreach_slot(pgp->paths, pp1, i) {
+                       if (sysfs_get_host_adapter_name(pp1, adapter_name2))
+                               goto out;
+                       if (strcmp(adapter_name1, adapter_name2) == 0) {
+                               found_hostgroup = 0;
+                               vector_foreach_slot(agp->host_groups, hgp, j) {
+                                       if (hgp->host_no == pp1->sg_id.host_no) {
+                                               if (store_path(hgp->paths, pp1))
+                                                       goto out;
+                                               hgp->num_paths++;
+                                               found_hostgroup = 1;
+                                               break;
+                                       }
+                               }
+                               if (!found_hostgroup) {
+                                       /* this path belongs to new host port
+                                        * within this adapter
+                                        */
+                                       hgp = alloc_hostgroup();
+                                       if (!hgp)
+                                               goto out;
+
+                                       if (store_hostgroup(agp->host_groups, hgp))
+                                               goto out;
+
+                                       agp->num_hosts++;
+                                       if (store_path(hgp->paths, pp1))
+                                               goto out;
+
+                                       hgp->host_no = pp1->sg_id.host_no;
+                                       hgp->num_paths++;
+                               }
+                               /* delete paths from original path_group
+                                * as they are added into adapter group now
+                                */
+                               vector_del_slot(pgp->paths, i);
+                               i--;
+                       }
+               }
+       }
+       return 0;
+
+out:   /* add back paths into pg as re-ordering failed
+        */
+       vector_foreach_slot(adapters, agp, i) {
+                       vector_foreach_slot(agp->host_groups, hgp, j) {
+                               while (VECTOR_SIZE(hgp->paths) > 0) {
+                                       pp = VECTOR_SLOT(hgp->paths, 0);
+                                       if (store_path(pgp->paths, pp))
+                                               condlog(3, "failed to restore "
+                                               "path %s into path group",
+                                                pp->dev);
+                                       vector_del_slot(hgp->paths, 0);
+                               }
+                       }
+               }
+       free_adaptergroup(adapters);
+       return 1;
+}
+
+/* re-order paths in pg by alternating adapters and host ports
+ * for optimized selection
+ */
+int order_paths_in_pg_by_alt_adapters(struct pathgroup *pgp, vector adapters,
+                int total_paths)
+{
+       int next_adapter_index = 0;
+       struct adapter_group *agp;
+       struct host_group *hgp;
+       struct path *pp;
+
+       while (total_paths > 0) {
+               agp = VECTOR_SLOT(adapters, next_adapter_index);
+               if (!agp) {
+                       condlog(0, "can't get adapter group %d", next_adapter_index);
+                       return 1;
+               }
+
+               hgp = VECTOR_SLOT(agp->host_groups, agp->next_host_index);
+               if (!hgp) {
+                       condlog(0, "can't get host group %d of adapter group %d", next_adapter_index, agp->next_host_index);
+                       return 1;
+               }
+
+               if (!hgp->num_paths) {
+                       agp->next_host_index++;
+                       agp->next_host_index %= agp->num_hosts;
+                       next_adapter_index++;
+                       next_adapter_index %= VECTOR_SIZE(adapters);
+                       continue;
+               }
+
+               pp  = VECTOR_SLOT(hgp->paths, 0);
+
+               if (store_path(pgp->paths, pp))
+                       return 1;
+
+               total_paths--;
+
+               vector_del_slot(hgp->paths, 0);
+
+               hgp->num_paths--;
+
+               agp->next_host_index++;
+               agp->next_host_index %= agp->num_hosts;
+               next_adapter_index++;
+               next_adapter_index %= VECTOR_SIZE(adapters);
+       }
+
+       /* all paths are added into path_group
+        * in crafted child order
+        */
+       return 0;
+}
+
+/* round-robin: order paths in path group to alternate
+ * between all host adapters
+ */
+int rr_optimize_path_order(struct pathgroup *pgp)
+{
+       vector adapters;
+       struct path *pp;
+       int total_paths;
+       int i;
+
+       total_paths = VECTOR_SIZE(pgp->paths);
+       vector_foreach_slot(pgp->paths, pp, i) {
+               if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
+                       pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
+                       pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
+                       pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) {
+                       /* return success as default path order
+                        * is maintained in path group
+                        */
+                       return 0;
+               }
+       }
+       adapters = vector_alloc();
+       if (!adapters)
+               return 0;
+
+       /* group paths in path group by host adapters
+        */
+       if (group_by_host_adapter(pgp, adapters)) {
+               /* already freed adapters */
+               condlog(3, "Failed to group paths by adapters");
+               return 0;
+       }
+
+       /* re-order paths in pg to alternate between adapters and host ports
+        */
+       if (order_paths_in_pg_by_alt_adapters(pgp, adapters, total_paths)) {
+               condlog(3, "Failed to re-order paths in pg by adapters "
+                       "and host ports");
+               free_adaptergroup(adapters);
+               /* return failure as original paths are
+                * removed form pgp
+                */
+               return 1;
+       }
+
+       free_adaptergroup(adapters);
+       return 0;
+}
+
 extern int
 setup_map (struct multipath * mpp, char * params, int params_size)
 {
@@ -76,6 +290,9 @@ setup_map (struct multipath * mpp, char * params, int params_size)
        select_dev_loss(mpp);
        select_reservation_key(mpp);
        select_retain_hwhandler(mpp);
+       select_deferred_remove(mpp);
+       select_delay_watch_checks(mpp);
+       select_delay_wait_checks(mpp);
 
        sysfs_set_scsi_tmo(mpp);
        /*
@@ -100,6 +317,22 @@ setup_map (struct multipath * mpp, char * params, int params_size)
         */
        mpp->bestpg = select_path_group(mpp);
 
+       /* re-order paths in all path groups in an optimized way
+        * for round-robin path selectors to get maximum throughput.
+        */
+       if (!strncmp(mpp->selector, "round-robin", 11)) {
+               vector_foreach_slot(mpp->pg, pgp, i) {
+                       if (VECTOR_SIZE(pgp->paths) <= 2)
+                               continue;
+                       if (rr_optimize_path_order(pgp)) {
+                               condlog(2, "cannot re-order paths for "
+                                       "optimization: %s",
+                                       mpp->alias);
+                               return 1;
+                       }
+               }
+       }
+
        /*
         * transform the mp->pg vector of vectors of paths
         * into a mp->params strings to feed the device-mapper
@@ -164,6 +397,8 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
                                cmpp->alias, mpp->alias);
                        strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
                        mpp->action = ACT_RENAME;
+                       if (force_reload)
+                               mpp->action = ACT_RENAME2;
                        return;
                }
                mpp->action = ACT_CREATE;
@@ -187,6 +422,9 @@ select_action (struct multipath * mpp, vector curmp, int force_reload)
                condlog(2, "%s: unable to rename %s to %s (%s is used by %s)",
                        mpp->wwid, cmpp->alias, mpp->alias,
                        mpp->alias, cmpp_by_name->wwid);
+               /* reset alias to existing alias */
+               FREE(mpp->alias);
+               mpp->alias = STRDUP(cmpp->alias);
                mpp->action = ACT_NOTHING;
                return;
        }
@@ -343,16 +581,22 @@ fail:
 extern int
 domap (struct multipath * mpp, char * params)
 {
-       int r = 0;
+       int r = DOMAP_FAIL;
 
        /*
         * last chance to quit before touching the devmaps
         */
-       if (conf->dry_run && mpp->action != ACT_NOTHING) {
+       if (conf->cmd == CMD_DRY_RUN && mpp->action != ACT_NOTHING) {
                print_multipath_topology(mpp, conf->verbosity);
                return DOMAP_DRY;
        }
 
+       if (mpp->action == ACT_CREATE &&
+           dm_map_present(mpp->alias)) {
+               condlog(3, "%s: map already present", mpp->alias);
+               mpp->action = ACT_RELOAD;
+       }
+
        switch (mpp->action) {
        case ACT_REJECT:
        case ACT_NOTHING:
@@ -375,12 +619,6 @@ domap (struct multipath * mpp, char * params)
                        return DOMAP_RETRY;
                }
 
-               if (dm_map_present(mpp->alias)) {
-                       condlog(3, "%s: map already present", mpp->alias);
-                       lock_multipath(mpp, 0);
-                       break;
-               }
-
                r = dm_addmap_create(mpp, params);
 
                lock_multipath(mpp, 0);
@@ -389,24 +627,34 @@ domap (struct multipath * mpp, char * params)
        case ACT_RELOAD:
                r = dm_addmap_reload(mpp, params);
                if (r)
-                       r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias);
+                       r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias,
+                                                0, MPATH_UDEV_RELOAD_FLAG);
                break;
 
        case ACT_RESIZE:
                r = dm_addmap_reload(mpp, params);
                if (r)
-                       r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1);
+                       r = dm_simplecmd_flush(DM_DEVICE_RESUME, mpp->alias, 1, 0);
                break;
 
        case ACT_RENAME:
                r = dm_rename(mpp->alias_old, mpp->alias);
                break;
 
+       case ACT_RENAME2:
+               r = dm_rename(mpp->alias_old, mpp->alias);
+               if (r) {
+                       r = dm_addmap_reload(mpp, params);
+                       if (r)
+                               r = dm_simplecmd_noflush(DM_DEVICE_RESUME, mpp->alias, 0, MPATH_UDEV_RELOAD_FLAG);
+               }
+               break;
+
        default:
                break;
        }
 
-       if (r) {
+       if (r == DOMAP_OK) {
                /*
                 * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
                 * succeeded
@@ -428,6 +676,10 @@ domap (struct multipath * mpp, char * params)
                         */
                        if (mpp->action != ACT_CREATE)
                                mpp->action = ACT_NOTHING;
+                       else {
+                               mpp->wait_for_udev = 1;
+                               mpp->uev_wait_tick = conf->uev_wait_timeout;
+                       }
                }
                dm_setgeometry(mpp);
                return DOMAP_OK;
@@ -461,16 +713,15 @@ int check_daemon(void)
 {
        int fd;
        char *reply;
-       size_t len;
        int ret = 0;
 
-       fd = ux_socket_connect(DEFAULT_SOCKET);
+       fd = mpath_connect();
        if (fd == -1)
                return 0;
 
-       if (send_packet(fd, "show daemon", 12) != 0)
+       if (send_packet(fd, "show daemon") != 0)
                goto out;
-       if (recv_packet(fd, &reply, &len) != 0)
+       if (recv_packet(fd, &reply, conf->uxsock_timeout) != 0)
                goto out;
 
        if (strstr(reply, "shutdown"))
@@ -481,7 +732,7 @@ int check_daemon(void)
 out_free:
        FREE(reply);
 out:
-       close(fd);
+       mpath_disconnect(fd);
        return ret;
 }
 
@@ -490,7 +741,6 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
 {
        int r = 1;
        int k, i;
-       char empty_buff[WWID_SIZE];
        char params[PARAMS_SIZE];
        struct multipath * mpp;
        struct path * pp1;
@@ -498,7 +748,9 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
        vector curmp = vecs->mpvec;
        vector pathvec = vecs->pathvec;
 
-       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) {
@@ -509,7 +761,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
                /* skip this path for some reason */
 
                /* 1. if path has no unique id or wwid blacklisted */
-               if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
+               if (strlen(pp1->wwid) == 0 ||
                    filter_path(conf, pp1) > 0) {
                        orphan_path(pp1, "wwid blacklisted");
                        continue;
@@ -520,8 +772,8 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
                        continue;
 
                /* 3. if path has disappeared */
-               if (!pp1->size) {
-                       orphan_path(pp1, "invalid size");
+               if (pp1->state == PATH_REMOVED) {
+                       orphan_path(pp1, "path removed");
                        continue;
                }
 
@@ -529,6 +781,12 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
                if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
                        continue;
 
+               /* If find_multipaths was selected check if the path is valid */
+               if (!refwwid && !should_multipath(pp1, pathvec)) {
+                       orphan_path(pp1, "only one path");
+                       continue;
+               }
+
                /*
                 * at this point, we know we really got a new mp
                 */
@@ -551,10 +809,11 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
                        if (strcmp(pp1->wwid, pp2->wwid))
                                continue;
 
-                       if (!pp2->size)
-                               continue;
+                       if (!mpp->size && pp2->size)
+                               mpp->size = pp2->size;
 
-                       if (pp2->size != mpp->size) {
+                       if (mpp->size && pp2->size &&
+                           pp2->size != mpp->size) {
                                /*
                                 * ouch, avoid feeding that to the DM
                                 */
@@ -566,7 +825,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
                        if (pp2->priority == PRIO_UNDEF)
                                mpp->action = ACT_REJECT;
                }
-               verify_paths(mpp, vecs, NULL);
+               verify_paths(mpp, vecs);
 
                params[0] = '\0';
                if (setup_map(mpp, params, PARAMS_SIZE)) {
@@ -703,11 +962,14 @@ get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid)
                        udev_device_unref(udevice);
                        if (!pp) {
                                if (ret == 1)
-                                       condlog(0, "%s can't store path info",
-                                               buff);
+                                       condlog(0, "%s: can't store path info",
+                                               dev);
                                return ret;
                        }
                }
+               if (pp->udev && filter_property(conf, pp->udev) > 0)
+                       return 2;
+
                refwwid = pp->wwid;
                goto out;
        }
@@ -732,9 +994,36 @@ get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid)
                                return ret;
                        }
                }
+               if (pp->udev && filter_property(conf, pp->udev) > 0)
+                       return 2;
+
+               refwwid = pp->wwid;
+               goto out;
+       }
+
+       if (dev_type == DEV_UEVENT) {
+               struct udev_device *udevice = udev_device_new_from_environment(conf->udev);
+
+               if (!udevice) {
+                       condlog(2, "%s: can't get udev device", dev);
+                       return 1;
+               }
+               ret = store_pathinfo(pathvec, conf->hwtable, udevice,
+                                    DI_SYSFS | DI_WWID, &pp);
+               udev_device_unref(udevice);
+               if (!pp) {
+                       if (ret == 1)
+                               condlog(0, "%s: can't store path info",
+                                       dev);
+                       return ret;
+               }
+               if (pp->udev && filter_property(conf, pp->udev) > 0)
+                       return 2;
+
                refwwid = pp->wwid;
                goto out;
        }
+
        if (dev_type == DEV_DEVMAP) {
 
                if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) {
@@ -765,7 +1054,7 @@ get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid)
 check:
                if (refwwid && strlen(refwwid)) {
                        if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
-                                       refwwid) > 0)
+                                       refwwid, NULL) > 0)
                        return 2;
                }
        }
index 650f080109b620456d53f27012822703f8b438df..c014b5533226d9a56571f87b9123de91c5ff1d2f 100644 (file)
@@ -18,6 +18,7 @@ enum actions {
        ACT_RENAME,
        ACT_CREATE,
        ACT_RESIZE,
+       ACT_RENAME2,
 };
 
 #define FLUSH_ONE 1
@@ -29,4 +30,4 @@ int reinstate_paths (struct multipath *mpp);
 int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
 int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid);
 int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh);
-
+int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
index b83d9fbe622d1e987460632c3b9ec9f2f59c2825..bce8bcc88995b51088629494435cf29d7eae66ef 100644 (file)
 #define DEFAULT_FAILBACK       -FAILBACK_MANUAL
 #define DEFAULT_RR_WEIGHT      RR_WEIGHT_NONE
 #define DEFAULT_NO_PATH_RETRY  NO_PATH_RETRY_UNDEF
-#define DEFAULT_PGTIMEOUT      -PGTIMEOUT_NONE
-#define DEFAULT_USER_FRIENDLY_NAMES    0
 #define DEFAULT_VERBOSITY      2
-#define DEFAULT_REASSIGN_MAPS  1
+#define DEFAULT_REASSIGN_MAPS  0
+#define DEFAULT_FIND_MULTIPATHS        0
 #define DEFAULT_FAST_IO_FAIL   5
 #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
 #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
+#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
+#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
+#define DEFAULT_UEVENT_STACKSIZE 256
+#define DEFAULT_RETRIGGER_DELAY 10
+#define DEFAULT_RETRIGGER_TRIES 3
+#define DEFAULT_UEV_WAIT_TIMEOUT 30
 
 #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_PIDFILE                "/" RUN_DIR "/multipathd.pid"
 #define DEFAULT_SOCKET         "/org/kernel/linux/storage/multipathd"
 #define DEFAULT_CONFIGFILE     "/etc/multipath.conf"
 #define DEFAULT_BINDINGS_FILE  "/etc/multipath/bindings"
 #define DEFAULT_WWIDS_FILE     "/etc/multipath/wwids"
+#define DEFAULT_CONFIG_DIR     "/etc/multipath/conf.d"
 
 char * set_default (char * str);
index 6eb2d96d4d811b8516e07c5abdf10b589e54b41c..36c1a204dfac9b426022617ef4af1875f3736897 100644 (file)
 #define UUID_PREFIX "mpath-"
 #define UUID_PREFIX_LEN 6
 
+#ifdef LIBDM_API_DEFERRED
+static int dm_cancel_remove_partmaps(const char * mapname);
+#endif
+
+static int do_foreach_partmaps(const char * mapname,
+                              int (*partmap_func)(const char *, void *),
+                              void *data);
+
 #ifndef LIBDM_API_COOKIE
 static inline int dm_task_set_cookie(struct dm_task *dmt, uint32_t *c, int a)
 {
        return 1;
 }
 
-void udev_wait(unsigned int c)
+void dm_udev_wait(unsigned int c)
 {
 }
 
-void udev_set_sync_support(int c)
-{
-}
-#else
-void udev_wait(unsigned int c)
+void dm_udev_set_sync_support(int c)
 {
-       dm_udev_wait(c);
 }
 
-void udev_set_sync_support(int c)
-{
-       dm_udev_set_sync_support(c);
-}
 #endif
 
 static void
@@ -105,7 +104,11 @@ dm_lib_prereq (void)
 {
        char version[64];
        int v[3];
-#ifdef LIBDM_API_COOKIE
+#if defined(LIBDM_API_DEFERRED)
+       int minv[3] = {1, 2, 89};
+#elif defined(DM_SUBSYSTEM_UDEV_FLAG0)
+       int minv[3] = {1, 2, 82};
+#elif defined(LIBDM_API_COOKIE)
        int minv[3] = {1, 2, 38};
 #else
        int minv[3] = {1, 2, 8};
@@ -201,11 +204,14 @@ dm_prereq (void)
        return dm_drv_prereq();
 }
 
+#define do_deferred(x) ((x) == DEFERRED_REMOVE_ON || (x) == DEFERRED_REMOVE_IN_PROGRESS)
+
 static int
-dm_simplecmd (int task, const char *name, int no_flush, int need_sync) {
+dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) {
        int r = 0;
        int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME ||
                                            task == DM_DEVICE_REMOVE));
+       uint32_t cookie = 0;
        struct dm_task *dmt;
 
        if (!(dmt = dm_task_create (task)))
@@ -220,24 +226,41 @@ dm_simplecmd (int task, const char *name, int no_flush, int need_sync) {
        if (no_flush)
                dm_task_no_flush(dmt);          /* for DM_DEVICE_SUSPEND/RESUME */
 #endif
-
-       if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
+#ifdef LIBDM_API_DEFERRED
+       if (do_deferred(deferred_remove))
+               dm_task_deferred_remove(dmt);
+#endif
+       if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, ((conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0) | udev_flags)) {
+               dm_udev_complete(cookie);
                goto out;
+       }
        r = dm_task_run (dmt);
 
+       if (udev_wait_flag) {
+               if (!r)
+                       dm_udev_complete(cookie);
+               else
+                       dm_udev_wait(cookie);
+       }
        out:
        dm_task_destroy (dmt);
        return r;
 }
 
 extern int
-dm_simplecmd_flush (int task, const char *name, int needsync) {
-       return dm_simplecmd(task, name, 0, needsync);
+dm_simplecmd_flush (int task, const char *name, int needsync, uint16_t udev_flags) {
+       return dm_simplecmd(task, name, 0, needsync, udev_flags, 0);
 }
 
 extern int
-dm_simplecmd_noflush (int task, const char *name) {
-       return dm_simplecmd(task, name, 1, 1);
+dm_simplecmd_noflush (int task, const char *name, int needsync, uint16_t udev_flags) {
+       return dm_simplecmd(task, name, 1, needsync, udev_flags, 0);
+}
+
+static int
+dm_device_remove (const char *name, int needsync, int deferred_remove) {
+       return dm_simplecmd(DM_DEVICE_REMOVE, name, 0, needsync, 0,
+                           deferred_remove);
 }
 
 extern int
@@ -246,6 +269,7 @@ dm_addmap (int task, const char *target, struct multipath *mpp, char * params,
        int r = 0;
        struct dm_task *dmt;
        char *prefixed_uuid = NULL;
+       uint32_t cookie = 0;
 
        if (!(dmt = dm_task_create (task)))
                return 0;
@@ -286,10 +310,18 @@ dm_addmap (int task, const char *target, struct multipath *mpp, char * params,
        dm_task_no_open_count(dmt);
 
        if (task == DM_DEVICE_CREATE &&
-           !dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
+           !dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0)) {
+               dm_udev_complete(cookie);
                goto freeout;
+       }
        r = dm_task_run (dmt);
 
+       if (task == DM_DEVICE_CREATE) {
+               if (!r)
+                       dm_udev_complete(cookie);
+               else
+                       dm_udev_wait(cookie);
+       }
        freeout:
        if (prefixed_uuid)
                FREE(prefixed_uuid);
@@ -307,7 +339,8 @@ dm_addmap_create (struct multipath *mpp, char * params) {
        for (ro = 0; ro <= 1; ro++) {
                int err;
 
-               if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, 1, ro))
+               if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH,
+                             mpp, params, 1, ro))
                        return 1;
                /*
                 * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
@@ -318,8 +351,11 @@ dm_addmap_create (struct multipath *mpp, char * params) {
                        condlog(3, "%s: failed to load map (a path might be in use)", mpp->alias);
                        dm_flush_map_nosync(mpp->alias);
                }
-               if (err != EROFS)
+               if (err != EROFS) {
+                       condlog(3, "%s: failed to load map, error %d",
+                               mpp->alias, err);
                        break;
+               }
        }
        return 0;
 }
@@ -549,6 +585,48 @@ out:
        return r;
 }
 
+extern int
+dm_is_mpath(const char * name)
+{
+       int r = 0;
+       struct dm_task *dmt;
+       struct dm_info info;
+       uint64_t start, length;
+       char *target_type = NULL;
+       char *params;
+       const char *uuid;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+               return 0;
+
+       if (!dm_task_set_name(dmt, name))
+               goto out;
+
+       dm_task_no_open_count(dmt);
+
+       if (!dm_task_run(dmt))
+               goto out;
+
+       if (!dm_task_get_info(dmt, &info) || !info.exists)
+               goto out;
+
+       uuid = dm_task_get_uuid(dmt);
+
+       if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0)
+               goto out;
+
+       /* Fetch 1st target */
+       dm_get_next_target(dmt, NULL, &start, &length, &target_type, &params);
+
+       if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
+               goto out;
+
+       r = 1;
+out:
+       dm_task_destroy(dmt);
+       return r;
+}
+
 static int
 dm_dev_t (const char * mapname, char * dev_t, int len)
 {
@@ -565,10 +643,9 @@ dm_dev_t (const char * mapname, char * dev_t, int len)
        if (!dm_task_run(dmt))
                goto out;
 
-       if (!dm_task_get_info(dmt, &info))
+       if (!dm_task_get_info(dmt, &info) || !info.exists)
                goto out;
 
-       r = info.open_count;
        if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
                    goto out;
 
@@ -597,6 +674,9 @@ dm_get_opencount (const char * mapname)
        if (!dm_task_get_info(dmt, &info))
                goto out;
 
+       if (!info.exists)
+               goto out;
+
        r = info.open_count;
 out:
        dm_task_destroy(dmt);
@@ -622,6 +702,9 @@ dm_get_major (char * mapname)
        if (!dm_task_get_info(dmt, &info))
                goto out;
 
+       if (!info.exists)
+               goto out;
+
        r = info.major;
 out:
        dm_task_destroy(dmt);
@@ -647,40 +730,88 @@ dm_get_minor (char * mapname)
        if (!dm_task_get_info(dmt, &info))
                goto out;
 
+       if (!info.exists)
+               goto out;
+
        r = info.minor;
 out:
        dm_task_destroy(dmt);
        return r;
 }
 
+static int
+partmap_in_use(const char *name, void *data)
+{
+       int part_count, *ret_count = (int *)data;
+       int open_count = dm_get_opencount(name);
+
+       if (ret_count)
+               (*ret_count)++;
+       part_count = 0;
+       if (open_count) {
+               if (do_foreach_partmaps(name, partmap_in_use, &part_count))
+                       return 1;
+               if (open_count != part_count) {
+                       condlog(2, "%s: map in use", name);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 extern int
-_dm_flush_map (const char * mapname, int need_sync)
+_dm_flush_map (const char * mapname, int need_sync, int deferred_remove)
 {
        int r;
 
-       if (!dm_map_present(mapname))
-               return 0;
-
-       if (dm_type(mapname, TGT_MPATH) <= 0)
+       if (!dm_is_mpath(mapname))
                return 0; /* nothing to do */
 
-       if (dm_remove_partmaps(mapname, need_sync))
+       /* If you aren't doing a deferred remove, make sure that no
+        * devices are in use */
+       if (!do_deferred(deferred_remove) && partmap_in_use(mapname, NULL))
+                       return 1;
+
+       if (dm_remove_partmaps(mapname, need_sync, deferred_remove))
                return 1;
 
-       if (dm_get_opencount(mapname)) {
+       if (!do_deferred(deferred_remove) && dm_get_opencount(mapname)) {
                condlog(2, "%s: map in use", mapname);
                return 1;
        }
 
-       r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync);
+       r = dm_device_remove(mapname, need_sync, deferred_remove);
 
        if (r) {
+               if (do_deferred(deferred_remove) && dm_map_present(mapname)) {
+                       condlog(4, "multipath map %s remove deferred",
+                               mapname);
+                       return 2;
+               }
                condlog(4, "multipath map %s removed", mapname);
                return 0;
        }
        return 1;
 }
 
+#ifdef LIBDM_API_DEFERRED
+
+int
+dm_flush_map_nopaths(const char * mapname, int deferred_remove)
+{
+       return _dm_flush_map(mapname, 1, deferred_remove);
+}
+
+#else
+
+int
+dm_flush_map_nopaths(const char * mapname, int deferred_remove)
+{
+       return _dm_flush_map(mapname, 1, 0);
+}
+
+#endif
+
 extern int
 dm_suspend_and_flush_map (const char * mapname)
 {
@@ -688,10 +819,7 @@ dm_suspend_and_flush_map (const char * mapname)
        unsigned long long mapsize;
        char params[PARAMS_SIZE] = {0};
 
-       if (!dm_map_present(mapname))
-               return 0;
-
-       if (dm_type(mapname, TGT_MPATH) <= 0)
+       if (!dm_is_mpath(mapname))
                return 0; /* nothing to do */
 
        if (!dm_get_map(mapname, &mapsize, params)) {
@@ -705,14 +833,14 @@ dm_suspend_and_flush_map (const char * mapname)
        if (s)
                queue_if_no_path = 0;
        else
-               s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 0);
+               s = dm_simplecmd_flush(DM_DEVICE_SUSPEND, mapname, 1, 0);
 
        if (!dm_flush_map(mapname)) {
                condlog(4, "multipath map %s removed", mapname);
                return 0;
        }
        condlog(2, "failed to remove multipath map %s", mapname);
-       dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname);
+       dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, 1, 0);
        if (queue_if_no_path)
                s = dm_queue_if_no_path((char *)mapname, 1);
        return 1;
@@ -752,7 +880,7 @@ dm_flush_maps (void)
 }
 
 int
-dm_message(char * mapname, char * message)
+dm_message(const char * mapname, char * message)
 {
        int r = 1;
        struct dm_task *dmt;
@@ -852,7 +980,6 @@ dm_get_maps (vector mp)
 {
        struct multipath * mpp;
        int r = 1;
-       int info;
        struct dm_task *dmt;
        struct dm_names *names;
        unsigned next = 0;
@@ -877,9 +1004,7 @@ dm_get_maps (vector mp)
        }
 
        do {
-               info = dm_type(names->name, TGT_MPATH);
-
-               if (info <= 0)
+               if (!dm_is_mpath(names->name))
                        goto next;
 
                mpp = alloc_multipath();
@@ -892,13 +1017,11 @@ dm_get_maps (vector mp)
                if (!mpp->alias)
                        goto out1;
 
-               if (info > 0) {
-                       if (dm_get_map(names->name, &mpp->size, NULL))
-                               goto out1;
+               if (dm_get_map(names->name, &mpp->size, NULL))
+                       goto out1;
 
-                       dm_get_uuid(names->name, mpp->wwid);
-                       dm_get_info(names->name, &mpp->dmi);
-               }
+               dm_get_uuid(names->name, mpp->wwid);
+               dm_get_info(names->name, &mpp->dmi);
 
                if (!vector_alloc_slot(mp))
                        goto out1;
@@ -997,8 +1120,10 @@ bad:
        return NULL;
 }
 
-int
-dm_remove_partmaps (const char * mapname, int need_sync)
+static int
+do_foreach_partmaps (const char * mapname,
+                    int (*partmap_func)(const char *, void *),
+                    void *data)
 {
        struct dm_task *dmt;
        struct dm_names *names;
@@ -1050,26 +1175,8 @@ dm_remove_partmaps (const char * mapname, int need_sync)
                     */
                    strstr(params, dev_t)
                   ) {
-                       /*
-                        * then it's a kpartx generated partition.
-                        * remove it.
-                        */
-                       /*
-                        * if the opencount is 0 maybe some other
-                        * partitions depend on it.
-                        */
-                       if (dm_get_opencount(names->name)) {
-                               dm_remove_partmaps(names->name, need_sync);
-                               if (dm_get_opencount(names->name)) {
-                                       condlog(2, "%s: map in use",
-                                               names->name);
-                                       goto out;
-                               }
-                       }
-                       condlog(4, "partition map %s removed",
-                               names->name);
-                       dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name,
-                                          need_sync);
+                       if (partmap_func(names->name, data) != 0)
+                               goto out;
                }
 
                next = names->next;
@@ -1082,6 +1189,109 @@ out:
        return r;
 }
 
+struct remove_data {
+       int need_sync;
+       int deferred_remove;
+};
+
+static int
+remove_partmap(const char *name, void *data)
+{
+       struct remove_data *rd = (struct remove_data *)data;
+
+       if (dm_get_opencount(name)) {
+               dm_remove_partmaps(name, rd->need_sync, rd->deferred_remove);
+               if (!do_deferred(rd->deferred_remove) &&
+                   dm_get_opencount(name)) {
+                       condlog(2, "%s: map in use", name);
+                       return 1;
+               }
+       }
+       condlog(4, "partition map %s removed", name);
+       dm_device_remove(name, rd->need_sync, rd->deferred_remove);
+       return 0;
+}
+
+int
+dm_remove_partmaps (const char * mapname, int need_sync, int deferred_remove)
+{
+       struct remove_data rd = { need_sync, deferred_remove };
+       return do_foreach_partmaps(mapname, remove_partmap, &rd);
+}
+
+#ifdef LIBDM_API_DEFERRED
+
+static int
+cancel_remove_partmap (const char *name, void *unused)
+{
+       if (dm_get_opencount(name))
+               dm_cancel_remove_partmaps(name);
+       if (dm_message(name, "@cancel_deferred_remove") != 0)
+               condlog(0, "%s: can't cancel deferred remove: %s", name,
+                       strerror(errno));
+       return 0;
+}
+
+static int
+dm_get_deferred_remove (char * mapname)
+{
+       int r = -1;
+       struct dm_task *dmt;
+       struct dm_info info;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+               return -1;
+
+       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.deferred_remove;
+out:
+       dm_task_destroy(dmt);
+       return r;
+}
+
+static int
+dm_cancel_remove_partmaps(const char * mapname) {
+       return do_foreach_partmaps(mapname, cancel_remove_partmap, NULL);
+}
+
+int
+dm_cancel_deferred_remove (struct multipath *mpp)
+{
+       int r = 0;
+
+       if (!dm_get_deferred_remove(mpp->alias))
+               return 0;
+       if (mpp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS)
+               mpp->deferred_remove = DEFERRED_REMOVE_ON;
+
+       dm_cancel_remove_partmaps(mpp->alias);
+       r = dm_message(mpp->alias, "@cancel_deferred_remove");
+       if (r)
+               condlog(0, "%s: can't cancel deferred remove: %s", mpp->alias,
+                               strerror(errno));
+       else
+               condlog(2, "%s: canceled deferred remove", mpp->alias);
+       return r;
+}
+
+#else
+
+int
+dm_cancel_deferred_remove (struct multipath *mpp)
+{
+       return 0;
+}
+
+#endif
+
 static struct dm_info *
 alloc_dminfo (void)
 {
@@ -1131,85 +1341,52 @@ out:
        return r;
 }
 
-int
-dm_rename_partmaps (char * old, char * new)
+struct rename_data {
+       const char *old;
+       char *new;
+       char *delim;
+};
+
+static int
+rename_partmap (const char *name, void *data)
 {
-       struct dm_task *dmt;
-       struct dm_names *names;
-       unsigned next = 0;
        char buff[PARAMS_SIZE];
-       unsigned long long size;
-       char dev_t[32];
-       int r = 1;
-
-       if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
-               return 1;
-
-       dm_task_no_open_count(dmt);
+       int offset;
+       struct rename_data *rd = (struct rename_data *)data;
 
-       if (!dm_task_run(dmt))
-               goto out;
-
-       if (!(names = dm_task_get_names(dmt)))
-               goto out;
-
-       if (!names->dev) {
-               r = 0; /* this is perfectly valid */
-               goto out;
-       }
-
-       if (dm_dev_t(old, &dev_t[0], 32))
-               goto out;
-
-       do {
-               if (
-                   /*
-                    * if devmap target is "linear"
-                    */
-                   (dm_type(names->name, TGT_PART) > 0) &&
-
-                   /*
-                    * and the multipath mapname and the part mapname start
-                    * the same
-                    */
-                   !strncmp(names->name, old, strlen(old)) &&
-
-                   /*
-                    * and we can fetch the map table from the kernel
-                    */
-                   !dm_get_map(names->name, &size, &buff[0]) &&
+       if (strncmp(name, rd->old, strlen(rd->old)) != 0)
+               return 0;
+       for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */
+       snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim,
+                name + offset);
+       dm_rename(name, buff);
+       condlog(4, "partition map %s renamed", name);
+       return 0;
+}
 
-                   /*
-                    * and the table maps over the multipath map
-                    */
-                   strstr(buff, dev_t)
-                  ) {
-                               /*
-                                * then it's a kpartx generated partition.
-                                * Rename it.
-                                */
-                               snprintf(buff, PARAMS_SIZE, "%s%s",
-                                        new, names->name + strlen(old));
-                               dm_rename(names->name, buff);
-                               condlog(4, "partition map %s renamed",
-                                       names->name);
-                  }
+int
+dm_rename_partmaps (const char * old, char * new)
+{
+       struct rename_data rd;
 
-               next = names->next;
-               names = (void *) names + next;
-       } while (next);
+       rd.old = old;
+       rd.new = new;
 
-       r = 0;
-out:
-       dm_task_destroy (dmt);
-       return r;
+       if (conf->partition_delim)
+               rd.delim = conf->partition_delim;
+       if (isdigit(new[strlen(new)-1]))
+               rd.delim = "p";
+       else
+               rd.delim = "";
+       return do_foreach_partmaps(old, rename_partmap, &rd);
 }
 
 int
-dm_rename (char * old, char * new)
+dm_rename (const char * old, char * new)
 {
        int r = 0;
        struct dm_task *dmt;
+       uint32_t cookie;
 
        if (dm_rename_partmaps(old, new))
                return r;
@@ -1225,14 +1402,18 @@ dm_rename (char * old, char * new)
 
        dm_task_no_open_count(dmt);
 
-       if (!dm_task_set_cookie(dmt, &conf->cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
-               goto out;
-       if (!dm_task_run(dmt))
+       if (!dm_task_set_cookie(dmt, &cookie, (conf->daemon)? DM_UDEV_DISABLE_LIBRARY_FALLBACK : 0))
                goto out;
+       r = dm_task_run(dmt);
+
+       if (!r)
+               dm_udev_complete(cookie);
+       else
+               dm_udev_wait(cookie);
 
-       r = 1;
 out:
        dm_task_destroy(dmt);
+
        return r;
 }
 
@@ -1297,7 +1478,7 @@ int dm_reassign_table(const char *name, char *old, char *new)
                        condlog(3, "%s: failed to reassign targets", name);
                        goto out_reload;
                }
-               dm_simplecmd_noflush(DM_DEVICE_RESUME, name);
+               dm_simplecmd_noflush(DM_DEVICE_RESUME, name, 1, MPATH_UDEV_RELOAD_FLAG);
        }
        r = 1;
 
index 58cd718aba67050022dc0fec9716fe98bf0b19e8..0d27723cdd3cf30a76d193bd01a33e81967a825f 100644 (file)
@@ -6,20 +6,29 @@
 #define TGT_MPATH      "multipath"
 #define TGT_PART       "linear"
 
+#ifdef DM_SUBSYSTEM_UDEV_FLAG0
+#define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0
+#else
+#define MPATH_UDEV_RELOAD_FLAG 0
+#endif
+
 void dm_init(void);
 int dm_prereq (void);
 int dm_drv_version (unsigned int * version, char * str);
-int dm_simplecmd_flush (int, const char *, int);
-int dm_simplecmd_noflush (int, const char *);
+int dm_simplecmd_flush (int, const char *, int, uint16_t);
+int dm_simplecmd_noflush (int, const char *, int, uint16_t);
 int dm_addmap_create (struct multipath *mpp, char *params);
 int dm_addmap_reload (struct multipath *mpp, char *params);
 int dm_map_present (const char *);
 int dm_get_map(const char *, unsigned long long *, char *);
 int dm_get_status(char *, char *);
 int dm_type(const char *, char *);
-int _dm_flush_map (const char *, int);
-#define dm_flush_map(mapname) _dm_flush_map(mapname, 1)
-#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0)
+int dm_is_mpath(const char *);
+int _dm_flush_map (const char *, int, int);
+int dm_flush_map_nopaths(const char * mapname, int deferred_remove);
+#define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0)
+#define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0, 0)
+int dm_cancel_deferred_remove(struct multipath *mpp);
 int dm_suspend_and_flush_map(const char * mapname);
 int dm_flush_maps (void);
 int dm_fail_path(char * mapname, char * path);
@@ -33,15 +42,14 @@ 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);
+int dm_remove_partmaps (const char * mapname, int need_sync,
+                       int deferred_remove);
 int dm_get_uuid(char *name, char *uuid);
 int dm_get_info (char * mapname, struct dm_info ** dmi);
-int dm_rename (char * old, char * new);
+int dm_rename (const char * old, char * new);
 int dm_reassign(const char * mapname);
 int dm_reassign_table(const char *name, char *old, char *new);
 int dm_setgeometry(struct multipath *mpp);
-void udev_wait(unsigned int c);
-void udev_set_sync_support(int c);
 
 #define VERSION_GE(v, minv) ( \
  (v[0] > minv[0]) || \
index 9db4725acfb6ac78270935757fa329281d8bf76c..89d42a1937b7bfcc17a88abfaf86905714cb05e6 100644 (file)
 #include "prio.h"
 #include "errno.h"
 #include <inttypes.h>
+#include <mpath_cmd.h>
 
-/*
- * default block handlers
- */
 static int
-polling_interval_handler(vector strvec)
+set_int(vector strvec, void *ptr)
 {
+       int *int_ptr = (int *)ptr;
        char * buff;
 
        buff = VECTOR_SLOT(strvec, 1);
-       conf->checkint = atoi(buff);
-       conf->max_checkint = MAX_CHECKINT(conf->checkint);
+       *int_ptr = atoi(buff);
 
        return 0;
 }
 
 static int
-def_fast_io_fail_handler(vector strvec)
+set_str(vector strvec, void *ptr)
 {
-       char * buff;
+       char **str_ptr = (char **)ptr;
 
-       buff = set_value(strvec);
-       if (strlen(buff) == 3 && !strcmp(buff, "off"))
-               conf->fast_io_fail = MP_FAST_IO_FAIL_OFF;
-       else if (sscanf(buff, "%d", &conf->fast_io_fail) != 1 ||
-                conf->fast_io_fail < MP_FAST_IO_FAIL_ZERO)
-               conf->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
-       else if (conf->fast_io_fail == 0)
-               conf->fast_io_fail = MP_FAST_IO_FAIL_ZERO;
+       if (*str_ptr)
+               FREE(*str_ptr);
+       *str_ptr = set_value(strvec);
+
+       if (!*str_ptr)
+               return 1;
 
-       FREE(buff);
        return 0;
 }
 
 static int
-def_dev_loss_handler(vector strvec)
+set_yes_no(vector strvec, void *ptr)
 {
        char * buff;
+       int *int_ptr = (int *)ptr;
 
        buff = set_value(strvec);
        if (!buff)
                return 1;
 
-       if (strlen(buff) == 8 && !strcmp(buff, "infinity"))
-               conf->dev_loss = MAX_DEV_LOSS_TMO;
-       else if (sscanf(buff, "%u", &conf->dev_loss) != 1)
-               conf->dev_loss = 0;
+       if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+               *int_ptr = YN_YES;
+       else
+               *int_ptr = YN_NO;
 
        FREE(buff);
        return 0;
 }
 
 static int
-verbosity_handler(vector strvec)
+set_yes_no_undef(vector strvec, void *ptr)
 {
        char * buff;
+       int *int_ptr = (int *)ptr;
 
-       buff = VECTOR_SLOT(strvec, 1);
-       conf->verbosity = atoi(buff);
+       buff = set_value(strvec);
+       if (!buff)
+               return 1;
 
+       if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
+               *int_ptr = YNU_NO;
+       else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+               *int_ptr = YNU_YES;
+       else
+               *int_ptr = YNU_UNDEF;
+
+       FREE(buff);
        return 0;
 }
 
 static int
-max_polling_interval_handler(vector strvec)
+print_int (char *buff, int len, void *ptr)
 {
-       char *buff;
-
-       buff = VECTOR_SLOT(strvec, 1);
-       conf->max_checkint = atoi(buff);
-
-       return 0;
+       int *int_ptr = (int *)ptr;
+       return snprintf(buff, len, "%i", *int_ptr);
 }
 
 static int
-reassign_maps_handler(vector strvec)
+print_nonzero (char *buff, int len, void *ptr)
 {
-       char * buff;
+       int *int_ptr = (int *)ptr;
+       if (!*int_ptr)
+               return 0;
+       return snprintf(buff, len, "%i", *int_ptr);
+}
 
-       buff = set_value(strvec);
-       if (!strcmp(buff, "yes"))
-               conf->reassign_maps = 1;
-       else if (!strcmp(buff, "no"))
-               conf->reassign_maps = 0;
-       else
-               return 1;
+static int
+print_str (char *buff, int len, void *ptr)
+{
+       char **str_ptr = (char **)ptr;
+       if (!*str_ptr)
+               return 0;
+       return snprintf(buff, len, "\"%s\"", *str_ptr);
+}
 
-       return 0;
+static int
+print_yes_no (char *buff, int len, void *ptr)
+{
+       int *int_ptr = (int *)ptr;
+       return snprintf(buff, len, "\"%s\"",
+                       (*int_ptr == YN_NO)? "no" : "yes");
 }
 
 static int
-multipath_dir_handler(vector strvec)
+print_yes_no_undef (char *buff, int len, void *ptr)
 {
-       conf->multipath_dir = set_value(strvec);
+       int *int_ptr = (int *)ptr;
+       if (!*int_ptr)
+               return 0;
+       return snprintf(buff, len, "\"%s\"",
+                       (*int_ptr == YNU_NO)? "no" : "yes");
+}
 
-       if (!conf->multipath_dir)
-               return 1;
+#define declare_def_handler(option, function)                          \
+static int                                                             \
+def_ ## option ## _handler (vector strvec)                             \
+{                                                                      \
+       return function (strvec, &conf->option);                        \
+}
+
+#define declare_def_snprint(option, function)                          \
+static int                                                             \
+snprint_def_ ## option (char * buff, int len, void * data)             \
+{                                                                      \
+       return function (buff, len, &conf->option);                     \
+}
+
+#define declare_def_snprint_defint(option, function, value)            \
+static int                                                             \
+snprint_def_ ## option (char * buff, int len, void * data)             \
+{                                                                      \
+       int i = value;                                                  \
+       if (!conf->option)                                              \
+               return function (buff, len, &i);                        \
+       return function (buff, len, &conf->option);                     \
+}
 
+#define declare_def_snprint_defstr(option, function, value)            \
+static int                                                             \
+snprint_def_ ## option (char * buff, int len, void * data)             \
+{                                                                      \
+       char *s = value;                                                \
+       if (!conf->option)                                              \
+               return function (buff, len, &s);                        \
+       return function (buff, len, &conf->option);                     \
+}
+
+#define declare_hw_handler(option, function)                           \
+static int                                                             \
+hw_ ## option ## _handler (vector strvec)                              \
+{                                                                      \
+       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);         \
+       if (!hwe)                                                       \
+               return 1;                                               \
+       return function (strvec, &hwe->option);                         \
+}
+
+#define declare_hw_snprint(option, function)                           \
+static int                                                             \
+snprint_hw_ ## option (char * buff, int len, void * data)              \
+{                                                                      \
+       struct hwentry * hwe = (struct hwentry *)data;                  \
+       return function (buff, len, &hwe->option);                      \
+}
+
+#define declare_ovr_handler(option, function)                          \
+static int                                                             \
+ovr_ ## option ## _handler (vector strvec)                             \
+{                                                                      \
+       if (!conf->overrides)                                           \
+               return 1;                                               \
+       return function (strvec, &conf->overrides->option);             \
+}
+
+#define declare_ovr_snprint(option, function)                          \
+static int                                                             \
+snprint_ovr_ ## option (char * buff, int len, void * data)             \
+{                                                                      \
+       return function (buff, len, &conf->overrides->option);          \
+}
+
+#define declare_mp_handler(option, function)                           \
+static int                                                             \
+mp_ ## option ## _handler (vector strvec)                              \
+{                                                                      \
+       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);         \
+       if (!mpe)                                                       \
+               return 1;                                               \
+       return function (strvec, &mpe->option);                         \
+}
+
+#define declare_mp_snprint(option, function)                           \
+static int                                                             \
+snprint_mp_ ## option (char * buff, int len, void * data)              \
+{                                                                      \
+       struct mpentry * mpe = (struct mpentry *)data;                  \
+       return function (buff, len, &mpe->option);                      \
+}
+
+declare_def_handler(checkint, set_int)
+declare_def_snprint(checkint, print_int)
+
+declare_def_handler(max_checkint, set_int)
+declare_def_snprint(max_checkint, print_int)
+
+declare_def_handler(verbosity, set_int)
+declare_def_snprint(verbosity, print_int)
+
+declare_def_handler(reassign_maps, set_yes_no)
+declare_def_snprint(reassign_maps, print_yes_no)
+
+declare_def_handler(multipath_dir, set_str)
+declare_def_snprint(multipath_dir, print_str)
+
+declare_def_handler(partition_delim, set_str)
+declare_def_snprint(partition_delim, print_str)
+
+declare_def_handler(find_multipaths, set_yes_no)
+declare_def_snprint(find_multipaths, print_yes_no)
+
+declare_def_handler(selector, set_str)
+declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
+declare_hw_handler(selector, set_str)
+declare_hw_snprint(selector, print_str)
+declare_ovr_handler(selector, set_str)
+declare_ovr_snprint(selector, print_str)
+declare_mp_handler(selector, set_str)
+declare_mp_snprint(selector, print_str)
+
+declare_def_handler(uid_attribute, set_str)
+declare_def_snprint_defstr(uid_attribute, print_str, DEFAULT_UID_ATTRIBUTE)
+declare_ovr_handler(uid_attribute, set_str)
+declare_ovr_snprint(uid_attribute, print_str)
+declare_hw_handler(uid_attribute, set_str)
+declare_hw_snprint(uid_attribute, print_str)
+
+declare_def_handler(getuid, set_str)
+declare_def_snprint(getuid, print_str)
+declare_ovr_handler(getuid, set_str)
+declare_ovr_snprint(getuid, print_str)
+declare_hw_handler(getuid, set_str)
+declare_hw_snprint(getuid, print_str)
+
+declare_def_handler(prio_name, set_str)
+declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
+declare_ovr_handler(prio_name, set_str)
+declare_ovr_snprint(prio_name, print_str)
+declare_hw_handler(prio_name, set_str)
+declare_hw_snprint(prio_name, print_str)
+declare_mp_handler(prio_name, set_str)
+declare_mp_snprint(prio_name, print_str)
+
+declare_def_handler(alias_prefix, set_str)
+declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
+declare_ovr_handler(alias_prefix, set_str)
+declare_ovr_snprint(alias_prefix, print_str)
+declare_hw_handler(alias_prefix, set_str)
+declare_hw_snprint(alias_prefix, print_str)
+
+declare_def_handler(prio_args, set_str)
+declare_def_snprint_defstr(prio_args, print_str, DEFAULT_PRIO_ARGS)
+declare_ovr_handler(prio_args, set_str)
+declare_ovr_snprint(prio_args, print_str)
+declare_hw_handler(prio_args, set_str)
+declare_hw_snprint(prio_args, print_str)
+declare_mp_handler(prio_args, set_str)
+declare_mp_snprint(prio_args, print_str)
+
+declare_def_handler(features, set_str)
+declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
+declare_ovr_handler(features, set_str)
+declare_ovr_snprint(features, print_str)
+declare_hw_handler(features, set_str)
+declare_hw_snprint(features, print_str)
+declare_mp_handler(features, set_str)
+declare_mp_snprint(features, print_str)
+
+declare_def_handler(checker_name, set_str)
+declare_def_snprint_defstr(checker_name, print_str, DEFAULT_CHECKER)
+declare_ovr_handler(checker_name, set_str)
+declare_ovr_snprint(checker_name, print_str)
+declare_hw_handler(checker_name, set_str)
+declare_hw_snprint(checker_name, print_str)
+
+declare_def_handler(minio, set_int)
+declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
+declare_ovr_handler(minio, set_int)
+declare_ovr_snprint(minio, print_nonzero)
+declare_hw_handler(minio, set_int)
+declare_hw_snprint(minio, print_nonzero)
+declare_mp_handler(minio, set_int)
+declare_mp_snprint(minio, print_nonzero)
+
+declare_def_handler(minio_rq, set_int)
+declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
+declare_ovr_handler(minio_rq, set_int)
+declare_ovr_snprint(minio_rq, print_nonzero)
+declare_hw_handler(minio_rq, set_int)
+declare_hw_snprint(minio_rq, print_nonzero)
+declare_mp_handler(minio_rq, set_int)
+declare_mp_snprint(minio_rq, print_nonzero)
+
+declare_def_handler(queue_without_daemon, set_yes_no)
+static int
+snprint_def_queue_without_daemon (char * buff, int len, void * data)
+{
+       switch (conf->queue_without_daemon) {
+       case QUE_NO_DAEMON_OFF:
+               return snprintf(buff, len, "\"no\"");
+       case QUE_NO_DAEMON_ON:
+               return snprintf(buff, len, "\"yes\"");
+       case QUE_NO_DAEMON_FORCE:
+               return snprintf(buff, len, "\"forced\"");
+       }
        return 0;
 }
 
+declare_def_handler(checker_timeout, set_int)
+declare_def_snprint(checker_timeout, print_nonzero)
+
+declare_def_handler(flush_on_last_del, set_yes_no_undef)
+declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
+declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
+declare_hw_handler(flush_on_last_del, set_yes_no_undef)
+declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
+declare_mp_handler(flush_on_last_del, set_yes_no_undef)
+declare_mp_snprint(flush_on_last_del, print_yes_no_undef)
+
+declare_def_handler(user_friendly_names, set_yes_no_undef)
+declare_def_snprint_defint(user_friendly_names, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(user_friendly_names, set_yes_no_undef)
+declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
+declare_hw_handler(user_friendly_names, set_yes_no_undef)
+declare_hw_snprint(user_friendly_names, print_yes_no_undef)
+declare_mp_handler(user_friendly_names, set_yes_no_undef)
+declare_mp_snprint(user_friendly_names, print_yes_no_undef)
+
+declare_def_handler(bindings_file, set_str)
+declare_def_snprint(bindings_file, print_str)
+
+declare_def_handler(wwids_file, set_str)
+declare_def_snprint(wwids_file, print_str)
+
+declare_def_handler(retain_hwhandler, set_yes_no_undef)
+declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
+declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
+declare_hw_handler(retain_hwhandler, set_yes_no_undef)
+declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
+
+declare_def_handler(detect_prio, set_yes_no_undef)
+declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(detect_prio, set_yes_no_undef)
+declare_ovr_snprint(detect_prio, print_yes_no_undef)
+declare_hw_handler(detect_prio, set_yes_no_undef)
+declare_hw_snprint(detect_prio, print_yes_no_undef)
+
+declare_def_handler(force_sync, set_yes_no)
+declare_def_snprint(force_sync, print_yes_no)
+
+declare_def_handler(deferred_remove, set_yes_no_undef)
+declare_def_snprint_defint(deferred_remove, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(deferred_remove, set_yes_no_undef)
+declare_ovr_snprint(deferred_remove, print_yes_no_undef)
+declare_hw_handler(deferred_remove, set_yes_no_undef)
+declare_hw_snprint(deferred_remove, print_yes_no_undef)
+declare_mp_handler(deferred_remove, set_yes_no_undef)
+declare_mp_snprint(deferred_remove, print_yes_no_undef)
+
+declare_def_handler(retrigger_tries, set_int)
+declare_def_snprint(retrigger_tries, print_int)
+
+declare_def_handler(retrigger_delay, set_int)
+declare_def_snprint(retrigger_delay, print_int)
+
+declare_def_handler(uev_wait_timeout, set_int)
+declare_def_snprint(uev_wait_timeout, print_int)
+
 static int
-def_selector_handler(vector strvec)
+def_config_dir_handler(vector strvec)
 {
-       conf->selector = set_value(strvec);
+       /* this is only valid in the main config file */
+       if (conf->processed_main_config)
+               return 0;
+       return set_str(strvec, &conf->config_dir);
+}
+declare_def_snprint(config_dir, print_str)
 
-       if (!conf->selector)
-               return 1;
+#define declare_def_attr_handler(option, function)                     \
+static int                                                             \
+def_ ## option ## _handler (vector strvec)                             \
+{                                                                      \
+       return function (strvec, &conf->option, &conf->attribute_flags);\
+}
 
-       return 0;
+#define declare_def_attr_snprint(option, function)                     \
+static int                                                             \
+snprint_def_ ## option (char * buff, int len, void * data)             \
+{                                                                      \
+       return function (buff, len, &conf->option,                      \
+                        &conf->attribute_flags);                       \
+}
+
+#define declare_mp_attr_handler(option, function)                      \
+static int                                                             \
+mp_ ## option ## _handler (vector strvec)                              \
+{                                                                      \
+       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);         \
+       if (!mpe)                                                       \
+               return 1;                                               \
+       return function (strvec, &mpe->option, &mpe->attribute_flags);  \
+}
+
+#define declare_mp_attr_snprint(option, function)                      \
+static int                                                             \
+snprint_mp_ ## option (char * buff, int len, void * data)              \
+{                                                                      \
+       struct mpentry * mpe = (struct mpentry *)data;                  \
+       return function (buff, len, &mpe->option,                       \
+                        &mpe->attribute_flags);                        \
 }
 
 static int
-def_pgpolicy_handler(vector strvec)
+set_mode(vector strvec, void *ptr, int *flags)
 {
-       char * buff;
+       mode_t mode;
+       mode_t *mode_ptr = (mode_t *)ptr;
+       char *buff;
 
        buff = set_value(strvec);
 
        if (!buff)
                return 1;
 
-       conf->pgpolicy = get_pgpolicy_id(buff);
-       FREE(buff);
+       if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
+               *flags |= (1 << ATTR_MODE);
+               *mode_ptr = mode;
+       }
 
+       FREE(buff);
        return 0;
 }
 
 static int
-def_uid_attribute_handler(vector strvec)
+set_uid(vector strvec, void *ptr, int *flags)
 {
-       conf->uid_attribute = set_value(strvec);
+       uid_t uid;
+       uid_t *uid_ptr = (uid_t *)ptr;
+       char *buff;
+       char passwd_buf[1024];
+       struct passwd info, *found;
 
-       if (!conf->uid_attribute)
+       buff = set_value(strvec);
+       if (!buff)
                return 1;
+       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
+               *flags |= (1 << ATTR_UID);
+               *uid_ptr = info.pw_uid;
+       }
+       else if (sscanf(buff, "%u", &uid) == 1){
+               *flags |= (1 << ATTR_UID);
+               *uid_ptr = uid;
+       }
 
+       FREE(buff);
        return 0;
 }
 
 static int
-def_getuid_callout_handler(vector strvec)
+set_gid(vector strvec, void *ptr, int *flags)
 {
-       conf->getuid = set_value(strvec);
+       gid_t gid;
+       gid_t *gid_ptr = (gid_t *)ptr;
+       char *buff;
+       char passwd_buf[1024];
+       struct passwd info, *found;
 
-       if (!conf->getuid)
+       buff = set_value(strvec);
+       if (!buff)
                return 1;
 
+       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
+               *flags |= (1 << ATTR_GID);
+               *gid_ptr = info.pw_gid;
+       }
+       else if (sscanf(buff, "%u", &gid) == 1){
+               *flags |= (1 << ATTR_GID);
+               *gid_ptr = gid;
+       }
+       FREE(buff);
        return 0;
 }
 
 static int
-def_prio_handler(vector strvec)
+print_mode(char * buff, int len, void *ptr, int *flags)
 {
-       conf->prio_name = set_value(strvec);
-
-       if (!conf->prio_name)
-               return 1;
-
-       return 0;
+       mode_t *mode_ptr = (mode_t *)ptr;
+       if ((*flags & (1 << ATTR_MODE)) == 0)
+               return 0;
+       return snprintf(buff, len, "0%o", *mode_ptr);
 }
 
 static int
-def_alias_prefix_handler(vector strvec)
+print_uid(char * buff, int len, void *ptr, int *flags)
 {
-       conf->alias_prefix = set_value(strvec);
-
-       if (!conf->alias_prefix)
-               return 1;
-
-       return 0;
+       uid_t *uid_ptr = (uid_t *)ptr;
+       if ((*flags & (1 << ATTR_UID)) == 0)
+               return 0;
+       return snprintf(buff, len, "0%o", *uid_ptr);
 }
 
 static int
-def_prio_args_handler(vector strvec)
+print_gid(char * buff, int len, void *ptr, int *flags)
 {
-       conf->prio_args = set_value(strvec);
+       gid_t *gid_ptr = (gid_t *)ptr;
+       if ((*flags & (1 << ATTR_GID)) == 0)
+               return 0;
+       return snprintf(buff, len, "0%o", *gid_ptr);
+}
 
-       if (!conf->prio_args)
-               return 1;
+declare_def_attr_handler(mode, set_mode)
+declare_def_attr_snprint(mode, print_mode)
+declare_mp_attr_handler(mode, set_mode)
+declare_mp_attr_snprint(mode, print_mode)
 
-       return 0;
-}
+declare_def_attr_handler(uid, set_uid)
+declare_def_attr_snprint(uid, print_uid)
+declare_mp_attr_handler(uid, set_uid)
+declare_mp_attr_snprint(uid, print_uid)
+
+declare_def_attr_handler(gid, set_gid)
+declare_def_attr_snprint(gid, print_gid)
+declare_mp_attr_handler(gid, set_gid)
+declare_mp_attr_snprint(gid, print_gid)
 
 static int
-def_features_handler(vector strvec)
+set_fast_io_fail(vector strvec, void *ptr)
 {
-       conf->features = set_value(strvec);
+       char * buff;
+       int *int_ptr = (int *)ptr;
 
-       if (!conf->features)
+       buff = set_value(strvec);
+       if (!buff)
                return 1;
 
+       if (strcmp(buff, "off") == 0)
+               *int_ptr = MP_FAST_IO_FAIL_OFF;
+       else if (sscanf(buff, "%d", int_ptr) != 1 ||
+                *int_ptr < MP_FAST_IO_FAIL_ZERO)
+               *int_ptr = MP_FAST_IO_FAIL_UNSET;
+       else if (*int_ptr == 0)
+               *int_ptr = MP_FAST_IO_FAIL_ZERO;
+
+       FREE(buff);
        return 0;
 }
 
-static int
-def_path_checker_handler(vector strvec)
+int
+print_fast_io_fail(char * buff, int len, void *ptr)
 {
-       conf->checker_name = set_value(strvec);
-
-       if (!conf->checker_name)
-               return 1;
+       int *int_ptr = (int *)ptr;
 
-       return 0;
+       if (*int_ptr == MP_FAST_IO_FAIL_UNSET)
+               return 0;
+       if (*int_ptr == MP_FAST_IO_FAIL_OFF)
+               return snprintf(buff, len, "\"off\"");
+       if (*int_ptr == MP_FAST_IO_FAIL_ZERO)
+               return snprintf(buff, len, "0");
+       return snprintf(buff, len, "%d", *int_ptr);
 }
 
+declare_def_handler(fast_io_fail, set_fast_io_fail)
+declare_def_snprint(fast_io_fail, print_fast_io_fail)
+declare_ovr_handler(fast_io_fail, set_fast_io_fail)
+declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
+declare_hw_handler(fast_io_fail, set_fast_io_fail)
+declare_hw_snprint(fast_io_fail, print_fast_io_fail)
+
 static int
-def_minio_handler(vector strvec)
+set_dev_loss(vector strvec, void *ptr)
 {
        char * buff;
+       unsigned int *uint_ptr = (unsigned int *)ptr;
 
        buff = set_value(strvec);
-
        if (!buff)
                return 1;
 
-       conf->minio = atoi(buff);
-       FREE(buff);
+       if (!strcmp(buff, "infinity"))
+               *uint_ptr = MAX_DEV_LOSS_TMO;
+       else if (sscanf(buff, "%u", uint_ptr) != 1)
+               *uint_ptr = 0;
 
+       FREE(buff);
        return 0;
 }
 
+int
+print_dev_loss(char * buff, int len, void *ptr)
+{
+       unsigned int *uint_ptr = (unsigned int *)ptr;
+
+       if (!*uint_ptr)
+               return 0;
+       if (*uint_ptr >= MAX_DEV_LOSS_TMO)
+               return snprintf(buff, len, "\"infinity\"");
+       return snprintf(buff, len, "%u", *uint_ptr);
+}
+
+declare_def_handler(dev_loss, set_dev_loss)
+declare_def_snprint(dev_loss, print_dev_loss)
+declare_ovr_handler(dev_loss, set_dev_loss)
+declare_ovr_snprint(dev_loss, print_dev_loss)
+declare_hw_handler(dev_loss, set_dev_loss)
+declare_hw_snprint(dev_loss, print_dev_loss)
+
 static int
-def_minio_rq_handler(vector strvec)
+set_pgpolicy(vector strvec, void *ptr)
 {
        char * buff;
+       int *int_ptr = (int *)ptr;
 
        buff = set_value(strvec);
-
        if (!buff)
                return 1;
 
-       conf->minio_rq = atoi(buff);
+       *int_ptr = get_pgpolicy_id(buff);
        FREE(buff);
 
        return 0;
 }
 
+int
+print_pgpolicy(char * buff, int len, void *ptr)
+{
+       char str[POLICY_NAME_SIZE];
+       int pgpolicy = *(int *)ptr;
+
+       if (!pgpolicy)
+               return 0;
+
+       get_pgpolicy_name(str, POLICY_NAME_SIZE, pgpolicy);
+
+       return snprintf(buff, len, "\"%s\"", str);
+}
+
+declare_def_handler(pgpolicy, set_pgpolicy)
+declare_def_snprint_defint(pgpolicy, print_pgpolicy, DEFAULT_PGPOLICY)
+declare_ovr_handler(pgpolicy, set_pgpolicy)
+declare_ovr_snprint(pgpolicy, print_pgpolicy)
+declare_hw_handler(pgpolicy, set_pgpolicy)
+declare_hw_snprint(pgpolicy, print_pgpolicy)
+declare_mp_handler(pgpolicy, set_pgpolicy)
+declare_mp_snprint(pgpolicy, print_pgpolicy)
+
 int
 get_sys_max_fds(int *max_fds)
 {
@@ -317,221 +735,170 @@ max_fds_handler(vector strvec)
 }
 
 static int
-def_mode_handler(vector strvec)
+snprint_max_fds (char * buff, int len, void * data)
 {
-       mode_t mode;
-       char *buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
+       int r = 0, max_fds;
 
-       if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
-               conf->attribute_flags |= (1 << ATTR_MODE);
-               conf->mode = mode;
-       }
+       if (!conf->max_fds)
+               return 0;
 
-       FREE(buff);
-       return 0;
+       r = get_sys_max_fds(&max_fds);
+       if (!r && conf->max_fds >= max_fds)
+               return snprintf(buff, len, "\"max\"");
+       else
+               return snprintf(buff, len, "%d", conf->max_fds);
 }
 
 static int
-def_uid_handler(vector strvec)
+set_rr_weight(vector strvec, void *ptr)
 {
-       uid_t uid;
-       char *buff;
-       char passwd_buf[1024];
-       struct passwd info, *found;
+       int *int_ptr = (int *)ptr;
+       char * buff;
 
        buff = set_value(strvec);
+
        if (!buff)
                return 1;
-       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-               conf->attribute_flags |= (1 << ATTR_UID);
-               conf->uid = info.pw_uid;
-       }
-       else if (sscanf(buff, "%u", &uid) == 1){
-               conf->attribute_flags |= (1 << ATTR_UID);
-               conf->uid = uid;
-       }
-
-       FREE(buff);
-       return 0;
-}
 
-static int
-def_gid_handler(vector strvec)
-{
-       gid_t gid;
-       char *buff;
-       char passwd_buf[1024];
-       struct passwd info, *found;
+       if (!strcmp(buff, "priorities"))
+               *int_ptr = RR_WEIGHT_PRIO;
 
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
+       if (!strcmp(buff, "uniform"))
+               *int_ptr = RR_WEIGHT_NONE;
 
-       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-               conf->attribute_flags |= (1 << ATTR_GID);
-               conf->gid = info.pw_gid;
-       }
-       else if (sscanf(buff, "%u", &gid) == 1){
-               conf->attribute_flags |= (1 << ATTR_GID);
-               conf->gid = gid;
-       }
        FREE(buff);
+
        return 0;
 }
 
-static int
-def_weight_handler(vector strvec)
+int
+print_rr_weight (char * buff, int len, void *ptr)
 {
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       if (strlen(buff) == 10 &&
-           !strcmp(buff, "priorities"))
-               conf->rr_weight = RR_WEIGHT_PRIO;
+       int *int_ptr = (int *)ptr;
 
-       if (strlen(buff) == strlen("uniform") &&
-           !strcmp(buff, "uniform"))
-               conf->rr_weight = RR_WEIGHT_NONE;
-
-       FREE(buff);
+       if (!*int_ptr)
+               return 0;
+       if (*int_ptr == RR_WEIGHT_PRIO)
+               return snprintf(buff, len, "\"priorities\"");
+       if (*int_ptr == RR_WEIGHT_NONE)
+               return snprintf(buff, len, "\"uniform\"");
 
        return 0;
 }
 
+declare_def_handler(rr_weight, set_rr_weight)
+declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
+declare_ovr_handler(rr_weight, set_rr_weight)
+declare_ovr_snprint(rr_weight, print_rr_weight)
+declare_hw_handler(rr_weight, set_rr_weight)
+declare_hw_snprint(rr_weight, print_rr_weight)
+declare_mp_handler(rr_weight, set_rr_weight)
+declare_mp_snprint(rr_weight, print_rr_weight)
+
 static int
-default_failback_handler(vector strvec)
+set_pgfailback(vector strvec, void *ptr)
 {
+       int *int_ptr = (int *)ptr;
        char * buff;
 
        buff = set_value(strvec);
 
        if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-               conf->pgfailback = -FAILBACK_MANUAL;
+               *int_ptr = -FAILBACK_MANUAL;
        else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-               conf->pgfailback = -FAILBACK_IMMEDIATE;
+               *int_ptr = -FAILBACK_IMMEDIATE;
        else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-               conf->pgfailback = -FAILBACK_FOLLOWOVER;
+               *int_ptr = -FAILBACK_FOLLOWOVER;
        else
-               conf->pgfailback = atoi(buff);
+               *int_ptr = atoi(buff);
 
        FREE(buff);
 
        return 0;
 }
 
+int
+print_pgfailback (char * buff, int len, void *ptr)
+{
+       int *int_ptr = (int *)ptr;
+
+       switch(*int_ptr) {
+       case  FAILBACK_UNDEF:
+               return 0;
+       case -FAILBACK_MANUAL:
+               return snprintf(buff, len, "\"manual\"");
+       case -FAILBACK_IMMEDIATE:
+               return snprintf(buff, len, "\"immediate\"");
+       case -FAILBACK_FOLLOWOVER:
+               return snprintf(buff, len, "\"followover\"");
+       default:
+               return snprintf(buff, len, "%i", *int_ptr);
+       }
+}
+
+declare_def_handler(pgfailback, set_pgfailback)
+declare_def_snprint_defint(pgfailback, print_pgfailback, DEFAULT_FAILBACK)
+declare_ovr_handler(pgfailback, set_pgfailback)
+declare_ovr_snprint(pgfailback, print_pgfailback)
+declare_hw_handler(pgfailback, set_pgfailback)
+declare_hw_snprint(pgfailback, print_pgfailback)
+declare_mp_handler(pgfailback, set_pgfailback)
+declare_mp_snprint(pgfailback, print_pgfailback)
+
 static int
-def_no_path_retry_handler(vector strvec)
+set_no_path_retry(vector strvec, void *ptr)
 {
+       int *int_ptr = (int *)ptr;
        char * buff;
 
        buff = set_value(strvec);
        if (!buff)
                return 1;
 
-       if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               conf->no_path_retry = NO_PATH_RETRY_FAIL;
-       else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-               conf->no_path_retry = NO_PATH_RETRY_QUEUE;
-       else if ((conf->no_path_retry = atoi(buff)) < 1)
-               conf->no_path_retry = NO_PATH_RETRY_UNDEF;
+       if (!strcmp(buff, "fail") || !strcmp(buff, "0"))
+               *int_ptr = NO_PATH_RETRY_FAIL;
+       else if (!strcmp(buff, "queue"))
+               *int_ptr = NO_PATH_RETRY_QUEUE;
+       else if ((*int_ptr = atoi(buff)) < 1)
+               *int_ptr = NO_PATH_RETRY_UNDEF;
 
        FREE(buff);
        return 0;
 }
 
+int
+print_no_path_retry(char * buff, int len, void *ptr)
+{
+       int *int_ptr = (int *)ptr;
+
+       switch(*int_ptr) {
+       case NO_PATH_RETRY_UNDEF:
+               return 0;
+       case NO_PATH_RETRY_FAIL:
+               return snprintf(buff, len, "\"fail\"");
+       case NO_PATH_RETRY_QUEUE:
+               return snprintf(buff, len, "\"queue\"");
+       default:
+               return snprintf(buff, len, "%i", *int_ptr);
+       }
+}
+
+declare_def_handler(no_path_retry, set_no_path_retry)
+declare_def_snprint(no_path_retry, print_no_path_retry)
+declare_ovr_handler(no_path_retry, set_no_path_retry)
+declare_ovr_snprint(no_path_retry, print_no_path_retry)
+declare_hw_handler(no_path_retry, set_no_path_retry)
+declare_hw_snprint(no_path_retry, print_no_path_retry)
+declare_mp_handler(no_path_retry, set_no_path_retry)
+declare_mp_snprint(no_path_retry, print_no_path_retry)
+
 static int
-def_queue_without_daemon(vector strvec)
+def_log_checker_err_handler(vector strvec)
 {
        char * buff;
 
        buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) ||
-                !strncmp(buff, "1", 1))
-               conf->queue_without_daemon = QUE_NO_DAEMON_ON;
-       else
-               conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
-
-       free(buff);
-       return 0;
-}
-
-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)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       /* Deprecated; device-mapper support has been removed */
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-def_flush_on_last_del_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-               conf->flush_on_last_del = FLUSH_DISABLED;
-       else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-               conf->flush_on_last_del = FLUSH_ENABLED;
-       else
-               conf->flush_on_last_del = FLUSH_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-def_log_checker_err_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
+
        if (!buff)
                return 1;
 
@@ -545,8 +912,17 @@ def_log_checker_err_handler(vector strvec)
 }
 
 static int
-def_reservation_key_handler(vector strvec)
+snprint_def_log_checker_err (char * buff, int len, void * data)
+{
+       if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
+               return snprintf(buff, len, "once");
+       return snprintf(buff, len, "always");
+}
+
+static int
+set_reservation_key(vector strvec, void *ptr)
 {
+       unsigned char **uchar_ptr = (unsigned char **)ptr;
        char *buff;
        char *tbuff;
        int j, k;
@@ -577,13 +953,13 @@ def_reservation_key_handler(vector strvec)
                return 1;
        }
 
-       if (!conf->reservation_key)
-               conf->reservation_key = (unsigned char *) malloc(8);
+       if (!*uchar_ptr)
+               *uchar_ptr = (unsigned char *) malloc(8);
 
-       memset(conf->reservation_key, 0, 8);
+       memset(*uchar_ptr, 0, 8);
 
        for (j = 7; j >= 0; --j) {
-               conf->reservation_key[j] = (prkey & 0xff);
+               (*uchar_ptr)[j] = (prkey & 0xff);
                prkey >>= 8;
        }
 
@@ -591,94 +967,100 @@ def_reservation_key_handler(vector strvec)
        return 0;
 }
 
+int
+print_reservation_key(char * buff, int len, void * ptr)
+{
+       unsigned char **uchar_ptr = (unsigned char **)ptr;
+       int i;
+       unsigned char *keyp;
+       uint64_t prkey = 0;
+
+       if (!*uchar_ptr)
+               return 0;
+       keyp = (unsigned char *)(*uchar_ptr);
+       for (i = 0; i < 8; i++) {
+               if (i > 0)
+                       prkey <<= 8;
+               prkey |= *keyp;
+               keyp++;
+       }
+       return snprintf(buff, len, "0x%" PRIx64, prkey);
+}
+
+declare_def_handler(reservation_key, set_reservation_key)
+declare_def_snprint(reservation_key, print_reservation_key)
+declare_mp_handler(reservation_key, set_reservation_key)
+declare_mp_snprint(reservation_key, print_reservation_key)
+
 static int
-def_names_handler(vector strvec)
+set_delay_checks(vector strvec, void *ptr)
 {
+       int *int_ptr = (int *)ptr;
        char * buff;
 
        buff = set_value(strvec);
-
        if (!buff)
                return 1;
 
-       if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               conf->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-       else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-                (strlen(buff) == 1 && !strcmp(buff, "1")))
-               conf->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-       else
-               conf->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
+       if (!strcmp(buff, "no") || !strcmp(buff, "0"))
+               *int_ptr = DELAY_CHECKS_OFF;
+       else if ((*int_ptr = atoi(buff)) < 1)
+               *int_ptr = DELAY_CHECKS_UNDEF;
 
        FREE(buff);
        return 0;
 }
 
-static int
-bindings_file_handler(vector strvec)
-{
-       conf->bindings_file = set_value(strvec);
-
-       if (!conf->bindings_file)
-               return 1;
-
-       return 0;
-}
-
-static int
-wwids_file_handler(vector strvec)
+int
+print_delay_checks(char * buff, int len, void *ptr)
 {
-       conf->wwids_file = set_value(strvec);
-
-       if (!conf->wwids_file)
-               return 1;
+       int *int_ptr = (int *)ptr;
 
-       return 0;
+       switch(*int_ptr) {
+       case DELAY_CHECKS_UNDEF:
+               return 0;
+       case DELAY_CHECKS_OFF:
+               return snprintf(buff, len, "\"off\"");
+       default:
+               return snprintf(buff, len, "%i", *int_ptr);
+       }
 }
 
-static int
-def_retain_hwhandler_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
+declare_def_handler(delay_watch_checks, set_delay_checks)
+declare_def_snprint(delay_watch_checks, print_delay_checks)
+declare_ovr_handler(delay_watch_checks, set_delay_checks)
+declare_ovr_snprint(delay_watch_checks, print_delay_checks)
+declare_hw_handler(delay_watch_checks, set_delay_checks)
+declare_hw_snprint(delay_watch_checks, print_delay_checks)
+declare_mp_handler(delay_watch_checks, set_delay_checks)
+declare_mp_snprint(delay_watch_checks, print_delay_checks)
 
-       if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               conf->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-       else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-                (strlen(buff) == 1 && !strcmp(buff, "1")))
-               conf->retain_hwhandler = RETAIN_HWHANDLER_ON;
-       else
-               conf->retain_hwhandler = RETAIN_HWHANDLER_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
+declare_def_handler(delay_wait_checks, set_delay_checks)
+declare_def_snprint(delay_wait_checks, print_delay_checks)
+declare_ovr_handler(delay_wait_checks, set_delay_checks)
+declare_ovr_snprint(delay_wait_checks, print_delay_checks)
+declare_hw_handler(delay_wait_checks, set_delay_checks)
+declare_hw_snprint(delay_wait_checks, print_delay_checks)
+declare_mp_handler(delay_wait_checks, set_delay_checks)
+declare_mp_snprint(delay_wait_checks, print_delay_checks)
 
 static int
-def_detect_prio_handler(vector strvec)
+def_uxsock_timeout_handler(vector strvec)
 {
-       char * buff;
+       unsigned int uxsock_timeout;
+       char *buff;
 
        buff = set_value(strvec);
-
        if (!buff)
                return 1;
 
-       if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               conf->detect_prio = DETECT_PRIO_OFF;
-       else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-                (strlen(buff) == 1 && !strcmp(buff, "1")))
-               conf->detect_prio = DETECT_PRIO_ON;
+       if (sscanf(buff, "%u", &uxsock_timeout) == 1 &&
+           uxsock_timeout > DEFAULT_REPLY_TIMEOUT)
+               conf->uxsock_timeout = uxsock_timeout;
        else
-               conf->detect_prio = DETECT_PRIO_UNDEF;
+               conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
 
-       FREE(buff);
+       free(buff);
        return 0;
 }
 
@@ -688,10 +1070,14 @@ def_detect_prio_handler(vector strvec)
 static int
 blacklist_handler(vector strvec)
 {
-       conf->blist_devnode = vector_alloc();
-       conf->blist_wwid = vector_alloc();
-       conf->blist_device = vector_alloc();
-       conf->blist_property = vector_alloc();
+       if (!conf->blist_devnode)
+               conf->blist_devnode = vector_alloc();
+       if (!conf->blist_wwid)
+               conf->blist_wwid = vector_alloc();
+       if (!conf->blist_device)
+               conf->blist_device = vector_alloc();
+       if (!conf->blist_property)
+               conf->blist_property = vector_alloc();
 
        if (!conf->blist_devnode || !conf->blist_wwid ||
            !conf->blist_device || !conf->blist_property)
@@ -703,10 +1089,14 @@ blacklist_handler(vector strvec)
 static int
 blacklist_exceptions_handler(vector strvec)
 {
-       conf->elist_devnode = vector_alloc();
-       conf->elist_wwid = vector_alloc();
-       conf->elist_device = vector_alloc();
-       conf->elist_property = vector_alloc();
+       if (!conf->elist_devnode)
+               conf->elist_devnode = vector_alloc();
+       if (!conf->elist_wwid)
+               conf->elist_wwid = vector_alloc();
+       if (!conf->elist_device)
+               conf->elist_device = vector_alloc();
+       if (!conf->elist_property)
+               conf->elist_property = vector_alloc();
 
        if (!conf->elist_devnode || !conf->elist_wwid ||
            !conf->elist_device || !conf->elist_property)
@@ -715,82 +1105,57 @@ blacklist_exceptions_handler(vector strvec)
        return 0;
 }
 
-static int
-ble_devnode_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return store_ble(conf->blist_devnode, buff, ORIGIN_CONFIG);
-}
-
-static int
-ble_except_devnode_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return store_ble(conf->elist_devnode, buff, ORIGIN_CONFIG);
+#define declare_ble_handler(option)                                    \
+static int                                                             \
+ble_ ## option ## _handler (vector strvec)                             \
+{                                                                      \
+       char * buff;                                                    \
+                                                                       \
+       if (!conf->option)                                              \
+               return 1;                                               \
+                                                                       \
+       buff = set_value(strvec);                                       \
+       if (!buff)                                                      \
+               return 1;                                               \
+                                                                       \
+       return store_ble(conf->option, buff, ORIGIN_CONFIG);            \
 }
 
-static int
-ble_wwid_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return store_ble(conf->blist_wwid, buff, ORIGIN_CONFIG);
+#define declare_ble_device_handler(name, option, vend, prod)           \
+static int                                                             \
+ble_ ## option ## _ ## name ## _handler (vector strvec)                        \
+{                                                                      \
+       char * buff;                                                    \
+                                                                       \
+       if (!conf->option)                                              \
+               return 1;                                               \
+                                                                       \
+       buff = set_value(strvec);                                       \
+       if (!buff)                                                      \
+               return 1;                                               \
+                                                                       \
+       return set_ble_device(conf->option, vend, prod, ORIGIN_CONFIG); \
 }
 
-static int
-ble_except_wwid_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return store_ble(conf->elist_wwid, buff, ORIGIN_CONFIG);
-}
+declare_ble_handler(blist_devnode)
+declare_ble_handler(elist_devnode)
+declare_ble_handler(blist_wwid)
+declare_ble_handler(elist_wwid)
+declare_ble_handler(blist_property)
+declare_ble_handler(elist_property)
 
 static int
-ble_property_handler(vector strvec)
+snprint_def_uxsock_timeout(char * buff, int len, void * data)
 {
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return store_ble(conf->blist_property, buff, ORIGIN_CONFIG);
+       return snprintf(buff, len, "%u", conf->uxsock_timeout);
 }
 
 static int
-ble_except_property_handler(vector strvec)
+snprint_ble_simple (char * buff, int len, void * data)
 {
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
+       struct blentry * ble = (struct blentry *)data;
 
-       return store_ble(conf->elist_property, buff, ORIGIN_CONFIG);
+       return snprintf(buff, len, "\"%s\"", ble->str);
 }
 
 static int
@@ -805,56 +1170,25 @@ ble_except_device_handler(vector strvec)
        return alloc_ble_device(conf->elist_device);
 }
 
-static int
-ble_vendor_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return set_ble_device(conf->blist_device, buff, NULL, ORIGIN_CONFIG);
-}
-
-static int
-ble_except_vendor_handler(vector strvec)
-{
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       return set_ble_device(conf->elist_device, buff, NULL, ORIGIN_CONFIG);
-}
+declare_ble_device_handler(vendor, blist_device, buff, NULL)
+declare_ble_device_handler(vendor, elist_device, buff, NULL)
+declare_ble_device_handler(product, blist_device, NULL, buff)
+declare_ble_device_handler(product, elist_device, NULL, buff)
 
 static int
-ble_product_handler(vector strvec)
+snprint_bled_vendor (char * buff, int len, void * data)
 {
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
+       struct blentry_device * bled = (struct blentry_device *)data;
 
-       return set_ble_device(conf->blist_device, NULL, buff, ORIGIN_CONFIG);
+       return snprintf(buff, len, "\"%s\"", bled->vendor);
 }
 
 static int
-ble_except_product_handler(vector strvec)
+snprint_bled_product (char * buff, int len, void * data)
 {
-       char * buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
+       struct blentry_device * bled = (struct blentry_device *)data;
 
-       return set_ble_device(conf->elist_device, NULL, buff, ORIGIN_CONFIG);
+       return snprintf(buff, len, "\"%s\"", bled->product);
 }
 
 /*
@@ -891,1985 +1225,180 @@ device_handler(vector strvec)
        return 0;
 }
 
-static int
-vendor_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+declare_hw_handler(vendor, set_str)
+declare_hw_snprint(vendor, print_str)
 
-       if (!hwe)
-               return 1;
+declare_hw_handler(product, set_str)
+declare_hw_snprint(product, print_str)
 
-       hwe->vendor = set_value(strvec);
+declare_hw_handler(revision, set_str)
+declare_hw_snprint(revision, print_str)
 
-       if (!hwe->vendor)
-               return 1;
+declare_hw_handler(bl_product, set_str)
+declare_hw_snprint(bl_product, print_str)
 
-       return 0;
-}
+declare_hw_handler(hwhandler, set_str)
+declare_hw_snprint(hwhandler, print_str)
 
+/*
+ * overrides handlers
+ */
 static int
-product_handler(vector strvec)
+overrides_handler(vector strvec)
 {
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
+       if (!conf->overrides)
+               conf->overrides = alloc_hwe();
 
-       hwe->product = set_value(strvec);
-
-       if (!hwe->product)
+       if (!conf->overrides)
                return 1;
 
        return 0;
 }
 
-static int
-revision_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
 
-       if (!hwe)
-               return 1;
 
-       hwe->revision = set_value(strvec);
+/*
+ * multipaths block handlers
+ */
+static int
+multipaths_handler(vector strvec)
+{
+       if (!conf->mptable)
+               conf->mptable = vector_alloc();
 
-       if (!hwe->revision)
+       if (!conf->mptable)
                return 1;
 
        return 0;
 }
 
 static int
-bl_product_handler(vector strvec)
+multipath_handler(vector strvec)
 {
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+       struct mpentry * mpe;
 
-       if (!hwe)
+       mpe = alloc_mpe();
+
+       if (!mpe)
                return 1;
 
-       hwe->bl_product = set_value(strvec);
-       if (!hwe->bl_product)
+       if (!vector_alloc_slot(conf->mptable)) {
+               free_mpe(mpe);
                return 1;
+       }
+       vector_set_slot(conf->mptable, mpe);
 
        return 0;
 }
 
+declare_mp_handler(wwid, set_str)
+declare_mp_snprint(wwid, print_str)
+
+declare_mp_handler(alias, set_str)
+declare_mp_snprint(alias, print_str)
+
+/*
+ * deprecated handlers
+ */
+
 static int
-hw_fast_io_fail_handler(vector strvec)
+deprecated_handler(vector strvec)
 {
        char * buff;
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
 
        buff = set_value(strvec);
-       if (strlen(buff) == 3 && !strcmp(buff, "off"))
-               hwe->fast_io_fail = MP_FAST_IO_FAIL_OFF;
-       else if (sscanf(buff, "%d", &hwe->fast_io_fail) != 1 ||
-                hwe->fast_io_fail < MP_FAST_IO_FAIL_ZERO)
-               hwe->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
-       else if (hwe->fast_io_fail == 0)
-               hwe->fast_io_fail = MP_FAST_IO_FAIL_ZERO;
+
+       if (!buff)
+               return 1;
 
        FREE(buff);
        return 0;
 }
 
 static int
-hw_dev_loss_handler(vector strvec)
+snprint_deprecated (char * buff, int len, void * data)
 {
-       char * buff;
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if (strlen(buff) == 8 && !strcmp(buff, "infinity"))
-               hwe->dev_loss = MAX_DEV_LOSS_TMO;
-       else if (sscanf(buff, "%u", &hwe->dev_loss) != 1)
-               hwe->dev_loss = 0;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_pgpolicy_handler(vector strvec)
-{
-       char * buff;
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       hwe->pgpolicy = get_pgpolicy_id(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-hw_uid_attribute_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       hwe->uid_attribute = set_value(strvec);
-
-       if (!hwe->uid_attribute)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_getuid_callout_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       hwe->getuid = set_value(strvec);
-
-       if (!hwe->getuid)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_selector_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->selector = set_value(strvec);
-
-       if (!hwe->selector)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_path_checker_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->checker_name = set_value(strvec);
-
-       if (!hwe->checker_name)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_features_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->features = set_value(strvec);
-
-       if (!hwe->features)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_handler_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->hwhandler = set_value(strvec);
-
-       if (!hwe->hwhandler)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_prio_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->prio_name = set_value(strvec);
-
-       if (!hwe->prio_name)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_alias_prefix_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->alias_prefix = set_value(strvec);
-
-       if (!hwe->alias_prefix)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_prio_args_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-       if (!hwe)
-               return 1;
-
-       hwe->prio_args = set_value(strvec);
-
-       if (!hwe->prio_args)
-               return 1;
-
-       return 0;
-}
-
-static int
-hw_failback_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-               hwe->pgfailback = -FAILBACK_MANUAL;
-       else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-               hwe->pgfailback = -FAILBACK_IMMEDIATE;
-       else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-               hwe->pgfailback = -FAILBACK_FOLLOWOVER;
-       else
-               hwe->pgfailback = atoi(buff);
-
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-hw_weight_handler(vector strvec)
-{
-       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       if (strlen(buff) == 10 &&
-           !strcmp(buff, "priorities"))
-               hwe->rr_weight = RR_WEIGHT_PRIO;
-
-       if (strlen(buff) == strlen("uniform") &&
-           !strcmp(buff, "uniform"))
-               hwe->rr_weight = RR_WEIGHT_NONE;
-
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-hw_no_path_retry_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char *buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               hwe->no_path_retry = NO_PATH_RETRY_FAIL;
-       else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-               hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
-       else if ((hwe->no_path_retry = atoi(buff)) < 1)
-               hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_minio_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       hwe->minio = atoi(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-hw_minio_rq_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       hwe->minio_rq = atoi(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-hw_pg_timeout_handler(vector strvec)
-{
-       char *buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       /* Deprecated; device-mapper support has been removed */
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_flush_on_last_del_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-               hwe->flush_on_last_del = FLUSH_DISABLED;
-       else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-               hwe->flush_on_last_del = FLUSH_ENABLED;
-       else
-               hwe->flush_on_last_del = FLUSH_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_names_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-               hwe->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-       else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-                (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-               hwe->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-       else
-               hwe->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_retain_hwhandler_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               hwe->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-       else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-                (strlen(buff) == 1 && !strcmp(buff, "1")))
-               hwe->retain_hwhandler = RETAIN_HWHANDLER_ON;
-       else
-               hwe->user_friendly_names = RETAIN_HWHANDLER_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-hw_detect_prio_handler(vector strvec)
-{
-       struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-       char * buff;
-
-       if (!hwe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               hwe->detect_prio = DETECT_PRIO_OFF;
-       else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-                (strlen(buff) == 1 && !strcmp(buff, "1")))
-               hwe->detect_prio = DETECT_PRIO_ON;
-       else
-               hwe->detect_prio = DETECT_PRIO_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-/*
- * multipaths block handlers
- */
-static int
-multipaths_handler(vector strvec)
-{
-       conf->mptable = vector_alloc();
-
-       if (!conf->mptable)
-               return 1;
-
-       return 0;
-}
-
-static int
-multipath_handler(vector strvec)
-{
-       struct mpentry * mpe;
-
-       mpe = alloc_mpe();
-
-       if (!mpe)
-               return 1;
-
-       if (!vector_alloc_slot(conf->mptable)) {
-               free_mpe(mpe);
-               return 1;
-       }
-       vector_set_slot(conf->mptable, mpe);
-
-       return 0;
-}
-
-static int
-wwid_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->wwid = set_value(strvec);
-
-       if (!mpe->wwid)
-               return 1;
-
-       return 0;
-}
-
-static int
-alias_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->alias = set_value(strvec);
-
-       if (!mpe->alias)
-               return 1;
-
-       return 0;
-}
-
-static int
-mp_pgpolicy_handler(vector strvec)
-{
-       char * buff;
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       mpe->pgpolicy = get_pgpolicy_id(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-mp_selector_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->selector = set_value(strvec);
-
-       if (!mpe->selector)
-               return 1;
-
-       return 0;
-}
-
-static int
-mp_failback_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-               mpe->pgfailback = -FAILBACK_MANUAL;
-       else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-               mpe->pgfailback = -FAILBACK_IMMEDIATE;
-       else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-               mpe->pgfailback = -FAILBACK_FOLLOWOVER;
-       else
-               mpe->pgfailback = atoi(buff);
-
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-mp_mode_handler(vector strvec)
-{
-       mode_t mode;
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char *buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-       if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
-               mpe->attribute_flags |= (1 << ATTR_MODE);
-               mpe->mode = mode;
-       }
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_uid_handler(vector strvec)
-{
-       uid_t uid;
-       char *buff;
-       char passwd_buf[1024];
-       struct passwd info, *found;
-
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-               mpe->attribute_flags |= (1 << ATTR_UID);
-               mpe->uid = info.pw_uid;
-       }
-       else if (sscanf(buff, "%u", &uid) == 1){
-               mpe->attribute_flags |= (1 << ATTR_UID);
-               mpe->uid = uid;
-       }
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_gid_handler(vector strvec)
-{
-       gid_t gid;
-       char *buff;
-       char passwd_buf[1024];
-       struct passwd info, *found;
-
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-               mpe->attribute_flags |= (1 << ATTR_GID);
-               mpe->gid = info.pw_gid;
-       }
-       else if (sscanf(buff, "%u", &gid) == 1) {
-               mpe->attribute_flags |= (1 << ATTR_GID);
-               mpe->gid = gid;
-       }
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_weight_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       if (strlen(buff) == 10 &&
-           !strcmp(buff, "priorities"))
-               mpe->rr_weight = RR_WEIGHT_PRIO;
-
-       if (strlen(buff) == strlen("uniform") &&
-           !strcmp(buff, "uniform"))
-               mpe->rr_weight = RR_WEIGHT_NONE;
-
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-mp_no_path_retry_handler(vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char *buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-           (strlen(buff) == 1 && !strcmp(buff, "0")))
-               mpe->no_path_retry = NO_PATH_RETRY_FAIL;
-       else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-               mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
-       else if ((mpe->no_path_retry = atoi(buff)) < 1)
-               mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_minio_handler(vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       mpe->minio = atoi(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-mp_minio_rq_handler(vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       mpe->minio_rq = atoi(buff);
-       FREE(buff);
-
-       return 0;
-}
-
-static int
-mp_pg_timeout_handler(vector strvec)
-{
-       char *buff;
-
-       buff = set_value(strvec);
-
-       if (!buff)
-               return 1;
-
-       /* Deprecated; device-mapper support has been removed */
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_features_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->features = set_value(strvec);
-
-       if (!mpe->features)
-               return 1;
-
-       return 0;
-}
-
-static int
-mp_flush_on_last_del_handler(vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-               mpe->flush_on_last_del = FLUSH_DISABLED;
-       else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-               mpe->flush_on_last_del = FLUSH_ENABLED;
-       else
-               mpe->flush_on_last_del = FLUSH_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-static int
-mp_prio_handler(vector strvec)
-{
-       struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->prio_name = set_value(strvec);
-
-       if (!mpe->prio_name)
-               return 1;
-
-       return 0;
-}
-
-static int
-mp_prio_args_handler (vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       if (!mpe)
-               return 1;
-
-       mpe->prio_args = set_value(strvec);
-       if (!mpe->prio_args)
-               return 1;
-
-       return 0;
-}
-
-static int
-mp_reservation_key_handler (vector strvec)
-{
-       char *buff;
-       char *tbuff;
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-       int j, k, len;
-       uint64_t prkey;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       tbuff = buff;
-       if (!memcmp(buff, "0x", 2))
-               buff = buff + 2;
-
-       len = strlen(buff);
-
-       k = strspn(buff, "0123456789aAbBcCdDeEfF");
-       if (len != k) {
-               FREE(tbuff);
-               return 1;
-       }
-
-       if (1 != sscanf (buff, "%" SCNx64 "", &prkey))
-       {
-               FREE(tbuff);
-               return 1;
-       }
-
-       if (!mpe->reservation_key)
-               mpe->reservation_key = (unsigned char *) malloc(8);
-
-       memset(mpe->reservation_key, 0, 8);
-
-       for (j = 7; j >= 0; --j) {
-               mpe->reservation_key[j] = (prkey & 0xff);
-               prkey >>= 8;
-       }
-
-       FREE(tbuff);
-       return 0;
-}
-
-static int
-mp_names_handler(vector strvec)
-{
-       struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-       char * buff;
-
-       if (!mpe)
-               return 1;
-
-       buff = set_value(strvec);
-       if (!buff)
-               return 1;
-
-       if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-           (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-               mpe->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-       else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-                (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-               mpe->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-       else
-               mpe->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
-
-       FREE(buff);
-       return 0;
-}
-
-/*
- * config file keywords printing
- */
-static int
-snprint_mp_wwid (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       return snprintf(buff, len, "%s", mpe->wwid);
-}
-
-static int
-snprint_mp_alias (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->alias)
-               return 0;
-
-       return snprintf(buff, len, "%s", mpe->alias);
-}
-
-static int
-snprint_mp_path_grouping_policy (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-       char str[POLICY_NAME_SIZE];
-
-       if (!mpe->pgpolicy)
-               return 0;
-       get_pgpolicy_name(str, POLICY_NAME_SIZE, mpe->pgpolicy);
-
-       return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_mp_selector (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->selector)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", mpe->selector);
-}
-
-static int
-snprint_mp_failback (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (mpe->pgfailback == FAILBACK_UNDEF ||
-           mpe->pgfailback == DEFAULT_FAILBACK)
-               return 0;
-
-       switch(mpe->pgfailback) {
-       case -FAILBACK_MANUAL:
-               return snprintf(buff, len, "\"manual\"");
-       case -FAILBACK_IMMEDIATE:
-               return snprintf(buff, len, "\"immediate\"");
-       case -FAILBACK_FOLLOWOVER:
-               return snprintf(buff, len, "\"followover\"");
-       default:
-               return snprintf(buff, len, "%i", mpe->pgfailback);
-       }
-       return 0;
-}
-
-static int
-snprint_mp_mode(char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if ((mpe->attribute_flags & (1 << ATTR_MODE)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", mpe->mode);
-}
-
-static int
-snprint_mp_uid(char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if ((mpe->attribute_flags & (1 << ATTR_UID)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", mpe->uid);
-}
-
-static int
-snprint_mp_gid(char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if ((mpe->attribute_flags & (1 << ATTR_GID)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", mpe->gid);
-}
-
-static int
-snprint_mp_rr_weight (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->rr_weight)
-               return 0;
-       if (mpe->rr_weight == RR_WEIGHT_PRIO)
-               return snprintf(buff, len, "\"priorities\"");
-       if (mpe->rr_weight == RR_WEIGHT_NONE)
-               return snprintf(buff, len, "\"uniform\"");
-
-       return 0;
-}
-
-static int
-snprint_mp_no_path_retry (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->no_path_retry)
-               return 0;
-
-       switch(mpe->no_path_retry) {
-       case NO_PATH_RETRY_UNDEF:
-               break;
-       case NO_PATH_RETRY_FAIL:
-               return snprintf(buff, len, "\"fail\"");
-       case NO_PATH_RETRY_QUEUE:
-               return snprintf(buff, len, "\"queue\"");
-       default:
-               return snprintf(buff, len, "%i",
-                               mpe->no_path_retry);
-       }
-       return 0;
-}
-
-static int
-snprint_mp_rr_min_io (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->minio)
-               return 0;
-
-       return snprintf(buff, len, "%u", mpe->minio);
-}
-
-static int
-snprint_mp_rr_min_io_rq (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->minio_rq)
-               return 0;
-
-       return snprintf(buff, len, "%u", mpe->minio_rq);
-}
-
-static int
-snprint_mp_pg_timeout (char * buff, int len, void * data)
-{
-       return 0;
-}
-
-static int
-snprint_mp_features (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->features)
-               return 0;
-       if (strlen(mpe->features) == strlen(conf->features) &&
-           !strcmp(mpe->features, conf->features))
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", mpe->features);
-}
-
-static int
-snprint_mp_flush_on_last_del (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       switch (mpe->flush_on_last_del) {
-       case FLUSH_DISABLED:
-               return snprintf(buff, len, "\"no\"");
-       case FLUSH_ENABLED:
-               return snprintf(buff, len, "\"yes\"");
-       }
-       return 0;
-}
-
-static int
-snprint_mp_prio(char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->prio_name)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", mpe->prio_name);
-}
-
-static int
-snprint_mp_prio_args(char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->prio_args)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", mpe->prio_args);
-}
-
-static int
-snprint_mp_reservation_key (char * buff, int len, void * data)
-{
-       int i;
-       unsigned char *keyp;
-       uint64_t prkey = 0;
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (!mpe->reservation_key)
-               return 0;
-       keyp = (unsigned char *)mpe->reservation_key;
-       for (i = 0; i < 8; i++) {
-               if (i > 0)
-                       prkey <<= 8;
-               prkey |= *keyp;
-               keyp++;
-       }
-
-       return snprintf(buff, len, "0x%" PRIx64, prkey);
-}
-
-       static int
-snprint_mp_user_friendly_names (char * buff, int len, void * data)
-{
-       struct mpentry * mpe = (struct mpentry *)data;
-
-       if (mpe->user_friendly_names == USER_FRIENDLY_NAMES_UNDEF)
-               return 0;
-       else if (mpe->user_friendly_names == USER_FRIENDLY_NAMES_OFF)
-               return snprintf(buff, len, "\"no\"");
-       else
-               return snprintf(buff, len, "\"yes\"");
-}
-
-static int
-snprint_hw_fast_io_fail(char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-       if (hwe->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
-               return 0;
-       if (hwe->fast_io_fail == conf->fast_io_fail)
-               return 0;
-       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);
-}
-
-static int
-snprint_hw_dev_loss(char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-       if (!hwe->dev_loss)
-               return 0;
-       if (hwe->dev_loss == conf->dev_loss)
-               return 0;
-       if (hwe->dev_loss >= MAX_DEV_LOSS_TMO)
-               return snprintf(buff, len, "\"infinity\"");
-
-       return snprintf(buff, len, "%u", hwe->dev_loss);
-}
-
-static int
-snprint_hw_vendor (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->vendor)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->vendor);
-}
-
-static int
-snprint_hw_product (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->product)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->product);
-}
-
-static int
-snprint_hw_revision (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->revision)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->revision);
-}
-
-static int
-snprint_hw_bl_product (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->bl_product)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->bl_product);
-}
-
-static int
-snprint_hw_uid_attribute (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->uid_attribute)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->uid_attribute);
-}
-
-static int
-snprint_hw_getuid_callout (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->getuid)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->getuid);
-}
-
-static int
-snprint_hw_prio (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->prio_name)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->prio_name);
-}
-
-static int
-snprint_hw_alias_prefix (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->alias_prefix)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->alias_prefix);
-}
-
-static int
-snprint_hw_prio_args (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->prio_args)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->prio_args);
-}
-
-static int
-snprint_hw_features (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->features)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->features);
-}
-
-static int
-snprint_hw_hardware_handler (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->hwhandler)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->hwhandler);
-}
-
-static int
-snprint_hw_selector (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->selector)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->selector);
-}
-
-static int
-snprint_hw_path_grouping_policy (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       char str[POLICY_NAME_SIZE];
-
-       if (!hwe->pgpolicy)
-               return 0;
-
-       get_pgpolicy_name(str, POLICY_NAME_SIZE, hwe->pgpolicy);
-
-       return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_hw_failback (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (hwe->pgfailback == FAILBACK_UNDEF ||
-           hwe->pgfailback == DEFAULT_FAILBACK)
-               return 0;
-
-       switch(hwe->pgfailback) {
-       case -FAILBACK_MANUAL:
-               return snprintf(buff, len, "\"manual\"");
-       case -FAILBACK_IMMEDIATE:
-               return snprintf(buff, len, "\"immediate\"");
-       case -FAILBACK_FOLLOWOVER:
-               return snprintf(buff, len, "\"followover\"");
-       default:
-               return snprintf(buff, len, "%i", hwe->pgfailback);
-       }
-       return 0;
-}
-
-static int
-snprint_hw_rr_weight (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->rr_weight)
-               return 0;
-       if (hwe->rr_weight == RR_WEIGHT_PRIO)
-               return snprintf(buff, len, "\"priorities\"");
-       if (hwe->rr_weight == RR_WEIGHT_NONE)
-               return snprintf(buff, len, "\"uniform\"");
-
-       return 0;
-}
-
-static int
-snprint_hw_no_path_retry (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->no_path_retry)
-               return 0;
-
-       switch(hwe->no_path_retry) {
-       case NO_PATH_RETRY_UNDEF:
-               break;
-       case NO_PATH_RETRY_FAIL:
-               return snprintf(buff, len, "\"fail\"");
-       case NO_PATH_RETRY_QUEUE:
-               return snprintf(buff, len, "\"queue\"");
-       default:
-               return snprintf(buff, len, "%i",
-                               hwe->no_path_retry);
-       }
-       return 0;
-}
-
-static int
-snprint_hw_rr_min_io (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->minio)
-               return 0;
-
-       return snprintf(buff, len, "%u", hwe->minio);
-}
-
-static int
-snprint_hw_rr_min_io_rq (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->minio_rq)
-               return 0;
-
-       return snprintf(buff, len, "%u", hwe->minio_rq);
-}
-
-static int
-snprint_hw_pg_timeout (char * buff, int len, void * data)
-{
-       return 0;
-}
-
-static int
-snprint_hw_flush_on_last_del (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       switch (hwe->flush_on_last_del) {
-       case FLUSH_DISABLED:
-               return snprintf(buff, len, "\"no\"");
-       case FLUSH_ENABLED:
-               return snprintf(buff, len, "\"yes\"");
-       }
-       return 0;
-}
-
-static int
-snprint_hw_path_checker (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (!hwe->checker_name)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", hwe->checker_name);
-}
-
-       static int
-snprint_hw_user_friendly_names (char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (hwe->user_friendly_names == USER_FRIENDLY_NAMES_UNDEF)
-               return 0;
-       else if (hwe->user_friendly_names == USER_FRIENDLY_NAMES_OFF)
-               return snprintf(buff, len, "\"no\"");
-       else
-               return snprintf(buff, len, "\"yes\"");
-}
-
-static int
-snprint_hw_retain_hwhandler_handler(char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (hwe->retain_hwhandler == RETAIN_HWHANDLER_ON)
-               return snprintf(buff, len, "\"yes\"");
-       else if (hwe->retain_hwhandler == RETAIN_HWHANDLER_OFF)
-               return snprintf(buff, len, "\"no\"");
-       else
-               return 0;
-}
-
-static int
-snprint_detect_prio(char * buff, int len, void * data)
-{
-       struct hwentry * hwe = (struct hwentry *)data;
-
-       if (hwe->detect_prio == DETECT_PRIO_ON)
-               return snprintf(buff, len, "\"yes\"");
-       else if (hwe->detect_prio == DETECT_PRIO_OFF)
-               return snprintf(buff, len, "\"no\"");
-       else
-               return 0;
-}
-
-static int
-snprint_def_polling_interval (char * buff, int len, void * data)
-{
-       return snprintf(buff, len, "%i", conf->checkint);
-}
-
-static int
-snprint_def_fast_io_fail(char * buff, int len, void * data)
-{
-       if (conf->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
-               return 0;
-       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);
-}
-
-static int
-snprint_def_dev_loss(char * buff, int len, void * data)
-{
-       if (!conf->dev_loss)
-               return 0;
-       if (conf->dev_loss >= MAX_DEV_LOSS_TMO)
-               return snprintf(buff, len, "\"infinity\"");
-       return snprintf(buff, len, "%u", conf->dev_loss);
-}
-
-static int
-snprint_def_verbosity (char * buff, int len, void * data)
-{
-       return snprintf(buff, len, "%i", conf->verbosity);
-}
-
-static int
-snprint_def_max_polling_interval (char * buff, int len, void * data)
-{
-       return snprintf(buff, len, "%i", conf->max_checkint);
-}
-
-static int
-snprint_reassign_maps (char * buff, int len, void * data)
-{
-       return snprintf(buff, len, "\"%s\"",
-                       conf->reassign_maps?"yes":"no");
-}
-
-static int
-snprint_def_multipath_dir (char * buff, int len, void * data)
-{
-       if (!conf->multipath_dir)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", conf->multipath_dir);
-}
-
-static int
-snprint_def_selector (char * buff, int len, void * data)
-{
-       if (!conf->selector)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_SELECTOR);
-
-       return snprintf(buff, len, "\"%s\"", conf->selector);
-}
-
-static int
-snprint_def_path_grouping_policy (char * buff, int len, void * data)
-{
-       char str[POLICY_NAME_SIZE];
-       int pgpolicy = conf->pgpolicy;
-
-       if (!pgpolicy)
-               pgpolicy = DEFAULT_PGPOLICY;
-
-       get_pgpolicy_name(str, POLICY_NAME_SIZE, pgpolicy);
-
-       return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_def_uid_attribute (char * buff, int len, void * data)
-{
-       if (!conf->uid_attribute)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_UID_ATTRIBUTE);
-
-       return snprintf(buff, len, "\"%s\"", conf->uid_attribute);
-}
-
-static int
-snprint_def_getuid_callout (char * buff, int len, void * data)
-{
-       if (!conf->getuid)
-               return 0;
-
-       return snprintf(buff, len, "\"%s\"", conf->getuid);
-}
-
-static int
-snprint_def_prio (char * buff, int len, void * data)
-{
-       if (!conf->prio_name)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_PRIO);
-
-       return snprintf(buff, len, "\"%s\"", conf->prio_name);
-}
-
-static int
-snprint_def_prio_args (char * buff, int len, void * data)
-{
-       if (!conf->prio_args)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_PRIO_ARGS);
-
-       return snprintf(buff, len, "\"%s\"", conf->prio_args);
-}
-
-static int
-snprint_def_features (char * buff, int len, void * data)
-{
-       if (!conf->features)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_FEATURES);
-
-       return snprintf(buff, len, "\"%s\"", conf->features);
-}
-
-static int
-snprint_def_path_checker (char * buff, int len, void * data)
-{
-       if (!conf->checker_name)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_CHECKER);
-
-       return snprintf(buff, len, "\"%s\"", conf->checker_name);
-}
-
-static int
-snprint_def_failback (char * buff, int len, void * data)
-{
-       switch(conf->pgfailback) {
-       case  FAILBACK_UNDEF:
-               return snprintf(buff, len, "\"undef\"");
-       case -FAILBACK_MANUAL:
-               return snprintf(buff, len, "\"manual\"");
-       case -FAILBACK_IMMEDIATE:
-               return snprintf(buff, len, "\"immediate\"");
-       case -FAILBACK_FOLLOWOVER:
-               return snprintf(buff, len, "\"followover\"");
-       default:
-               return snprintf(buff, len, "%i", conf->pgfailback);
-       }
-       return 0;
-}
-
-static int
-snprint_def_rr_min_io (char * buff, int len, void * data)
-{
-       if (!conf->minio)
-               return 0;
-
-       return snprintf(buff, len, "%u", conf->minio);
-}
-
-static int
-snprint_def_rr_min_io_rq (char * buff, int len, void * data)
-{
-       if (!conf->minio_rq)
-               return 0;
-
-       return snprintf(buff, len, "%u", conf->minio_rq);
-}
-
-static int
-snprint_max_fds (char * buff, int len, void * data)
-{
-       int r = 0, max_fds;
-
-       if (!conf->max_fds)
-               return 0;
-
-       r = get_sys_max_fds(&max_fds);
-       if (!r && conf->max_fds >= max_fds)
-               return snprintf(buff, len, "\"max\"");
-       else
-               return snprintf(buff, len, "%d", conf->max_fds);
-}
-
-static int
-snprint_def_mode(char * buff, int len, void * data)
-{
-       if ((conf->attribute_flags & (1 << ATTR_MODE)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", conf->mode);
-}
-
-static int
-snprint_def_uid(char * buff, int len, void * data)
-{
-       if ((conf->attribute_flags & (1 << ATTR_UID)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", conf->uid);
-}
-
-static int
-snprint_def_gid(char * buff, int len, void * data)
-{
-       if ((conf->attribute_flags & (1 << ATTR_GID)) == 0)
-               return 0;
-       return snprintf(buff, len, "0%o", conf->gid);
-}
-
-static int
-snprint_def_rr_weight (char * buff, int len, void * data)
-{
-       if (!conf->rr_weight || conf->rr_weight == RR_WEIGHT_NONE)
-               return snprintf(buff, len, "\"uniform\"");
-       if (conf->rr_weight == RR_WEIGHT_PRIO)
-               return snprintf(buff, len, "\"priorities\"");
-
-       return 0;
-}
-
-static int
-snprint_def_no_path_retry (char * buff, int len, void * data)
-{
-       switch(conf->no_path_retry) {
-       case NO_PATH_RETRY_UNDEF:
-               break;
-       case NO_PATH_RETRY_FAIL:
-               return snprintf(buff, len, "\"fail\"");
-       case NO_PATH_RETRY_QUEUE:
-               return snprintf(buff, len, "\"queue\"");
-       default:
-               return snprintf(buff, len, "%i",
-                               conf->no_path_retry);
-       }
-       return 0;
-}
-
-static int
-snprint_def_queue_without_daemon (char * buff, int len, void * data)
-{
-       switch (conf->queue_without_daemon) {
-       case QUE_NO_DAEMON_OFF:
-               return snprintf(buff, len, "\"no\"");
-       case QUE_NO_DAEMON_ON:
-               return snprintf(buff, len, "\"yes\"");
-       case QUE_NO_DAEMON_FORCE:
-               return snprintf(buff, len, "\"forced\"");
-       }
-       return 0;
-}
-
-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)
-{
-       return 0;
-}
-
-static int
-snprint_def_flush_on_last_del (char * buff, int len, void * data)
-{
-       switch (conf->flush_on_last_del) {
-       case FLUSH_UNDEF:
-       case FLUSH_DISABLED:
-               return snprintf(buff, len, "\"no\"");
-       case FLUSH_ENABLED:
-       case FLUSH_IN_PROGRESS:
-               return snprintf(buff, len, "\"yes\"");
-       }
        return 0;
 }
 
-static int
-snprint_def_log_checker_err (char * buff, int len, void * data)
-{
-       if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
-               return snprintf(buff, len, "once");
-       return snprintf(buff, len, "always");
-}
-
-static int
-snprint_def_user_friendly_names (char * buff, int len, void * data)
-{
-       if (conf->user_friendly_names  == USER_FRIENDLY_NAMES_ON)
-               return snprintf(buff, len, "\"yes\"");
-       else
-               return snprintf(buff, len, "\"no\"");
-}
-
-static int
-snprint_def_alias_prefix (char * buff, int len, void * data)
-{
-       if (!conf->alias_prefix)
-               return snprintf(buff, len, "\"%s\"", DEFAULT_ALIAS_PREFIX);
-       return snprintf(buff, len, "\"%s\"", conf->alias_prefix);
-}
-
-static int
-snprint_def_bindings_file (char * buff, int len, void * data)
-{
-       if (conf->bindings_file == NULL)
-               return 0;
-       return snprintf(buff, len, "\"%s\"", conf->bindings_file);
-}
-
-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_reservation_key(char * buff, int len, void * data)
-{
-       int i;
-       unsigned char *keyp;
-       uint64_t prkey = 0;
-
-       if (!conf->reservation_key)
-               return 0;
-       keyp = (unsigned char *)conf->reservation_key;
-       for (i = 0; i < 8; i++) {
-               if (i > 0)
-                       prkey <<= 8;
-               prkey |= *keyp;
-               keyp++;
-       }
-       return snprintf(buff, len, "0x%" PRIx64, prkey);
-}
-
-static int
-snprint_def_retain_hwhandler_handler(char * buff, int len, void * data)
-{
-       if (conf->retain_hwhandler == RETAIN_HWHANDLER_ON)
-               return snprintf(buff, len, "yes");
-       else
-               return snprintf(buff, len, "no");
-}
-
-static int
-snprint_def_detect_prio(char * buff, int len, void * data)
-{
-       if (conf->detect_prio == DETECT_PRIO_ON)
-               return snprintf(buff, len, "yes");
-       else
-               return snprintf(buff, len, "no");
-}
-
-static int
-snprint_ble_simple (char * buff, int len, void * data)
-{
-       struct blentry * ble = (struct blentry *)data;
-
-       return snprintf(buff, len, "\"%s\"", ble->str);
-}
-
-static int
-snprint_bled_vendor (char * buff, int len, void * data)
-{
-       struct blentry_device * bled = (struct blentry_device *)data;
-
-       return snprintf(buff, len, "\"%s\"", bled->vendor);
-}
-
-static int
-snprint_bled_product (char * buff, int len, void * data)
-{
-       struct blentry_device * bled = (struct blentry_device *)data;
-
-       return snprintf(buff, len, "\"%s\"", bled->product);
-}
-
 #define __deprecated
 
 void
 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("max_polling_interval", &max_polling_interval_handler, &snprint_def_max_polling_interval);
-       install_keyword("reassign_maps", &reassign_maps_handler, &snprint_reassign_maps);
-       install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir);
+       install_keyword("verbosity", &def_verbosity_handler, &snprint_def_verbosity);
+       install_keyword("polling_interval", &def_checkint_handler, &snprint_def_checkint);
+       install_keyword("max_polling_interval", &def_max_checkint_handler, &snprint_def_max_checkint);
+       install_keyword("reassign_maps", &def_reassign_maps_handler, &snprint_def_reassign_maps);
+       install_keyword("multipath_dir", &def_multipath_dir_handler, &snprint_def_multipath_dir);
        install_keyword("path_selector", &def_selector_handler, &snprint_def_selector);
-       install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
+       install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_pgpolicy);
        install_keyword("uid_attribute", &def_uid_attribute_handler, &snprint_def_uid_attribute);
-       install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
-       install_keyword("prio", &def_prio_handler, &snprint_def_prio);
+       install_keyword("getuid_callout", &def_getuid_handler, &snprint_def_getuid);
+       install_keyword("prio", &def_prio_name_handler, &snprint_def_prio_name);
        install_keyword("prio_args", &def_prio_args_handler, &snprint_def_prio_args);
        install_keyword("features", &def_features_handler, &snprint_def_features);
-       install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
-       install_keyword("checker", &def_path_checker_handler, NULL);
+       install_keyword("path_checker", &def_checker_name_handler, &snprint_def_checker_name);
+       install_keyword("checker", &def_checker_name_handler, NULL);
        install_keyword("alias_prefix", &def_alias_prefix_handler, &snprint_def_alias_prefix);
-       install_keyword("failback", &default_failback_handler, &snprint_def_failback);
-       install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
-       install_keyword("rr_min_io_rq", &def_minio_rq_handler, &snprint_def_rr_min_io_rq);
+       install_keyword("failback", &def_pgfailback_handler, &snprint_def_pgfailback);
+       install_keyword("rr_min_io", &def_minio_handler, &snprint_def_minio);
+       install_keyword("rr_min_io_rq", &def_minio_rq_handler, &snprint_def_minio_rq);
        install_keyword("max_fds", &max_fds_handler, &snprint_max_fds);
-       install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
+       install_keyword("rr_weight", &def_rr_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("queue_without_daemon", &def_queue_without_daemon_handler, &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("pg_timeout", &deprecated_handler, &snprint_deprecated);
        install_keyword("flush_on_last_del", &def_flush_on_last_del_handler, &snprint_def_flush_on_last_del);
-       install_keyword("user_friendly_names", &def_names_handler, &snprint_def_user_friendly_names);
+       install_keyword("user_friendly_names", &def_user_friendly_names_handler, &snprint_def_user_friendly_names);
        install_keyword("mode", &def_mode_handler, &snprint_def_mode);
        install_keyword("uid", &def_uid_handler, &snprint_def_uid);
        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("bindings_file", &bindings_file_handler, &snprint_def_bindings_file);
-       install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file);
+       install_keyword("bindings_file", &def_bindings_file_handler, &snprint_def_bindings_file);
+       install_keyword("wwids_file", &def_wwids_file_handler, &snprint_def_wwids_file);
        install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err);
        install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key);
-       install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler);
+       install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler);
        install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
+       install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
+       install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
+       install_keyword("partition_delimiter", &def_partition_delim_handler, &snprint_def_partition_delim);
+       install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
+       install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks);
+       install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks);
+       install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths);
+       install_keyword("uxsock_timeout", &def_uxsock_timeout_handler, &snprint_def_uxsock_timeout);
+       install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries);
+       install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay);
+       install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout);
        __deprecated install_keyword("default_selector", &def_selector_handler, NULL);
        __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
        __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
-       __deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
+       __deprecated install_keyword("default_getuid_callout", &def_getuid_handler, NULL);
        __deprecated install_keyword("default_features", &def_features_handler, NULL);
-       __deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
+       __deprecated install_keyword("default_path_checker", &def_checker_name_handler, NULL);
 
        install_keyword_root("blacklist", &blacklist_handler);
-       install_keyword_multi("devnode", &ble_devnode_handler, &snprint_ble_simple);
-       install_keyword_multi("wwid", &ble_wwid_handler, &snprint_ble_simple);
-       install_keyword_multi("property", &ble_property_handler, &snprint_ble_simple);
+       install_keyword_multi("devnode", &ble_blist_devnode_handler, &snprint_ble_simple);
+       install_keyword_multi("wwid", &ble_blist_wwid_handler, &snprint_ble_simple);
+       install_keyword_multi("property", &ble_blist_property_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_device_handler, NULL);
        install_sublevel();
-       install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
-       install_keyword("product", &ble_product_handler, &snprint_bled_product);
+       install_keyword("vendor", &ble_blist_device_vendor_handler, &snprint_bled_vendor);
+       install_keyword("product", &ble_blist_device_product_handler, &snprint_bled_product);
        install_sublevel_end();
        install_keyword_root("blacklist_exceptions", &blacklist_exceptions_handler);
-       install_keyword_multi("devnode", &ble_except_devnode_handler, &snprint_ble_simple);
-       install_keyword_multi("wwid", &ble_except_wwid_handler, &snprint_ble_simple);
-       install_keyword_multi("property", &ble_except_property_handler, &snprint_ble_simple);
+       install_keyword_multi("devnode", &ble_elist_devnode_handler, &snprint_ble_simple);
+       install_keyword_multi("wwid", &ble_elist_wwid_handler, &snprint_ble_simple);
+       install_keyword_multi("property", &ble_elist_property_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_except_device_handler, NULL);
        install_sublevel();
-       install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor);
-       install_keyword("product", &ble_except_product_handler, &snprint_bled_product);
+       install_keyword("vendor", &ble_elist_device_vendor_handler, &snprint_bled_vendor);
+       install_keyword("product", &ble_elist_device_product_handler, &snprint_bled_product);
        install_sublevel_end();
 
 #if 0
@@ -2886,56 +1415,88 @@ init_keywords(void)
        install_keyword_root("devices", &devices_handler);
        install_keyword_multi("device", &device_handler, NULL);
        install_sublevel();
-       install_keyword("vendor", &vendor_handler, &snprint_hw_vendor);
-       install_keyword("product", &product_handler, &snprint_hw_product);
-       install_keyword("revision", &revision_handler, &snprint_hw_revision);
-       install_keyword("product_blacklist", &bl_product_handler, &snprint_hw_bl_product);
-       install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_path_grouping_policy);
+       install_keyword("vendor", &hw_vendor_handler, &snprint_hw_vendor);
+       install_keyword("product", &hw_product_handler, &snprint_hw_product);
+       install_keyword("revision", &hw_revision_handler, &snprint_hw_revision);
+       install_keyword("product_blacklist", &hw_bl_product_handler, &snprint_hw_bl_product);
+       install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_pgpolicy);
        install_keyword("uid_attribute", &hw_uid_attribute_handler, &snprint_hw_uid_attribute);
-       install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
+       install_keyword("getuid_callout", &hw_getuid_handler, &snprint_hw_getuid);
        install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
-       install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
-       install_keyword("checker", &hw_path_checker_handler, NULL);
+       install_keyword("path_checker", &hw_checker_name_handler, &snprint_hw_checker_name);
+       install_keyword("checker", &hw_checker_name_handler, NULL);
        install_keyword("alias_prefix", &hw_alias_prefix_handler, &snprint_hw_alias_prefix);
        install_keyword("features", &hw_features_handler, &snprint_hw_features);
-       install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
-       install_keyword("prio", &hw_prio_handler, &snprint_hw_prio);
+       install_keyword("hardware_handler", &hw_hwhandler_handler, &snprint_hw_hwhandler);
+       install_keyword("prio", &hw_prio_name_handler, &snprint_hw_prio_name);
        install_keyword("prio_args", &hw_prio_args_handler, &snprint_hw_prio_args);
-       install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
-       install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
+       install_keyword("failback", &hw_pgfailback_handler, &snprint_hw_pgfailback);
+       install_keyword("rr_weight", &hw_rr_weight_handler, &snprint_hw_rr_weight);
        install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
-       install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
-       install_keyword("rr_min_io_rq", &hw_minio_rq_handler, &snprint_hw_rr_min_io_rq);
-       install_keyword("pg_timeout", &hw_pg_timeout_handler, &snprint_hw_pg_timeout);
+       install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_minio);
+       install_keyword("rr_min_io_rq", &hw_minio_rq_handler, &snprint_hw_minio_rq);
+       install_keyword("pg_timeout", &deprecated_handler, &snprint_deprecated);
        install_keyword("flush_on_last_del", &hw_flush_on_last_del_handler, &snprint_hw_flush_on_last_del);
        install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail);
        install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss);
-       install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names);
-       install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler);
-       install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio);
+       install_keyword("user_friendly_names", &hw_user_friendly_names_handler, &snprint_hw_user_friendly_names);
+       install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler);
+       install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio);
+       install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove);
+       install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks);
+       install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks);
        install_sublevel_end();
 
+       install_keyword_root("overrides", &overrides_handler);
+       install_keyword("path_grouping_policy", &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy);
+       install_keyword("uid_attribute", &ovr_uid_attribute_handler, &snprint_ovr_uid_attribute);
+       install_keyword("getuid_callout", &ovr_getuid_handler, &snprint_ovr_getuid);
+       install_keyword("path_selector", &ovr_selector_handler, &snprint_ovr_selector);
+       install_keyword("path_checker", &ovr_checker_name_handler, &snprint_ovr_checker_name);
+       install_keyword("checker", &ovr_checker_name_handler, NULL);
+       install_keyword("alias_prefix", &ovr_alias_prefix_handler, &snprint_ovr_alias_prefix);
+       install_keyword("features", &ovr_features_handler, &snprint_ovr_features);
+       install_keyword("prio", &ovr_prio_name_handler, &snprint_ovr_prio_name);
+       install_keyword("prio_args", &ovr_prio_args_handler, &snprint_ovr_prio_args);
+       install_keyword("failback", &ovr_pgfailback_handler, &snprint_ovr_pgfailback);
+       install_keyword("rr_weight", &ovr_rr_weight_handler, &snprint_ovr_rr_weight);
+       install_keyword("no_path_retry", &ovr_no_path_retry_handler, &snprint_ovr_no_path_retry);
+       install_keyword("rr_min_io", &ovr_minio_handler, &snprint_ovr_minio);
+       install_keyword("rr_min_io_rq", &ovr_minio_rq_handler, &snprint_ovr_minio_rq);
+       install_keyword("flush_on_last_del", &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
+       install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail);
+       install_keyword("dev_loss_tmo", &ovr_dev_loss_handler, &snprint_ovr_dev_loss);
+       install_keyword("user_friendly_names", &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
+       install_keyword("retain_attached_hw_handler", &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
+       install_keyword("detect_prio", &ovr_detect_prio_handler, &snprint_ovr_detect_prio);
+       install_keyword("deferred_remove", &ovr_deferred_remove_handler, &snprint_ovr_deferred_remove);
+       install_keyword("delay_watch_checks", &ovr_delay_watch_checks_handler, &snprint_ovr_delay_watch_checks);
+       install_keyword("delay_wait_checks", &ovr_delay_wait_checks_handler, &snprint_ovr_delay_wait_checks);
+
        install_keyword_root("multipaths", &multipaths_handler);
        install_keyword_multi("multipath", &multipath_handler, NULL);
        install_sublevel();
-       install_keyword("wwid", &wwid_handler, &snprint_mp_wwid);
-       install_keyword("alias", &alias_handler, &snprint_mp_alias);
-       install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_path_grouping_policy);
+       install_keyword("wwid", &mp_wwid_handler, &snprint_mp_wwid);
+       install_keyword("alias", &mp_alias_handler, &snprint_mp_alias);
+       install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_pgpolicy);
        install_keyword("path_selector", &mp_selector_handler, &snprint_mp_selector);
-       install_keyword("prio", &mp_prio_handler, &snprint_mp_prio);
+       install_keyword("prio", &mp_prio_name_handler, &snprint_mp_prio_name);
        install_keyword("prio_args", &mp_prio_args_handler, &snprint_mp_prio_args);
-       install_keyword("failback", &mp_failback_handler, &snprint_mp_failback);
-       install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
+       install_keyword("failback", &mp_pgfailback_handler, &snprint_mp_pgfailback);
+       install_keyword("rr_weight", &mp_rr_weight_handler, &snprint_mp_rr_weight);
        install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
-       install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_rr_min_io);
-       install_keyword("rr_min_io_rq", &mp_minio_rq_handler, &snprint_mp_rr_min_io_rq);
-       install_keyword("pg_timeout", &mp_pg_timeout_handler, &snprint_mp_pg_timeout);
+       install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_minio);
+       install_keyword("rr_min_io_rq", &mp_minio_rq_handler, &snprint_mp_minio_rq);
+       install_keyword("pg_timeout", &deprecated_handler, &snprint_deprecated);
        install_keyword("flush_on_last_del", &mp_flush_on_last_del_handler, &snprint_mp_flush_on_last_del);
        install_keyword("features", &mp_features_handler, &snprint_mp_features);
        install_keyword("mode", &mp_mode_handler, &snprint_mp_mode);
        install_keyword("uid", &mp_uid_handler, &snprint_mp_uid);
        install_keyword("gid", &mp_gid_handler, &snprint_mp_gid);
        install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
-       install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names);
+       install_keyword("user_friendly_names", &mp_user_friendly_names_handler, &snprint_mp_user_friendly_names);
+       install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove);
+       install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks);
+       install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks);
        install_sublevel_end();
 }
index 688eab7432181d29ec7675b755fb98e079dbe3aa..4fdd5766c6572ae4ca9edc4288fd16b994b3b78e 100644 (file)
@@ -7,5 +7,13 @@
 
 void init_keywords(void);
 int get_sys_max_fds(int *);
+int print_rr_weight (char * buff, int len, void *ptr);
+int print_pgfailback (char * buff, int len, void *ptr);
+int print_pgpolicy(char * buff, int len, void *ptr);
+int print_no_path_retry(char * buff, int len, void *ptr);
+int print_fast_io_fail(char * buff, int len, void *ptr);
+int print_dev_loss(char * buff, int len, void *ptr);
+int print_reservation_key(char * buff, int len, void * ptr);
+int print_delay_checks(char * buff, int len, void *ptr);
 
 #endif /* _DICT_H */
index 228ffd34ec229d5eeab103990ba2b0b6725e4cdc..bd653543f3960c34f9f9d5ee21050599893c5fbd 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2005 Mike Anderson
  */
 #include <stdio.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "prio.h"
 #include "defaults.h"
 
+int
+alloc_path_with_pathinfo (vector hwtable, struct udev_device *udevice,
+                         int flag, struct path **pp_ptr)
+{
+       int err = PATHINFO_FAILED;
+       struct path * pp;
+       const char * devname;
+
+       if (pp_ptr)
+               *pp_ptr = NULL;
+
+       devname = udev_device_get_sysname(udevice);
+       if (!devname)
+               return PATHINFO_FAILED;
+
+       pp = alloc_path();
+
+       if (!pp)
+               return PATHINFO_FAILED;
+
+       if (safe_sprintf(pp->dev, "%s", devname)) {
+               condlog(0, "pp->dev too small");
+       } else {
+               pp->udev = udev_device_ref(udevice);
+               err = pathinfo(pp, hwtable, flag | DI_BLACKLIST);
+       }
+
+       if (err)
+               free_path(pp);
+       else if (pp_ptr)
+               *pp_ptr = pp;
+       return err;
+}
+
 int
 store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
                int flag, struct path **pp_ptr)
 {
-       int err = 1;
+       int err = PATHINFO_FAILED;
        struct path * pp;
        const char * devname;
 
@@ -42,12 +77,12 @@ store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
 
        devname = udev_device_get_sysname(udevice);
        if (!devname)
-               return 1;
+               return PATHINFO_FAILED;
 
        pp = alloc_path();
 
        if (!pp)
-               return 1;
+               return PATHINFO_FAILED;
 
        if(safe_sprintf(pp->dev, "%s", devname)) {
                condlog(0, "pp->dev too small");
@@ -55,7 +90,8 @@ store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
        }
        pp->udev = udev_device_ref(udevice);
        err = pathinfo(pp, hwtable,
-                      (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST));
+                      (conf->cmd == CMD_REMOVE_WWID)? flag :
+                                                      (flag | DI_BLACKLIST));
        if (err)
                goto out;
 
@@ -80,22 +116,19 @@ path_discover (vector pathvec, struct config * conf,
 
        devname = udev_device_get_sysname(udevice);
        if (!devname)
-               return 0;
+               return PATHINFO_FAILED;
 
        if (filter_property(conf, udevice) > 0)
-               return 0;
+               return PATHINFO_SKIPPED;
 
        if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
                           (char *)devname) > 0)
-               return 0;
+               return PATHINFO_SKIPPED;
 
        pp = find_path_by_dev(pathvec, (char *)devname);
        if (!pp) {
-               if (store_pathinfo(pathvec, conf->hwtable,
-                                  udevice, flag, NULL) != 1)
-                       return 0;
-               else
-                       return 1;
+               return store_pathinfo(pathvec, conf->hwtable,
+                                     udevice, flag, NULL);
        }
        return pathinfo(pp, conf->hwtable, flag);
 }
@@ -107,11 +140,11 @@ path_discovery (vector pathvec, struct config * conf, int flag)
        struct udev_list_entry *entry;
        struct udev_device *udevice;
        const char *devpath;
-       int r = 0;
+       int num_paths = 0, total_paths = 0;
 
        udev_iter = udev_enumerate_new(conf->udev);
        if (!udev_iter)
-               return 1;
+               return -ENOMEM;
 
        udev_enumerate_add_match_subsystem(udev_iter, "block");
        udev_enumerate_scan_devices(udev_iter);
@@ -124,25 +157,27 @@ path_discovery (vector pathvec, struct config * conf, int flag)
                udevice = udev_device_new_from_syspath(conf->udev, devpath);
                if (!udevice) {
                        condlog(4, "%s: no udev information", devpath);
-                       r++;
                        continue;
                }
                devtype = udev_device_get_devtype(udevice);
                if(devtype && !strncmp(devtype, "disk", 4)) {
-                       r += path_discover(pathvec, conf,
-                                                  udevice, flag);
+                       total_paths++;
+                       if (path_discover(pathvec, conf,
+                                         udevice, flag) == PATHINFO_OK)
+                               num_paths++;
                }
                udev_device_unref(udevice);
        }
        udev_enumerate_unref(udev_iter);
-       condlog(4, "Discovery status %d", r);
-       return r;
+       condlog(4, "Discovered %d/%d paths", num_paths, total_paths);
+       return (total_paths - num_paths);
 }
 
 #define declare_sysfs_get_str(fname)                                   \
 extern ssize_t                                                         \
 sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len) \
 {                                                                      \
+       int l;                                                  \
        const char * attr;                                              \
        const char * devname;                                           \
                                                                        \
@@ -157,19 +192,44 @@ sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len)    \
                        devname, #fname);                               \
                return -ENXIO;                                          \
        }                                                               \
-       if (strchop(attr) > len) {                                      \
+       for (l = strlen(attr); l >= 1 && isspace(attr[l-1]); l--);      \
+       if (l > len) {                                                  \
                condlog(3, "%s: overflow in attribute %s",              \
                        devname, #fname);                               \
                return -EINVAL;                                         \
        }                                                               \
-       return strlcpy(buff, attr, len);                                \
+       strlcpy(buff, attr, len);                                       \
+       return strchop(buff);                                           \
 }
 
 declare_sysfs_get_str(devtype);
 declare_sysfs_get_str(vendor);
 declare_sysfs_get_str(model);
 declare_sysfs_get_str(rev);
-declare_sysfs_get_str(dev);
+
+ssize_t
+sysfs_get_vpd (struct udev_device * udev, int pg,
+              unsigned char * buff, size_t len)
+{
+       ssize_t attr_len;
+       char attrname[9];
+       const char * devname;
+
+       if (!udev) {
+               condlog(3, "No udev device given\n");
+               return -ENOSYS;
+       }
+
+       devname = udev_device_get_sysname(udev);
+       sprintf(attrname, "vpd_pg%02x", pg);
+       attr_len = sysfs_bin_attr_get_value(udev, attrname, buff, len);
+       if (attr_len < 0) {
+               condlog(3, "%s: attribute %s not found in sysfs",
+                       devname, attrname);
+               return attr_len;
+       }
+       return attr_len;
+}
 
 int
 sysfs_get_timeout(struct path *pp, unsigned int *timeout)
@@ -239,6 +299,19 @@ sysfs_get_tgt_nodename (struct path *pp, char * node)
                }
        }
 
+       /* Check for USB */
+       tgtdev = udev_device_get_parent(parent);
+       while (tgtdev) {
+               value = udev_device_get_subsystem(tgtdev);
+               if (value && !strcmp(value, "usb")) {
+                       pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
+                       tgtname = udev_device_get_sysname(tgtdev);
+                       strncpy(node, tgtname, strlen(tgtname));
+                       condlog(3, "%s: skip USB device %s", pp->dev, node);
+                       return 1;
+               }
+               tgtdev = udev_device_get_parent(tgtdev);
+       }
        parent = udev_device_get_parent_with_subsystem_devtype(pp->udev, "scsi", "scsi_target");
        if (!parent)
                return 1;
@@ -285,7 +358,7 @@ sysfs_get_tgt_nodename (struct path *pp, char * node)
                if (tgtdev) {
                        const char *value;
 
-                       value = udev_device_get_sysattr_value(tgtdev, "tgtname");
+                       value = udev_device_get_sysattr_value(tgtdev, "targetname");
                        if (value) {
                                pp->sg_id.proto_id = SCSI_PROTOCOL_ISCSI;
                                pp->sg_id.transport_id = tgtid;
@@ -313,7 +386,95 @@ sysfs_get_tgt_nodename (struct path *pp, char * node)
                snprintf(node, NODE_NAME_SIZE, "ata-%d.00", tgtid);
                return 0;
        }
+       /* Unknown SCSI transport. Keep fingers crossed */
        pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
+       return 0;
+}
+
+int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name)
+{
+       int proto_id;
+
+       if (!pp || !adapter_name)
+               return 1;
+
+       proto_id = pp->sg_id.proto_id;
+
+       if (proto_id != SCSI_PROTOCOL_FCP &&
+           proto_id != SCSI_PROTOCOL_SAS &&
+           proto_id != SCSI_PROTOCOL_ISCSI &&
+           proto_id != SCSI_PROTOCOL_SRP) {
+               return 1;
+       }
+       /* iscsi doesn't have adapter info in sysfs
+        * get ip_address for grouping paths
+        */
+       if (pp->sg_id.proto_id == SCSI_PROTOCOL_ISCSI)
+               return sysfs_get_iscsi_ip_address(pp, adapter_name);
+
+       /* fetch adapter pci name for other protocols
+        */
+       return sysfs_get_host_pci_name(pp, adapter_name);
+}
+
+int sysfs_get_host_pci_name(struct path *pp, char *pci_name)
+{
+       struct udev_device *hostdev, *parent;
+       char host_name[HOST_NAME_LEN];
+       const char *driver_name, *value;
+
+       if (!pp || !pci_name)
+               return 1;
+
+       sprintf(host_name, "host%d", pp->sg_id.host_no);
+       hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
+                       "scsi_host", host_name);
+       if (!hostdev)
+               return 1;
+
+       parent = udev_device_get_parent(hostdev);
+       while (parent) {
+               driver_name = udev_device_get_driver(parent);
+               if (!driver_name) {
+                       parent = udev_device_get_parent(parent);
+                       continue;
+               }
+               if (!strcmp(driver_name, "pcieport"))
+                       break;
+               parent = udev_device_get_parent(parent);
+       }
+       if (parent) {
+               /* pci_device found
+                */
+               value = udev_device_get_sysname(parent);
+
+               strncpy(pci_name, value, SLOT_NAME_SIZE);
+               udev_device_unref(hostdev);
+               return 0;
+       }
+       udev_device_unref(hostdev);
+       return 1;
+}
+
+int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address)
+{
+       struct udev_device *hostdev;
+       char host_name[HOST_NAME_LEN];
+       const char *value;
+
+       sprintf(host_name, "host%d", pp->sg_id.host_no);
+       hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
+                       "iscsi_host", host_name);
+       if (hostdev) {
+               value = udev_device_get_sysattr_value(hostdev,
+                               "ipaddress");
+               if (value) {
+                       strncpy(ip_address, value, SLOT_NAME_SIZE);
+                       udev_device_unref(hostdev);
+                       return 0;
+               } else
+                       udev_device_unref(hostdev);
+       }
        return 1;
 }
 
@@ -609,6 +770,29 @@ get_serial (char * str, int maxlen, int fd)
        return 1;
 }
 
+#define DEFAULT_SGIO_LEN 254
+
+static int
+sgio_get_vpd (unsigned char * buff, int maxlen, int fd)
+{
+       int len = DEFAULT_SGIO_LEN;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return -1;
+       }
+retry:
+       if (0 == do_inq(fd, 0, 1, 0x83, buff, len)) {
+               len = buff[3] + (buff[2] << 8);
+               if (len >= maxlen)
+                       return len;
+               if (len > DEFAULT_SGIO_LEN)
+                       goto retry;
+               return 0;
+       }
+       return -1;
+}
+
 static int
 get_geometry(struct path *pp)
 {
@@ -626,6 +810,256 @@ get_geometry(struct path *pp)
        return 0;
 }
 
+static int
+parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
+{
+       char *p = NULL;
+       int len = in[3] + (in[2] << 8);
+
+       if (len >= out_len) {
+               condlog(2, "vpd pg80 overflow, %d/%d bytes required",
+                       len, (int)out_len);
+               len = out_len;
+       }
+       if (len > 0) {
+               memcpy(out, in + 4, len);
+               out[len] = '\0';
+       }
+       /*
+        * Strip trailing whitspaces
+        */
+       p = out + len - 1;
+       while (p > out && *p == ' ') {
+               *p = '\0';
+               p--;
+               len --;
+       }
+       return len;
+}
+
+static int
+parse_vpd_pg83(const unsigned char *in, size_t in_len,
+              char *out, size_t out_len)
+{
+       unsigned char *d;
+       unsigned char *vpd = NULL;
+       int len = -ENODATA, vpd_type, vpd_len, prio = -1, i, naa_prio;
+
+       d = (unsigned char *)in + 4;
+       while (d < (unsigned char *)in + in_len) {
+               /* Select 'association: LUN' */
+               if ((d[1] & 0x30) != 0) {
+                       d += d[3] + 4;
+                       continue;
+               }
+               switch (d[1] & 0xf) {
+               case 0x3:
+                       /* NAA: Prio 5 */
+                       switch (d[4] >> 4) {
+                       case 6:
+                               /* IEEE Registered Extended: Prio 8 */
+                               naa_prio = 8;
+                               break;
+                       case 5:
+                               /* IEEE Registered: Prio 7 */
+                               naa_prio = 7;
+                               break;
+                       case 2:
+                               /* IEEE Extended: Prio 6 */
+                               naa_prio = 6;
+                               break;
+                       case 3:
+                               /* IEEE Locally assigned: Prio 1 */
+                               naa_prio = 1;
+                               break;
+                       default:
+                               /* Default: no priority */
+                               naa_prio = -1;
+                               break;
+                       }
+                       if (prio < naa_prio) {
+                               prio = naa_prio;
+                               vpd = d;
+                       }
+                       break;
+               case 0x8:
+                       /* SCSI Name: Prio 4 */
+                       if (memcmp(d + 4, "eui.", 4) &&
+                           memcmp(d + 4, "naa.", 4) &&
+                           memcmp(d + 4, "iqn.", 4))
+                               continue;
+                       if (prio < 4) {
+                               prio = 4;
+                               vpd = d;
+                       }
+                       break;
+               case 0x2:
+                       /* EUI-64: Prio 3 */
+                       if (prio < 3) {
+                               prio = 3;
+                               vpd = d;
+                       }
+                       break;
+               case 0x1:
+                       /* T-10 Vendor ID: Prio 2 */
+                       if (prio < 2) {
+                               prio = 2;
+                               vpd = d;
+                       }
+                       break;
+               }
+               d += d[3] + 4;
+       }
+       if (prio > 0) {
+               vpd_type = vpd[1] & 0xf;
+               vpd_len = vpd[3];
+               vpd += 4;
+               if (vpd_type == 0x2 || vpd_type == 0x3) {
+                       int i;
+
+                       len = sprintf(out, "%d", vpd_type);
+                       for (i = 0; i < vpd_len; i++) {
+                               len += sprintf(out + len,
+                                              "%02x", vpd[i]);
+                               if (len >= out_len)
+                                       break;
+                       }
+               } else if (vpd_type == 0x8) {
+                       if (!memcmp("eui.", vpd, 4)) {
+                               out[0] =  '2';
+                               len = 1;
+                               vpd += 4;
+                               vpd_len -= 4;
+                               for (i = 0; i < vpd_len; i++) {
+                                       len += sprintf(out + len, "%c",
+                                                      tolower(vpd[i]));
+                                       if (len >= out_len)
+                                               break;
+                               }
+                               len = vpd_len + 1;
+                               out[len] = '\0';
+                       } else if (!memcmp("naa.", vpd, 4)) {
+                               out[0] = '3';
+                               len = 1;
+                               vpd += 4;
+                               vpd_len -= 4;
+                               for (i = 0; i < vpd_len; i++) {
+                                       len += sprintf(out + len, "%c",
+                                                      tolower(vpd[i]));
+                                       if (len >= out_len)
+                                               break;
+                               }
+                               len = vpd_len + 1;
+                               out[len] = '\0';
+                       } else {
+                               out[0] = '8';
+                               len = 1;
+                               vpd += 4;
+                               vpd_len -= 4;
+                               if (vpd_len > out_len + 2)
+                                       vpd_len = out_len - 2;
+                               memcpy(out, vpd, vpd_len);
+                               len = vpd_len + 1;
+                               out[len] = '\0';
+                       }
+               } else if (vpd_type == 0x1) {
+                       unsigned char *p;
+                       int p_len;
+
+                       out[0] = '1';
+                       len = 1;
+                       p = vpd;
+                       while ((p = memchr(vpd, ' ', vpd_len))) {
+                               p_len = p - vpd;
+                               if (len + p_len > out_len - 1)
+                                       p_len = out_len - len - 2;
+                               memcpy(out + len, vpd, p_len);
+                               len += p_len;
+                               if (len >= out_len - 1) {
+                                       out[len] = '\0';
+                                       break;
+                               }
+                               out[len] = '_';
+                               len ++;
+                               vpd = p;
+                               vpd_len -= p_len;
+                               while (vpd && *vpd == ' ') {
+                                       vpd++;
+                                       vpd_len --;
+                               }
+                       }
+                       if (len > 1 && out[len - 1] == '_') {
+                               out[len - 1] = '\0';
+                               len--;
+                       }
+               }
+       }
+       return len;
+}
+
+static int
+get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
+{
+       int len, buff_len;
+       unsigned char buff[4096];
+
+       memset(buff, 0x0, 4096);
+       if (!parent || sysfs_get_vpd(parent, pg, buff, 4096) <= 0) {
+               condlog(3, "failed to read sysfs vpd pg%02x", pg);
+               return -EINVAL;
+       }
+
+       if (buff[1] != pg) {
+               condlog(3, "vpd pg%02x error, invalid vpd page %02x",
+                       pg, buff[1]);
+               return -ENODATA;
+       }
+       buff_len = (buff[2] << 8) + buff[3] + 4;
+       if (buff_len > 4096)
+               condlog(3, "vpd pg%02x page truncated", pg);
+
+       if (pg == 0x80)
+               len = parse_vpd_pg80(buff, str, maxlen);
+       else if (pg == 0x83)
+               len = parse_vpd_pg83(buff, buff_len, str, maxlen);
+       else
+               len = -ENOSYS;
+
+       return len;
+}
+
+static int
+get_vpd_sgio (int fd, int pg, char * str, int maxlen)
+{
+       int len, buff_len;
+       unsigned char buff[4096];
+
+       memset(buff, 0x0, 4096);
+       if (sgio_get_vpd(buff, 4096, fd) <= 0) {
+               condlog(3, "failed to issue vpd inquiry for pg%02x",
+                       pg);
+               return -errno;
+       }
+
+       if (buff[1] != pg) {
+               condlog(3, "vpd pg%02x error, invalid vpd page %02x",
+                       pg, buff[1]);
+               return -ENODATA;
+       }
+       buff_len = (buff[2] << 8) + buff[3] + 4;
+       if (buff_len > 4096)
+               condlog(3, "vpd pg%02x page truncated", pg);
+
+       if (pg == 0x80)
+               len = parse_vpd_pg80(buff, str, maxlen);
+       else if (pg == 0x83)
+               len = parse_vpd_pg83(buff, buff_len, str, maxlen);
+       else
+               len = -ENOSYS;
+
+       return len;
+}
+
 static int
 scsi_sysfs_pathinfo (struct path * pp)
 {
@@ -684,10 +1118,11 @@ scsi_sysfs_pathinfo (struct path * pp)
        /*
         * target node name
         */
-       if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
-               condlog(3, "%s: tgt_node_name = %s",
-                       pp->dev, pp->tgt_node_name);
-       }
+       if(sysfs_get_tgt_nodename(pp, pp->tgt_node_name))
+               return 1;
+
+       condlog(3, "%s: tgt_node_name = %s",
+               pp->dev, pp->tgt_node_name);
 
        return 0;
 }
@@ -810,6 +1245,8 @@ cciss_sysfs_pathinfo (struct path * pp)
 static int
 common_sysfs_pathinfo (struct path * pp)
 {
+       dev_t devt;
+
        if (!pp)
                return 1;
 
@@ -817,10 +1254,8 @@ common_sysfs_pathinfo (struct path * pp)
                condlog(4, "%s: udev not initialised", pp->dev);
                return 1;
        }
-       if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE) <= 0) {
-               condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
-               return 1;
-       }
+       devt = udev_device_get_devnum(pp->udev);
+       snprintf(pp->dev_t, BLK_DEV_SIZE, "%d:%d", major(devt), minor(devt));
 
        condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
 
@@ -867,9 +1302,7 @@ path_offline (struct path * pp)
 
        condlog(3, "%s: path state = %s", pp->dev, buff);
 
-       if (!strncmp(buff, "offline", 7) ||
-           !strncmp(buff, "quiesce", 7) ||
-           !strncmp(buff, "transport-offline", 17)) {
+       if (!strncmp(buff, "offline", 7)) {
                pp->offline = 1;
                return PATH_DOWN;
        }
@@ -914,10 +1347,34 @@ sysfs_pathinfo(struct path * pp)
 static int
 scsi_ioctl_pathinfo (struct path * pp, int mask)
 {
-       if (mask & DI_SERIAL) {
-               get_serial(pp->serial, SERIAL_SIZE, pp->fd);
-               condlog(3, "%s: serial = %s", pp->dev, pp->serial);
+       struct udev_device *parent;
+       const char *attr_path = NULL;
+
+       if (!(mask & DI_SERIAL))
+               return 0;
+
+       parent = pp->udev;
+       while (parent) {
+               const char *subsys = udev_device_get_subsystem(parent);
+               if (subsys && !strncmp(subsys, "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 0;
+
+       if (get_vpd_sysfs(parent, 0x80, pp->serial, SERIAL_SIZE) > 0)
+               condlog(3, "%s: serial = %s",
+                       pp->dev, pp->serial);
 
        return 0;
 }
@@ -942,7 +1399,7 @@ get_state (struct path * pp, int daemon)
 
        if (!checker_selected(c)) {
                if (daemon) {
-                       if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
+                       if (pathinfo(pp, conf->hwtable, DI_SYSFS) != PATHINFO_OK) {
                                condlog(3, "%s: couldn't get sysfs pathinfo",
                                        pp->dev);
                                return PATH_UNCHECKED;
@@ -961,8 +1418,12 @@ get_state (struct path * pp, int daemon)
                }
        }
        checker_clear_message(c);
-       if (daemon)
-               checker_set_async(c);
+       if (daemon) {
+               if (conf->force_sync == 0)
+                       checker_set_async(c);
+               else
+                       checker_set_sync(c);
+       }
        if (!conf->checker_timeout &&
            sysfs_get_timeout(pp, &(c->timeout)) <= 0)
                c->timeout = DEF_TIMEOUT;
@@ -1003,11 +1464,53 @@ get_prio (struct path * pp)
        return 0;
 }
 
+static int
+get_udev_uid(struct path * pp, char *uid_attribute)
+{
+       ssize_t len;
+       const char *value;
+
+       value = udev_device_get_property_value(pp->udev,
+                                              uid_attribute);
+       if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH)
+               value = getenv(uid_attribute);
+       if (value && strlen(value)) {
+               if (strlen(value) + 1 > WWID_SIZE) {
+                       condlog(0, "%s: wwid overflow", pp->dev);
+                       len = WWID_SIZE;
+               } else {
+                       len = strlen(value);
+               }
+               strncpy(pp->wwid, value, len);
+       } else {
+               condlog(3, "%s: no %s attribute", pp->dev,
+                       uid_attribute);
+               len = -EINVAL;
+       }
+       return len;
+}
+
+static int
+get_vpd_uid(struct path * pp)
+{
+       struct udev_device *parent = pp->udev;
+
+       while (parent) {
+               const char *subsys = udev_device_get_subsystem(parent);
+               if (subsys && !strncmp(subsys, "scsi", 4))
+                       break;
+               parent = udev_device_get_parent(parent);
+       }
+
+       return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE);
+}
+
 static int
 get_uid (struct path * pp)
 {
        char *c;
-       const char *origin;
+       const char *origin = "unknown";
+       ssize_t len = 0;
 
        if (!pp->uid_attribute && !pp->getuid)
                select_getuid(pp);
@@ -1026,39 +1529,50 @@ get_uid (struct path * pp)
                if (apply_format(pp->getuid, &buff[0], pp)) {
                        condlog(0, "error formatting uid callout command");
                        memset(pp->wwid, 0, WWID_SIZE);
+                       len = -EINVAL;
                } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
                        condlog(3, "error calling out %s", buff);
                        memset(pp->wwid, 0, WWID_SIZE);
-               }
+                       len = -EIO;
+               } else
+                       len = strlen(pp->wwid);
                origin = "callout";
        } else {
-               const char *value;
-
-               value = udev_device_get_property_value(pp->udev,
-                                                      pp->uid_attribute);
-               if ((!value || strlen(value) == 0) && conf->dry_run == 2)
-                       value = getenv(pp->uid_attribute);
-               if (value && strlen(value)) {
-                       size_t len = WWID_SIZE;
+               if (pp->uid_attribute) {
+                       len = get_udev_uid(pp, pp->uid_attribute);
+                       origin = "udev";
+                       if (len <= 0)
+                               condlog(1,
+                                       "%s: failed to get udev uid: %s",
+                                       pp->dev, strerror(-len));
 
-                       if (strlen(value) + 1 > WWID_SIZE) {
-                               condlog(0, "%s: wwid overflow", pp->dev);
-                       } else {
-                               len = strlen(value);
+               }
+               if (len <= 0 && pp->retriggers >= conf->retrigger_tries &&
+                   !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) {
+                       len = get_vpd_uid(pp);
+                       origin = "sysfs";
+                       pp->uid_attribute = NULL;
+                       if (len < 0) {
+                               condlog(1, "%s: failed to get sysfs uid: %s",
+                                       pp->dev, strerror(-len));
+                               len = get_vpd_sgio(pp->fd, 0x83, pp->wwid,
+                                                  WWID_SIZE);
+                               origin = "sgio";
                        }
-                       strncpy(pp->wwid, value, len);
-               } else {
-                       condlog(3, "%s: no %s attribute", pp->dev,
-                               pp->uid_attribute);
                }
-               origin = "udev";
        }
-       /* Strip any trailing blanks */
-       c = strchr(pp->wwid, '\0');
-       c--;
-       while (c && c >= pp->wwid && *c == ' ') {
-               *c = '\0';
+       if ( len < 0 ) {
+               condlog(1, "%s: failed to get %s uid: %s",
+                       pp->dev, origin, strerror(-len));
+               memset(pp->wwid, 0x0, WWID_SIZE);
+       } else {
+               /* Strip any trailing blanks */
+               c = strchr(pp->wwid, '\0');
                c--;
+               while (c && c >= pp->wwid && *c == ' ') {
+                       *c = '\0';
+                       c--;
+               }
        }
        condlog(3, "%s: uid = %s (%s)", pp->dev,
                *pp->wwid == '\0' ? "<empty>" : pp->wwid, origin);
@@ -1071,7 +1585,7 @@ pathinfo (struct path *pp, vector hwtable, int mask)
        int path_state;
 
        if (!pp)
-               return 1;
+               return PATHINFO_FAILED;
 
        condlog(3, "%s: mask = 0x%x", pp->dev, mask);
 
@@ -1079,12 +1593,12 @@ pathinfo (struct path *pp, vector hwtable, int mask)
         * fetch info available in sysfs
         */
        if (mask & DI_SYSFS && sysfs_pathinfo(pp))
-               return 1;
+               return PATHINFO_FAILED;
 
        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;
+                       return PATHINFO_SKIPPED;
                }
        }
 
@@ -1123,6 +1637,11 @@ pathinfo (struct path *pp, vector hwtable, int mask)
                                goto blank;
                        if (pp->state == PATH_TIMEOUT)
                                pp->state = PATH_DOWN;
+                       if (pp->state == PATH_UP && !pp->size) {
+                               condlog(3, "%s: device size is 0, "
+                                       "path unuseable", pp->dev);
+                               pp->state = PATH_GHOST;
+                       }
                } else {
                        condlog(3, "%s: path inaccessible", pp->dev);
                        pp->chkrstate = pp->state = path_state;
@@ -1132,12 +1651,21 @@ pathinfo (struct path *pp, vector hwtable, int mask)
                }
        }
 
-       if ((mask & DI_WWID) && !strlen(pp->wwid))
+       if ((mask & DI_WWID) && !strlen(pp->wwid)) {
                get_uid(pp);
+               if (!strlen(pp->wwid)) {
+                       pp->initialized = INIT_MISSING_UDEV;
+                       pp->tick = conf->retrigger_delay;
+                       return PATHINFO_OK;
+               }
+               else
+                       pp->tick = 1;
+       }
+
        if (mask & DI_BLACKLIST && mask & DI_WWID) {
                if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
-                               pp->wwid) > 0) {
-                       return 2;
+                               pp->wwid, pp->dev) > 0) {
+                       return PATHINFO_SKIPPED;
                }
        }
 
@@ -1145,15 +1673,14 @@ pathinfo (struct path *pp, vector hwtable, int mask)
          * Retrieve path priority, even for PATH_DOWN paths if it has never
          * been successfully obtained before.
          */
-       if ((mask & DI_PRIO) && path_state == PATH_UP) {
+       if ((mask & DI_PRIO) && path_state == PATH_UP && strlen(pp->wwid)) {
                if (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF) {
-                       if (!strlen(pp->wwid))
-                               get_uid(pp);
                        get_prio(pp);
                }
        }
 
-       return 0;
+       pp->initialized = INIT_OK;
+       return PATHINFO_OK;
 
 blank:
        /*
@@ -1161,6 +1688,7 @@ blank:
         */
        memset(pp->wwid, 0, WWID_SIZE);
        pp->chkrstate = pp->state = PATH_DOWN;
+       pp->initialized = INIT_FAILED;
 
-       return 0;
+       return PATHINFO_OK;
 }
index 3d2d0cecbd3b4155b9a55d3605a0940af55b7e62..5931bc66c44c5e43b9f9b9e205e07e44cb9b9578 100644 (file)
 #define SCSI_COMMAND_TERMINATED 0x22
 #define SG_ERR_DRIVER_SENSE     0x08
 
+#define PATHINFO_OK 0
+#define PATHINFO_FAILED 1
+#define PATHINFO_SKIPPED 2
+
 struct config;
 
-ssize_t 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 *);
 int path_offline (struct path *);
 int get_state (struct path * pp, int daemon);
 int pathinfo (struct path *, vector hwtable, int mask);
+int alloc_path_with_pathinfo (vector hwtable, struct udev_device *udevice,
+                             int flag, struct path **pp_ptr);
 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);
+int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
+int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
+ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff,
+                      size_t len);
 
 /*
  * discovery bitmask
index 2562ba1d30bb54d51b9258d9878fba9de39a8711..2209b2dc8c892f9074494633e105d939ae8af05d 100644 (file)
 static int
 merge_words (char ** dst, char * word, int space)
 {
-       char * p;
+       char * p = *dst;
        int len;
 
        len = strlen(*dst) + strlen(word) + space;
        *dst = REALLOC(*dst, len + 1);
 
-       if (!*dst)
+       if (!*dst) {
+               free(p);
                return 1;
+       }
 
        p = *dst;
 
index bb73a40cbb8560bf98ad9ecda2a0117c6f04b2fb..a4ae053f5277ccfd4d5d3d431a6e5730ccc99c90 100644 (file)
@@ -272,6 +272,8 @@ static struct hwentry default_hw[] = {
                .checker_name  = EMC_CLARIION,
                .prio_name     = PRIO_EMC,
                .prio_args     = NULL,
+               .retain_hwhandler = RETAIN_HWHANDLER_ON,
+               .detect_prio   = DETECT_PRIO_ON,
        },
        {
                .vendor        = "EMC",
@@ -287,6 +289,19 @@ static struct hwentry default_hw[] = {
                .prio_name     = DEFAULT_PRIO,
                .prio_args     = NULL,
        },
+       {
+               .vendor        = "XtremIO",
+               .product       = "XtremApp",
+               .features      = DEFAULT_FEATURES,
+               .hwhandler     = DEFAULT_HWHANDLER,
+               .selector      = "queue-length 0",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
+               .checker_name  = TUR,
+               .fast_io_fail  = 5,
+               .prio_name     = DEFAULT_PRIO,
+               .prio_args     = NULL,
+       },
        /*
         * Fujitsu controller family
         *
@@ -308,7 +323,7 @@ static struct hwentry default_hw[] = {
        },
        {
                .vendor        = "FUJITSU",
-               .product       = "ETERNUS_DX(L|400|8000)",
+               .product       = "ETERNUS_DX(H|L|M|400|8000)",
                .features      = "1 queue_if_no_path",
                .hwhandler     = DEFAULT_HWHANDLER,
                .pgpolicy      = GROUP_BY_PRIO,
@@ -772,6 +787,36 @@ static struct hwentry default_hw[] = {
                .prio_name     = PRIO_RDAC,
                .prio_args     = NULL,
        },
+       {
+               /* DELL MD36xxi */
+               .vendor        = "DELL",
+               .product       = "MD36xxi",
+               .bl_product    = "Universal Xport",
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .rr_weight     = RR_WEIGHT_NONE,
+               .no_path_retry = 15,
+               .checker_name  = RDAC,
+               .prio_name     = PRIO_RDAC,
+               .prio_args     = NULL,
+       },
+       {
+               /* DELL MD36xxf */
+               .vendor        = "DELL",
+               .product       = "MD36xxf",
+               .bl_product    = "Universal Xport",
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .rr_weight     = RR_WEIGHT_NONE,
+               .no_path_retry = 15,
+               .checker_name  = RDAC,
+               .prio_name     = PRIO_RDAC,
+               .prio_args     = NULL,
+       },
        /*
         * NETAPP controller family
         *
@@ -1121,6 +1166,22 @@ static struct hwentry default_hw[] = {
                .prio_name     = PRIO_ALUA,
                .prio_args     = NULL,
        },
+       {
+               .vendor        = "PURE",
+               .product       = "FlashArray",
+               .features      = DEFAULT_FEATURES,
+               .hwhandler     = DEFAULT_HWHANDLER,
+               .selector      = "queue-length 0",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .checker_name  = TUR,
+               .fast_io_fail  = 10,
+               .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
+               .prio_name     = DEFAULT_PRIO,
+               .no_path_retry = 0,
+               .dev_loss      = 60,
+               .prio_args     = NULL,
+       },
        /*
         * EOL
         */
index 8626630f6b9fe1c4b020fd7f2bed1884f7036148..a0d81845f8a84a51fc825e7c1bb9e1f99a48ac69 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _LIST_H
 #define _LIST_H
 
+#include <stddef.h>
+
 /**
  * container_of - cast a member of a structure out to the containing structure
  *
@@ -161,18 +163,18 @@ static inline int list_empty(struct list_head *head)
        return head->next == head;
 }
 
-static inline void __list_splice(struct list_head *list,
-                                struct list_head *head)
+static inline void __list_splice(const struct list_head *list,
+                                struct list_head *prev,
+                                struct list_head *next)
 {
        struct list_head *first = list->next;
        struct list_head *last = list->prev;
-       struct list_head *at = head->next;
 
-       first->prev = head;
-       head->next = first;
+       first->prev = prev;
+       prev->next = first;
 
-       last->next = at;
-       at->prev = last;
+       last->next = next;
+       next->prev = last;
 }
 
 /**
@@ -183,7 +185,19 @@ static inline void __list_splice(struct list_head *list,
 static inline void list_splice(struct list_head *list, struct list_head *head)
 {
        if (!list_empty(list))
-               __list_splice(list, head);
+               __list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+                                   struct list_head *head)
+{
+       if (!list_empty(list))
+               __list_splice(list, head->prev, head);
 }
 
 /**
@@ -197,7 +211,24 @@ static inline void list_splice_init(struct list_head *list,
                                    struct list_head *head)
 {
        if (!list_empty(list)) {
-               __list_splice(list, head);
+               __list_splice(list, head, head->next);
+               INIT_LIST_HEAD(list);
+       }
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+                                        struct list_head *head)
+{
+       if (!list_empty(list)) {
+               __list_splice(list, head->prev, head);
                INIT_LIST_HEAD(list);
        }
 }
index 47d75a1173188b747823388dac8336d12d07b402..e6f4b5c6c345192b71b51c8675be880bd0114cd0 100644 (file)
@@ -25,7 +25,7 @@ int logq_running;
 void log_safe (int prio, const char * fmt, va_list ap)
 {
        if (log_thr == (pthread_t)0) {
-               syslog(prio, fmt, ap);
+               vsyslog(prio, fmt, ap);
                return;
        }
 
index 526c45b3e1b0c684a2da02780697164043c9505c..e4296ee49155b8858e6ec2ce22622bdff8a811c3 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <syslog.h>
+#include <errno.h>
 
 #include "parser.h"
 #include "memory.h"
@@ -279,110 +280,15 @@ out:
        return NULL;
 }
 
-int
-read_line(char *buf, int size)
+static int
+read_line(FILE *stream, char *buf, int size)
 {
-       int ch;
-       int count = 0;
-
-       while ((ch = fgetc(stream)) != EOF && (int) ch != '\n'
-              && (int) ch != '\r') {
-               if (count < size)
-                       buf[count] = (int) ch;
-               else
-                       break;
-               count++;
-       }
-       return (ch == EOF) ? 0 : 1;
-}
-
-vector
-read_value_block(void)
-{
-       char *buf;
-       int i;
-       char *str = NULL;
-       char *dup;
-       vector vec = NULL;
-       vector elements = vector_alloc();
-
-       if (!elements)
-               return NULL;
+       char *p;
 
-       buf = (char *) MALLOC(MAXBUF);
-
-       if (!buf) {
-               vector_free(elements);
-               return NULL;
-       }
-
-       while (read_line(buf, MAXBUF)) {
-               vec = alloc_strvec(buf);
-               if (vec) {
-                       str = VECTOR_SLOT(vec, 0);
-                       if (!strcmp(str, EOB)) {
-                               free_strvec(vec);
-                               break;
-                       }
-
-                       for (i = 0; i < VECTOR_SIZE(vec); i++) {
-                               str = VECTOR_SLOT(vec, i);
-                               dup = (char *) MALLOC(strlen(str) + 1);
-                               if (!dup)
-                                       goto out;
-                               memcpy(dup, str, strlen(str));
-
-                               if (!vector_alloc_slot(elements)) {
-                                       free_strvec(vec);
-                                       goto out1;
-                               }
-
-                               vector_set_slot(elements, dup);
-                       }
-                       free_strvec(vec);
-               }
-               memset(buf, 0, MAXBUF);
-       }
-       FREE(buf);
-       return elements;
-out1:
-       FREE(dup);
-out:
-       FREE(buf);
-       vector_free(elements);
-       return NULL;
-}
-
-int
-alloc_value_block(vector strvec, void (*alloc_func) (vector))
-{
-       char *buf;
-       char *str = NULL;
-       vector vec = NULL;
-
-       buf = (char *) MALLOC(MAXBUF);
-
-       if (!buf)
-               return 1;
-
-       while (read_line(buf, MAXBUF)) {
-               vec = alloc_strvec(buf);
-               if (vec) {
-                       str = VECTOR_SLOT(vec, 0);
-                       if (!strcmp(str, EOB)) {
-                               free_strvec(vec);
-                               break;
-                       }
-
-                       if (VECTOR_SIZE(vec))
-                               (*alloc_func) (vec);
-
-                       free_strvec(vec);
-               }
-               memset(buf, 0, MAXBUF);
-       }
-       FREE(buf);
-       return 0;
+       if (fgets(buf, size, stream) == NULL)
+               return 0;
+       strtok_r(buf, "\n\r", &p);
+       return 1;
 }
 
 void *
@@ -395,36 +301,57 @@ set_value(vector strvec)
        char *alloc = NULL;
        char *tmp;
 
-       if (!str)
+       if (!str) {
+               condlog(0, "option '%s' missing value",
+                       (char *)VECTOR_SLOT(strvec, 0));
                return NULL;
-
+       }
        size = strlen(str);
-       if (size == 0)
+       if (size == 0) {
+               condlog(0, "option '%s' has empty value",
+                       (char *)VECTOR_SLOT(strvec, 0));
                return NULL;
-
-       if (*str == '"') {
-               for (i = 2; i < VECTOR_SIZE(strvec); i++) {
-                       str = VECTOR_SLOT(strvec, i);
-                       len += strlen(str);
-                       if (!alloc)
-                               alloc =
-                                   (char *) MALLOC(sizeof (char *) *
-                                                   (len + 1));
-                       else {
-                               alloc =
-                                   REALLOC(alloc, sizeof (char *) * (len + 1));
-                               tmp = VECTOR_SLOT(strvec, i-1);
-                               if (alloc && *str != '"' && *tmp != '"')
-                                       strncat(alloc, " ", 1);
-                       }
-
-                       if (alloc && i != VECTOR_SIZE(strvec)-1)
-                               strncat(alloc, str, strlen(str));
-               }
-       } else {
-               alloc = MALLOC(sizeof (char *) * (size + 1));
+       }
+       if (*str != '"') {
+               alloc = MALLOC(sizeof (char) * (size + 1));
                if (alloc)
                        memcpy(alloc, str, size);
+               else
+                       condlog(0, "can't allocate memeory for option '%s'",
+                               (char *)VECTOR_SLOT(strvec, 0));
+               return alloc;
+       }
+       /* Even empty quotes counts as a value (An empty string) */
+       alloc = (char *) MALLOC(sizeof (char));
+       if (!alloc) {
+               condlog(0, "can't allocate memeory for option '%s'",
+                       (char *)VECTOR_SLOT(strvec, 0));
+               return NULL;
+       }
+       for (i = 2; i < VECTOR_SIZE(strvec); i++) {
+               str = VECTOR_SLOT(strvec, i);
+               if (!str) {
+                       free(alloc);
+                       condlog(0, "parse error for option '%s'",
+                               (char *)VECTOR_SLOT(strvec, 0));
+                       return NULL;
+               }
+               if (*str == '"')
+                       break;
+               tmp = alloc;
+               /* The first +1 is for the NULL byte. The rest are for the
+                * spaces between words */
+               len += strlen(str) + 1;
+               alloc = REALLOC(alloc, sizeof (char) * len);
+               if (!alloc) {
+                       FREE(tmp);
+                       condlog(0, "can't allocate memeory for option '%s'",
+                               (char *)VECTOR_SLOT(strvec, 0));
+                       return NULL;
+               }
+               if (*alloc != '\0')
+                       strncat(alloc, " ", 1);
+               strncat(alloc, str, strlen(str));
        }
        return alloc;
 }
@@ -432,14 +359,15 @@ set_value(vector strvec)
 /* non-recursive configuration stream handler */
 static int kw_level = 0;
 
-int warn_on_duplicates(vector uniques, char *str)
+int warn_on_duplicates(vector uniques, char *str, char *file)
 {
        char *tmp;
        int i;
 
        vector_foreach_slot(uniques, tmp, i) {
                if (!strcmp(str, tmp)) {
-                       condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
+                       condlog(1, "%s line %d, duplicate keyword: %s",
+                               file, line_nr, str);
                        return 0;
                }
        }
@@ -465,10 +393,83 @@ void free_uniques(vector uniques)
 }
 
 int
-process_stream(vector keywords)
+is_sublevel_keyword(char *str)
+{
+       return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 ||
+               strcmp(str, "blacklist_exceptions") == 0 ||
+               strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 ||
+               strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 ||
+               strcmp(str, "multipath") == 0);
+}
+
+int
+validate_config_strvec(vector strvec, char *file)
+{
+       char *str;
+       int i;
+
+       str = VECTOR_SLOT(strvec, 0);
+       if (str == NULL) {
+               condlog(0, "can't parse option on line %d of %s",
+                       line_nr, file);
+       return -1;
+       }
+       if (*str == '}') {
+               if (VECTOR_SIZE(strvec) > 1)
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
+               return 0;
+       }
+       if (*str == '{') {
+               condlog(0, "invalid keyword '%s' on line %d of %s",
+                       str, line_nr, file);
+               return -1;
+       }
+       if (is_sublevel_keyword(str)) {
+               str = VECTOR_SLOT(strvec, 1);
+               if (str == NULL)
+                       condlog(0, "missing '{' on line %d of %s",
+                               line_nr, file);
+               else if (*str != '{')
+                       condlog(0, "expecting '{' on line %d of %s. found '%s'",
+                               line_nr, file, str);
+               else if (VECTOR_SIZE(strvec) > 2)
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
+               return 0;
+       }
+       str = VECTOR_SLOT(strvec, 1);
+       if (str == NULL) {
+               condlog(0, "missing value for option '%s' on line %d of %s",
+                       (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
+               return -1;
+       }
+       if (*str != '"') {
+               if (VECTOR_SIZE(strvec) > 2)
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
+               return 0;
+       }
+       for (i = 2; i < VECTOR_SIZE(strvec); i++) {
+               str = VECTOR_SLOT(strvec, i);
+               if (str == NULL) {
+                       condlog(0, "can't parse value on line %d of %s",
+                               line_nr, file);
+                       return -1;
+               }
+               if (*str == '"') {
+                       if (VECTOR_SIZE(strvec) > i + 1)
+                               condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
+                       return 0;
+               }
+       }
+       condlog(0, "missing closing quotes on line %d of %s",
+               line_nr, file);
+       return 0;
+}
+
+static int
+process_stream(FILE *stream, vector keywords, char *file)
 {
        int i;
-       int r = 0;
+       int r = 0, t;
        struct keyword *keyword;
        char *str;
        char *buf;
@@ -486,19 +487,26 @@ process_stream(vector keywords)
                return 1;
        }
 
-       while (read_line(buf, MAXBUF)) {
+       while (read_line(stream, buf, MAXBUF)) {
                line_nr++;
                strvec = alloc_strvec(buf);
-               memset(buf,0, MAXBUF);
-
                if (!strvec)
                        continue;
 
+               if (validate_config_strvec(strvec, file) != 0) {
+                       free_strvec(strvec);
+                       continue;
+               }
+
                str = VECTOR_SLOT(strvec, 0);
 
-               if (!strcmp(str, EOB) && kw_level > 0) {
-                       free_strvec(strvec);
-                       break;
+               if (!strcmp(str, EOB)) {
+                       if (kw_level > 0) {
+                               free_strvec(strvec);
+                               break;
+                       }
+                       condlog(0, "unmatched '%s' at line %d of %s",
+                               EOB, line_nr, file);
                }
 
                for (i = 0; i < VECTOR_SIZE(keywords); i++) {
@@ -506,25 +514,31 @@ process_stream(vector keywords)
 
                        if (!strcmp(keyword->string, str)) {
                                if (keyword->unique &&
-                                   warn_on_duplicates(uniques, str)) {
+                                   warn_on_duplicates(uniques, str, file)) {
                                                r = 1;
                                                free_strvec(strvec);
                                                goto out;
                                }
-                               if (keyword->handler)
-                                       r += (*keyword->handler) (strvec);
+                               if (keyword->handler) {
+                                       t = (*keyword->handler) (strvec);
+                                       r += t;
+                                       if (t)
+                                               condlog(1, "multipath.conf +%d, parsing failed: %s",
+                                                       line_nr, buf);
+                               }
 
                                if (keyword->sub) {
                                        kw_level++;
-                                       r += process_stream(keyword->sub);
+                                       r += process_stream(stream,
+                                                           keyword->sub, file);
                                        kw_level--;
                                }
                                break;
                        }
                }
                if (i >= VECTOR_SIZE(keywords))
-                       condlog(1, "multipath.conf +%d, invalid keyword: %s",
-                               line_nr, str);
+                       condlog(1, "%s line %d, invalid keyword: %s",
+                               file, line_nr, str);
 
                free_strvec(strvec);
        }
@@ -548,27 +562,25 @@ int alloc_keywords(void)
 
 /* Data initialization */
 int
-init_data(char *conf_file, void (*init_keywords) (void))
+process_file(char *file)
 {
        int r;
+       FILE *stream;
 
-       stream = fopen(conf_file, "r");
+       if (!keywords) {
+               condlog(0, "No keywords alocated");
+               return 1;
+       }
+       stream = fopen(file, "r");
        if (!stream) {
-               syslog(LOG_WARNING, "Configuration file open problem");
+               condlog(0, "couldn't open configuration file '%s': %s",
+                       file, strerror(errno));
                return 1;
        }
 
-       /* Init Keywords structure */
-       (*init_keywords) ();
-
-/* Dump configuration *
-  vector_dump(keywords);
-  dump_keywords(keywords, 0);
-*/
-
        /* Stream handling */
        line_nr = 0;
-       r = process_stream(keywords);
+       r = process_stream(stream, keywords, file);
        fclose(stream);
        //free_keywords(keywords);
 
index 8bf1c7668adf522aed6cf9240312e2e1adbdd980..ba6859e5e4b9bfffc9d7220b9112ed4eb90ffb6c 100644 (file)
@@ -47,9 +47,6 @@ struct keyword {
        int unique;
 };
 
-/* global var exported */
-FILE *stream;
-
 /* Reloading helpers */
 #define SET_RELOAD      (reload = 1)
 #define UNSET_RELOAD    (reload = 0)
@@ -72,13 +69,9 @@ extern int _install_keyword(char *string, int (*handler) (vector),
 extern void dump_keywords(vector keydump, int level);
 extern void free_keywords(vector keywords);
 extern vector alloc_strvec(char *string);
-extern int read_line(char *buf, int size);
-extern vector read_value_block(void);
-extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
 extern void *set_value(vector strvec);
-extern int process_stream(vector keywords);
 extern int alloc_keywords(void);
-extern int init_data(char *conf_file, void (*init_keywords) (void));
+extern int process_file(char *conf_file);
 extern struct keyword * find_keyword(vector v, char * name);
 void set_current_keywords (vector *k);
 int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
index f76ad6050516f32c8e1074379b3fdd0dbfa2b1c1..2981d51d867139906d535defda1f2e44048cd826 100644 (file)
@@ -27,7 +27,7 @@ get_pgpolicy_id (char * str)
        if (0 == strncmp(str, "group_by_node_name", 18))
                return GROUP_BY_NODE_NAME;
 
-       return -1;
+       return IOPOLICY_UNDEF;
 }
 
 extern int
index 3c526c2235c0b9cb59522600d0e924eeb6627586..76bda935cbb85f5f62c4d4992557b4ee57be9907 100644 (file)
@@ -10,6 +10,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <libudev.h>
 
 #include "checkers.h"
 #include "vector.h"
 #define MAX(x,y) (x > y) ? x : y
 #define TAIL     (line + len - 1 - c)
 #define NOPAD    s = c
-#define PAD(x)   while ((int)(c - s) < (x) && (c < (line + len - 1))) \
-                       *c++ = ' '; s = c
+#define PAD(x) \
+do { \
+       while ((int)(c - s) < (x) && (c < (line + len - 1))) \
+               *c++ = ' '; \
+       s = c; \
+} while (0)
+
 #define ENDLINE \
                if (c > line) \
                        line[c - line - 1] = '\n'
-#define PRINT(var, size, format, args...)      \
-               fwd = snprintf(var, size, format, ##args); \
-                c += (fwd >= size) ? size : fwd;
+#define PRINT(var, size, format, args...) \
+do { \
+       fwd = snprintf(var, size, format, ##args); \
+       c += (fwd >= size) ? size : fwd; \
+} while (0)
 
 /*
  * information printing helpers
  */
 static int
-snprint_str (char * buff, size_t len, char * str)
+snprint_str (char * buff, size_t len, const char * str)
 {
        return snprintf(buff, len, "%s", str);
 }
@@ -248,11 +256,20 @@ snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
 static int
 snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
 {
-       struct path * pp = first_path(mpp);
-       if (!pp)
-               return 0;
-       return snprintf(buff, len, "%s,%s",
-                       pp->vendor_id, pp->product_id);
+       struct pathgroup * pgp;
+       struct path * pp;
+       int i, j;
+
+       vector_foreach_slot(mpp->pg, pgp, i) {
+               if (!pgp)
+                       continue;
+               vector_foreach_slot(pgp->paths, pp, j) {
+                       if (strlen(pp->vendor_id) && strlen(pp->product_id))
+                               return snprintf(buff, len, "%s,%s",
+                                               pp->vendor_id, pp->product_id);
+               }
+       }
+       return snprintf(buff, len, "##,##");
 }
 
 static int
@@ -286,7 +303,7 @@ snprint_path_uuid (char * buff, size_t len, struct path * pp)
 static int
 snprint_hcil (char * buff, size_t len, struct path * pp)
 {
-       if (pp->sg_id.host_no < 0)
+       if (!pp || pp->sg_id.host_no < 0)
                return snprintf(buff, len, "#:#:#:#");
 
        return snprintf(buff, len, "%i:%i:%i:%i",
@@ -299,7 +316,7 @@ snprint_hcil (char * buff, size_t len, struct path * pp)
 static int
 snprint_dev (char * buff, size_t len, struct path * pp)
 {
-       if (!strlen(pp->dev))
+       if (!pp || !strlen(pp->dev))
                return snprintf(buff, len, "-");
        else
                return snprint_str(buff, len, pp->dev);
@@ -308,7 +325,7 @@ snprint_dev (char * buff, size_t len, struct path * pp)
 static int
 snprint_dev_t (char * buff, size_t len, struct path * pp)
 {
-       if (!strlen(pp->dev))
+       if (!pp || !strlen(pp->dev))
                return snprintf(buff, len, "#:#");
        else
                return snprint_str(buff, len, pp->dev_t);
@@ -317,7 +334,9 @@ snprint_dev_t (char * buff, size_t len, struct path * pp)
 static int
 snprint_offline (char * buff, size_t len, struct path * pp)
 {
-       if (pp->offline)
+       if (!pp)
+               return snprintf(buff, len, "unknown");
+       else if (pp->offline)
                return snprintf(buff, len, "offline");
        else
                return snprintf(buff, len, "running");
@@ -326,6 +345,9 @@ snprint_offline (char * buff, size_t len, struct path * pp)
 static int
 snprint_chk_state (char * buff, size_t len, struct path * pp)
 {
+       if (!pp)
+               return snprintf(buff, len, "undef");
+
        switch (pp->state) {
        case PATH_UP:
                return snprintf(buff, len, "ready");
@@ -339,6 +361,8 @@ snprint_chk_state (char * buff, size_t len, struct path * pp)
                return snprintf(buff, len, "i/o pending");
        case PATH_TIMEOUT:
                return snprintf(buff, len, "i/o timeout");
+       case PATH_DELAYED:
+               return snprintf(buff, len, "delayed");
        default:
                return snprintf(buff, len, "undef");
        }
@@ -347,6 +371,9 @@ snprint_chk_state (char * buff, size_t len, struct path * pp)
 static int
 snprint_dm_path_state (char * buff, size_t len, struct path * pp)
 {
+       if (!pp)
+               return snprintf(buff, len, "undef");
+
        switch (pp->dmstate) {
        case PSTATE_ACTIVE:
                return snprintf(buff, len, "active");
@@ -367,7 +394,7 @@ snprint_vpr (char * buff, size_t len, struct path * pp)
 static int
 snprint_next_check (char * buff, size_t len, struct path * pp)
 {
-       if (!pp->mpp)
+       if (!pp || !pp->mpp)
                return snprintf(buff, len, "orphan");
 
        return snprint_progress(buff, len, pp->tick, pp->checkint);
@@ -376,7 +403,7 @@ snprint_next_check (char * buff, size_t len, struct path * pp)
 static int
 snprint_pri (char * buff, size_t len, struct path * pp)
 {
-       return snprint_int(buff, len, pp->priority);
+       return snprint_int(buff, len, pp ? pp->priority : -1);
 }
 
 static int
@@ -435,6 +462,93 @@ snprint_path_mpp (char * buff, size_t len, struct path * pp)
        return snprint_str(buff, len, pp->mpp->alias);
 }
 
+static int
+snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
+{
+       struct udev_device *host_dev = NULL;
+       char host_id[32];
+       const char *value = NULL;
+       int ret;
+
+       if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
+               return snprintf(buff, len, "[undef]");
+       sprintf(host_id, "host%d", pp->sg_id.host_no);
+       host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host",
+                                                         host_id);
+       if (!host_dev) {
+               condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
+               goto out;
+       }
+       value = udev_device_get_sysattr_value(host_dev, attr);
+       if (value)
+               ret = snprint_str(buff, len, value);
+       udev_device_unref(host_dev);
+out:
+       if (!value)
+               ret = snprintf(buff, len, "[unknown]");
+       return ret;
+}
+
+int
+snprint_host_wwnn (char * buff, size_t len, struct path * pp)
+{
+       return snprint_host_attr(buff, len, pp, "node_name");
+}
+
+int
+snprint_host_wwpn (char * buff, size_t len, struct path * pp)
+{
+       return snprint_host_attr(buff, len, pp, "port_name");
+}
+
+int
+snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
+{
+       struct udev_device *rport_dev = NULL;
+       char rport_id[32];
+       const char *value = NULL;
+       int ret;
+
+       if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
+               return snprintf(buff, len, "[undef]");
+       sprintf(rport_id, "rport-%d:%d-%d",
+               pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
+       rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+                               "fc_remote_ports", rport_id);
+       if (!rport_dev) {
+               condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
+                       rport_id);
+               goto out;
+       }
+       value = udev_device_get_sysattr_value(rport_dev, "port_name");
+       if (value)
+               ret = snprint_str(buff, len, value);
+       udev_device_unref(rport_dev);
+out:
+       if (!value)
+               ret = snprintf(buff, len, "[unknown]");
+       return ret;
+}
+
+
+int
+snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
+{
+       if (pp->tgt_node_name[0] == '\0')
+               return snprintf(buff, len, "[undef]");
+       return snprint_str(buff, len, pp->tgt_node_name);
+}
+
+static int
+snprint_host_adapter (char * buff, size_t len, struct path * pp)
+{
+       char adapter[SLOT_NAME_SIZE];
+
+       if (sysfs_get_host_adapter_name(pp, adapter))
+               return snprintf(buff, len, "[undef]");
+       return snprint_str(buff, len, adapter);
+}
+
 static int
 snprint_path_checker (char * buff, size_t len, struct path * pp)
 {
@@ -479,6 +593,11 @@ struct path_data pd[] = {
        {'S', "size",          0, snprint_path_size},
        {'z', "serial",        0, snprint_path_serial},
        {'m', "multipath",     0, snprint_path_mpp},
+       {'N', "host WWNN",     0, snprint_host_wwnn},
+       {'n', "target WWNN",   0, snprint_tgt_wwnn},
+       {'R', "host WWPN",     0, snprint_host_wwpn},
+       {'r', "target WWPN",   0, snprint_tgt_wwpn},
+       {'a', "host adapter",  0, snprint_host_adapter},
        {0, NULL, 0 , NULL}
 };
 
@@ -629,7 +748,7 @@ snprint_multipath_header (char * line, int len, char * format)
 
 int
 snprint_multipath (char * line, int len, char * format,
-            struct multipath * mpp)
+            struct multipath * mpp, int pad)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
@@ -656,7 +775,8 @@ snprint_multipath (char * line, int len, char * format,
 
                data->snprint(buff, MAX_FIELD_LEN, mpp);
                PRINT(c, TAIL, "%s", buff);
-               PAD(data->width);
+               if (pad)
+                       PAD(data->width);
                buff[0] = '\0';
        } while (*f++);
 
@@ -699,7 +819,7 @@ snprint_path_header (char * line, int len, char * format)
 
 int
 snprint_path (char * line, int len, char * format,
-            struct path * pp)
+            struct path * pp, int pad)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
@@ -726,7 +846,8 @@ snprint_path (char * line, int len, char * format,
 
                data->snprint(buff, MAX_FIELD_LEN, pp);
                PRINT(c, TAIL, "%s", buff);
-               PAD(data->width);
+               if (pad)
+                       PAD(data->width);
        } while (*f++);
 
        ENDLINE;
@@ -797,6 +918,7 @@ print_multipath_topology (struct multipath * mpp, int verbosity)
                }
        } while (resize);
        printf("%s", buff);
+       FREE(buff);
 }
 
 extern int
@@ -817,7 +939,7 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
        reset_multipath_layout();
 
        if (verbosity == 1)
-               return snprint_multipath(buff, len, "%n", mpp);
+               return snprint_multipath(buff, len, "%n", mpp, 1);
 
        if(isatty(1))
                c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
@@ -836,10 +958,11 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
        if(isatty(1))
                c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
 
-       fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
+       fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1);
        if (fwd > len)
                return len;
-       fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp);
+       fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp,
+                                1);
        if (fwd > len)
                return len;
 
@@ -866,7 +989,7 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
                                strcpy(f, " |- " PRINT_PATH_INDENT);
                        else
                                strcpy(f, " `- " PRINT_PATH_INDENT);
-                       fwd += snprint_path(buff + fwd, len - fwd, fmt, pp);
+                       fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1);
                        if (fwd > len)
                                return len;
                }
@@ -986,6 +1109,36 @@ snprint_mptable (char * buff, int len, vector mptable)
        return fwd;
 }
 
+extern int
+snprint_overrides (char * buff, int len, struct hwentry *overrides)
+{
+       int fwd = 0;
+       int i;
+       struct keyword *rootkw;
+       struct keyword *kw;
+
+       rootkw = find_keyword(NULL, "overrides");
+       if (!rootkw)
+               return 0;
+
+       fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
+       if (fwd > len)
+               return len;
+       if (!overrides)
+               goto out;
+       iterate_sub_keywords(rootkw, kw, i) {
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, NULL);
+               if (fwd > len)
+                       return len;
+       }
+out:
+       fwd += snprintf(buff + fwd, len - fwd, "}\n");
+       if (fwd > len)
+               return len;
+       return fwd;
+}
+
 extern int
 snprint_defaults (char * buff, int len)
 {
@@ -1334,8 +1487,10 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
        if (!(blkdir = opendir("/sys/block")))
                return 1;
 
-       if ((len - fwd - threshold) <= 0)
+       if ((len - fwd - threshold) <= 0) {
+               closedir(blkdir);
                return len;
+       }
        fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
 
        strcpy(devpath,"/sys/block/");
@@ -1353,8 +1508,10 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
                if (S_ISDIR(statbuf.st_mode) == 0)
                        continue;
 
-               if ((len - fwd - threshold)  <= 0)
+               if ((len - fwd - threshold)  <= 0) {
+                       closedir(blkdir);
                        return len;
+               }
 
                fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
                pp = find_path_by_dev(vecs->pathvec, devptr);
@@ -1364,7 +1521,7 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
                        if (r > 0)
                                fwd += snprintf(buff + fwd, len - fwd,
                                                " devnode blacklisted, unmonitored");
-                       else if (r < 0)
+                       else if (r <= 0)
                                fwd += snprintf(buff + fwd, len - fwd,
                                                " devnode whitelisted, unmonitored");
                } else
@@ -1394,7 +1551,7 @@ print_path (struct path * pp, char * style)
        char line[MAX_LINE_LEN];
 
        memset(&line[0], 0, MAX_LINE_LEN);
-       snprint_path(&line[0], MAX_LINE_LEN, style, pp);
+       snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
        printf("%s", line);
 }
 
@@ -1404,7 +1561,7 @@ print_multipath (struct multipath * mpp, char * style)
        char line[MAX_LINE_LEN];
 
        memset(&line[0], 0, MAX_LINE_LEN);
-       snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
+       snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp, 1);
        printf("%s", line);
 }
 
index aef182b5a58d9bee2f2d2c667ce51946919e22ee..8bd0bbc2e17ba462e8f909a8603a1e21c34e0682 100644 (file)
@@ -37,8 +37,8 @@ void get_path_layout (vector pathvec, int header);
 void get_multipath_layout (vector mpvec, int header);
 int snprint_path_header (char *, int, char *);
 int snprint_multipath_header (char *, int, char *);
-int snprint_path (char *, int, char *, struct path *);
-int snprint_multipath (char *, int, char *, struct multipath *);
+int snprint_path (char *, int, char *, struct path *, int);
+int snprint_multipath (char *, int, char *, struct multipath *, int);
 int snprint_multipath_topology (char *, int, struct multipath * mpp,
                                int verbosity);
 int snprint_defaults (char *, int);
@@ -50,6 +50,11 @@ int snprint_status (char *, int, struct vectors *);
 int snprint_devices (char *, int, struct vectors *);
 int snprint_hwtable (char *, int, vector);
 int snprint_mptable (char *, int, vector);
+int snprint_overrides (char *, int, struct hwentry *);
+int snprint_host_wwnn (char *, size_t, struct path *);
+int snprint_host_wwpn (char *, size_t, struct path *);
+int snprint_tgt_wwnn (char *, size_t, struct path *);
+int snprint_tgt_wwpn (char *, size_t, struct path *);
 
 void print_multipath_topology (struct multipath * mpp, int verbosity);
 void print_path (struct path * pp, char * style);
index 05a8cf1895d10219675d63c4d9169dabcddf5fdb..ab8eca9edf3a784e8421a1da359194a506de4ecb 100644 (file)
 
 static LIST_HEAD(prioritizers);
 
+unsigned int get_prio_timeout(unsigned int default_timeout)
+{
+       if (conf->checker_timeout)
+               return conf->checker_timeout * 1000;
+       return default_timeout;
+}
+
 int init_prio (void)
 {
        if (!add_prio(DEFAULT_PRIO))
@@ -125,7 +132,7 @@ int prio_getprio (struct prio * p, struct path * pp)
 
 int prio_selected (struct prio * p)
 {
-       if (!p || !p->getprio)
+       if (!p)
                return 0;
        return (p->getprio) ? 1 : 0;
 }
@@ -162,7 +169,7 @@ void prio_put (struct prio * dst)
 {
        struct prio * src;
 
-       if (!dst)
+       if (!dst || !dst->getprio)
                return;
 
        src = prio_lookup(dst->name);
index 4eeb216e9c96ecef5da0b6f89742a098bfd29a2f..495688f456729232247337fed1b405bd4439712d 100644 (file)
@@ -51,6 +51,7 @@ struct prio {
        int (*getprio)(struct path *, char *);
 };
 
+unsigned int get_prio_timeout(unsigned int default_timeout);
 int init_prio (void);
 void cleanup_prio (void);
 struct prio * add_prio (char *);
index 4165ec60f820d3eb027d3b708a7845257aba7c43..cd4aafc21ef591c7de9dcc47f07fe767f9028e92 100644 (file)
@@ -51,44 +51,58 @@ static const char *aas_print_string(int rc)
 }
 
 int
-get_alua_info(int fd)
+get_alua_info(struct path * pp)
 {
        int     rc;
        int     tpg;
-       int     aas;
 
-       rc = get_target_port_group_support(fd);
-       if (rc < 0)
-               return -ALUA_PRIO_TPGS_FAILED;
-
-       if (rc == TPGS_NONE)
-               return -ALUA_PRIO_NOT_SUPPORTED;
-
-       tpg = get_target_port_group(fd);
-       if (tpg < 0)
+       tpg = get_target_port_group(pp);
+       if (tpg < 0) {
+               rc = get_target_port_group_support(pp->fd);
+               if (rc < 0)
+                       return -ALUA_PRIO_TPGS_FAILED;
+               if (rc == TPGS_NONE)
+                       return -ALUA_PRIO_NOT_SUPPORTED;
                return -ALUA_PRIO_RTPG_FAILED;
-
+       }
        condlog(3, "reported target port group is %i", tpg);
-       rc = get_asymmetric_access_state(fd, tpg);
+       rc = get_asymmetric_access_state(pp->fd, tpg);
        if (rc < 0)
                return -ALUA_PRIO_GETAAS_FAILED;
-       aas = (rc & 0x0f);
 
        condlog(3, "aas = %02x [%s]%s", rc, aas_print_string(rc),
                (rc & 0x80) ? " [preferred]" : "");
        return rc;
 }
 
+int get_exclusive_perf_arg(char *args)
+{
+       char *ptr;
+
+       if (args == NULL)
+               return 0;
+       ptr = strstr(args, "exclusive_pref_bit");
+       if (!ptr)
+               return 0;
+       if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t')
+               return 0;
+       if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t')
+               return 0;
+       return 1;
+}
+
 int getprio (struct path * pp, char * args)
 {
        int rc;
        int aas;
        int priopath;
+       int exclusive_perf;
 
        if (pp->fd < 0)
                return -ALUA_PRIO_NO_INFORMATION;
 
-       rc = get_alua_info(pp->fd);
+       exclusive_perf = get_exclusive_perf_arg(args);
+       rc = get_alua_info(pp);
        if (rc >= 0) {
                aas = (rc & 0x0f);
                priopath = (rc & 0x80);
@@ -108,7 +122,7 @@ int getprio (struct path * pp, char * args)
                        default:
                                rc = 0;
                }
-               if (priopath && aas != AAS_OPTIMIZED)
+               if (priopath && (aas != AAS_OPTIMIZED || exclusive_perf))
                        rc += 80;
        } else {
                switch(-rc) {
@@ -119,10 +133,10 @@ int getprio (struct path * pp, char * args)
                                condlog(0, "%s: couldn't get target port group", pp->dev);
                                break;
                        case ALUA_PRIO_GETAAS_FAILED:
-                               condlog(0, "%s: couln't get asymmetric access state", pp->dev);
+                               condlog(0, "%s: couldn't get asymmetric access state", pp->dev);
                                break;
                        case ALUA_PRIO_TPGS_FAILED:
-                               condlog(3, "%s: couln't get supported alua states", pp->dev);
+                               condlog(3, "%s: couldn't get supported alua states", pp->dev);
                                break;
                }
        }
index 981ba0616d7ba5d8b7ddb3b7200aed57b0202822..636aae553ad9aa992df0e61771b1bf6513d14f63 100644 (file)
 #include <string.h>
 #include <sys/ioctl.h>
 #include <inttypes.h>
+#include <libudev.h>
 
 #define __user
 #include <scsi/sg.h>
 
+#include "../structs.h"
+#include "../prio.h"
+#include "../discovery.h"
 #include "alua_rtpg.h"
 
 #define SENSE_BUFF_LEN  32
-#define DEF_TIMEOUT     60000
+#define SGIO_TIMEOUT     60000
 
 /*
  * Macro used to print debug messaged.
@@ -134,7 +138,7 @@ do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
        hdr.dxfer_len           = resplen;
        hdr.sbp                 = sense;
        hdr.mx_sb_len           = sizeof(sense);
-       hdr.timeout             = DEF_TIMEOUT;
+       hdr.timeout             = get_prio_timeout(SGIO_TIMEOUT);
 
        if (ioctl(fd, SG_IO, &hdr) < 0) {
                PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
@@ -169,8 +173,27 @@ get_target_port_group_support(int fd)
        return rc;
 }
 
+static int
+get_sysfs_pg83(struct path *pp, unsigned char *buff, int buflen)
+{
+       struct udev_device *parent = pp->udev;
+
+       while (parent) {
+               const char *subsys = udev_device_get_subsystem(parent);
+               if (subsys && !strncmp(subsys, "scsi", 4))
+                       break;
+               parent = udev_device_get_parent(parent);
+       }
+
+       if (!parent || sysfs_get_vpd(parent, 0x83, buff, buflen) <= 0) {
+               PRINT_DEBUG("failed to read sysfs vpd pg83\n");
+               return -1;
+       }
+       return 0;
+}
+
 int
-get_target_port_group(int fd)
+get_target_port_group(struct path * pp)
 {
        unsigned char           *buf;
        struct vpd83_data *     vpd83;
@@ -178,7 +201,7 @@ get_target_port_group(int fd)
        int                     rc;
        int                     buflen, scsi_buflen;
 
-       buflen = 128; /* Lets start from 128 */
+       buflen = 4096;
        buf = (unsigned char *)malloc(buflen);
        if (!buf) {
                PRINT_DEBUG("malloc failed: could not allocate"
@@ -187,24 +210,29 @@ get_target_port_group(int fd)
        }
 
        memset(buf, 0, buflen);
-       rc = do_inquiry(fd, 1, 0x83, buf, buflen);
-       if (rc < 0)
-               goto out;
 
-       scsi_buflen = (buf[2] << 8 | buf[3]) + 4;
-       if (buflen < scsi_buflen) {
-               free(buf);
-               buf = (unsigned char *)malloc(scsi_buflen);
-               if (!buf) {
-                       PRINT_DEBUG("malloc failed: could not allocate"
-                                    "%u bytes\n", scsi_buflen);
-                       return -RTPG_RTPG_FAILED;
-               }
-               buflen = scsi_buflen;
-               memset(buf, 0, buflen);
-               rc = do_inquiry(fd, 1, 0x83, buf, buflen);
+       rc = get_sysfs_pg83(pp, buf, buflen);
+
+       if (rc < 0) {
+               rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen);
                if (rc < 0)
                        goto out;
+
+               scsi_buflen = (buf[2] << 8 | buf[3]) + 4;
+               if (buflen < scsi_buflen) {
+                       free(buf);
+                       buf = (unsigned char *)malloc(scsi_buflen);
+                       if (!buf) {
+                               PRINT_DEBUG("malloc failed: could not allocate"
+                                           "%u bytes\n", scsi_buflen);
+                               return -RTPG_RTPG_FAILED;
+                       }
+                       buflen = scsi_buflen;
+                       memset(buf, 0, buflen);
+                       rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen);
+                       if (rc < 0)
+                               goto out;
+               }
        }
 
        vpd83 = (struct vpd83_data *) buf;
@@ -253,7 +281,7 @@ do_rtpg(int fd, void* resp, long resplen)
        hdr.dxfer_len           = resplen;
        hdr.mx_sb_len           = sizeof(sense);
        hdr.sbp                 = sense;
-       hdr.timeout             = DEF_TIMEOUT;
+       hdr.timeout             = get_prio_timeout(SGIO_TIMEOUT);
 
        if (ioctl(fd, SG_IO, &hdr) < 0)
                return -RTPG_RTPG_FAILED;
@@ -277,7 +305,7 @@ get_asymmetric_access_state(int fd, unsigned int tpg)
        int                     buflen;
        uint32_t                scsi_buflen;
 
-       buflen = 128; /* Initial value from old code */
+       buflen = 4096;
        buf = (unsigned char *)malloc(buflen);
        if (!buf) {
                PRINT_DEBUG ("malloc failed: could not allocate"
index c43e0a95f71562c9832858a09eed857c0e01123e..91a15a478506473561adc229b7a37bf4efd81e6c 100644 (file)
@@ -23,7 +23,7 @@
 #define RTPG_TPG_NOT_FOUND                     4
 
 int get_target_port_group_support(int fd);
-int get_target_port_group(int fd);
+int get_target_port_group(struct path * pp);
 int get_asymmetric_access_state(int fd, unsigned int tpg);
 
 #endif /* __RTPG_H__ */
index 87e9a8d3969adafb30dc36e600b3944b7df515ad..e49809c365597191933331f84fda30eac278b62b 100644 (file)
 
 int emc_clariion_prio(const char *dev, int fd)
 {
-       unsigned char sense_buffer[256];
+       unsigned char sense_buffer[128];
        unsigned char sb[128];
        unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
-                                               sizeof(sb), 0};
+                                               sizeof(sense_buffer), 0};
        struct sg_io_hdr io_hdr;
        int ret = PRIO_UNDEF;
 
        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-       memset(&sense_buffer, 0, 256);
+       memset(&sense_buffer, 0, 128);
        io_hdr.interface_id = 'S';
        io_hdr.cmd_len = sizeof (inqCmdBlk);
        io_hdr.mx_sb_len = sizeof (sb);
@@ -31,7 +31,7 @@ int emc_clariion_prio(const char *dev, int fd)
        io_hdr.dxferp = sense_buffer;
        io_hdr.cmdp = inqCmdBlk;
        io_hdr.sbp = sb;
-       io_hdr.timeout = 60000;
+       io_hdr.timeout = get_prio_timeout(60000);
        io_hdr.pack_id = 0;
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
                pp_emc_log(0, "sending query command failed");
index f748707062d584b1aac9f3471899fce1d9776cf4..8043b5b60e0153c947501695f7bacb7f28105419 100644 (file)
@@ -114,7 +114,7 @@ int hds_modular_prio (const char *dev, int fd)
        io_hdr.dxferp = inqBuff;
        io_hdr.cmdp = inqCmdBlk;
        io_hdr.sbp = sense_buffer;
-       io_hdr.timeout = 2000;  /* TimeOut = 2 seconds */
+       io_hdr.timeout = get_prio_timeout(2000); /* TimeOut = 2 seconds */
 
        if (ioctl (fd, SG_IO, &io_hdr) < 0) {
                pp_hds_log(0, "SG_IO error");
index c24baad6dfb44733d8bff77aab71ffd41bc79092..4950cf73e9b5d47a2688927628daa56f28bb796b 100644 (file)
@@ -46,7 +46,7 @@ int hp_sw_prio(const char *dev, int fd)
        io_hdr.dxfer_direction = SG_DXFER_NONE;
        io_hdr.cmdp = turCmdBlk;
        io_hdr.sbp = sb;
-       io_hdr.timeout = 60000;
+       io_hdr.timeout = get_prio_timeout(60000);
        io_hdr.pack_id = 0;
  retry:
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
index 94406df9107add2bca400b03ecc4bf26a4ff323e..0bcc48bcffd20860d2c2f8d7a7325f8a9281cb94 100644 (file)
@@ -109,6 +109,7 @@ int iet_prio(const char *dev, char * args)
                        ssize_t nchars = readlink(path, buffer, sizeof(buffer)-1);
                        if (nchars != -1) {
                                char *device;
+                               buffer[nchars] = '\0';
                                device = find_regex(buffer,"(sd[a-z]+)");
                                // if device parsed is the right one
                                if (device!=NULL && strncmp(device, dev, strlen(device)) == 0) {
@@ -118,6 +119,7 @@ int iet_prio(const char *dev, char * args)
                                        if (ip!=NULL && strncmp(ip, preferredip, strlen(ip)) == 0) {
                                                // high prio
                                                free(ip);
+                                               free(device);
                                                closedir(dir_p);
                                                return 20;
                                        }
index 026d45dc998667faf890d6038c907290642ead15..5e82a17b8a7e321d0d2714405c36e004ea968269 100644 (file)
@@ -89,7 +89,7 @@ static int send_gva(const char *dev, int fd, unsigned char pg,
        io_hdr.dxferp = results;
        io_hdr.cmdp = cdb;
        io_hdr.sbp = sb;
-       io_hdr.timeout = SG_TIMEOUT;
+       io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
        io_hdr.pack_id = 0;
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
                pp_ontap_log(0, "SG_IO ioctl failed, errno=%d", errno);
@@ -141,7 +141,7 @@ static int get_proxy(const char *dev, int fd)
        io_hdr.dxferp = results;
        io_hdr.cmdp = cdb;
        io_hdr.sbp = sb;
-       io_hdr.timeout = SG_TIMEOUT;
+       io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
        io_hdr.pack_id = 0;
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
                pp_ontap_log(0, "ioctl sending inquiry command failed, "
index 441b3b09cf5bc53040952a4928147bc355672c8a..a21005536e67591a3e8b3260aa6bc8473b3f9a79 100644 (file)
 
 int rdac_prio(const char *dev, int fd)
 {
-       unsigned char sense_buffer[256];
+       unsigned char sense_buffer[128];
        unsigned char sb[128];
        unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
-                                               sizeof(sb), 0};
+                                               sizeof(sense_buffer), 0};
        struct sg_io_hdr io_hdr;
        int ret = 0;
 
        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-       memset(sense_buffer, 0, 256);
+       memset(sense_buffer, 0, 128);
        io_hdr.interface_id = 'S';
        io_hdr.cmd_len = sizeof (inqCmdBlk);
        io_hdr.mx_sb_len = sizeof (sb);
@@ -31,7 +31,7 @@ int rdac_prio(const char *dev, int fd)
        io_hdr.dxferp = sense_buffer;
        io_hdr.cmdp = inqCmdBlk;
        io_hdr.sbp = sb;
-       io_hdr.timeout = 60000;
+       io_hdr.timeout = get_prio_timeout(60000);
        io_hdr.pack_id = 0;
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
                pp_rdac_log(0, "sending inquiry command failed");
index 54c90396e630221db292dd8fb95f49875791d5b9..ba8c555aef04e46b383dc273b7349dbacd4b7e13 100644 (file)
@@ -32,6 +32,8 @@
 #include <memory.h>
 #include <debug.h>
 #include <regex.h>
+#include <structs_vec.h>
+#include <print.h>
 
 char *get_next_string(char **temp, char *split_char)
 {
@@ -42,6 +44,36 @@ char *get_next_string(char **temp, char *split_char)
        return token;
 }
 
+#define CHECK_LEN \
+do { \
+       if ((p - str) >= (len - 1)) { \
+               condlog(0, "%s: %s - buffer size too small", pp->dev, pp->prio.name); \
+               return -1; \
+       } \
+} while(0)
+
+static int
+build_wwn_path(struct path *pp, char *str, int len)
+{
+       char *p = str;
+
+       p += snprint_host_wwnn(p, str + len - p, pp);
+       CHECK_LEN;
+       p += snprintf(p, str + len - p, ":");
+       CHECK_LEN;
+       p += snprint_host_wwpn(p, str + len - p, pp);
+       CHECK_LEN;
+       p += snprintf(p, str + len - p, ":");
+       CHECK_LEN;
+       p += snprint_tgt_wwnn(p, str + len - p, pp);
+       CHECK_LEN;
+       p += snprintf(p, str + len - p, ":");
+       CHECK_LEN;
+       p += snprint_tgt_wwpn(p, str + len - p, pp);
+       CHECK_LEN;
+       return 0;
+}
+
 /* main priority routine */
 int prio_path_weight(struct path *pp, char *prio_args)
 {
@@ -61,17 +93,25 @@ int prio_path_weight(struct path *pp, char *prio_args)
        regex = get_next_string(&temp, split_char);
 
        /* Return default priority if the argument is not parseable */
-       if (!regex)
+       if (!regex) {
+               FREE(arg);
                return priority;
+       }
 
        if (!strcmp(regex, HBTL)) {
                sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no,
                        pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun);
        } else if (!strcmp(regex, DEV_NAME)) {
                strcpy(path, pp->dev);
+       } else if (!strcmp(regex, WWN)) {
+               if (build_wwn_path(pp, path, FILE_NAME_SIZE) != 0) {
+                       FREE(arg);
+                       return priority;
+               }
        } else {
                condlog(0, "%s: %s - Invalid arguments", pp->dev,
                        pp->prio.name);
+               FREE(arg);
                return priority;
        }
 
index 509f21565d06d8c10a0f0a79756195a5583125d8..93d8c43ee89fbe5d639908540669862ba6cb062e 100644 (file)
@@ -4,6 +4,7 @@
 #define PRIO_WEIGHTED_PATH "weightedpath"
 #define HBTL "hbtl"
 #define DEV_NAME "devname"
+#define WWN "wwn"
 #define DEFAULT_PRIORITY 0
 
 int prio_path_weight(struct path *pp, char *prio_args);
index 7b7944d9d85c43de99da0dac28b7277a99b0b19d..8abe360dff43c82acc134770240da111ac1a0370 100644 (file)
@@ -17,6 +17,7 @@
 #include "devmapper.h"
 #include "prio.h"
 #include "discovery.h"
+#include "dict.h"
 #include "prioritizers/alua_rtpg.h"
 #include <inttypes.h>
 
@@ -29,57 +30,96 @@ pgpolicyfn *pgpolicies[] = {
        group_by_node_name
 };
 
+#define do_set(var, src, dest, msg)                                    \
+do {                                                                   \
+       if (src && src->var) {                                          \
+               dest = src->var;                                        \
+               origin = msg;                                           \
+               goto out;                                               \
+       }                                                               \
+} while(0)
+#define do_default(dest, value)                                                \
+do {                                                                   \
+       dest = value;                                                   \
+       origin = "(internal default)";                                  \
+} while(0)
+
+#define mp_set_mpe(var)                                                        \
+do_set(var, mp->mpe, mp->var, "(LUN setting)")
+#define mp_set_hwe(var)                                                        \
+do_set(var, mp->hwe, mp->var, "(controller setting)")
+#define mp_set_ovr(var)                                                        \
+do_set(var, conf->overrides, mp->var, "(overrides setting)")
+#define mp_set_conf(var)                                               \
+do_set(var, conf, mp->var, "(config file default)")
+#define mp_set_default(var, value)                                     \
+do_default(mp->var, value)
+
+#define pp_set_mpe(var)                                                        \
+do_set(var, mpe, pp->var, "(LUN setting)")
+#define pp_set_hwe(var)                                                        \
+do_set(var, pp->hwe, pp->var, "(controller setting)")
+#define pp_set_conf(var)                                               \
+do_set(var, conf, pp->var, "(config file default)")
+#define pp_set_ovr(var)                                                        \
+do_set(var, conf->overrides, pp->var, "(overrides setting)")
+#define pp_set_default(var, value)                                     \
+do_default(pp->var, value)
+
+#define do_attr_set(var, src, shift, msg)                              \
+do {                                                                   \
+       if (src && (src->attribute_flags & (1 << shift))) {             \
+               mp->attribute_flags |= (1 << shift);                    \
+               mp->var = src->var;                                     \
+               origin = msg;                                           \
+               goto out;                                               \
+       }                                                               \
+} while(0)
+
+#define set_attr_mpe(var, shift)                                       \
+do_attr_set(var, mp->mpe, shift, "(LUN setting)")
+#define set_attr_conf(var, shift)                                      \
+do_attr_set(var, conf, shift, "(config file default)")
+
 extern int
 select_mode (struct multipath *mp)
 {
-       if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_MODE))) {
-               mp->attribute_flags |= (1 << ATTR_MODE);
-               mp->mode = mp->mpe->mode;
-               condlog(3, "mode = 0%o (LUN setting)", mp->mode);
-       }
-       else if (conf->attribute_flags & (1 << ATTR_MODE)) {
-               mp->attribute_flags |= (1 << ATTR_MODE);
-               mp->mode = conf->mode;
-               condlog(3, "mode = 0%o (config file default)", mp->mode);
-       }
-       else
-               mp->attribute_flags &= ~(1 << ATTR_MODE);
+       char *origin;
+
+       set_attr_mpe(mode, ATTR_MODE);
+       set_attr_conf(mode, ATTR_MODE);
+       mp->attribute_flags &= ~(1 << ATTR_MODE);
+       return 0;
+out:
+       condlog(3, "%s: mode = 0%o %s", mp->alias, mp->mode, origin);
        return 0;
 }
 
 extern int
 select_uid (struct multipath *mp)
 {
-       if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_UID))) {
-               mp->attribute_flags |= (1 << ATTR_UID);
-               mp->uid = mp->mpe->uid;
-               condlog(3, "uid = %u (LUN setting)", mp->uid);
-       }
-       else if (conf->attribute_flags & (1 << ATTR_UID)) {
-               mp->attribute_flags |= (1 << ATTR_UID);
-               mp->uid = conf->uid;
-               condlog(3, "uid = %u (config file default)", mp->uid);
-       }
-       else
-               mp->attribute_flags &= ~(1 << ATTR_UID);
+       char *origin;
+
+       set_attr_mpe(uid, ATTR_UID);
+       set_attr_conf(uid, ATTR_UID);
+       mp->attribute_flags &= ~(1 << ATTR_UID);
+       return 0;
+out:
+       condlog(3, "%s: uid = 0%o %s", mp->alias, mp->uid, origin);
        return 0;
 }
 
 extern int
 select_gid (struct multipath *mp)
 {
-       if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_GID))) {
-               mp->attribute_flags |= (1 << ATTR_GID);
-               mp->gid = mp->mpe->gid;
-               condlog(3, "gid = %u (LUN setting)", mp->gid);
-       }
-       else if (conf->attribute_flags & (1 << ATTR_GID)) {
-               mp->attribute_flags |= (1 << ATTR_GID);
-               mp->gid = conf->gid;
-               condlog(3, "gid = %u (config file default)", mp->gid);
-       }
-       else
-               mp->attribute_flags &= ~(1 << ATTR_GID);
+       char *origin;
+
+       set_attr_mpe(gid, ATTR_GID);
+       set_attr_conf(gid, ATTR_GID);
+       mp->attribute_flags &= ~(1 << ATTR_GID);
+       return 0;
+out:
+       condlog(3, "%s: gid = 0%o %s", mp->alias, mp->gid, origin);
        return 0;
 }
 
@@ -91,205 +131,165 @@ select_gid (struct multipath *mp)
 extern int
 select_rr_weight (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->rr_weight) {
-               mp->rr_weight = mp->mpe->rr_weight;
-               condlog(3, "%s: rr_weight = %i (LUN setting)",
-                       mp->alias, mp->rr_weight);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->rr_weight) {
-               mp->rr_weight = mp->hwe->rr_weight;
-               condlog(3, "%s: rr_weight = %i (controller setting)",
-                       mp->alias, mp->rr_weight);
-               return 0;
-       }
-       if (conf->rr_weight) {
-               mp->rr_weight = conf->rr_weight;
-               condlog(3, "%s: rr_weight = %i (config file default)",
-                       mp->alias, mp->rr_weight);
-               return 0;
-       }
-       mp->rr_weight = RR_WEIGHT_NONE;
-       condlog(3, "%s: rr_weight = %i (internal default)",
-               mp->alias, mp->rr_weight);
+       char *origin, buff[13];
+
+       mp_set_mpe(rr_weight);
+       mp_set_ovr(rr_weight);
+       mp_set_hwe(rr_weight);
+       mp_set_conf(rr_weight);
+       mp_set_default(rr_weight, RR_WEIGHT_NONE);
+out:
+       print_rr_weight(buff, 13, &mp->rr_weight);
+       condlog(3, "%s: rr_weight = %s %s", mp->alias, buff, origin);
        return 0;
 }
 
 extern int
 select_pgfailback (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->pgfailback != FAILBACK_UNDEF) {
-               mp->pgfailback = mp->mpe->pgfailback;
-               condlog(3, "%s: pgfailback = %i (LUN setting)",
-                       mp->alias, mp->pgfailback);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
-               mp->pgfailback = mp->hwe->pgfailback;
-               condlog(3, "%s: pgfailback = %i (controller setting)",
-                       mp->alias, mp->pgfailback);
-               return 0;
-       }
-       if (conf->pgfailback != FAILBACK_UNDEF) {
-               mp->pgfailback = conf->pgfailback;
-               condlog(3, "%s: pgfailback = %i (config file default)",
-                       mp->alias, mp->pgfailback);
-               return 0;
-       }
-       mp->pgfailback = DEFAULT_FAILBACK;
-       condlog(3, "%s: pgfailover = %i (internal default)",
-               mp->alias, mp->pgfailback);
+       char *origin, buff[13];
+
+       mp_set_mpe(pgfailback);
+       mp_set_ovr(pgfailback);
+       mp_set_hwe(pgfailback);
+       mp_set_conf(pgfailback);
+       mp_set_default(pgfailback, DEFAULT_FAILBACK);
+out:
+       print_pgfailback(buff, 13, &mp->pgfailback);
+       condlog(3, "%s: failback = %s %s", mp->alias, buff, origin);
        return 0;
 }
 
 extern int
 select_pgpolicy (struct multipath * mp)
 {
-       char pgpolicy_name[POLICY_NAME_SIZE];
+       char *origin, buff[POLICY_NAME_SIZE];
 
        if (conf->pgpolicy_flag > 0) {
                mp->pgpolicy = conf->pgpolicy_flag;
-               mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-               get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-                                 mp->pgpolicy);
-               condlog(3, "%s: pgpolicy = %s (cmd line flag)",
-                       mp->alias, pgpolicy_name);
-               return 0;
-       }
-       if (mp->mpe && mp->mpe->pgpolicy > 0) {
-               mp->pgpolicy = mp->mpe->pgpolicy;
-               mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-               get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-                                 mp->pgpolicy);
-               condlog(3, "%s: pgpolicy = %s (LUN setting)",
-                       mp->alias, pgpolicy_name);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->pgpolicy > 0) {
-               mp->pgpolicy = mp->hwe->pgpolicy;
-               mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-               get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-                                 mp->pgpolicy);
-               condlog(3, "%s: pgpolicy = %s (controller setting)",
-                       mp->alias, pgpolicy_name);
-               return 0;
-       }
-       if (conf->pgpolicy > 0) {
-               mp->pgpolicy = conf->pgpolicy;
-               mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-               get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-                                 mp->pgpolicy);
-               condlog(3, "%s: pgpolicy = %s (config file default)",
-                       mp->alias, pgpolicy_name);
-               return 0;
+               origin = "(cmd line flag)";
+               goto out;
        }
-       mp->pgpolicy = DEFAULT_PGPOLICY;
+       mp_set_mpe(pgpolicy);
+       mp_set_ovr(pgpolicy);
+       mp_set_hwe(pgpolicy);
+       mp_set_conf(pgpolicy);
+       mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
+out:
        mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-       get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE, mp->pgpolicy);
-       condlog(3, "%s: pgpolicy = %s (internal default)",
-               mp->alias, pgpolicy_name);
+       get_pgpolicy_name(buff, POLICY_NAME_SIZE, mp->pgpolicy);
+       condlog(3, "%s: path_grouping_policy = %s %s", mp->alias, buff, origin);
        return 0;
 }
 
 extern int
 select_selector (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->selector) {
-               mp->selector = mp->mpe->selector;
-               condlog(3, "%s: selector = %s (LUN setting)",
-                       mp->alias, mp->selector);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->selector) {
-               mp->selector = mp->hwe->selector;
-               condlog(3, "%s: selector = %s (controller setting)",
-                       mp->alias, mp->selector);
-               return 0;
-       }
-       if (conf->selector) {
-               mp->selector = conf->selector;
-               condlog(3, "%s: selector = %s (config file default)",
-                       mp->alias, mp->selector);
-               return 0;
-       }
-       mp->selector = set_default(DEFAULT_SELECTOR);
-       condlog(3, "%s: selector = %s (internal default)",
-               mp->alias, mp->selector);
+       char *origin;
+
+       mp_set_mpe(selector);
+       mp_set_ovr(selector);
+       mp_set_hwe(selector);
+       mp_set_conf(selector);
+       mp_set_default(selector, DEFAULT_SELECTOR);
+out:
+       mp->selector = STRDUP(mp->selector);
+       condlog(3, "%s: path_selector = \"%s\" %s", mp->alias, mp->selector,
+               origin);
        return 0;
 }
 
 static void
 select_alias_prefix (struct multipath * mp)
 {
-       if (mp->hwe && mp->hwe->alias_prefix) {
-               mp->alias_prefix = mp->hwe->alias_prefix;
-               condlog(3, "%s: alias_prefix = %s (controller setting)",
-                       mp->wwid, mp->alias_prefix);
-               return;
-       }
-       if (conf->alias_prefix) {
-               mp->alias_prefix = conf->alias_prefix;
-               condlog(3, "%s: alias_prefix = %s (config file default)",
-                       mp->wwid, mp->alias_prefix);
-               return;
-       }
-       mp->alias_prefix = set_default(DEFAULT_ALIAS_PREFIX);
-       condlog(3, "%s: alias_prefix = %s (internal default)",
-               mp->wwid, mp->alias_prefix);
+       char *origin;
+
+       mp_set_ovr(alias_prefix);
+       mp_set_hwe(alias_prefix);
+       mp_set_conf(alias_prefix);
+       mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
+out:
+       condlog(3, "%s: alias_prefix = %s %s", mp->wwid, mp->alias_prefix,
+               origin);
 }
 
 static int
 want_user_friendly_names(struct multipath * mp)
 {
-       if (mp->mpe &&
-           mp->mpe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
-               return (mp->mpe->user_friendly_names == USER_FRIENDLY_NAMES_ON);
-       if (mp->hwe &&
-           mp->hwe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
-               return (mp->hwe->user_friendly_names == USER_FRIENDLY_NAMES_ON);
-       return (conf->user_friendly_names  == USER_FRIENDLY_NAMES_ON);
+
+       char *origin;
+       int user_friendly_names;
+
+       do_set(user_friendly_names, mp->mpe, user_friendly_names,
+              "(LUN setting)");
+       do_set(user_friendly_names, conf->overrides, user_friendly_names,
+              "(overrides setting)");
+       do_set(user_friendly_names, mp->hwe, user_friendly_names,
+              "(controller setting)");
+       do_set(user_friendly_names, conf, user_friendly_names,
+              "(config file setting)");
+       do_default(user_friendly_names, USER_FRIENDLY_NAMES_OFF);
+out:
+       condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
+               (user_friendly_names == USER_FRIENDLY_NAMES_ON)? "yes" : "no",
+               origin);
+       return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
 }
 
 extern int
 select_alias (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->alias)
+       char *origin = NULL;
+
+       if (mp->mpe && mp->mpe->alias) {
                mp->alias = STRDUP(mp->mpe->alias);
-       else {
-               mp->alias = NULL;
-               if (want_user_friendly_names(mp)) {
-                       select_alias_prefix(mp);
-                       mp->alias = get_user_friendly_alias(mp->wwid,
-                                       conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
-               }
-               if (mp->alias == NULL)
-                       mp->alias = STRDUP(mp->wwid);
+               origin = "(LUN setting)";
+               goto out;
+       }
+
+       mp->alias = NULL;
+       if (!want_user_friendly_names(mp))
+               goto out;
+
+       select_alias_prefix(mp);
+
+       if (strlen(mp->alias_old) > 0) {
+               mp->alias = use_existing_alias(mp->wwid, conf->bindings_file,
+                               mp->alias_old, mp->alias_prefix,
+                               conf->bindings_read_only);
+               memset (mp->alias_old, 0, WWID_SIZE);
+               origin = "(using existing alias)";
        }
 
+       if (mp->alias == NULL) {
+               mp->alias = get_user_friendly_alias(mp->wwid,
+                               conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
+               origin = "(user_friendly_name)";
+       }
+out:
+       if (mp->alias == NULL) {
+               mp->alias = STRDUP(mp->wwid);
+               origin = "(default to wwid)";
+       }
+       if (mp->alias)
+               condlog(3, "%s: alias = %s %s", mp->wwid, mp->alias, origin);
        return mp->alias ? 0 : 1;
 }
 
 extern int
 select_features (struct multipath * mp)
 {
-       struct mpentry * mpe;
        char *origin;
 
-       if ((mpe = find_mpe(mp->wwid)) && mpe->features) {
-               mp->features = STRDUP(mpe->features);
-               origin = "LUN setting";
-       } else if (mp->hwe && mp->hwe->features) {
-               mp->features = STRDUP(mp->hwe->features);
-               origin = "controller setting";
-       } else if (conf->features) {
-               mp->features = STRDUP(conf->features);
-               origin = "config file default";
-       } else {
-               mp->features = set_default(DEFAULT_FEATURES);
-               origin = "internal default";
-       }
-       condlog(3, "%s: features = %s (%s)",
-               mp->alias, mp->features, origin);
+       mp_set_mpe(features);
+       mp_set_ovr(features);
+       mp_set_hwe(features);
+       mp_set_conf(features);
+       mp_set_default(features, DEFAULT_FEATURES);
+out:
+       mp->features = STRDUP(mp->features);
+       condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
+
        if (strstr(mp->features, "queue_if_no_path")) {
                if (mp->no_path_retry == NO_PATH_RETRY_UNDEF)
                        mp->no_path_retry = NO_PATH_RETRY_QUEUE;
@@ -305,45 +305,31 @@ select_features (struct multipath * mp)
 extern int
 select_hwhandler (struct multipath * mp)
 {
-       if (mp->hwe && mp->hwe->hwhandler) {
-               mp->hwhandler = mp->hwe->hwhandler;
-               condlog(3, "%s: hwhandler = %s (controller setting)",
-                       mp->alias, mp->hwhandler);
-               return 0;
-       }
-       if (conf->hwhandler) {
-               mp->hwhandler = conf->hwhandler;
-               condlog(3, "%s: hwhandler = %s (config file default)",
-                       mp->alias, mp->hwhandler);
-               return 0;
-       }
-       mp->hwhandler = set_default(DEFAULT_HWHANDLER);
-       condlog(3, "%s: hwhandler = %s (internal default)",
-               mp->alias, mp->hwhandler);
+       char *origin;
+
+       mp_set_hwe(hwhandler);
+       mp_set_conf(hwhandler);
+       mp_set_default(hwhandler, DEFAULT_HWHANDLER);
+out:
+       mp->hwhandler = STRDUP(mp->hwhandler);
+       condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias, mp->hwhandler,
+               origin);
        return 0;
 }
 
 extern int
 select_checker(struct path *pp)
 {
+       char *origin, *checker_name;
        struct checker * c = &pp->checker;
 
-       if (pp->hwe && pp->hwe->checker_name) {
-               checker_get(c, pp->hwe->checker_name);
-               condlog(3, "%s: path checker = %s (controller setting)",
-                       pp->dev, checker_name(c));
-               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));
-               goto out;
-       }
-       checker_get(c, DEFAULT_CHECKER);
-       condlog(3, "%s: path checker = %s (internal default)",
-               pp->dev, checker_name(c));
+       do_set(checker_name, conf->overrides, checker_name, "(overrides setting)");
+       do_set(checker_name, pp->hwe, checker_name, "(controller setting)");
+       do_set(checker_name, conf, checker_name, "(config file setting)");
+       do_default(checker_name, DEFAULT_CHECKER);
 out:
+       checker_get(c, checker_name);
+       condlog(3, "%s: path_checker = %s %s", pp->dev, c->name, origin);
        if (conf->checker_timeout) {
                c->timeout = conf->checker_timeout;
                condlog(3, "%s: checker timeout = %u s (config file default)",
@@ -363,33 +349,22 @@ out:
 extern int
 select_getuid (struct path * pp)
 {
-       if (pp->hwe && pp->hwe->uid_attribute) {
-               pp->uid_attribute = pp->hwe->uid_attribute;
-               condlog(3, "%s: uid_attribute = %s (controller setting)",
-                       pp->dev, pp->uid_attribute);
-               return 0;
-       }
-       if (pp->hwe && pp->hwe->getuid) {
-               pp->getuid = pp->hwe->getuid;
-               condlog(3, "%s: getuid = %s (deprecated) (controller setting)",
-                       pp->dev, pp->getuid);
-               return 0;
-       }
-       if (conf->uid_attribute) {
-               pp->uid_attribute = conf->uid_attribute;
-               condlog(3, "%s: uid_attribute = %s (config file default)",
-                       pp->dev, pp->uid_attribute);
-               return 0;
-       }
-       if (conf->getuid) {
-               pp->getuid = conf->getuid;
-               condlog(3, "%s: getuid = %s (deprecated) (config file default)",
-                       pp->dev, pp->getuid);
-               return 0;
-       }
-       pp->uid_attribute = STRDUP(DEFAULT_UID_ATTRIBUTE);
-       condlog(3, "%s: uid_attribute = %s (internal default)",
-               pp->dev, pp->uid_attribute);
+       char *origin;
+
+       pp_set_ovr(getuid);
+       pp_set_ovr(uid_attribute);
+       pp_set_hwe(getuid);
+       pp_set_hwe(uid_attribute);
+       pp_set_conf(getuid);
+       pp_set_conf(uid_attribute);
+       pp_set_default(uid_attribute, DEFAULT_UID_ATTRIBUTE);
+out:
+       if (pp->uid_attribute)
+               condlog(3, "%s: uid_attribute = %s %s", pp->dev,
+                       pp->uid_attribute, origin);
+       else if (pp->getuid)
+               condlog(3, "%s: getuid = \"%s\" %s", pp->dev, pp->getuid,
+                       origin);
        return 0;
 }
 
@@ -398,10 +373,12 @@ detect_prio(struct path * pp)
 {
        int ret;
        struct prio *p = &pp->prio;
+       int tpgs = 0;
 
-       if (get_target_port_group_support(pp->fd) <= 0)
+       if ((tpgs = get_target_port_group_support(pp->fd)) <= 0)
                return;
-       ret = get_target_port_group(pp->fd);
+       pp->tpgs = tpgs;
+       ret = get_target_port_group(pp);
        if (ret < 0)
                return;
        if (get_asymmetric_access_state(pp->fd, ret) < 0)
@@ -409,140 +386,107 @@ detect_prio(struct path * pp)
        prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
 }
 
+#define set_prio(src, msg)                                             \
+do {                                                                   \
+       if (src && src->prio_name) {                                    \
+               prio_get(p, src->prio_name, src->prio_args);            \
+               origin = msg;                                           \
+               goto out;                                               \
+       }                                                               \
+} while(0)
+
 extern int
 select_prio (struct path * pp)
 {
+       char *origin;
        struct mpentry * mpe;
        struct prio * p = &pp->prio;
 
        if (pp->detect_prio == DETECT_PRIO_ON) {
                detect_prio(pp);
                if (prio_selected(p)) {
-                       condlog(3, "%s: prio = %s (detected setting)",
-                               pp->dev, prio_name(p));
-                       return 0;
-               }
-       }
-
-       if ((mpe = find_mpe(pp->wwid))) {
-               if (mpe->prio_name) {
-                       prio_get(p, mpe->prio_name, mpe->prio_args);
-                       condlog(3, "%s: prio = %s (LUN setting)",
-                               pp->dev, prio_name(p));
-                       return 0;
+                       origin = "(detected setting)";
+                       goto out;
                }
        }
-
-       if (pp->hwe && pp->hwe->prio_name) {
-               prio_get(p, pp->hwe->prio_name, pp->hwe->prio_args);
-               condlog(3, "%s: prio = %s (controller setting)",
-                       pp->dev, pp->hwe->prio_name);
-               condlog(3, "%s: prio args = %s (controller setting)",
-                       pp->dev, pp->hwe->prio_args);
-               return 0;
-       }
-       if (conf->prio_name) {
-               prio_get(p, conf->prio_name, conf->prio_args);
-               condlog(3, "%s: prio = %s (config file default)",
-                       pp->dev, conf->prio_name);
-               condlog(3, "%s: prio args = %s (config file default)",
-                       pp->dev, conf->prio_args);
-               return 0;
-       }
+       mpe = find_mpe(pp->wwid);
+       set_prio(mpe, "(LUN setting)");
+       set_prio(conf->overrides, "(overrides setting)");
+       set_prio(pp->hwe, "controller setting)");
+       set_prio(conf, "(config file default)");
        prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
-       condlog(3, "%s: prio = %s (internal default)",
-               pp->dev, DEFAULT_PRIO);
-       condlog(3, "%s: prio args = %s (internal default)",
-               pp->dev, DEFAULT_PRIO_ARGS);
+       origin = "(internal default)";
+out:
+       /*
+        * fetch tpgs mode for alua, if its not already obtained
+        */
+       if (!strncmp(prio_name(p), PRIO_ALUA, PRIO_NAME_LEN)) {
+               int tpgs = 0;
+               if(!pp->tpgs && 
+                  (tpgs = get_target_port_group_support(pp->fd)) >= 0)
+                       pp->tpgs = tpgs;
+       }
+       condlog(3, "%s: prio = %s %s", pp->dev, prio_name(p), origin);
+       condlog(3, "%s: prio args = \"%s\" %s", pp->dev, prio_args(p), origin);
        return 0;
 }
 
 extern int
 select_no_path_retry(struct multipath *mp)
 {
+       char *origin = NULL;
+       char buff[12];
+
        if (mp->flush_on_last_del == FLUSH_IN_PROGRESS) {
                condlog(0, "flush_on_last_del in progress");
                mp->no_path_retry = NO_PATH_RETRY_FAIL;
                return 0;
        }
-       if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
-               mp->no_path_retry = mp->mpe->no_path_retry;
-               condlog(3, "%s: no_path_retry = %i (multipath setting)",
-                       mp->alias, mp->no_path_retry);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
-               mp->no_path_retry = mp->hwe->no_path_retry;
-               condlog(3, "%s: no_path_retry = %i (controller setting)",
-                       mp->alias, mp->no_path_retry);
-               return 0;
-       }
-       if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
-               mp->no_path_retry = conf->no_path_retry;
-               condlog(3, "%s: no_path_retry = %i (config file default)",
-                       mp->alias, mp->no_path_retry);
-               return 0;
-       }
-       if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
-               condlog(3, "%s: no_path_retry = %i (inherited setting)",
-                       mp->alias, mp->no_path_retry);
+       mp_set_mpe(no_path_retry);
+       mp_set_ovr(no_path_retry);
+       mp_set_hwe(no_path_retry);
+       mp_set_conf(no_path_retry);
+out:
+       print_no_path_retry(buff, 12, &mp->no_path_retry);
+       if (origin)
+               condlog(3, "%s: no_path_retry = %s %s", mp->alias, buff,
+                       origin);
+       else if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
+               condlog(3, "%s: no_path_retry = %s (inheritied setting)",
+                       mp->alias, buff);
        else
-               condlog(3, "%s: no_path_retry = %i (internal default)",
-                       mp->alias, mp->no_path_retry);
+               condlog(3, "%s: no_path_retry = undef (internal default)",
+                       mp->alias);
        return 0;
 }
 
 int
 select_minio_rq (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->minio_rq) {
-               mp->minio = mp->mpe->minio_rq;
-               condlog(3, "%s: minio = %i rq (LUN setting)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->minio_rq) {
-               mp->minio = mp->hwe->minio_rq;
-               condlog(3, "%s: minio = %i rq (controller setting)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       if (conf->minio) {
-               mp->minio = conf->minio_rq;
-               condlog(3, "%s: minio = %i rq (config file default)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       mp->minio = DEFAULT_MINIO_RQ;
-       condlog(3, "%s: minio = %i rq (internal default)",
-               mp->alias, mp->minio);
+       char *origin;
+
+       do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
+       do_set(minio_rq, conf->overrides, mp->minio, "(overrides setting)");
+       do_set(minio_rq, mp->hwe, mp->minio, "(controller setting)");
+       do_set(minio_rq, conf, mp->minio, "(config file setting)");
+       do_default(mp->minio, DEFAULT_MINIO_RQ);
+out:
+       condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
        return 0;
 }
 
 int
 select_minio_bio (struct multipath * mp)
 {
-       if (mp->mpe && mp->mpe->minio) {
-               mp->minio = mp->mpe->minio;
-               condlog(3, "%s: minio = %i (LUN setting)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->minio) {
-               mp->minio = mp->hwe->minio;
-               condlog(3, "%s: minio = %i (controller setting)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       if (conf->minio) {
-               mp->minio = conf->minio;
-               condlog(3, "%s: minio = %i (config file default)",
-                       mp->alias, mp->minio);
-               return 0;
-       }
-       mp->minio = DEFAULT_MINIO;
-       condlog(3, "%s: minio = %i (internal default)",
-               mp->alias, mp->minio);
+       char *origin;
+
+       mp_set_mpe(minio);
+       mp_set_ovr(minio);
+       mp_set_hwe(minio);
+       mp_set_conf(minio);
+       mp_set_default(minio, DEFAULT_MINIO);
+out:
+       condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
        return 0;
 }
 
@@ -560,164 +504,158 @@ select_minio (struct multipath * mp)
 extern int
 select_fast_io_fail(struct multipath *mp)
 {
-       if (mp->hwe && mp->hwe->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
-               mp->fast_io_fail = mp->hwe->fast_io_fail;
-               if (mp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
-                       condlog(3, "%s: fast_io_fail_tmo = off "
-                               "(controller setting)", mp->alias);
-               else
-                       condlog(3, "%s: fast_io_fail_tmo = %d "
-                               "(controller setting)", 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_UNSET) {
-               mp->fast_io_fail = conf->fast_io_fail;
-               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 == MP_FAST_IO_FAIL_ZERO ? 0 : mp->fast_io_fail);
-               return 0;
-       }
-       mp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
+       char *origin, buff[12];
+
+       mp_set_ovr(fast_io_fail);
+       mp_set_hwe(fast_io_fail);
+       mp_set_conf(fast_io_fail);
+       mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
+out:
+       print_fast_io_fail(buff, 12, &mp->fast_io_fail);
+       condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin);
        return 0;
 }
 
 extern int
 select_dev_loss(struct multipath *mp)
 {
-       if (mp->hwe && mp->hwe->dev_loss) {
-               mp->dev_loss = mp->hwe->dev_loss;
-               condlog(3, "%s: dev_loss_tmo = %u (controller default)",
-                       mp->alias, mp->dev_loss);
-               return 0;
-       }
-       if (conf->dev_loss) {
-               mp->dev_loss = conf->dev_loss;
-               condlog(3, "%s: dev_loss_tmo = %u (config file default)",
-                       mp->alias, mp->dev_loss);
-               return 0;
-       }
+       char *origin, buff[12];
+
+       mp_set_ovr(dev_loss);
+       mp_set_hwe(dev_loss);
+       mp_set_conf(dev_loss);
        mp->dev_loss = 0;
        return 0;
+out:
+       print_dev_loss(buff, 12, &mp->dev_loss);
+       condlog(3, "%s: dev_loss_tmo = %s %s", mp->alias, buff, origin);
+       return 0;
 }
 
 extern int
 select_flush_on_last_del(struct multipath *mp)
 {
+       char *origin;
+
        if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
                return 0;
-       if (mp->mpe && mp->mpe->flush_on_last_del != FLUSH_UNDEF) {
-               mp->flush_on_last_del = mp->mpe->flush_on_last_del;
-               condlog(3, "%s: flush_on_last_del = %i (multipath setting)",
-                       mp->alias, mp->flush_on_last_del);
-               return 0;
-       }
-       if (mp->hwe && mp->hwe->flush_on_last_del != FLUSH_UNDEF) {
-               mp->flush_on_last_del = mp->hwe->flush_on_last_del;
-               condlog(3, "%s: flush_on_last_del = %i (controler setting)",
-                       mp->alias, mp->flush_on_last_del);
-               return 0;
-       }
-       if (conf->flush_on_last_del != FLUSH_UNDEF) {
-               mp->flush_on_last_del = conf->flush_on_last_del;
-               condlog(3, "%s: flush_on_last_del = %i (config file default)",
-                       mp->alias, mp->flush_on_last_del);
-               return 0;
-       }
-       mp->flush_on_last_del = FLUSH_UNDEF;
-       condlog(3, "%s: flush_on_last_del = DISABLED (internal default)",
-               mp->alias);
+       mp_set_mpe(flush_on_last_del);
+       mp_set_ovr(flush_on_last_del);
+       mp_set_hwe(flush_on_last_del);
+       mp_set_conf(flush_on_last_del);
+       mp_set_default(flush_on_last_del, FLUSH_DISABLED);
+out:
+       condlog(3, "%s: flush_on_last_del = %s %s", mp->alias,
+               (mp->flush_on_last_del == FLUSH_ENABLED)? "yes" : "no", origin);
        return 0;
 }
 
 extern int
 select_reservation_key (struct multipath * mp)
 {
-       int j;
-       unsigned char *keyp;
-       uint64_t prkey = 0;
+       char *origin, buff[12];
 
+       mp_set_mpe(reservation_key);
+       mp_set_conf(reservation_key);
        mp->reservation_key = NULL;
-
-       if (mp->mpe && mp->mpe->reservation_key) {
-               keyp =  mp->mpe->reservation_key;
-               for (j = 0; j < 8; ++j) {
-                       if (j > 0)
-                               prkey <<= 8;
-                       prkey |= *keyp;
-                       ++keyp;
-               }
-
-               condlog(3, "%s: reservation_key = 0x%" PRIx64 " "
-                               "(multipath setting)",  mp->alias, prkey);
-
-               mp->reservation_key = mp->mpe->reservation_key;
-               return 0;
-       }
-
-       if (conf->reservation_key) {
-               keyp = conf->reservation_key;
-               for (j = 0; j < 8; ++j) {
-                       if (j > 0)
-                               prkey <<= 8;
-                       prkey |= *keyp;
-                       ++keyp;
-               }
-
-               condlog(3, "%s: reservation_key  = 0x%" PRIx64
-                               " (config file default)", mp->alias, prkey);
-
-               mp->reservation_key = conf->reservation_key;
-               return 0;
-       }
-
+       return 0;
+out:
+       print_reservation_key(buff, 12, &mp->reservation_key);
+       condlog(3, "%s: reservation_key = %s %s", mp->alias, buff, origin);
        return 0;
 }
 
 extern int
 select_retain_hwhandler (struct multipath * mp)
 {
+       char *origin;
        unsigned int minv_dm_retain[3] = {1, 5, 0};
 
        if (!VERSION_GE(conf->version, minv_dm_retain)) {
                mp->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-               condlog(3, "%s: retain_attached_hw_handler disabled (requires kernel version >= 1.5.0)", mp->alias);
-               return 0;
-       }
-
-       if (mp->hwe && mp->hwe->retain_hwhandler) {
-               mp->retain_hwhandler = mp->hwe->retain_hwhandler;
-               condlog(3, "%s: retain_attached_hw_handler = %d (controller default)", mp->alias, mp->retain_hwhandler);
-               return 0;
-       }
-       if (conf->retain_hwhandler) {
-               mp->retain_hwhandler = conf->retain_hwhandler;
-               condlog(3, "%s: retain_attached_hw_handler = %d (config file default)", mp->alias, mp->retain_hwhandler);
-               return 0;
+               origin = "(requires kernel version >= 1.5.0)";
+               goto out;
        }
-       mp->retain_hwhandler = 0;
-       condlog(3, "%s: retain_attached_hw_handler = %d (compiled in default)", mp->alias, mp->retain_hwhandler);
+       mp_set_ovr(retain_hwhandler);
+       mp_set_hwe(retain_hwhandler);
+       mp_set_conf(retain_hwhandler);
+       mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
+out:
+       condlog(3, "%s: retain_attached_hw_handler = %s %s", mp->alias,
+               (mp->retain_hwhandler == RETAIN_HWHANDLER_ON)? "yes" : "no",
+               origin);
        return 0;
 }
 
 extern int
 select_detect_prio (struct path * pp)
 {
-       if (pp->hwe && pp->hwe->detect_prio) {
-               pp->detect_prio = pp->hwe->detect_prio;
-               condlog(3, "%s: detect_prio = %d (controller default)", pp->dev, pp->detect_prio);
-               return 0;
-       }
-       if (conf->detect_prio) {
-               pp->detect_prio = conf->detect_prio;
-               condlog(3, "%s: detect_prio = %d (config file default)", pp->dev, pp->detect_prio);
+       char *origin;
+
+       pp_set_ovr(detect_prio);
+       pp_set_hwe(detect_prio);
+       pp_set_conf(detect_prio);
+       pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
+out:
+       condlog(3, "%s: detect_prio = %s %s", pp->dev,
+               (pp->detect_prio == DETECT_PRIO_ON)? "yes" : "no", origin);
+       return 0;
+}
+
+extern int
+select_deferred_remove (struct multipath *mp)
+{
+       char *origin;
+
+#ifndef LIBDM_API_DEFERRED
+       mp->deferred_remove = DEFERRED_REMOVE_OFF;
+       origin = "(not compiled with support)";
+       goto out;
+#endif
+       if (mp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) {
+               condlog(3, "%s: deferred remove in progress", mp->alias);
                return 0;
        }
-       pp->detect_prio = 0;
-       condlog(3, "%s: detect_prio = %d (compiled in default)", pp->dev, pp->detect_prio);
+       mp_set_mpe(deferred_remove);
+       mp_set_ovr(deferred_remove);
+       mp_set_hwe(deferred_remove);
+       mp_set_conf(deferred_remove);
+       mp_set_default(deferred_remove, DEFAULT_DEFERRED_REMOVE);
+out:
+       condlog(3, "%s: deferred_remove = %s %s", mp->alias,
+               (mp->deferred_remove == DEFERRED_REMOVE_ON)? "yes" : "no",
+               origin);
+       return 0;
+}
+
+extern int
+select_delay_watch_checks(struct multipath *mp)
+{
+       char *origin, buff[12];
+
+       mp_set_mpe(delay_watch_checks);
+       mp_set_ovr(delay_watch_checks);
+       mp_set_hwe(delay_watch_checks);
+       mp_set_conf(delay_watch_checks);
+       mp_set_default(delay_watch_checks, DEFAULT_DELAY_CHECKS);
+out:
+       print_delay_checks(buff, 12, &mp->delay_watch_checks);
+       condlog(3, "%s: delay_watch_checks = %s %s", mp->alias, buff, origin);
+       return 0;
+}
+
+extern int
+select_delay_wait_checks(struct multipath *mp)
+{
+       char *origin, buff[12];
+
+       mp_set_mpe(delay_wait_checks);
+       mp_set_ovr(delay_wait_checks);
+       mp_set_hwe(delay_wait_checks);
+       mp_set_conf(delay_wait_checks);
+       mp_set_default(delay_wait_checks, DEFAULT_DELAY_CHECKS);
+out:
+       print_delay_checks(buff, 12, &mp->delay_wait_checks);
+       condlog(3, "%s: delay_wait_checks = %s %s", mp->alias, buff, origin);
        return 0;
 }
index 05c6a4ec25fcc106098d8043ded273b975ea8d43..f9598e74e0e22445adf60cbe6f1b2ff1adff3d15 100644 (file)
@@ -19,3 +19,6 @@ int select_dev_loss(struct multipath *mp);
 int select_reservation_key(struct multipath *mp);
 int select_retain_hwhandler (struct multipath * mp);
 int select_detect_prio(struct path * pp);
+int select_deferred_remove(struct multipath *mp);
+int select_delay_watch_checks (struct multipath * mp);
+int select_delay_wait_checks (struct multipath * mp);
index 049f17dd720886bac0b7f30ca7204cbff6e574be..0538327a3ac03c246fff43a0437a90057085fc46 100644 (file)
 #include "blacklist.h"
 #include "prio.h"
 
+struct adapter_group *
+alloc_adaptergroup(void)
+{
+       struct adapter_group *agp;
+
+       agp = (struct adapter_group *)MALLOC(sizeof(struct adapter_group));
+
+       if (!agp)
+               return NULL;
+
+       agp->host_groups = vector_alloc();
+       if (!agp->host_groups) {
+               FREE(agp);
+               agp = NULL;
+       }
+       return agp;
+}
+
+void free_adaptergroup(vector adapters)
+{
+       int i;
+       struct adapter_group *agp;
+
+       vector_foreach_slot(adapters, agp, i) {
+               free_hostgroup(agp->host_groups);
+               FREE(agp);
+       }
+       vector_free(adapters);
+}
+
+void free_hostgroup(vector hostgroups)
+{
+       int i;
+       struct host_group *hgp;
+
+       if (!hostgroups)
+               return;
+
+       vector_foreach_slot(hostgroups, hgp, i) {
+               vector_free(hgp->paths);
+               FREE(hgp);
+       }
+       vector_free(hostgroups);
+}
+
+struct host_group *
+alloc_hostgroup(void)
+{
+       struct host_group *hgp;
+
+       hgp = (struct host_group *)MALLOC(sizeof(struct host_group));
+
+       if (!hgp)
+               return NULL;
+
+       hgp->paths = vector_alloc();
+
+       if (!hgp->paths) {
+               FREE(hgp);
+               hgp = NULL;
+       }
+       return hgp;
+}
+
 struct path *
 alloc_path (void)
 {
@@ -142,10 +206,7 @@ free_multipath_attributes (struct multipath * mpp)
        if (!mpp)
                return;
 
-       if (mpp->selector &&
-           mpp->selector != conf->selector &&
-           (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
-           (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
+       if (mpp->selector) {
                FREE(mpp->selector);
                mpp->selector = NULL;
        }
@@ -155,9 +216,7 @@ free_multipath_attributes (struct multipath * mpp)
                mpp->features = NULL;
        }
 
-       if (mpp->hwhandler &&
-           mpp->hwhandler != conf->hwhandler &&
-           (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
+       if (mpp->hwhandler) {
                FREE(mpp->hwhandler);
                mpp->hwhandler = NULL;
        }
@@ -242,6 +301,26 @@ store_pathgroup (vector pgvec, struct pathgroup * pgp)
        return 0;
 }
 
+int
+store_hostgroup(vector hostgroupvec, struct host_group * hgp)
+{
+       if (!vector_alloc_slot(hostgroupvec))
+               return 1;
+
+       vector_set_slot(hostgroupvec, hgp);
+       return 0;
+}
+
+int
+store_adaptergroup(vector adapters, struct adapter_group * agp)
+{
+       if (!vector_alloc_slot(adapters))
+               return 1;
+
+       vector_set_slot(adapters, agp);
+       return 0;
+}
+
 struct multipath *
 find_mp_by_minor (vector mpvec, int minor)
 {
index 64de06e6c039ccfc4e45f5baa77f7fa2cfa37f8d..ab7dc258c68ac4456cd58f1204922f9f37f17446 100644 (file)
@@ -15,7 +15,8 @@
 #define BLK_DEV_SIZE           33
 #define PATH_SIZE              512
 #define NAME_SIZE              512
-
+#define HOST_NAME_LEN          16
+#define SLOT_NAME_SIZE         40
 
 #define SCSI_VENDOR_SIZE       9
 #define SCSI_PRODUCT_SIZE      17
@@ -66,15 +67,15 @@ enum pgstates {
        PGSTATE_ACTIVE
 };
 
-enum queue_without_daemon_states {
-       QUE_NO_DAEMON_OFF,
-       QUE_NO_DAEMON_ON,
-       QUE_NO_DAEMON_FORCE,
+enum yes_no_states {
+       YN_NO,
+       YN_YES,
 };
 
-enum pgtimeouts {
-       PGTIMEOUT_UNDEF,
-       PGTIMEOUT_NONE
+enum queue_without_daemon_states {
+       QUE_NO_DAEMON_OFF = YN_NO,
+       QUE_NO_DAEMON_ON = YN_YES,
+       QUE_NO_DAEMON_FORCE,
 };
 
 enum attribute_bits {
@@ -83,10 +84,16 @@ enum attribute_bits {
        ATTR_MODE,
 };
 
+enum yes_no_undef_states {
+       YNU_UNDEF,
+       YNU_NO,
+       YNU_YES,
+};
+
 enum flush_states {
-       FLUSH_UNDEF,
-       FLUSH_DISABLED,
-       FLUSH_ENABLED,
+       FLUSH_UNDEF = YNU_UNDEF,
+       FLUSH_DISABLED = YNU_NO,
+       FLUSH_ENABLED = YNU_YES,
        FLUSH_IN_PROGRESS,
 };
 
@@ -96,21 +103,28 @@ enum log_checker_err_states {
 };
 
 enum user_friendly_names_states {
-       USER_FRIENDLY_NAMES_UNDEF,
-       USER_FRIENDLY_NAMES_OFF,
-       USER_FRIENDLY_NAMES_ON,
+       USER_FRIENDLY_NAMES_UNDEF = YNU_UNDEF,
+       USER_FRIENDLY_NAMES_OFF = YNU_NO,
+       USER_FRIENDLY_NAMES_ON = YNU_YES,
 };
 
 enum retain_hwhandler_states {
-       RETAIN_HWHANDLER_UNDEF,
-       RETAIN_HWHANDLER_OFF,
-       RETAIN_HWHANDLER_ON,
+       RETAIN_HWHANDLER_UNDEF = YNU_UNDEF,
+       RETAIN_HWHANDLER_OFF = YNU_NO,
+       RETAIN_HWHANDLER_ON = YNU_YES,
 };
 
 enum detect_prio_states {
-       DETECT_PRIO_UNDEF,
-       DETECT_PRIO_OFF,
-       DETECT_PRIO_ON,
+       DETECT_PRIO_UNDEF = YNU_UNDEF,
+       DETECT_PRIO_OFF = YNU_NO,
+       DETECT_PRIO_ON = YNU_YES,
+};
+
+enum deferred_remove_states {
+       DEFERRED_REMOVE_UNDEF = YNU_UNDEF,
+       DEFERRED_REMOVE_OFF = YNU_NO,
+       DEFERRED_REMOVE_ON = YNU_YES,
+       DEFERRED_REMOVE_IN_PROGRESS,
 };
 
 enum scsi_protocol {
@@ -126,6 +140,18 @@ enum scsi_protocol {
        SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
 };
 
+enum delay_checks_states {
+       DELAY_CHECKS_OFF = -1,
+       DELAY_CHECKS_UNDEF = 0,
+};
+
+enum initialized_states {
+       INIT_FAILED,
+       INIT_MISSING_UDEV,
+       INIT_REQUESTED_UDEV,
+       INIT_OK,
+};
+
 struct sg_id {
        int host_no;
        int channel;
@@ -172,6 +198,9 @@ struct path {
        int priority;
        int pgindex;
        int detect_prio;
+       int watch_checks;
+       int wait_checks;
+       int tpgs;
        char * uid_attribute;
        char * getuid;
        struct prio prio;
@@ -179,6 +208,8 @@ struct path {
        struct checker checker;
        struct multipath * mpp;
        int fd;
+       int initialized;
+       int retriggers;
 
        /* configlet pointers */
        struct hwentry * hwe;
@@ -195,6 +226,8 @@ struct multipath {
        int bestpg;
        int queuedio;
        int action;
+       int wait_for_udev;
+       int uev_wait_tick;
        int pgfailback;
        int failback_tick;
        int rr_weight;
@@ -206,6 +239,9 @@ struct multipath {
        int attribute_flags;
        int fast_io_fail;
        int retain_hwhandler;
+       int deferred_remove;
+       int delay_watch_checks;
+       int delay_wait_checks;
        unsigned int dev_loss;
        uid_t uid;
        gid_t gid;
@@ -251,6 +287,20 @@ struct pathgroup {
        char * selector;
 };
 
+struct adapter_group {
+       char adapter_name[SLOT_NAME_SIZE];
+       struct pathgroup *pgp;
+       int num_hosts;
+       vector host_groups;
+       int next_host_index;
+};
+
+struct host_group {
+       int host_no;
+       int num_paths;
+       vector paths;
+};
+
 struct path * alloc_path (void);
 struct pathgroup * alloc_pathgroup (void);
 struct multipath * alloc_multipath (void);
@@ -263,6 +313,14 @@ void free_multipath_attributes (struct multipath *);
 void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths);
 void free_multipathvec (vector mpvec, enum free_path_mode free_paths);
 
+struct adapter_group * alloc_adaptergroup(void);
+struct host_group * alloc_hostgroup(void);
+void free_adaptergroup(vector adapters);
+void free_hostgroup(vector hostgroups);
+
+int store_adaptergroup(vector adapters, struct adapter_group *agp);
+int store_hostgroup(vector hostgroupvec, struct host_group *hgp);
+
 int store_path (vector pathvec, struct path * pp);
 int store_pathgroup (vector pgvec, struct pathgroup * pgp);
 
index 76c7e0204f74ced256b7a1da057eb60e682a07a9..d9a731ab0c68455f94e04c3773c0eddf76f8317b 100644 (file)
@@ -8,6 +8,7 @@
 #include "debug.h"
 #include "structs.h"
 #include "structs_vec.h"
+#include "sysfs.h"
 #include "waiter.h"
 #include "devmapper.h"
 #include "dmparser.h"
@@ -226,6 +227,12 @@ extract_hwe_from_path(struct multipath * mpp)
        }
 
        if (pp) {
+               if (!strlen(pp->vendor_id) ||
+                   !strlen(pp->product_id) ||
+                   !strlen(pp->rev)) {
+                       condlog(3, "%s: no device details available", pp->dev);
+                       return NULL;
+               }
                condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
                condlog(3, "%s: product = %s", pp->dev, pp->product_id);
                condlog(3, "%s: rev = %s", pp->dev, pp->rev);
@@ -281,12 +288,38 @@ update_multipath_status (struct multipath *mpp)
        return 0;
 }
 
+void sync_paths(struct multipath *mpp, vector pathvec)
+{
+       struct path *pp;
+       struct pathgroup  *pgp;
+       int found, i, j;
+
+       vector_foreach_slot (mpp->paths, pp, i) {
+               found = 0;
+               vector_foreach_slot(mpp->pg, pgp, j) {
+                       if (find_slot(pgp->paths, (void *)pp) != -1) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
+                       vector_del_slot(mpp->paths, i--);
+                       orphan_path(pp, "path removed externally");
+               }
+       }
+       update_mpp_paths(mpp, pathvec);
+       vector_foreach_slot (mpp->paths, pp, i)
+               pp->mpp = mpp;
+}
+
 extern int
 update_multipath_strings (struct multipath *mpp, vector pathvec)
 {
        if (!mpp)
                return 1;
 
+       update_mpp_paths(mpp, pathvec);
        condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
 
        free_multipath_attributes(mpp);
@@ -295,6 +328,7 @@ update_multipath_strings (struct multipath *mpp, vector pathvec)
 
        if (update_multipath_table(mpp, pathvec))
                return 1;
+       sync_paths(mpp, pathvec);
 
        if (update_multipath_status(mpp))
                return 1;
@@ -365,6 +399,8 @@ __setup_multipath (struct vectors * vecs, struct multipath * mpp, int reset)
                select_pgfailback(mpp);
                set_no_path_retry(mpp);
                select_flush_on_last_del(mpp);
+               if (VECTOR_SIZE(mpp->paths) != 0)
+                       dm_cancel_deferred_remove(mpp);
        }
 
        return 0;
@@ -403,12 +439,29 @@ out:
        return NULL;
 }
 
+static void
+find_existing_alias (struct multipath * mpp,
+                    struct vectors *vecs)
+{
+       struct multipath * mp;
+       int i;
+
+       vector_foreach_slot (vecs->mpvec, mp, i)
+               if (strcmp(mp->wwid, mpp->wwid) == 0) {
+                       strncpy(mpp->alias_old, mp->alias, WWID_SIZE);
+                       return;
+               }
+}
+
 extern struct multipath *
 add_map_with_path (struct vectors * vecs,
                   struct path * pp, int add_vec)
 {
        struct multipath * mpp;
 
+       if (!strlen(pp->wwid))
+               return NULL;
+
        if (!(mpp = alloc_multipath()))
                return NULL;
 
@@ -416,6 +469,7 @@ add_map_with_path (struct vectors * vecs,
        mpp->hwe = pp->hwe;
 
        strcpy(mpp->wwid, pp->wwid);
+       find_existing_alias(mpp, vecs);
        if (select_alias(mpp))
                goto out;
        mpp->size = pp->size;
@@ -438,7 +492,7 @@ out:
 }
 
 extern int
-verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
+verify_paths(struct multipath * mpp, struct vectors * vecs)
 {
        struct path * pp;
        int count = 0;
@@ -451,7 +505,8 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
                /*
                 * see if path is in sysfs
                 */
-               if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE) <= 0) {
+               if (sysfs_attr_get_value(pp->udev, "dev",
+                                        pp->dev_t, BLK_DEV_SIZE) < 0) {
                        if (pp->state != PATH_DOWN) {
                                condlog(1, "%s: removing valid path %s in state %d",
                                        mpp->alias, pp->dev, pp->state);
@@ -463,14 +518,10 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
                        vector_del_slot(mpp->paths, i);
                        i--;
 
-                       if (rpvec)
-                               store_path(rpvec, pp);
-                       else {
-                               if ((j = find_slot(vecs->pathvec,
-                                                  (void *)pp)) != -1)
-                                       vector_del_slot(vecs->pathvec, j);
-                               free_path(pp);
-                       }
+                       if ((j = find_slot(vecs->pathvec,
+                                          (void *)pp)) != -1)
+                               vector_del_slot(vecs->pathvec, j);
+                       free_path(pp);
                } else {
                        condlog(4, "%s: verified path %s dev_t %s",
                                mpp->alias, pp->dev, pp->dev_t);
@@ -493,13 +544,9 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset)
                return 2;
        }
 
-       free_pgvec(mpp->pg, KEEP_PATHS);
-       mpp->pg = NULL;
-
        if (__setup_multipath(vecs, mpp, reset))
                return 1; /* mpp freed in setup_multipath */
 
-       adopt_paths(vecs->pathvec, mpp, 0);
        /*
         * compare checkers states with DM states
         */
@@ -510,7 +557,7 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset)
 
                        if (pp->state != PATH_DOWN) {
                                int oldstate = pp->state;
-                               condlog(2, "%s: mark as failed", pp->dev_t);
+                               condlog(2, "%s: mark as failed", pp->dev);
                                mpp->stat_path_failures++;
                                pp->state = PATH_DOWN;
                                if (oldstate == PATH_UP ||
@@ -526,7 +573,6 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset)
                        }
                }
        }
-
        return 0;
 }
 
index c6278ac7b91e76abfa8c12bf2316ef764e495f4c..eb8e672473528ef4dff6ebd6a2a70b49e1b5f091 100644 (file)
@@ -19,7 +19,7 @@ int adopt_paths (vector pathvec, struct multipath * mpp, int get_info);
 void orphan_paths (vector pathvec, struct multipath * mpp);
 void orphan_path (struct path * pp, const char *reason);
 
-int verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec);
+int verify_paths(struct multipath * mpp, struct vectors * vecs);
 int update_mpp_paths(struct multipath * mpp, vector pathvec);
 int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
                       int reset);
index e5834f996ca5657e42dde95b4c385ebb61e580a3..de7df405f4f2d21447dbaefcb026dfc6e068eab2 100644 (file)
@@ -74,6 +74,61 @@ ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
                return -EPERM;
        }
 
+       /* read attribute value */
+       fd = open(devpath, O_RDONLY);
+       if (fd < 0) {
+               condlog(4, "attribute '%s' can not be opened: %s",
+                       devpath, strerror(errno));
+               return -errno;
+       }
+       size = read(fd, value, value_len);
+       if (size < 0) {
+               condlog(4, "read from %s failed: %s", devpath, strerror(errno));
+               size = -errno;
+       } else if (size == value_len) {
+               condlog(4, "overflow while reading from %s", devpath);
+               size = 0;
+       } else {
+               value[size] = '\0';
+       }
+
+       close(fd);
+       if (size > 0)
+               size = strchop(value);
+       return size;
+}
+
+ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name,
+                                unsigned char * value, size_t value_len)
+{
+       char devpath[PATH_SIZE];
+       struct stat statbuf;
+       int fd;
+       ssize_t size = -1;
+
+       if (!dev || !attr_name || !value)
+               return 0;
+
+       snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
+                attr_name);
+       condlog(4, "open '%s'", devpath);
+       if (stat(devpath, &statbuf) != 0) {
+               condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
+               return -ENXIO;
+       }
+
+       /* skip directories */
+       if (S_ISDIR(statbuf.st_mode)) {
+               condlog(4, "%s is a directory", devpath);
+               return -EISDIR;
+       }
+
+       /* skip non-writeable files */
+       if ((statbuf.st_mode & S_IRUSR) == 0) {
+               condlog(4, "%s is not readable", devpath);
+               return -EPERM;
+       }
+
        /* read attribute value */
        fd = open(devpath, O_RDONLY);
        if (fd < 0) {
@@ -156,7 +211,7 @@ sysfs_get_size (struct path *pp, unsigned long long * size)
                return 1;
 
        attr[0] = '\0';
-       if (sysfs_attr_get_value(pp->udev, "size", attr, 255) == 0) {
+       if (sysfs_attr_get_value(pp->udev, "size", attr, 255) <= 0) {
                condlog(3, "%s: No size attribute in sysfs", pp->dev);
                return 1;
        }
index 34f3e00082f43decad7dc6f8ec777481349760cb..2588c247ffcfd7ce7eb56f76581df56fc391e57f 100644 (file)
@@ -9,6 +9,8 @@ ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
                             char * value, size_t value_len);
 ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name,
                             char * value, size_t value_len);
+ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name,
+                                unsigned char * value, size_t value_len);
 int sysfs_get_size (struct path *pp, unsigned long long * size);
 int sysfs_check_holders(char * check_devt, char * new_devt);
 #endif
index 9ee3ade64d898269476d8c22f3024c2f1eeb39fa..478c6cef74d2ad43679dc57151e07d6e63834f3d 100644 (file)
 #include <sys/socket.h>
 #include <sys/user.h>
 #include <sys/un.h>
+#include <sys/poll.h>
 #include <linux/types.h>
 #include <linux/netlink.h>
 #include <pthread.h>
+#include <signal.h>
 #include <limits.h>
 #include <sys/mman.h>
 #include <libudev.h>
@@ -182,6 +184,80 @@ int uevent_dispatch(int (*uev_trigger)(struct uevent *, void * trigger_data),
        return 0;
 }
 
+struct uevent *uevent_from_buffer(char *buf, ssize_t buflen)
+{
+       struct uevent *uev;
+       char *buffer;
+       size_t bufpos;
+       int i;
+       char *pos;
+
+       uev = alloc_uevent();
+       if (!uev) {
+               condlog(1, "lost uevent, oom");
+               return NULL;
+       }
+
+       if ((size_t)buflen > sizeof(buf)-1)
+               buflen = sizeof(buf)-1;
+
+       /*
+        * Copy the shared receive buffer contents to buffer private
+        * to this uevent so we can immediately reuse the shared buffer.
+        */
+       memcpy(uev->buffer, buf, HOTPLUG_BUFFER_SIZE + OBJECT_SIZE);
+       buffer = uev->buffer;
+       buffer[buflen] = '\0';
+
+       /* save start of payload */
+       bufpos = strlen(buffer) + 1;
+
+       /* action string */
+       uev->action = buffer;
+       pos = strchr(buffer, '@');
+       if (!pos) {
+               condlog(3, "bad action string '%s'", buffer);
+               FREE(uev);
+               return NULL;
+       }
+       pos[0] = '\0';
+
+       /* sysfs path */
+       uev->devpath = &pos[1];
+
+       /* hotplug events have the environment attached - reconstruct envp[] */
+       for (i = 0; (bufpos < (size_t)buflen) && (i < HOTPLUG_NUM_ENVP-1); i++) {
+               int keylen;
+               char *key;
+
+               key = &buffer[bufpos];
+               keylen = strlen(key);
+               uev->envp[i] = key;
+               /* Filter out sequence number */
+               if (strncmp(key, "SEQNUM=", 7) == 0) {
+                       char *eptr;
+
+                       uev->seqnum = strtoul(key + 7, &eptr, 10);
+                       if (eptr == key + 7)
+                               uev->seqnum = -1;
+               }
+               bufpos += keylen + 1;
+       }
+       uev->envp[i] = NULL;
+
+       condlog(3, "uevent %ld '%s' from '%s'", uev->seqnum,
+               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]);
+
+       return uev;
+}
+
 int failback_listen(void)
 {
        int sock;
@@ -266,12 +342,9 @@ int failback_listen(void)
        }
 
        while (1) {
-               int i;
-               char *pos;
                size_t bufpos;
                ssize_t buflen;
                struct uevent *uev;
-               char *buffer;
                struct msghdr smsg;
                struct iovec iov;
                char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
@@ -324,69 +397,9 @@ int failback_listen(void)
                        buflen = sizeof(buf)-1;
                }
 
-               uev = alloc_uevent();
-
-               if (!uev) {
-                       condlog(1, "lost uevent, oom");
+               uev = uevent_from_buffer(buf, buflen);
+               if (!uev)
                        continue;
-               }
-
-               if ((size_t)buflen > sizeof(buf)-1)
-                       buflen = sizeof(buf)-1;
-
-               /*
-                * Copy the shared receive buffer contents to buffer private
-                * to this uevent so we can immediately reuse the shared buffer.
-                */
-               memcpy(uev->buffer, buf, HOTPLUG_BUFFER_SIZE + OBJECT_SIZE);
-               buffer = uev->buffer;
-               buffer[buflen] = '\0';
-
-               /* save start of payload */
-               bufpos = strlen(buffer) + 1;
-
-               /* action string */
-               uev->action = buffer;
-               pos = strchr(buffer, '@');
-               if (!pos) {
-                       condlog(3, "bad action string '%s'", buffer);
-                       continue;
-               }
-               pos[0] = '\0';
-
-               /* sysfs path */
-               uev->devpath = &pos[1];
-
-               /* hotplug events have the environment attached - reconstruct envp[] */
-               for (i = 0; (bufpos < (size_t)buflen) && (i < HOTPLUG_NUM_ENVP-1); i++) {
-                       int keylen;
-                       char *key;
-
-                       key = &buffer[bufpos];
-                       keylen = strlen(key);
-                       uev->envp[i] = key;
-                       /* Filter out sequence number */
-                       if (strncmp(key, "SEQNUM=", 7) == 0) {
-                               char *eptr;
-
-                               uev->seqnum = strtoul(key + 7, &eptr, 10);
-                               if (eptr == key + 7)
-                                       uev->seqnum = -1;
-                       }
-                       bufpos += keylen + 1;
-               }
-               uev->envp[i] = NULL;
-
-               condlog(3, "uevent %ld '%s' from '%s'", uev->seqnum,
-                       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.
                 */
@@ -401,12 +414,72 @@ exit:
        return 1;
 }
 
+struct uevent *uevent_from_udev_device(struct udev_device *dev)
+{
+       struct uevent *uev;
+       int i = 0;
+       char *pos, *end;
+       struct udev_list_entry *list_entry;
+
+       uev = alloc_uevent();
+       if (!uev) {
+               udev_device_unref(dev);
+               condlog(1, "lost uevent, oom");
+               return NULL;
+       }
+       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;
+       }
+       uev->udev = 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]);
+       return uev;
+}
+
 int uevent_listen(struct udev *udev)
 {
-       int err;
+       int err = 2;
        struct udev_monitor *monitor = NULL;
-       int fd, socket_flags;
+       int fd, fd_ep = -1, socket_flags, events;
        int need_failback = 1;
+       int timeout = 30;
+       sigset_t mask;
+       LIST_HEAD(uevlisten_tmp);
+
        /*
         * Queue uevents for service by dedicated thread so that the uevent
         * listening thread does not block on multipathd locks (vecs->lock)
@@ -423,7 +496,6 @@ int uevent_listen(struct udev *udev)
        monitor = udev_monitor_new_from_netlink(udev, "udev");
        if (!monitor) {
                condlog(2, "failed to create udev monitor");
-               err = 2;
                goto out;
        }
 #ifdef LIBUDEV_API_RECVBUF
@@ -455,77 +527,63 @@ int uevent_listen(struct udev *udev)
                condlog(2, "failed to enable receiving : %s", strerror(-err));
                goto out;
        }
+
+       pthread_sigmask(SIG_SETMASK, NULL, &mask);
+       sigdelset(&mask, SIGHUP);
+       sigdelset(&mask, SIGUSR1);
+       events = 0;
        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");
+               struct pollfd ev_poll;
+               struct timespec poll_timeout;
+               int fdcount;
+
+               memset(&ev_poll, 0, sizeof(struct pollfd));
+               ev_poll.fd = fd;
+               ev_poll.events = POLLIN;
+               memset(&poll_timeout, 0, sizeof(struct timespec));
+               poll_timeout.tv_sec = timeout;
+               errno = 0;
+               fdcount = ppoll(&ev_poll, 1, &poll_timeout, &mask);
+               if (fdcount && ev_poll.revents & POLLIN) {
+                       timeout = 0;
+                       dev = udev_monitor_receive_device(monitor);
+                       if (!dev) {
+                               condlog(0, "failed getting udev device");
+                               continue;
+                       }
+                       uev = uevent_from_udev_device(dev);
+                       if (!uev)
+                               continue;
+                       list_add_tail(&uev->node, &uevlisten_tmp);
+                       events++;
                        continue;
                }
-
-               uev = alloc_uevent();
-               if (!uev) {
-                       udev_device_unref(dev);
-                       condlog(1, "lost uevent, oom");
-                       continue;
+               if (fdcount < 0) {
+                       if (errno != EINTR)
+                               condlog(0, "error receiving "
+                                       "uevent message: %m");
+                       err = -errno;
+                       break;
                }
-               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;
+               if (!list_empty(&uevlisten_tmp)) {
+                       /*
+                        * Queue uevents and poke service pthread.
+                        */
+                       condlog(3, "Forwarding %d uevents", events);
+                       pthread_mutex_lock(uevq_lockp);
+                       list_splice_tail_init(&uevlisten_tmp, &uevq);
+                       pthread_cond_signal(uev_condp);
+                       pthread_mutex_unlock(uevq_lockp);
+                       events = 0;
                }
-               uev->udev = 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);
+               timeout = 30;
        }
        need_failback = 0;
 out:
+       if (fd_ep >= 0)
+               close(fd_ep);
        if (monitor)
                udev_monitor_unref(monitor);
        if (need_failback)
index 06a63118fc41dccd67d7e8caab0c9fcec4ebc66c..ac0d1b2c2029b243c13f6afba8a38e68d189489b 100644 (file)
@@ -112,7 +112,8 @@ size_t strlcpy(char *dst, const char *src, size_t size)
                bytes++;
        }
 
-       if (bytes == size)
+       /* If size == 0 there is no space for a final null... */
+       if (size)
                *q = '\0';
        return bytes;
 }
@@ -165,7 +166,7 @@ devt2devname (char *devname, int devname_len, char *devt)
                sprintf(block_path,"/sys/dev/block/%u:%u", major, minor);
                if (lstat(block_path, &statbuf) == 0) {
                        if (S_ISLNK(statbuf.st_mode) &&
-                           readlink(block_path, dev, FILE_NAME_SIZE) > 0) {
+                           readlink(block_path, dev, FILE_NAME_SIZE-1) > 0) {
                                char *p = strrchr(dev, '/');
 
                                if (!p) {
index aff7a623081fdd8740e985bdc4b3767e68be3d8a..e91abd947cb73ea63c2a63cb16b328c92f51d9f3 100644 (file)
 #ifdef USE_SYSTEMD
 #include <systemd/sd-daemon.h>
 #endif
+#include <mpath_cmd.h>
 
 #include "memory.h"
 #include "uxsock.h"
 #include "debug.h"
-
-/*
- * connect to a unix domain socket
- */
-int ux_socket_connect(const char *name)
-{
-       int fd, len;
-       struct sockaddr_un addr;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_LOCAL;
-       addr.sun_path[0] = '\0';
-       len = strlen(name) + 1 + sizeof(sa_family_t);
-       strncpy(&addr.sun_path[1], name, len);
-
-       fd = socket(AF_LOCAL, SOCK_STREAM, 0);
-       if (fd == -1) {
-               condlog(3, "Couldn't create ux_socket, error %d", errno);
-               return -1;
-       }
-
-       if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
-               condlog(3, "Couldn't connect to ux_socket, error %d", errno);
-               close(fd);
-               return -1;
-       }
-
-       return fd;
-}
-
 /*
  * create a unix domain socket and start listening on it
  * return a file descriptor open on the socket
@@ -128,7 +99,7 @@ size_t write_all(int fd, const void *buf, size_t len)
 /*
  * keep reading until its all read
  */
-size_t read_all(int fd, void *buf, size_t len)
+ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout)
 {
        size_t total = 0;
        ssize_t n;
@@ -138,21 +109,20 @@ size_t read_all(int fd, void *buf, size_t len)
        while (len) {
                pfd.fd = fd;
                pfd.events = POLLIN;
-               ret = poll(&pfd, 1, 1000);
+               ret = poll(&pfd, 1, timeout);
                if (!ret) {
-                       errno = ETIMEDOUT;
-                       return total;
+                       return -ETIMEDOUT;
                } else if (ret < 0) {
                        if (errno == EINTR)
                                continue;
-                       return total;
+                       return -errno;
                } else if (!pfd.revents & POLLIN)
                        continue;
                n = read(fd, buf, len);
                if (n < 0) {
                        if ((errno == EINTR) || (errno == EAGAIN))
                                continue;
-                       return total;
+                       return -errno;
                }
                if (!n)
                        return total;
@@ -166,7 +136,7 @@ size_t read_all(int fd, void *buf, size_t len)
 /*
  * send a packet in length prefix format
  */
-int send_packet(int fd, const char *buf, size_t len)
+int send_packet(int fd, const char *buf)
 {
        int ret = 0;
        sigset_t set, old;
@@ -176,10 +146,7 @@ int send_packet(int fd, const char *buf, size_t len)
        sigaddset(&set, SIGPIPE);
        pthread_sigmask(SIG_BLOCK, &set, &old);
 
-       if (write_all(fd, &len, sizeof(len)) != sizeof(len))
-               ret = -1;
-       if (!ret && write_all(fd, buf, len) != len)
-               ret = -1;
+       ret = mpath_send_cmd(fd, buf);
 
        /* And unblock it again */
        pthread_sigmask(SIG_SETMASK, &old, NULL);
@@ -190,25 +157,23 @@ int send_packet(int fd, const char *buf, size_t len)
 /*
  * receive a packet in length prefix format
  */
-int recv_packet(int fd, char **buf, size_t *len)
+int recv_packet(int fd, char **buf, unsigned int timeout)
 {
-       if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) {
-               (*buf) = NULL;
-               *len = 0;
-               return -1;
-       }
-       if (len == 0) {
-               (*buf) = NULL;
-               return 0;
-       }
-       (*buf) = MALLOC(*len);
+       int err;
+       ssize_t len;
+
+       *buf = NULL;
+       len = mpath_recv_reply_len(fd, timeout);
+       if (len <= 0)
+               return len;
+       (*buf) = MALLOC(len);
        if (!*buf)
-               return -1;
-       if (read_all(fd, *buf, *len) != *len) {
+               return -ENOMEM;
+       err = mpath_recv_reply_data(fd, *buf, len, timeout);
+       if (err) {
                FREE(*buf);
                (*buf) = NULL;
-               *len = 0;
-               return -1;
+               return err;
        }
        return 0;
 }
index fd825527932cd5f8d005292941478e72ddf6a7b8..c1cf81f9aa76494e83858d0777f9010c71c467ce 100644 (file)
@@ -1,7 +1,6 @@
 /* some prototypes */
-int ux_socket_connect(const char *name);
 int ux_socket_listen(const char *name);
-int send_packet(int fd, const char *buf, size_t len);
-int recv_packet(int fd, char **buf, size_t *len);
+int send_packet(int fd, const char *buf);
+int recv_packet(int fd, char **buf, unsigned int timeout);
 size_t write_all(int fd, const void *buf, size_t len);
-size_t read_all(int fd, void *buf, size_t len);
+ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout);
index 8519300c13a246458883f48c4cfd32028b216689..d8c5e6e1d93f10b698e9653f15edfd36062743b5 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef _VERSION_H
 #define _VERSION_H
 
-#define VERSION_CODE 0x000500
-#define DATE_CODE    0x0c110d
+#define VERSION_CODE 0x000600
+#define DATE_CODE    0x120410
 
 #define PROG    "multipath-tools"
 
index eca179908c445d47eaa933d62e76d7ec23561104..567c93db79c705fbae48313d9533eadfab2b4ba6 100644 (file)
@@ -260,6 +260,37 @@ out:
        return ret;
 }
 
+int
+should_multipath(struct path *pp1, vector pathvec)
+{
+       int i;
+       struct path *pp2;
+
+       if (!conf->find_multipaths && !conf->ignore_new_devs)
+               return 1;
+
+       condlog(4, "checking if %s should be multipathed", pp1->dev);
+       if (!conf->ignore_new_devs) {
+               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)
 {
index f3b21faf17d4251037c568a8b2ce69a6f8c6c8db..95270129daa0ef4e9b026a3e23a0e79510fda575 100644 (file)
@@ -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 ad8e607bd9331fee75b86141a940254fdf4437a1..6f7a5cfc0da03d7e3cda8c30189a166d9b21f682 100644 (file)
@@ -5,7 +5,7 @@ include ../Makefile.inc
 OBJS = main.o 
 
 CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) 
-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath -ludev
+LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev
 
 EXEC = mpathpersist
 
index 235e130939605c7d4fa86a1186ba51c2e0cb3fcf..0be034dea3111d5a1b6f533eb5fdd9fd87db2e11 100644 (file)
 #      #
 #      # name    : checker_timeout
 #      # scope   : multipath & multipathd
-#      # desc    : The timeout to use for path checkers that issue scsi
-#      #           commands with an explicit timeout, in seconds.
+#      # desc    : The timeout to use for path checkers and prioritizers
+#      #           that issue scsi commands with an explicit timeout, in
+#      #           seconds.
 #      # values  : n > 0
 #      # default : taken from /sys/block/sd<x>/device/timeout
 #      checker_timeout 60
 #      # default : determined by the OS
 #      dev_loss_tmo 600
 #
+#      #
 #      # name    : bindings_file
 #      # scope   : multipath
 #      # desc    : The location of the bindings file that is used with
 #      # default : "/var/lib/multipath/bindings"
 #      bindings_file "/etc/multipath/bindings"
 #
+#      #
 #      # name    : wwids_file
 #      # scope   : multipath
 #      # desc    : The location of the wwids file multipath uses to
 #      # default : "/var/lib/multipath/wwids"
 #      wwids_file "/etc/multipath/wwids"
 #
+#      #
 #      # name    : reservation_key
 #      # scope   : multipath
 #      # desc    : Service action reservation key used by mpathpersist.
 #      # default : (null)
 #      reservation_key "mpathkey"
 #
+#      #
+#      # name    : force_sync
+#      # scope   : multipathd
+#      # desc    : If set to yes, multipath will run all of the checkers in
+#      #           sync mode, even if the checker has an async mode.
+#      # values  : yes|no
+#      # default : no
+#      force_sync yes
+#
+#      #
+#      # name    : config_dir
+#      # scope   : multipath & multipathd
+#      # desc    : If not set to an empty string, multipath will search
+#      #           this directory alphabetically for files ending in ".conf"
+#      #           and it will read configuration information from these
+#      #           files, just as if it was in /etc/multipath.conf
+#      # values  : "" or a fully qualified pathname
+#      # default : "/etc/multipath/conf.d"
+#
+#      #
+#      # name    : delay_watch_checks
+#      # scope   : multipathd
+#      # desc    : If set to a value greater than 0, multipathd will watch
+#      #           paths that have recently become valid for this many
+#      #           checks.  If they fail again while they are being watched,
+#      #           when they next become valid, they will not be used until
+#      #           they have stayed up for delay_wait_checks checks.
+#      # values  : no|<n> > 0
+#      # default : no
+#      delay_watch_checks 12
+#
+#      #
+#      # name    : delay_wait_checks
+#      # scope   : multipathd
+#      # desc    : If set to a value greater than 0, when a device that has
+#      #           recently come back online fails again within
+#      #           delay_watch_checks checks, the next time it comes back
+#      #           online, it will marked and delayed, and not used until
+#      #           it has passed delay_wait_checks checks.
+#      # values  : no|<n> > 0
+#      # default : no
+#      delay_wait_checks 12
 #}
 #      
 ##
 #              # default : determined by the process
 #              gid 0
 #
+#              #
+#              # name    : delay_watch_checks
+#              # scope   : multipathd
+#              # desc    : If set to a value greater than 0, multipathd will
+#              #           watch paths that have recently become valid for
+#              #           this many checks.  If they fail again while they
+#              #           are being watched, when they next become valid,
+#              #           they will not be used until they have stayed up for
+#              #           delay_wait_checks checks.
+#              # values  : no|<n> > 0
+#              delay_watch_checks 12
+#
+#              #
+#              # name    : delay_wait_checks
+#              # scope   : multipathd
+#              # desc    : If set to a value greater than 0, when a device
+#              #           that has recently come back online fails again
+#              #           within delay_watch_checks checks, the next time it
+#              #           comes online, it will marked and delayed, and not
+#              #           used until it has passed delay_wait_checks checks.
+#              # values  : no|<n> > 0
+#              delay_wait_checks 12
 #      }
 #      multipath {
 #              wwid    1DEC_____321816758474
 ## scope : multipath & multipathd
 ## desc  : list of per storage controller settings
 ##       overrides default settings (device_maps block)
-##         overriden by per multipath settings (multipaths block)
+##        overriden by per multipath settings (multipaths block)
+##       and the overrides settings (overrides block)
 ##
 #devices {
 #      #
 #              #           before removing it from the system.
 #              # values  : n > 0
 #              dev_loss_tmo 600
+#
+#              #
+#              # name    : delay_watch_checks
+#              # scope   : multipathd
+#              # desc    : If set to a value greater than 0, multipathd will
+#              #           watch paths that have recently become valid for
+#              #           this many checks.  If they fail again while they
+#              #           are being watched, when they next become valid,
+#              #           they will not be used until they have stayed up for
+#              #           delay_wait_checks checks.
+#              # values  : no|<n> > 0
+#              delay_watch_checks 12
+#
+#              #
+#              # name    : delay_wait_checks
+#              # scope   : multipathd
+#              # desc    : If set to a value greater than 0, when a device
+#              #           that has recently come back online fails again
+#              #           within delay_watch_checks checks, the next time it
+#              #           comes online, it will marked and delayed, and not
+#              #           used until it has passed delay_wait_checks checks.
+#              # values  : no|<n> > 0
+#              delay_wait_checks 12
+#
 #      }
 #      device {
 #              vendor                  "COMPAQ  "
 #              rr_weight               priorities
 #      }
 #}
+#
+##
+## name  : devices
+## scope : multipath & multipathd
+## desc  : list of settings to override all hadware settings for all devices
+##       overrides default settings (device_maps block)
+##       and per device type settings (devices block)
+##        overriden by per multipath settings (multipaths block)
+##
+#      attributes and values are identical to the device block
+#
+#overrides {
+#      dev_loss_tmo            60
+#      no_path_retry           fail
+#}
index e76190267160f8e1941ed9a5e6b7d5c2842a6edf..a4e68b1876965443252cfb10d430dfed0a1183af 100644 (file)
 #      log_checker_err always
 #      retain_attached_hw_handler no
 #      detect_prio no
+#      config_dir "/etc/multipath/conf.d"
+#      delay_watch_checks no
+#      delay_wait_checks no
+#      missing_uev_wait_timeout 30
 #}
 #blacklist {
 #      devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
-#      devnode "^hd[a-z]"
+#      devnode "^(td|hd|vd)[a-z]"
 #      devnode "^dcssblk[0-9]*"
+#      devnode "^nvme.*"
 #      device {
 #              vendor "DGC"
 #              product "LUNZ"
@@ -69,7 +74,7 @@
 #      }
 #}
 #blacklist_exceptions {
-#      property "(ID_SCSI_VPD|ID_WWN)"
+#      property "(SCSI_IDENT_.*|ID_WWN)"
 #}
 #devices {
 #      device {
 #              failback "immediate"
 #              rr_weight "uniform"
 #              no_path_retry 60
+#              retain_attached_hw_handler yes
+#              detect_prio yes
 #      }
 #      device {
 #              vendor "EMC"
 #      }
 #      device {
 #              vendor "FUJITSU"
-#              product "ETERNUS_DX(L|400|8000)"
+#              product "ETERNUS_DX(L|M|400|8000)"
 #              path_grouping_policy "group_by_prio"
 #              path_checker "tur"
 #              features "1 queue_if_no_path"
 #              no_path_retry 15
 #      }
 #      device {
+#              vendor "DELL"
+#              product "MD36xxi"
+#              product_blacklist "Universal Xport"
+#              path_grouping_policy "group_by_prio"
+#              path_checker "rdac"
+#              features "2 pg_init_retries 50"
+#              hardware_handler "1 rdac"
+#              prio "rdac"
+#              failback "immediate"
+#              rr_weight "uniform"
+#              no_path_retry 15
+#      }
+#      device {
+#              vendor "DELL"
+#              product "MD36xxf"
+#              product_blacklist "Universal Xport"
+#              path_grouping_policy "group_by_prio"
+#              path_checker "rdac"
+#              features "2 pg_init_retries 50"
+#              hardware_handler "1 rdac"
+#              prio "rdac"
+#              failback "immediate"
+#              rr_weight "uniform"
+#              no_path_retry 15
+#      }
+#      device {
 #              vendor "NETAPP"
 #              product "LUN.*"
 #              path_grouping_policy "group_by_prio"
 #              rr_weight "uniform"
 #              no_path_retry "queue"
 #      }
+#      device {
+#              vendor "PURE"
+#              path_selector "queue-length 0"
+#              path_grouping_policy "multibus"
+#              path_checker "tur"
+#              fast_io_fail_tmo 10
+#              user_friendly_names "no"
+#              no_path_retry 0
+#              features 0
+#              dev_loss_tmo 60
+#      }
 #}
 #multipaths {
 #}
+#overrides {
+#}
index bda1b7593d612e9da23801c3c7792ebe023f1726..f7b9b8aaab90b05f42e10dc3da787d59d86a5867 100644 (file)
@@ -72,3 +72,6 @@
 #              path_grouping_policy    multibus
 #      }
 #}
+#overrides {
+#      no_path_retry                   fail
+#}
diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
new file mode 100644 (file)
index 0000000..2e7076d
--- /dev/null
@@ -0,0 +1,40 @@
+ACTION!="add|change", GOTO="mpath_end"
+ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="mpath_end"
+ENV{DM_UUID}!="mpath-?*", GOTO="mpath_end"
+
+# Do not initiate scanning if no path is available,
+# otherwise there would be a hang or IO error on access.
+# We'd like to avoid this, especially within udev processing.
+ENV{DM_NR_VALID_PATHS}!="?*", IMPORT{db}="DM_NR_VALID_PATHS"
+ENV{DM_NR_VALID_PATHS}!="0", GOTO="mpath_blkid_end"
+IMPORT{db}="ID_FS_TYPE"
+IMPORT{db}="ID_FS_USAGE"
+IMPORT{db}="ID_FS_UUID"
+IMPORT{db}="ID_FS_UUID_ENC"
+IMPORT{db}="ID_FS_VERSION"
+LABEL="mpath_blkid_end"
+
+# Also skip all foreign rules if no path is available.
+# Remember the original value of DM_DISABLE_OTHER_RULES_FLAG
+# and restore it back once we have at least one path available.
+IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD"
+ENV{DM_ACTION}=="PATH_FAILED",\
+       ENV{DM_NR_VALID_PATHS}=="0",\
+       ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="",\
+       ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}",\
+       ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
+ENV{DM_ACTION}=="PATH_REINSTATED",\
+       ENV{DM_NR_VALID_PATHS}=="1",\
+       ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}",\
+       ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="",\
+       ENV{DM_ACTIVATION}="1"
+
+# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem.
+# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its
+# paths are lost/recovered. For any stack above the mpath device, this is not
+# something that should be reacted upon since it would be useless extra work.
+# It's exactly mpath's job to provide *seamless* device access to any of the
+# paths that are available underneath.
+ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0"
+
+LABEL="mpath_end"
index 5e5958dc92bff20078cd509410906c262f23b87e..37072359c96088c4c94e64fabbd2c1c1c7a6f583 100644 (file)
@@ -6,8 +6,9 @@ include ../Makefile.inc
 
 OBJS = main.o
 
-CFLAGS += -I$(multipathdir)
-LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev
+CFLAGS += -I$(multipathdir) -I$(mpathcmddir)
+LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev \
+       -L$(mpathcmddir) -lmpathcmd
 
 EXEC = multipath
 
@@ -21,6 +22,9 @@ $(EXEC): $(OBJS)
 install:
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
        $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+       $(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir)
+       $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir)
+       $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
        $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
        $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
@@ -28,6 +32,8 @@ install:
 
 uninstall:
        rm $(DESTDIR)$(bindir)/$(EXEC)
+       rm $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
+       rm $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
        rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
        rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
 
diff --git a/multipath/dev_t.h b/multipath/dev_t.h
deleted file mode 100644 (file)
index aa80d5e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MAJOR(dev)      ((dev & 0xfff00) >> 8)
-#define MINOR(dev)      ((dev & 0xff) | ((dev >> 12) & 0xfff00))
-#define MKDEV(ma,mi)    ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
index 64c8fc5dcc2791870f14553c4bff59d711d8019f..d14a9137374a753dc5e4d7eacdda53561fcabe26 100644 (file)
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <libudev.h>
+#include <syslog.h>
 
 #include <checkers.h>
 #include <prio.h>
@@ -55,7 +56,8 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <wwids.h>
-#include "dev_t.h"
+#include <uxsock.h>
+#include <mpath_cmd.h>
 
 int logsink;
 
@@ -84,7 +86,7 @@ usage (char * progname)
 {
        fprintf (stderr, VERSION_STRING);
        fprintf (stderr, "Usage:\n");
-       fprintf (stderr, "  %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+       fprintf (stderr, "  %s [-a|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
        fprintf (stderr, "  %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
        fprintf (stderr, "  %s -F [-v lvl]\n", progname);
        fprintf (stderr, "  %s -t\n", progname);
@@ -97,13 +99,14 @@ usage (char * progname)
                "  -ll     show multipath topology (maximum info)\n" \
                "  -f      flush a multipath device map\n" \
                "  -F      flush all multipath device maps\n" \
+               "  -a      add a device wwid to the wwids file\n" \
                "  -c      check if a device should be a path in a multipath device\n" \
                "  -q      allow queue_if_no_path when multipathd is not running\n"\
                "  -d      dry run, do not create or update devmaps\n" \
                "  -t      dump internal hardware table\n" \
                "  -r      force devmap reload\n" \
+               "  -i      ignore wwids file\n" \
                "  -B      treat the bindings file as read only\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" \
@@ -195,6 +198,9 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
                        continue;
                }
 
+               if (conf->cmd == CMD_VALID_PATH)
+                       continue;
+
                dm_get_map(mpp->alias, &mpp->size, params);
                condlog(3, "params = %s", params);
                dm_get_status(mpp->alias, status);
@@ -207,18 +213,19 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
                 * If not in "fast list mode", we need to fetch information
                 * about them
                 */
-               if (conf->list != 1)
+               if (conf->cmd != CMD_LIST_SHORT)
                        update_paths(mpp);
 
-               if (conf->list > 1)
+               if (conf->cmd == CMD_LIST_LONG)
                        mpp->bestpg = select_path_group(mpp);
 
                disassemble_status(status, mpp);
 
-               if (conf->list)
+               if (conf->cmd == CMD_LIST_SHORT ||
+                   conf->cmd == CMD_LIST_LONG)
                        print_multipath_topology(mpp, conf->verbosity);
 
-               if (!conf->dry_run)
+               if (conf->cmd == CMD_CREATE)
                        reinstate_paths(mpp);
        }
        return 0;
@@ -260,10 +267,11 @@ configure (void)
        /*
         * if we have a blacklisted device parameter, exit early
         */
-       if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 &&
+       if (dev && conf->dev_type == DEV_DEVNODE &&
+           conf->cmd != CMD_REMOVE_WWID &&
            (filter_devnode(conf->blist_devnode,
                            conf->elist_devnode, dev) > 0)) {
-               if (conf->dry_run == 2)
+               if (conf->cmd == CMD_VALID_PATH)
                        printf("%s is not a valid multipath device path\n",
                               conf->dev);
                goto out;
@@ -276,13 +284,14 @@ configure (void)
                int failed = get_refwwid(conf->dev, conf->dev_type, pathvec,
                                         &refwwid);
                if (!refwwid) {
-                       if (failed == 2 && conf->dry_run == 2)
+                       condlog(3, "%s: failed to get wwid", conf->dev);
+                       if (failed == 2 && conf->cmd == CMD_VALID_PATH)
                                printf("%s is not a valid multipath device path\n", conf->dev);
                        else
                                condlog(3, "scope is nul");
                        goto out;
                }
-               if (conf->dry_run == 3) {
+               if (conf->cmd == CMD_REMOVE_WWID) {
                        r = remove_wwid(refwwid);
                        if (r == 0)
                                printf("wwid '%s' removed\n", refwwid);
@@ -293,14 +302,29 @@ configure (void)
                        }
                        goto out;
                }
+               if (conf->cmd == CMD_ADD_WWID) {
+                       r = remember_wwid(refwwid);
+                       if (r == 0)
+                               printf("wwid '%s' added\n", refwwid);
+                       else
+                               printf("failed adding '%s' to wwids file\n",
+                                      refwwid);
+                       goto out;
+               }
                condlog(3, "scope limited to %s", refwwid);
-               if (conf->dry_run == 2) {
-                       if (check_wwids_file(refwwid, 0) == 0){
-                               printf("%s is a valid multipath device path\n", conf->dev);
+               /* If you are ignoring the wwids file and find_multipaths is
+                * set, you need to actually check if there are two available
+                * paths to determine if this path should be multipathed. To
+                * do this, we put off the check until after discovering all
+                * the paths */
+               if (conf->cmd == CMD_VALID_PATH &&
+                   (!conf->find_multipaths || !conf->ignore_wwids)) {
+                       if (conf->ignore_wwids ||
+                           check_wwids_file(refwwid, 0) == 0)
                                r = 0;
-                       }
-                       else
-                               printf("%s is not a valid multipath device path\n", conf->dev);
+
+                       printf("%s %s a valid multipath device path\n",
+                              conf->dev, r == 0 ? "is" : "is not");
                        goto out;
                }
        }
@@ -311,17 +335,17 @@ configure (void)
        if (conf->dev)
                di_flag = DI_WWID;
 
-       if (conf->list > 1)
+       if (conf->cmd == CMD_LIST_LONG)
                /* extended path info '-ll' */
                di_flag |= DI_SYSFS | DI_CHECKER;
-       else if (conf->list)
+       else if (conf->cmd == CMD_LIST_SHORT)
                /* minimum path info '-l' */
                di_flag |= DI_SYSFS;
        else
                /* maximum info */
                di_flag = DI_ALL;
 
-       if (path_discovery(pathvec, conf, di_flag))
+       if (path_discovery(pathvec, conf, di_flag) < 0)
                goto out;
 
        if (conf->verbosity > 2)
@@ -334,7 +358,21 @@ configure (void)
 
        filter_pathvec(pathvec, refwwid);
 
-       if (conf->list) {
+
+       if (conf->cmd == CMD_VALID_PATH) {
+               /* This only happens if find_multipaths is and
+                * ignore_wwids is set.
+                * If there is currently a multipath device matching
+                * the refwwid, or there is more than one path matching
+                * the refwwid, then the path is valid */
+               if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
+                       r = 0;
+               printf("%s %s a valid multipath device path\n",
+                      conf->dev, r == 0 ? "is" : "is not");
+               goto out;
+       }
+
+       if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
                r = 0;
                goto out;
        }
@@ -342,7 +380,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)
@@ -357,7 +395,7 @@ out:
 static int
 dump_config (void)
 {
-       char * c;
+       char * c, * tmp = NULL;
        char * reply;
        unsigned int maxlen = 256;
        int again = 1;
@@ -365,9 +403,12 @@ dump_config (void)
        reply = MALLOC(maxlen);
 
        while (again) {
-               if (!reply)
+               if (!reply) {
+                       if (tmp)
+                               free(tmp);
                        return 1;
-               c = reply;
+               }
+               c = tmp = reply;
                c += snprint_defaults(c, reply + maxlen - c);
                again = ((c - reply) == maxlen);
                if (again) {
@@ -392,10 +433,19 @@ dump_config (void)
                        reply = REALLOC(reply, maxlen *= 2);
                        continue;
                }
-               c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
+               c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
                again = ((c - reply) == maxlen);
-               if (again)
+               if (again) {
                        reply = REALLOC(reply, maxlen *= 2);
+                       continue;
+               }
+               if (VECTOR_SIZE(conf->mptable) > 0) {
+                       c += snprint_mptable(c, reply + maxlen - c,
+                                            conf->mptable);
+                       again = ((c - reply) == maxlen);
+                       if (again)
+                               reply = REALLOC(reply, maxlen *= 2);
+               }
        }
 
        printf("%s", reply);
@@ -409,7 +459,7 @@ get_dev_type(char *dev) {
        int i;
 
        if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
-               if (dm_is_dm_major(MAJOR(buf.st_rdev)))
+               if (dm_is_dm_major(major(buf.st_rdev)))
                        return DEV_DEVMAP;
                return DEV_DEVNODE;
        }
@@ -429,11 +479,11 @@ main (int argc, char *argv[])
        int r = 1;
 
        udev = udev_new();
-
+       logsink = 0;
        if (load_config(DEFAULT_CONFIGFILE, udev))
                exit(1);
 
-       while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) {
+       while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BritquwW")) != EOF ) {
                switch(arg) {
                case 1: printf("optarg : %s\n",optarg);
                        break;
@@ -456,11 +506,11 @@ main (int argc, char *argv[])
                        conf->allow_queueing = 1;
                        break;
                case 'c':
-                       conf->dry_run = 2;
+                       conf->cmd = CMD_VALID_PATH;
                        break;
                case 'd':
-                       if (!conf->dry_run)
-                               conf->dry_run = 1;
+                       if (conf->cmd == CMD_CREATE)
+                               conf->cmd = CMD_DRY_RUN;
                        break;
                case 'f':
                        conf->remove = FLUSH_ONE;
@@ -469,11 +519,10 @@ main (int argc, char *argv[])
                        conf->remove = FLUSH_ALL;
                        break;
                case 'l':
-                       conf->list = 1;
-                       conf->dry_run = 1;
-
                        if (optarg && !strncmp(optarg, "l", 1))
-                               conf->list++;
+                               conf->cmd = CMD_LIST_LONG;
+                       else
+                               conf->cmd = CMD_LIST_SHORT;
 
                        break;
                case 'M':
@@ -492,17 +541,27 @@ main (int argc, char *argv[])
                case 'r':
                        conf->force_reload = 1;
                        break;
+               case 'i':
+                       conf->ignore_wwids = 1;
+                       break;
                case 't':
                        r = dump_config();
                        goto out_free_config;
                case 'h':
                        usage(argv[0]);
                        exit(0);
+               case 'u':
+                       conf->cmd = CMD_VALID_PATH;
+                       conf->dev_type = DEV_UEVENT;
+                       break;
                case 'w':
-                       conf->dry_run = 3;
+                       conf->cmd = CMD_REMOVE_WWID;
                        break;
                case 'W':
-                       conf->dry_run = 4;
+                       conf->cmd = CMD_RESET_WWIDS;
+                       break;
+               case 'a':
+                       conf->cmd = CMD_ADD_WWID;
                        break;
                case ':':
                        fprintf(stderr, "Missing option argument\n");
@@ -526,6 +585,7 @@ main (int argc, char *argv[])
        if (dm_prereq())
                exit(1);
        dm_drv_version(conf->version, TGT_MPATH);
+       dm_udev_set_sync_support(1);
 
        if (optind < argc) {
                conf->dev = MALLOC(FILE_NAME_SIZE);
@@ -534,9 +594,15 @@ main (int argc, char *argv[])
                        goto out;
 
                strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
-               conf->dev_type = get_dev_type(conf->dev);
+               if (conf->dev_type != DEV_UEVENT)
+                       conf->dev_type = get_dev_type(conf->dev);
        }
        conf->daemon = 0;
+       if (conf->dev_type == DEV_UEVENT) {
+               openlog("multipath", 0, LOG_DAEMON);
+               setlogmask(LOG_UPTO(conf->verbosity + 3));
+               logsink = 1;
+       }
 
        if (conf->max_fds) {
                struct rlimit fd_limit;
@@ -558,16 +624,28 @@ main (int argc, char *argv[])
        }
        dm_init();
 
-       if (conf->dry_run == 2 &&
+       if (conf->cmd == CMD_VALID_PATH &&
            (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
                condlog(0, "the -c option requires a path to check");
                goto out;
        }
-       if (conf->dry_run == 3 && !conf->dev) {
+       if (conf->cmd == CMD_VALID_PATH &&
+           conf->dev_type == DEV_UEVENT) {
+               int fd;
+
+               fd = mpath_connect();
+               if (fd == -1) {
+                       printf("%s is not a valid multipath device path\n",
+                               conf->dev);
+                       goto out;
+               }
+               mpath_disconnect(fd);
+       }
+       if (conf->cmd == CMD_REMOVE_WWID && !conf->dev) {
                condlog(0, "the -w option requires a device");
                goto out;
        }
-       if (conf->dry_run == 4) {
+       if (conf->cmd == CMD_RESET_WWIDS) {
                struct multipath * mpp;
                int i;
                vector curmp;
@@ -604,14 +682,15 @@ main (int argc, char *argv[])
                condlog(3, "restart multipath configuration process");
 
 out:
-       udev_wait(conf->cookie);
-
        dm_lib_release();
        dm_lib_exit();
 
        cleanup_prio();
        cleanup_checkers();
 
+       if (conf->dev_type == DEV_UEVENT)
+               closelog();
+
 out_free_config:
        /*
         * Freeing config must be done after dm_lib_exit(), because
index a2262aca6aa41879a87db24e7f6dc0de83054efc..966139ecfa0a7d91a7712c25cc4df909055ba7a1 100644 (file)
@@ -8,7 +8,7 @@ multipath \- Device mapper target autoconfig
 .RB [\| \-b\ \c
 .IR bindings_file \|]
 .RB [\| \-d \|]
-.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w | \-W \|]
+.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \|-i | \-a | \|-u | \-w | \-W \|]
 .RB [\| \-p\ \c
 .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
 .RB [\| device \|]
@@ -55,6 +55,9 @@ print internal hardware table to stdout
 .B \-r
 force devmap reload
 .TP
+.B \-i
+ignore wwids file when processing devices
+.TP
 .B \-B
 treat the bindings file as read only
 .TP
@@ -68,6 +71,13 @@ check if a block device should be a path in a multipath device
 .B \-q
 allow device tables with queue_if_no_path when multipathd is not running
 .TP
+.B \-a
+add the wwid for the specified device to the wwids file
+.TP
+.B \-u
+check if the device specified in the program environment should be
+a path in a multipath device.
+.TP
 .B \-w
 remove the wwid for the specified device from the wwids file
 .TP
index cf5bec08c493fbb7c78a389c7f46c132ffc89d70..0d4df0f707c4fc3073f6b761f7dbe87f6ee83a95 100644 (file)
@@ -55,12 +55,15 @@ section.
 .TP
 .B multipaths
 This section defines the multipath topologies. They are indexed by a
-\fIWorld Wide Identifier\fR(wwid), which is taken to be the value of
-the udev attribute given by the
-\fIuid_attribute\fR keyword.
+\fIWorld Wide Identifier\fR(wwid). For details on the wwid generation
+see section \fBWWID generation\fR below.
 .TP
 .B devices
 This section defines the device-specific settings.
+.TP
+.B overrides
+This section defines values for attributes that should override the
+device-specific settings for all devices.
 .RE
 .LP
 .SH "defaults section"
@@ -87,6 +90,28 @@ directory where the dynamic shared objects are stored; default is system
 dependent, commonly
 .I /lib/multipath
 .TP
+.B find_multipaths
+If set to
+.I yes
+, instead of trying to create a multipath device for every non-blacklisted
+path, multipath will only create a device if one of three condidions are
+met.
+.I 1
+There are at least two non-blacklisted paths with the same wwid,
+.I 2
+the user manually forces the creation, by specifying a device with the multipath
+command, or
+.I 3
+a path has the same WWID as a multipath device that was previously created
+while find_multipaths was set (even if that multipath device doesn't currently
+exist).
+Whenever a multipath device is created with find_multipaths set, multipath will
+remeber the WWID of the device, so that it will automatically create the
+device again, as soon as it sees a path with that WWID. This should allow most
+users to have multipath automatically choose the correct paths to make into
+multipath devices, without having to edit the blacklist; Default is
+.I no
+.TP
 .B verbosity
 default verbosity. Higher values increase the verbosity level. Valid
 levels are between 0 and 6; default is
@@ -150,7 +175,7 @@ identifier. Default value is
 .B getuid_callout
 The default program and args to callout to obtain a unique path
 identifier. Should be specified with an absolute path.
-This parameter is deprecated; \fIuid_attribute\fR should be used instead.
+This parameter is deprecated.
 .TP
 .B prio
 The name of the path priority routine. The specified routine
@@ -168,7 +193,9 @@ Return a constant priority of \fI1\fR.
 Generate the path priority for EMC arrays.
 .TP
 .B alua
-Generate the path priority based on the SCSI-3 ALUA settings.
+Generate the path priority based on the SCSI-3 ALUA settings. This prioritizer
+accepts the optional prio_arg
+.I exclusive_pref_bit
 .TP
 .B ontap
 Generate the path priority for NetApp arrays.
@@ -194,13 +221,29 @@ Default value is \fBnone\fR.
 .RE
 .TP
 .B prio_args
-Arguments to pass to to the prio function.  Currently only used with
-.I weighted, which needs a value of the form
-.I "<hbtl|devname> <regex1> <prio1> <regex2> <prio2> ..."
+Arguments to pass to to the prio function. This only applies to certain
+prioritizers
+.RS
+.TP 12
+.B weighted
+Needs a value of the form
+.I "<hbtl|devname|wwn> <regex1> <prio1> <regex2> <prio2> ..."
 .I hbtl
 regex can be of SCSI H:B:T:L format  Ex: 1:0:.:. , *:0:0:.
 .I devname
 regex can be of device name format  Ex: sda , sd.e
+.I wwn
+regex can be of the form
+.I "host_wwnn:host_wwpn:target_wwnn:target_wwpn"
+these values can be looked up through sysfs or by running
+.I mulitpathd show paths format "%N:%R:%n:%r" Ex: 0x200100e08ba0aea0:0x210100e08ba0aea0:.*:.* , .*:.*:iqn.2009-10.com.redhat.msp.lab.ask-06:.*
+.TP
+.B alua
+If
+.I exclusive_pref_bit
+is set, paths with the TPGS pref bit set will always be in their own path
+group.
+.RE
 .TP
 .B features
 Specify any device-mapper features to be used. Syntax is
@@ -330,8 +373,8 @@ maximum number of open fds is taken from the calling process. It is usually
 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
-explicit timeout, in seconds; default taken from
+Specify the timeout to use for path checkers and prioritizers that issue scsi
+commands with an explicit timeout, in seconds; default taken from
 .I /sys/block/sd<x>/device/timeout
 .TP
 .B fast_io_fail_tmo
@@ -364,7 +407,7 @@ multipathd running, access to the paths cannot be restored, and the kernel
 cannot be told to stop queueing IO. Setting queue_without_daemon to
 .I no
 , avoids this problem. Default is
-.I yes
+.I no
 .TP
 .B bindings_file
 The full pathname of the binding file to be used when the user_friendly_names option is set. Defaults to
@@ -409,6 +452,68 @@ will automatically use the
 .I alua
 prioritizer. If not, the prioritizer will be selected as usual. Default is
 .I no
+.TP
+.B force_sync
+If set to
+.I yes
+, multipathd will call the path checkers in sync mode only.  This means that
+only one checker will run at a time.  This is useful in the case where many
+multipathd checkers running in parallel causes significant CPU pressure. The
+Default is
+.I no
+.TP
+.B deferred_remove
+If set to
+.I yes
+, multipathd will do a deferred remove instead of a regular remove when the
+last path device has been deleted.  This means that if the multipath device is
+still in use, it will be freed when the last user closes it.  If path is added
+to the multipath device before the last user closes it, the deferred remove
+will be canceled. Default is
+.I no
+.TP
+.B config_dir
+If set to anything other than "", multipath will search this directory
+alphabetically for file ending in ".conf" and it will read configuration
+information from them, just as if it was in /etc/multipath.conf.  config_dir
+must either be "" or a fully qualified directory name. Default is
+.I "/etc/multipath/conf.d"
+.TP
+.B delay_watch_checks
+If set to a value greater than 0, multipathd will watch paths that have
+recently become valid for this many checks.  If they fail again while they are
+being watched, when they next become valid, they will not be used until they
+have stayed up for
+.I delay_wait_checks
+checks. Default is
+.I no
+.TP
+.B delay_wait_checks
+If set to a value greater than 0, when a device that has recently come back
+online fails again within
+.I delay_watch_checks
+checks, the next time it comes back online, it will marked and delayed, and not
+used until it has passed
+.I delay_wait_checks
+checks. Default is
+.I no
+.TP
+.B uxsock_timeout
+CLI receive timeout in milliseconds. For larger systems CLI commands
+might timeout before the multipathd lock is released and the CLI command
+can be processed. This will result in errors like
+'timeout receiving packet' to be returned from CLI commands.
+In these cases it is recommended to increase the CLI timeout to avoid
+those issues. The default is
+.I 1000
+.TP
+.B missing_uev_wait_timeout
+Controls how many seconds multipathd will wait, after a new multipath device
+is created, to receive a change event from udev for the device, before
+automatically enabling device reloads. Usually multipathd will delay reloads
+on a device until it receives a change uevent from the initial table load. The
+default is
+.I 30
 .
 .SH "blacklist section"
 The
@@ -426,7 +531,7 @@ The \fIWorld Wide Identification\fR of a device.
 Regular expression of the device nodes to be excluded.
 .TP
 .B property
-Regular expresion of the udev property to be excluded.
+Regular expression of the udev property to be excluded.
 .TP
 .B device
 Subsection for the device description. This subsection recognizes the
@@ -453,8 +558,8 @@ The following keywords are recognized:
 The \fIWorld Wide Identification\fR of a device.
 .TP
 .B property
-Regular expresion of the udev property to be whitelisted. Defaults to
-.I (ID_WWN|ID_SCSI_VPD)
+Regular expression of the udev property to be whitelisted. Defaults to
+.I (ID_WWN|SCSI_IDENT_.*)
 .TP
 .B devnode
 Regular expression of the device nodes to be whitelisted.
@@ -527,6 +632,12 @@ section:
 .B features
 .TP
 .B reservation_key
+.TP
+.B deferred_remove
+.TP
+.B delay_watch_checks
+.TP
+.B delay_wait_checks
 .RE
 .PD
 .LP
@@ -617,9 +728,98 @@ section:
 .B retain_attached_hw_handler
 .TP
 .B detect_prio
+.TP
+.B deferred_remove
+.TP
+.B delay_watch_checks
+.TP
+.B delay_wait_checks
 .RE
 .PD
 .LP
+.SH "overrides section"
+The overrides section recognizes the following optional attributes; if not set
+the values are taken from the
+.I devices
+or
+.I defaults
+sections:
+.sp 1
+.PD .1v
+.RS
+.TP 18
+.B path_grouping_policy
+.TP
+.B uid_attribute
+.TP
+.B getuid_callout
+.TP
+.B path_selector
+.TP
+.B path_checker
+.TP
+.B alias_prefix
+.TP
+.B features
+.TP
+.B prio
+.TP
+.B prio_args
+.TP
+.B failback
+.TP
+.B rr_weight
+.TP
+.B no_path_retry
+.TP
+.B rr_min_io
+.TP
+.B rr_min_io_rq
+.TP
+.B flush_on_last_del
+.TP
+.B fast_io_fail_tmo
+.TP
+.B dev_loss_tmo
+.TP
+.B user_friendly_names
+.TP
+.B retain_attached_hw_handler
+.TP
+.B detect_prio
+.TP
+.B deferred_remove
+.TP
+.B delay_watch_checks
+.TP
+.B delay_wait_checks
+.RE
+.PD
+.LP
+.SH "WWID generation"
+Multipath uses a \fIWorld Wide Identification\fR (wwid) to determine
+which paths belong to the same device. Each path presenting the same
+wwid is assumed to point to the same device.
+.LP
+The wwid is generated by three methods (in the order of preference):
+.TP 17
+.B getuid_callout
+Use the specified external program; cf \fIgetuid_callout\fR above.
+Care should be taken when using this method; the external program
+needs to be loaded from disk for execution, which might lead to
+deadlock situations in an all-paths-down scenario.
+.TP
+.B uid_attribute
+Use the value of the specified udev attribute; cf \fIuid_attribute\fR
+above. This method is preferred to \fIgetuid_callout\fR as multipath
+does not need to call any external programs here. However, under
+certain circumstances udev might not be able to generate the requested
+variable.
+.TP
+.B vpd_pg83
+If none of the \fIgetuid_callout\fR or \fIuid_attribute\fR parameters
+are present multipath will try to use the sysfs attribute
+\fIvpd_pg83\fR to generate the wwid.
 .SH "KNOWN ISSUES"
 The usage of
 .B queue_if_no_path
diff --git a/multipath/multipath.rules b/multipath/multipath.rules
new file mode 100644 (file)
index 0000000..c8fb7e6
--- /dev/null
@@ -0,0 +1,22 @@
+# Set DM_MULTIPATH_DEVICE_PATH if the device should be handled by multipath
+SUBSYSTEM!="block", GOTO="end_mpath"
+ACTION!="add|change", GOTO="end_mpath"
+KERNEL!="sd*|dasd*", GOTO="end_mpath"
+
+ENV{DEVTYPE}!="partition", GOTO="test_dev"
+IMPORT{parent}="DM_MULTIPATH_DEVICE_PATH"
+ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{ID_FS_TYPE}="none", \
+       ENV{SYSTEMD_READY}="0"
+GOTO="end_mpath"
+
+LABEL="test_dev"
+
+ENV{MPATH_SBIN_PATH}="/sbin"
+TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin"
+
+ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \
+       PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -u %k", \
+       ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="none", \
+       ENV{SYSTEMD_READY}="0"
+
+LABEL="end_mpath"
index 781122aee6b007ad092240f787794943ef36b56d..9b0210f13959d9667caf7a798e7433a45ece2071 100644 (file)
@@ -5,16 +5,21 @@ include ../Makefile.inc
 #
 # basic flags setting
 #
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
 ifdef SYSTEMD
        CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
 endif
 LDFLAGS += -lpthread -ldevmapper -lreadline
 ifdef SYSTEMD
-       LDFLAGS += -lsystemd-daemon
+       ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1)
+               LDFLAGS += -lsystemd
+       else
+               LDFLAGS += -lsystemd-daemon
+       endif
 endif
 LDFLAGS += -ludev -ldl \
-       -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist
+       -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \
+       -L$(mpathcmddir) -lmpathcmd
 
 #
 # debuging stuff
index 2a5edfaa6c78b4db660f318b2d0cd736d397d9ec..6a5c6db6bb0be32165af7e8bb046e13e5ff0563a 100644 (file)
@@ -26,7 +26,7 @@ alloc_handler (void)
 }
 
 static int
-add_key (vector vec, char * str, unsigned long code, int has_param)
+add_key (vector vec, char * str, uint64_t code, int has_param)
 {
        struct key * kw;
 
@@ -57,7 +57,7 @@ out:
 }
 
 int
-add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *))
+add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *))
 {
        struct handler * h;
 
@@ -79,7 +79,7 @@ add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *))
 }
 
 static struct handler *
-find_handler (unsigned long fp)
+find_handler (uint64_t fp)
 {
        int i;
        struct handler *h;
@@ -92,7 +92,7 @@ find_handler (unsigned long fp)
 }
 
 int
-set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *))
+set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *))
 {
        struct handler * h = find_handler(fp);
 
@@ -180,7 +180,7 @@ load_keys (void)
        r += add_key(keys, "config", CONFIG, 0);
        r += add_key(keys, "blacklist", BLACKLIST, 0);
        r += add_key(keys, "devices", DEVICES, 0);
-       r += add_key(keys, "format", FMT, 1);
+       r += add_key(keys, "raw", RAW, 0);
        r += add_key(keys, "wildcards", WILDCARDS, 0);
        r += add_key(keys, "quit", QUIT, 0);
        r += add_key(keys, "exit", QUIT, 0);
@@ -188,6 +188,7 @@ load_keys (void)
        r += add_key(keys, "getprstatus", GETPRSTATUS, 0);
        r += add_key(keys, "setprstatus", SETPRSTATUS, 0);
        r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0);
+       r += add_key(keys, "format", FMT, 1);
 
        if (r) {
                free_keys(keys);
@@ -292,11 +293,11 @@ out:
        return r;
 }
 
-static unsigned long 
+static uint64_t
 fingerprint(vector vec)
 {
        int i;
-       unsigned long fp = 0;
+       uint64_t fp = 0;
        struct key * kw;
 
        if (!vec)
@@ -320,52 +321,90 @@ alloc_handlers (void)
 }
 
 static int
-genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
+genhelp_sprint_aliases (char * reply, int maxlen, vector keys,
+                       struct key * refkw)
 {
-       int i, fwd = 0;
+       int i, len = 0;
        struct key * kw;
 
-       vector_foreach_slot (keys, kw, i)
-               if (kw->code == refkw->code && kw != refkw)
-                       fwd += sprintf(reply, "|%s", kw->str);
+       vector_foreach_slot (keys, kw, i) {
+               if (kw->code == refkw->code && kw != refkw) {
+                       len += snprintf(reply + len, maxlen - len,
+                                       "|%s", kw->str);
+                       if (len >= maxlen)
+                               return len;
+               }
+       }
 
-       return fwd;
+       return len;
 }
 
-static char *
-genhelp_handler (void)
-{
+static int
+do_genhelp(char *reply, int maxlen) {
+       int len = 0;
        int i, j;
-       unsigned long fp;
+       uint64_t fp;
        struct handler * h;
        struct key * kw;
-       char * reply;
-       char * p;
 
-       reply = MALLOC(INITIAL_REPLY_LEN);
-
-       if (!reply)
-               return NULL;
-
-       p = reply;
-       p += sprintf(p, VERSION_STRING);
-       p += sprintf(p, "CLI commands reference:\n");
+       len += snprintf(reply + len, maxlen - len, VERSION_STRING);
+       if (len >= maxlen)
+               goto out;
+       len += snprintf(reply + len, maxlen - len, "CLI commands reference:\n");
+       if (len >= maxlen)
+               goto out;
 
        vector_foreach_slot (handlers, h, i) {
                fp = h->fingerprint;
                vector_foreach_slot (keys, kw, j) {
                        if ((kw->code & fp)) {
                                fp -= kw->code;
-                               p += sprintf(p, " %s", kw->str);
-                               p += genhelp_sprint_aliases(p, keys, kw);
-
-                               if (kw->has_param)
-                                       p += sprintf(p, " $%s", kw->str);
+                               len += snprintf(reply + len , maxlen - len,
+                                               " %s", kw->str);
+                               if (len >= maxlen)
+                                       goto out;
+                               len += genhelp_sprint_aliases(reply + len,
+                                                             maxlen - len,
+                                                             keys, kw);
+                               if (len >= maxlen)
+                                       goto out;
+
+                               if (kw->has_param) {
+                                       len += snprintf(reply + len,
+                                                       maxlen - len,
+                                                       " $%s", kw->str);
+                                       if (len >= maxlen)
+                                               goto out;
+                               }
                        }
                }
-               p += sprintf(p, "\n");
+               len += snprintf(reply + len, maxlen - len, "\n");
+               if (len >= maxlen)
+                       goto out;
        }
+out:
+       return len;
+}
 
+
+static char *
+genhelp_handler (void)
+{
+       char * reply;
+       char * p = NULL;
+       int maxlen = INITIAL_REPLY_LEN;
+       int again = 1;
+
+       reply = MALLOC(maxlen);
+
+       while (again) {
+               if (!reply)
+                       return NULL;
+               p = reply;
+               p += do_genhelp(reply, maxlen);
+               again = ((p - reply) >= maxlen);
+               REALLOC_REPLY(reply, again, maxlen);
+       }
        return reply;
 }
 
@@ -403,7 +442,7 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data)
 }
 
 char *
-get_keyparam (vector v, unsigned long code)
+get_keyparam (vector v, uint64_t code)
 {
        struct key * kw;
        int i;
@@ -425,12 +464,15 @@ cli_init (void) {
 
        add_handler(LIST+PATHS, NULL);
        add_handler(LIST+PATHS+FMT, NULL);
+       add_handler(LIST+PATHS+RAW+FMT, NULL);
+       add_handler(LIST+PATH, NULL);
        add_handler(LIST+STATUS, NULL);
        add_handler(LIST+DAEMON, NULL);
        add_handler(LIST+MAPS, NULL);
        add_handler(LIST+MAPS+STATUS, NULL);
        add_handler(LIST+MAPS+STATS, NULL);
        add_handler(LIST+MAPS+FMT, NULL);
+       add_handler(LIST+MAPS+RAW+FMT, NULL);
        add_handler(LIST+MAPS+TOPOLOGY, NULL);
        add_handler(LIST+TOPOLOGY, NULL);
        add_handler(LIST+MAP+TOPOLOGY, NULL);
@@ -474,7 +516,7 @@ void cli_exit(void)
 }
 
 static int
-key_match_fingerprint (struct key * kw, unsigned long fp)
+key_match_fingerprint (struct key * kw, uint64_t fp)
 {
        if (!fp)
                return 0;
@@ -489,7 +531,7 @@ char *
 key_generator (const char * str, int state)
 {
        static int index, len, has_param;
-       static unsigned long rlfp;      
+       static uint64_t rlfp;
        struct key * kw;
        int i;
        struct handler *h;
@@ -559,7 +601,7 @@ key_generator (const char * str, int state)
                         * nfp is the candidate fingerprint we try to
                         * validate against all known command fingerprints.
                         */
-                       unsigned long nfp = rlfp | kw->code;
+                       uint64_t nfp = rlfp | kw->code;
                        vector_foreach_slot(handlers, h, i) {
                                if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
                                        /*
index 09fdc68ea82768dac6d0f792ca794fa0da93c305..2aa19d57ee363b966db0eefe13e66e706ac8c8ff 100644 (file)
@@ -1,3 +1,5 @@
+#include <stdint.h>
+
 enum {
        __LIST,
        __ADD,
@@ -26,13 +28,14 @@ enum {
        __CONFIG,
        __BLACKLIST,
        __DEVICES,
-       __FMT,
+       __RAW,
        __WILDCARDS,
        __QUIT,
        __SHUTDOWN,
        __GETPRSTATUS,
        __SETPRSTATUS,
        __UNSETPRSTATUS,
+       __FMT,
 };
 
 #define LIST           (1 << __LIST)
@@ -62,35 +65,50 @@ enum {
 #define CONFIG         (1 << __CONFIG)
 #define BLACKLIST      (1 << __BLACKLIST)
 #define DEVICES                (1 << __DEVICES)
-#define FMT            (1 << __FMT)
+#define RAW            (1 << __RAW)
 #define COUNT          (1 << __COUNT)
 #define WILDCARDS      (1 << __WILDCARDS)
 #define QUIT           (1 << __QUIT)
 #define SHUTDOWN       (1 << __SHUTDOWN)
-#define GETPRSTATUS    (1UL << __GETPRSTATUS)
-#define SETPRSTATUS    (1UL << __SETPRSTATUS)
-#define UNSETPRSTATUS  (1UL << __UNSETPRSTATUS)
+#define GETPRSTATUS    (1ULL << __GETPRSTATUS)
+#define SETPRSTATUS    (1ULL << __SETPRSTATUS)
+#define UNSETPRSTATUS  (1ULL << __UNSETPRSTATUS)
+#define FMT            (1ULL << __FMT)
+
+#define INITIAL_REPLY_LEN      1200
 
-#define INITIAL_REPLY_LEN      1100
+#define REALLOC_REPLY(r, a, m)                                 \
+       do {                                                    \
+               if ((a)) {                                      \
+                       char *tmp = (r);                        \
+                       (r) = REALLOC((r), (m) * 2);            \
+                       if ((r)) {                              \
+                               memset((r) + (m), 0, (m));      \
+                               (m) *= 2;                       \
+                       }                                       \
+                       else                                    \
+                               free(tmp);                      \
+               }                                               \
+       } while (0)
 
 struct key {
        char * str;
        char * param;
-       unsigned long code;
+       uint64_t code;
        int has_param;
 };
 
 struct handler {
-       unsigned long fingerprint;
+       uint64_t fingerprint;
        int (*fn)(void *, char **, int *, void *);
 };
 
 int alloc_handlers (void);
-int add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *));
-int set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *));
+int add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *));
+int set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *));
 int parse_cmd (char * cmd, char ** reply, int * len, void *);
 int load_keys (void);
-char * get_keyparam (vector v, unsigned long code);
+char * get_keyparam (vector v, uint64_t code);
 void free_keys (vector vec);
 void free_handlers (void);
 int cli_init (void);
index f7fc5224edbbf7389258dcafc59a3bfc2af21875..168b8729bf21f5bfa8df28f82cc9bab9dc668793 100644 (file)
 #include "cli.h"
 #include "uevent.h"
 
-#define REALLOC_REPLY(r, a, m)                                 \
-       do {                                                    \
-               if ((a)) {                                      \
-                       (r) = REALLOC((r), (m) * 2);            \
-                       if ((r)) {                              \
-                               memset((r) + (m), 0, (m));      \
-                               (m) *= 2;                       \
-                       }                                       \
-               }                                               \
-       } while (0)
-
 int
-show_paths (char ** r, int * len, struct vectors * vecs, char * style)
+show_paths (char ** r, int * len, struct vectors * vecs, char * style,
+           int pretty)
 {
        int i;
        struct path * pp;
@@ -53,13 +43,42 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style)
 
                c = reply;
 
-               if (VECTOR_SIZE(vecs->pathvec) > 0)
+               if (pretty && VECTOR_SIZE(vecs->pathvec) > 0)
                        c += snprint_path_header(c, reply + maxlen - c,
                                                 style);
 
                vector_foreach_slot(vecs->pathvec, pp, i)
                        c += snprint_path(c, reply + maxlen - c,
-                                         style, pp);
+                                         style, pp, pretty);
+
+               again = ((c - reply) == (maxlen - 1));
+
+               REALLOC_REPLY(reply, again, maxlen);
+       }
+       *r = reply;
+       *len = (int)(c - reply + 1);
+       return 0;
+}
+
+int
+show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
+          char * style)
+{
+       char * c;
+       char * reply;
+       unsigned int maxlen = INITIAL_REPLY_LEN;
+       int again = 1;
+
+       get_path_layout(vecs->pathvec, 1);
+       reply = MALLOC(maxlen);
+
+       while (again) {
+               if (!reply)
+                       return 1;
+
+               c = reply;
+
+               c += snprint_path(c, reply + maxlen - c, style, pp, 0);
 
                again = ((c - reply) == (maxlen - 1));
 
@@ -144,7 +163,7 @@ show_config (char ** r, int * len)
        unsigned int maxlen = INITIAL_REPLY_LEN;
        int again = 1;
 
-       reply = MALLOC(maxlen);
+       c = reply = MALLOC(maxlen);
 
        while (again) {
                if (!reply)
@@ -152,47 +171,35 @@ show_config (char ** r, int * len)
                c = reply;
                c += snprint_defaults(c, reply + maxlen - c);
                again = ((c - reply) == maxlen);
-               if (again) {
-                       reply = REALLOC(reply, maxlen * 2);
-                       if (!reply)
-                               return 1;
-                       memset(reply + maxlen, 0, maxlen);
-                       maxlen *= 2;
+               REALLOC_REPLY(reply, again, maxlen);
+               if (again)
                        continue;
-               }
                c += snprint_blacklist(c, reply + maxlen - c);
                again = ((c - reply) == maxlen);
-               if (again) {
-                       reply = REALLOC(reply, maxlen * 2);
-                       if (!reply)
-                               return 1;
-                       memset(reply + maxlen, 0, maxlen);
-                       maxlen *= 2;
+               REALLOC_REPLY(reply, again, maxlen);
+               if (again)
                        continue;
-               }
                c += snprint_blacklist_except(c, reply + maxlen - c);
                again = ((c - reply) == maxlen);
-               if (again) {
-                       reply = REALLOC(reply, maxlen * 2);
-                       if (!reply)
-                               return 1;
-                       memset(reply + maxlen, 0, maxlen);
-                       maxlen *= 2;
+               REALLOC_REPLY(reply, again, maxlen);
+               if (again)
                        continue;
-               }
                c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
                again = ((c - reply) == maxlen);
-               if (again) {
-                       reply = REALLOC(reply, maxlen * 2);
-                       if (!reply)
-                               return 1;
-                       memset(reply + maxlen, 0, maxlen);
-                       maxlen *= 2;
+               REALLOC_REPLY(reply, again, maxlen);
+               if (again)
                        continue;
-               }
-               c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
+               c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
                again = ((c - reply) == maxlen);
                REALLOC_REPLY(reply, again, maxlen);
+               if (again)
+                       continue;
+               if (VECTOR_SIZE(conf->mptable) > 0) {
+                       c += snprint_mptable(c, reply + maxlen - c,
+                                            conf->mptable);
+                       again = ((c - reply) == maxlen);
+                       REALLOC_REPLY(reply, again, maxlen);
+               }
        }
        *r = reply;
        *len = (int)(c - reply + 1);
@@ -214,7 +221,7 @@ cli_list_paths (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list paths (operator)");
 
-       return show_paths(reply, len, vecs, PRINT_PATH_CHECKER);
+       return show_paths(reply, len, vecs, PRINT_PATH_CHECKER, 1);
 }
 
 int
@@ -225,7 +232,33 @@ cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list paths (operator)");
 
-       return show_paths(reply, len, vecs, fmt);
+       return show_paths(reply, len, vecs, fmt, 1);
+}
+
+int
+cli_list_paths_raw (void * v, char ** reply, int * len, void * data)
+{
+       struct vectors * vecs = (struct vectors *)data;
+       char * fmt = get_keyparam(v, FMT);
+
+       condlog(3, "list paths (operator)");
+
+       return show_paths(reply, len, vecs, fmt, 0);
+}
+
+int
+cli_list_path (void * v, char ** reply, int * len, void * data)
+{
+       struct vectors * vecs = (struct vectors *)data;
+       char * param = get_keyparam(v, PATH);
+       struct path *pp;
+
+       param = convert_dev(param, 1);
+       condlog(3, "%s: list path (operator)", param);
+
+       pp = find_path_by_dev(vecs->pathvec, param);
+
+       return show_path(reply, len, vecs, pp, "%o");
 }
 
 int
@@ -316,7 +349,8 @@ show_daemon (char ** r, int *len)
 }
 
 int
-show_maps (char ** r, int *len, struct vectors * vecs, char * style)
+show_maps (char ** r, int *len, struct vectors * vecs, char * style,
+          int pretty)
 {
        int i;
        struct multipath * mpp;
@@ -333,13 +367,13 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style)
                        return 1;
 
                c = reply;
-               if (VECTOR_SIZE(vecs->mpvec) > 0)
+               if (pretty && VECTOR_SIZE(vecs->mpvec) > 0)
                        c += snprint_multipath_header(c, reply + maxlen - c,
                                                      style);
 
                vector_foreach_slot(vecs->mpvec, mpp, i)
                        c += snprint_multipath(c, reply + maxlen - c,
-                                              style, mpp);
+                                              style, mpp, pretty);
 
                again = ((c - reply) == (maxlen - 1));
 
@@ -358,7 +392,18 @@ cli_list_maps_fmt (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list maps (operator)");
 
-       return show_maps(reply, len, vecs, fmt);
+       return show_maps(reply, len, vecs, fmt, 1);
+}
+
+int
+cli_list_maps_raw (void * v, char ** reply, int * len, void * data)
+{
+       struct vectors * vecs = (struct vectors *)data;
+       char * fmt = get_keyparam(v, FMT);
+
+       condlog(3, "list maps (operator)");
+
+       return show_maps(reply, len, vecs, fmt, 0);
 }
 
 int
@@ -368,7 +413,7 @@ cli_list_maps (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list maps (operator)");
 
-       return show_maps(reply, len, vecs, PRINT_MAP_NAMES);
+       return show_maps(reply, len, vecs, PRINT_MAP_NAMES, 1);
 }
 
 int
@@ -388,7 +433,7 @@ cli_list_maps_status (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list maps status (operator)");
 
-       return show_maps(reply, len, vecs, PRINT_MAP_STATUS);
+       return show_maps(reply, len, vecs, PRINT_MAP_STATUS, 1);
 }
 
 int
@@ -398,7 +443,7 @@ cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
 
        condlog(3, "list maps stats (operator)");
 
-       return show_maps(reply, len, vecs, PRINT_MAP_STATS);
+       return show_maps(reply, len, vecs, PRINT_MAP_STATS, 1);
 }
 
 int
@@ -466,7 +511,7 @@ cli_del_path (void * v, char ** reply, int * len, void * data)
        pp = find_path_by_dev(vecs->pathvec, param);
        if (!pp) {
                condlog(0, "%s: path already removed", param);
-               return 0;
+               return 1;
        }
        return ev_remove_path(pp, vecs);
 }
@@ -478,37 +523,50 @@ cli_add_map (void * v, char ** reply, int * len, void * data)
        char * param = get_keyparam(v, MAP);
        int major, minor;
        char dev_path[PATH_SIZE];
-       char *alias;
-       int rc;
+       char *alias, *refwwid;
+       int rc, count = 0;
 
        param = convert_dev(param, 0);
        condlog(2, "%s: add map (operator)", param);
 
-       if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param) > 0) {
+       if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param, NULL) > 0) {
                *reply = strdup("blacklisted\n");
                *len = strlen(*reply) + 1;
                condlog(2, "%s: map blacklisted", param);
-               return 0;
-       }
-       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;
+               return 1;
        }
-       sprintf(dev_path,"dm-%d", minor);
-       alias = dm_mapname(major, minor);
+       do {
+               minor = dm_get_minor(param);
+               if (minor < 0)
+                       condlog(2, "%s: not a device mapper table", param);
+               major = dm_get_major(param);
+               if (major < 0)
+                       condlog(2, "%s: not a device mapper table", param);
+               sprintf(dev_path, "dm-%d", minor);
+               alias = dm_mapname(major, minor);
+               /*if there is no mapname found, we first create the device*/
+               if (!alias && !count) {
+                       condlog(2, "%s: mapname not found for %d:%d",
+                               param, major, minor);
+                       rc = get_refwwid(param, DEV_DEVMAP, vecs->pathvec,
+                                                               &refwwid);
+                       if (refwwid) {
+                               if (coalesce_paths(vecs, NULL, refwwid, 0))
+                                       condlog(2, "%s: coalesce_paths failed",
+                                                                       param);
+                               dm_lib_release();
+                       }
+               } /*we attempt to create device only once*/
+               count++;
+       } while (!alias && (count < 2));
+
        if (!alias) {
-               condlog(2, "%s: mapname not found for %d:%d",
-                       param, major, minor);
-               return 0;
+               condlog(2, "%s: add map failed", param);
+               return 1;
        }
        rc = ev_add_map(dev_path, alias, vecs);
        FREE(alias);
+       FREE(refwwid);
        return rc;
 }
 
@@ -527,19 +585,19 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
        minor = dm_get_minor(param);
        if (minor < 0) {
                condlog(2, "%s: not a device mapper table", param);
-               return 0;
+               return 1;
        }
        major = dm_get_major(param);
        if (major < 0) {
                condlog(2, "%s: not a device mapper table", param);
-               return 0;
+               return 1;
        }
        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 1;
        }
        rc = ev_remove_map(param, alias, minor, vecs);
        FREE(alias);
@@ -565,6 +623,11 @@ cli_reload(void *v, char **reply, int *len, void *data)
                condlog(0, "%s: invalid map name. cannot reload", mapname);
                return 1;
        }
+       if (mpp->wait_for_udev) {
+               condlog(2, "%s: device not fully created, failing reload",
+                       mpp->alias);
+               return 1;
+       }
 
        return reload_map(vecs, mpp, 0);
 }
@@ -611,6 +674,12 @@ cli_resize(void *v, char **reply, int *len, void *data)
                return 1;
        }
 
+       if (mpp->wait_for_udev) {
+               condlog(2, "%s: device not fully created, failing resize",
+                       mpp->alias);
+               return 1;
+       }
+
        pgp = VECTOR_SLOT(mpp->pg, 0);
 
        if (!pgp){
@@ -775,6 +844,12 @@ cli_reconfigure(void * v, char ** reply, int * len, void * data)
 {
        struct vectors * vecs = (struct vectors *)data;
 
+       if (need_to_delay_reconfig(vecs)) {
+               conf->delayed_reconfig = 1;
+               condlog(2, "delaying reconfigure (operator)");
+               return 0;
+       }
+
        condlog(2, "reconfigure (operator)");
 
        return reconfigure(vecs);
@@ -785,17 +860,25 @@ cli_suspend(void * v, char ** reply, int * len, void * data)
 {
        struct vectors * vecs = (struct vectors *)data;
        char * param = get_keyparam(v, MAP);
-       int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param);
+       int r;
+       struct multipath * mpp;
 
        param = convert_dev(param, 0);
-       condlog(2, "%s: suspend (operator)", param);
+       mpp = find_mp_by_alias(vecs->mpvec, param);
+       if (!mpp)
+               return 1;
 
-       if (!r) /* error */
+       if (mpp->wait_for_udev) {
+               condlog(2, "%s: device not fully created, failing suspend",
+                       mpp->alias);
                return 1;
+       }
 
-       struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+       r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0, 0);
 
-       if (!mpp)
+       condlog(2, "%s: suspend (operator)", param);
+
+       if (!r) /* error */
                return 1;
 
        dm_get_info(param, &mpp->dmi);
@@ -807,17 +890,25 @@ cli_resume(void * v, char ** reply, int * len, void * data)
 {
        struct vectors * vecs = (struct vectors *)data;
        char * param = get_keyparam(v, MAP);
-       int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param);
+       int r;
+       struct multipath * mpp;
 
        param = convert_dev(param, 0);
-       condlog(2, "%s: resume (operator)", param);
+       mpp = find_mp_by_alias(vecs->mpvec, param);
+       if (!mpp)
+               return 1;
 
-       if (!r) /* error */
+       if (mpp->wait_for_udev) {
+               condlog(2, "%s: device not fully created, failing resume",
+                       mpp->alias);
                return 1;
+       }
 
-       struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+       r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0, 0);
 
-       if (!mpp)
+       condlog(2, "%s: resume (operator)", param);
+
+       if (!r) /* error */
                return 1;
 
        dm_get_info(param, &mpp->dmi);
@@ -850,9 +941,21 @@ cli_reinstate(void * v, char ** reply, int * len, void * data)
 int
 cli_reassign (void * v, char ** reply, int * len, void * data)
 {
+       struct vectors * vecs = (struct vectors *)data;
        char * param = get_keyparam(v, MAP);
+       struct multipath *mpp;
 
        param = convert_dev(param, 0);
+       mpp = find_mp_by_alias(vecs->mpvec, param);
+       if (!mpp)
+               return 1;
+
+       if (mpp->wait_for_udev) {
+               condlog(2, "%s: device not fully created, failing reassign",
+                       mpp->alias);
+               return 1;
+       }
+
        condlog(3, "%s: reset devices (operator)", param);
 
        dm_reassign(param);
index de51961c4fe8e876db1c25771fa47d020d097b3b..799f8da228b558a30d680ef300f1a77c6ffe6530 100644 (file)
@@ -1,9 +1,12 @@
 int cli_list_paths (void * v, char ** reply, int * len, void * data);
 int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data);
+int cli_list_paths_raw (void * v, char ** reply, int * len, void * data);
+int cli_list_path (void * v, char ** reply, int * len, void * data);
 int cli_list_status (void * v, char ** reply, int * len, void * data);
 int cli_list_daemon (void * v, char ** reply, int * len, void * data);
 int cli_list_maps (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_fmt (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_raw (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
 int cli_list_map_topology (void * v, char ** reply, int * len, void * data);
index af93f32c2a08cef4426feccd2862fe9113ffb5f0..bbcfe0d5ec7bca92b2d122f92ba08987678aaf9c 100644 (file)
@@ -21,6 +21,7 @@
 #include <systemd/sd-daemon.h>
 #endif
 #include <semaphore.h>
+#include <mpath_cmd.h>
 #include <mpath_persist.h>
 #include <time.h>
 
  */
 #include <checkers.h>
 
+#ifdef USE_SYSTEMD
+static int use_watchdog;
+#endif
+
 /*
  * libmultipath
  */
 #include <print.h>
 #include <configure.h>
 #include <prio.h>
+#include <wwids.h>
 #include <pgpolicies.h>
 #include <uevent.h>
 #include <log.h>
+#include "prioritizers/alua_rtpg.h"
 
 #include "main.h"
 #include "pidfile.h"
@@ -192,7 +199,8 @@ sync_map_state(struct multipath *mpp)
        vector_foreach_slot (mpp->pg, pgp, i){
                vector_foreach_slot (pgp->paths, pp, j){
                        if (pp->state == PATH_UNCHECKED || 
-                           pp->state == PATH_WILD)
+                           pp->state == PATH_WILD ||
+                           pp->state == PATH_DELAYED)
                                continue;
                        if ((pp->dmstate == PSTATE_FAILED ||
                             pp->dmstate == PSTATE_UNDEF) &&
@@ -218,19 +226,30 @@ sync_maps_state(vector mpvec)
 }
 
 static int
-flush_map(struct multipath * mpp, struct vectors * vecs)
+flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
 {
+       int r;
+
+       if (nopaths)
+               r = dm_flush_map_nopaths(mpp->alias, mpp->deferred_remove);
+       else
+               r = dm_flush_map(mpp->alias);
        /*
         * clear references to this map before flushing so we can ignore
         * the spurious uevent we may generate with the dm_flush_map call below
         */
-       if (dm_flush_map(mpp->alias)) {
+       if (r) {
                /*
                 * May not really be an error -- if the map was already flushed
                 * from the device mapper by dmsetup(8) for instance.
                 */
-               condlog(0, "%s: can't flush", mpp->alias);
-               return 1;
+               if (r == 1)
+                       condlog(0, "%s: can't flush", mpp->alias);
+               else {
+                       condlog(2, "%s: devmap deferred remove", mpp->alias);
+                       mpp->deferred_remove = DEFERRED_REMOVE_IN_PROGRESS;
+               }
+               return r;
        }
        else {
                dm_lib_release();
@@ -243,6 +262,47 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
        return 0;
 }
 
+int
+update_map (struct multipath *mpp, struct vectors *vecs)
+{
+       int retries = 3;
+       char params[PARAMS_SIZE] = {0};
+
+retry:
+       condlog(4, "%s: updating new map", mpp->alias);
+       if (adopt_paths(vecs->pathvec, mpp, 1)) {
+               condlog(0, "%s: failed to adopt paths for new map update",
+                       mpp->alias);
+               retries = -1;
+               goto fail;
+       }
+       verify_paths(mpp, vecs);
+       mpp->flush_on_last_del = FLUSH_UNDEF;
+       mpp->action = ACT_RELOAD;
+
+       if (setup_map(mpp, params, PARAMS_SIZE)) {
+               condlog(0, "%s: failed to setup new map in update", mpp->alias);
+               retries = -1;
+               goto fail;
+       }
+       if (domap(mpp, params) <= 0 && retries-- > 0) {
+               condlog(0, "%s: map_udate sleep", mpp->alias);
+               sleep(1);
+               goto retry;
+       }
+       dm_lib_release();
+
+fail:
+       if (setup_multipath(vecs, mpp))
+               return 1;
+
+       sync_map_state(mpp);
+
+       if (retries < 0)
+               condlog(0, "%s: failed reload in new map update", mpp->alias);
+       return 0;
+}
+
 static int
 uev_add_map (struct uevent * uev, struct vectors * vecs)
 {
@@ -277,7 +337,7 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
 
        map_present = dm_map_present(alias);
 
-       if (map_present && dm_type(alias, TGT_MPATH) <= 0) {
+       if (map_present && !dm_is_mpath(alias)) {
                condlog(4, "%s: not a multipath map", alias);
                return 0;
        }
@@ -285,6 +345,20 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
        mpp = find_mp_by_alias(vecs->mpvec, alias);
 
        if (mpp) {
+               if (mpp->wait_for_udev > 1) {
+                       if (update_map(mpp, vecs))
+                       /* setup multipathd removed the map */
+                               return 1;
+               }
+               if (mpp->wait_for_udev) {
+                       mpp->wait_for_udev = 0;
+                       if (conf->delayed_reconfig &&
+                           !need_to_delay_reconfig(vecs)) {
+                               condlog(2, "reconfigure (delayed)");
+                               reconfigure(vecs);
+                               return 0;
+                       }
+               }
                /*
                 * Not really an error -- we generate our own uevent
                 * if we create a multipath mapped device as a result
@@ -302,10 +376,15 @@ ev_add_map (char * dev, char * alias, struct vectors * vecs)
        /*
         * now we can register the map
         */
-       if (map_present && (mpp = add_map_without_path(vecs, alias))) {
-               sync_map_state(mpp);
-               condlog(2, "%s: devmap %s registered", alias, dev);
-               return 0;
+       if (map_present) {
+               if ((mpp = add_map_without_path(vecs, alias))) {
+                       sync_map_state(mpp);
+                       condlog(2, "%s: devmap %s registered", alias, dev);
+                       return 0;
+               } else {
+                       condlog(2, "%s: uev_add_map failed", dev);
+                       return 1;
+               }
        }
        r = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
 
@@ -369,21 +448,21 @@ ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs)
        if (!mpp) {
                condlog(2, "%s: devmap not registered, can't remove",
                        devname);
-               return 0;
+               return 1;
        }
        if (strcmp(mpp->alias, alias)) {
                condlog(2, "%s: minor number mismatch (map %d, event %d)",
                        mpp->alias, mpp->dmi->minor, minor);
-               return 0;
+               return 1;
        }
-       return flush_map(mpp, vecs);
+       return flush_map(mpp, vecs, 0);
 }
 
 static int
 uev_add_path (struct uevent *uev, struct vectors * vecs)
 {
        struct path *pp;
-       int ret, i;
+       int ret = 0, i;
 
        condlog(2, "%s: add path (uevent)", uev->kernel);
        if (strstr(uev->kernel, "..") != NULL) {
@@ -396,44 +475,58 @@ uev_add_path (struct uevent *uev, struct vectors * vecs)
 
        pp = find_path_by_dev(vecs->pathvec, uev->kernel);
        if (pp) {
+               int r;
+
                condlog(0, "%s: spurious uevent, path already in pathvec",
                        uev->kernel);
-               if (pp->mpp)
-                       return 0;
-               if (!strlen(pp->wwid)) {
+               if (!pp->mpp && !strlen(pp->wwid)) {
+                       condlog(3, "%s: reinitialize path", uev->kernel);
                        udev_device_unref(pp->udev);
                        pp->udev = udev_device_ref(uev->udev);
-                       ret = pathinfo(pp, conf->hwtable,
-                                      DI_ALL | DI_BLACKLIST);
-                       if (ret == 2) {
+                       r = pathinfo(pp, conf->hwtable,
+                                    DI_ALL | DI_BLACKLIST);
+                       if (r == PATHINFO_OK)
+                               ret = ev_add_path(pp, vecs);
+                       else if (r == PATHINFO_SKIPPED) {
+                               condlog(3, "%s: remove blacklisted path",
+                                       uev->kernel);
                                i = find_slot(vecs->pathvec, (void *)pp);
                                if (i != -1)
                                        vector_del_slot(vecs->pathvec, i);
                                free_path(pp);
-                               return 0;
-                       } else if (ret == 1) {
+                       } else {
                                condlog(0, "%s: failed to reinitialize path",
                                        uev->kernel);
-                               return 1;
+                               ret = 1;
                        }
                }
-       } else {
-               /*
-                * get path vital state
-                */
-               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;
-               }
+               return ret;
+       }
+
+       /*
+        * get path vital state
+        */
+       ret = alloc_path_with_pathinfo(conf->hwtable, uev->udev,
+                                      DI_ALL, &pp);
+       if (!pp) {
+               if (ret == PATHINFO_SKIPPED)
+                       return 0;
+               condlog(3, "%s: failed to get path info", uev->kernel);
+               return 1;
+       }
+       ret = store_path(vecs->pathvec, pp);
+       if (!ret) {
                pp->checkint = conf->checkint;
+               ret = ev_add_path(pp, vecs);
+       } else {
+               condlog(0, "%s: failed to store path info, "
+                       "dropping event",
+                       uev->kernel);
+               free_path(pp);
+               ret = 1;
        }
 
-       return ev_add_path(pp, vecs);
+       return ret;
 }
 
 /*
@@ -445,30 +538,32 @@ 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;
+       int ret;
 
        /*
         * need path UID to go any further
         */
-       if (memcmp(empty_buff, pp->wwid, WWID_SIZE) == 0) {
+       if (strlen(pp->wwid) == 0) {
                condlog(0, "%s: failed to get path uid", pp->dev);
                goto fail; /* leave path added to pathvec */
        }
-       mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+       mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+       if (mpp && mpp->wait_for_udev) {
+               mpp->wait_for_udev = 2;
+               orphan_path(pp, "waiting for create to complete");
+               return 0;
+       }
+
+       pp->mpp = mpp;
 rescan:
        if (mpp) {
-               if ((!pp->size) || (mpp->size != pp->size)) {
-                       if (!pp->size)
-                               condlog(0, "%s: failed to add new path %s, "
-                                       "device size is 0",
-                                       mpp->alias, pp->dev);
-                       else
-                               condlog(0, "%s: failed to add new path %s, "
-                                       "device size mismatch",
-                                       mpp->alias, pp->dev);
+               if (mpp->size != pp->size) {
+                       condlog(0, "%s: failed to add new path %s, "
+                               "device size mismatch",
+                               mpp->alias, pp->dev);
                        int i = find_slot(vecs->pathvec, (void *)pp);
                        if (i != -1)
                                vector_del_slot(vecs->pathvec, i);
@@ -481,21 +576,14 @@ rescan:
                if (adopt_paths(vecs->pathvec, mpp, 1))
                        goto fail; /* leave path added to pathvec */
 
-               verify_paths(mpp, vecs, NULL);
+               verify_paths(mpp, vecs);
                mpp->flush_on_last_del = FLUSH_UNDEF;
                mpp->action = ACT_RELOAD;
-       }
-       else {
-               if (!pp->size) {
-                       condlog(0, "%s: failed to create new map,"
-                               " device size is 0 ", pp->dev);
-                       int i = find_slot(vecs->pathvec, (void *)pp);
-                       if (i != -1)
-                               vector_del_slot(vecs->pathvec, i);
-                       free_path(pp);
-                       return 1;
+       } else {
+               if (!should_multipath(pp, vecs->pathvec)) {
+                       orphan_path(pp, "only one path");
+                       return 0;
                }
-
                condlog(4,"%s: creating new map", pp->dev);
                if ((mpp = add_map_with_path(vecs, pp, 1))) {
                        mpp->action = ACT_CREATE;
@@ -523,7 +611,15 @@ rescan:
        /*
         * reload the map for the multipath mapped device
         */
-       if (domap(mpp, params) <= 0) {
+retry:
+       ret = domap(mpp, params);
+       if (ret <= 0) {
+               if (ret < 0 && retries-- > 0) {
+                       condlog(0, "%s: retry domap for addition of new "
+                               "path %s", mpp->alias, pp->dev);
+                       sleep(1);
+                       goto retry;
+               }
                condlog(0, "%s: failed in domap for addition of new "
                        "path %s", mpp->alias, pp->dev);
                /*
@@ -561,7 +657,7 @@ rescan:
                return 0;
        }
        else
-               return 1;
+               goto fail;
 
 fail_map:
        remove_map(mpp, vecs, 1);
@@ -627,7 +723,7 @@ ev_remove_path (struct path *pp, struct vectors * vecs)
                                mpp->flush_on_last_del = FLUSH_IN_PROGRESS;
                                dm_queue_if_no_path(mpp->alias, 0);
                        }
-                       if (!flush_map(mpp, vecs)) {
+                       if (!flush_map(mpp, vecs, 1)) {
                                condlog(2, "%s: removed map after"
                                        " removing all paths",
                                        alias);
@@ -644,6 +740,12 @@ ev_remove_path (struct path *pp, struct vectors * vecs)
                                " removal of path %s", mpp->alias, pp->dev);
                        goto fail;
                }
+
+               if (mpp->wait_for_udev) {
+                       mpp->wait_for_udev = 2;
+                       goto out;
+               }
+
                /*
                 * reload the map
                 */
@@ -657,9 +759,8 @@ ev_remove_path (struct path *pp, struct vectors * vecs)
                        /*
                         * update our state from kernel
                         */
-                       if (setup_multipath(vecs, mpp)) {
-                               goto fail;
-                       }
+                       if (setup_multipath(vecs, mpp))
+                               return 1;
                        sync_map_state(mpp);
 
                        condlog(2, "%s [%s]: path removed from map %s",
@@ -684,21 +785,29 @@ static int
 uev_update_path (struct uevent *uev, struct vectors * vecs)
 {
        int ro, retval = 0;
+       struct path * pp;
+
+       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->initialized == INIT_REQUESTED_UDEV)
+               return uev_add_path(uev, vecs);
 
        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) {
+                       if (pp->mpp->wait_for_udev) {
+                               pp->mpp->wait_for_udev = 2;
+                               return 0;
+                       }
+
                        retval = reload_map(vecs, pp->mpp, 0);
 
                        condlog(2, "%s: map %s reloaded (retval %d)",
@@ -864,12 +973,15 @@ uxlsnrloop (void * ap)
 
        set_handler_callback(LIST+PATHS, cli_list_paths);
        set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
+       set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
+       set_handler_callback(LIST+PATH, cli_list_path);
        set_handler_callback(LIST+MAPS, cli_list_maps);
        set_handler_callback(LIST+STATUS, cli_list_status);
        set_handler_callback(LIST+DAEMON, cli_list_daemon);
        set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
        set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
        set_handler_callback(LIST+MAPS+FMT, cli_list_maps_fmt);
+       set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);
        set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
        set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
        set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
@@ -949,19 +1061,23 @@ fail_path (struct path * pp, int del_active)
 /*
  * caller must have locked the path list before calling that function
  */
-static void
+static int
 reinstate_path (struct path * pp, int add_active)
 {
+       int ret = 0;
+
        if (!pp->mpp)
-               return;
+               return 0;
 
-       if (dm_reinstate_path(pp->mpp->alias, pp->dev_t))
+       if (dm_reinstate_path(pp->mpp->alias, pp->dev_t)) {
                condlog(0, "%s: reinstate failed", pp->dev_t);
-       else {
+               ret = 1;
+       } else {
                condlog(2, "%s: reinstated", pp->dev_t);
                if (add_active)
                        update_queue_mode_add_path(pp->mpp);
        }
+       return ret;
 }
 
 static void
@@ -1031,6 +1147,33 @@ followover_should_failback(struct path * pp)
        return 1;
 }
 
+static void
+missing_uev_wait_tick(struct vectors *vecs)
+{
+       struct multipath * mpp;
+       unsigned int i;
+       int timed_out = 0;
+
+       vector_foreach_slot (vecs->mpvec, mpp, i) {
+               if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
+                       timed_out = 1;
+                       condlog(0, "%s: timeout waiting on creation uevent. enabling reloads", mpp->alias);
+                       if (mpp->wait_for_udev > 1 && update_map(mpp, vecs)) {
+                               /* update_map removed map */
+                               i--;
+                               continue;
+                       }
+                       mpp->wait_for_udev = 0;
+               }
+       }
+
+       if (timed_out && conf->delayed_reconfig &&
+           !need_to_delay_reconfig(vecs)) {
+               condlog(2, "reconfigure (delayed)");
+               reconfigure(vecs);
+       }
+}
+
 static void
 defered_failback_tick (vector mpvec)
 {
@@ -1116,14 +1259,28 @@ check_path (struct vectors * vecs, struct path * pp)
        int newstate;
        int new_path_up = 0;
        int chkr_new_path_up = 0;
+       int add_active;
+       int disable_reinstate = 0;
        int oldchkrstate = pp->chkrstate;
 
-       if (!pp->mpp)
+       if ((pp->initialized == INIT_OK ||
+            pp->initialized == INIT_REQUESTED_UDEV) && !pp->mpp)
                return 0;
 
        if (pp->tick && --pp->tick)
                return 0; /* don't check this path yet */
 
+       if (!pp->mpp && pp->initialized == INIT_MISSING_UDEV &&
+           pp->retriggers < conf->retrigger_tries) {
+               condlog(2, "%s: triggering change event to reinitialize",
+                       pp->dev);
+               pp->initialized = INIT_REQUESTED_UDEV;
+               pp->retriggers++;
+               sysfs_attr_set_value(pp->udev, "uevent", "change",
+                                    strlen("change"));
+               return 0;
+       } 
+
        /*
         * provision a next check soonest,
         * in case we exit abnormaly from here
@@ -1131,11 +1288,14 @@ check_path (struct vectors * vecs, struct path * pp)
        pp->tick = conf->checkint;
 
        newstate = path_offline(pp);
-       if (newstate == PATH_REMOVED) {
-               condlog(2, "%s: remove path (checker)", pp->dev);
-               ev_remove_path(pp, vecs);
-               return 0;
-       }
+       /*
+        * Wait for uevent for removed paths;
+        * some LLDDs like zfcp keep paths unavailable
+        * without sending uevents.
+        */
+       if (newstate == PATH_REMOVED)
+               newstate = PATH_DOWN;
+
        if (newstate == PATH_UP)
                newstate = get_state(pp, 1);
        else
@@ -1147,7 +1307,7 @@ check_path (struct vectors * vecs, struct path * pp)
                return 1;
        }
        if (!pp->mpp) {
-               if (!strlen(pp->wwid) &&
+               if (!strlen(pp->wwid) && pp->initialized != INIT_MISSING_UDEV &&
                    (newstate == PATH_UP || newstate == PATH_GHOST)) {
                        condlog(2, "%s: add missing path", pp->dev);
                        if (pathinfo(pp, conf->hwtable, DI_ALL) == 0) {
@@ -1173,6 +1333,30 @@ check_path (struct vectors * vecs, struct path * pp)
                        pp->dev);
                pp->dmstate = PSTATE_UNDEF;
        }
+       /* if update_multipath_strings orphaned the path, quit early */
+       if (!pp->mpp)
+               return 0;
+
+       if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
+            pp->wait_checks > 0) {
+               if (pp->mpp && pp->mpp->nr_active > 0) {
+                       pp->state = PATH_DELAYED;
+                       pp->wait_checks--;
+                       return 1;
+               } else
+                       pp->wait_checks = 0;
+       }
+
+       /*
+        * don't reinstate failed path, if its in stand-by
+        * and if target supports only implicit tpgs mode.
+        * this will prevent unnecessary i/o by dm on stand-by
+        * paths if there are no other active paths in map.
+        */
+       disable_reinstate = (newstate == PATH_GHOST &&
+                           pp->mpp->nr_active == 0 &&
+                           pp->tpgs == TPGS_IMPLICIT) ? 1 : 0;
+
        pp->chkrstate = newstate;
        if (newstate != pp->state) {
                int oldstate = pp->state;
@@ -1192,9 +1376,14 @@ check_path (struct vectors * vecs, struct path * pp)
                         * proactively fail path in the DM
                         */
                        if (oldstate == PATH_UP ||
-                           oldstate == PATH_GHOST)
+                           oldstate == PATH_GHOST) {
                                fail_path(pp, 1);
-                       else
+                               if (pp->mpp->delay_wait_checks > 0 &&
+                                   pp->watch_checks > 0) {
+                                       pp->wait_checks = pp->mpp->delay_wait_checks;
+                                       pp->watch_checks = 0;
+                               }
+                       }else
                                fail_path(pp, 0);
 
                        /*
@@ -1221,11 +1410,21 @@ check_path (struct vectors * vecs, struct path * pp)
                 * reinstate this path
                 */
                if (oldstate != PATH_UP &&
-                   oldstate != PATH_GHOST)
-                       reinstate_path(pp, 1);
-               else
-                       reinstate_path(pp, 0);
-
+                   oldstate != PATH_GHOST) {
+                       if (pp->mpp->delay_watch_checks > 0)
+                               pp->watch_checks = pp->mpp->delay_watch_checks;
+                       add_active = 1;
+               } else {
+                       if (pp->watch_checks > 0)
+                               pp->watch_checks--;
+                       add_active = 0;
+               }
+               if (!disable_reinstate && reinstate_path(pp, add_active)) {
+                       condlog(3, "%s: reload map", pp->dev);
+                       ev_add_path(pp, vecs);
+                       pp->tick = 1;
+                       return 0;
+               }
                new_path_up = 1;
 
                if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
@@ -1239,10 +1438,16 @@ check_path (struct vectors * vecs, struct path * pp)
                        enable_group(pp);
        }
        else if (newstate == PATH_UP || newstate == PATH_GHOST) {
-               if (pp->dmstate == PSTATE_FAILED ||
-                   pp->dmstate == PSTATE_UNDEF) {
+               if ((pp->dmstate == PSTATE_FAILED ||
+                   pp->dmstate == PSTATE_UNDEF) &&
+                   !disable_reinstate) {
                        /* Clear IO errors */
-                       reinstate_path(pp, 0);
+                       if (reinstate_path(pp, 0)) {
+                               condlog(3, "%s: reload map", pp->dev);
+                               ev_add_path(pp, vecs);
+                               pp->tick = 1;
+                               return 0;
+                       }
                } else {
                        LOG_MSG(4, checker_message(&pp->checker));
                        if (pp->checkint != conf->max_checkint) {
@@ -1258,6 +1463,8 @@ check_path (struct vectors * vecs, struct path * pp)
                                condlog(4, "%s: delay next check %is",
                                        pp->dev_t, pp->checkint);
                        }
+                       if (pp->watch_checks > 0)
+                               pp->watch_checks--;
                        pp->tick = pp->checkint;
                }
        }
@@ -1271,6 +1478,9 @@ check_path (struct vectors * vecs, struct path * pp)
 
        pp->state = newstate;
 
+
+       if (pp->mpp->wait_for_udev)
+               return 1;
        /*
         * path prio refreshing
         */
@@ -1322,7 +1532,7 @@ checkerloop (void *ap)
                pthread_testcancel();
                condlog(4, "tick");
 #ifdef USE_SYSTEMD
-               if (conf->watchdog)
+               if (use_watchdog)
                        sd_notify(0, "WATCHDOG=1");
 #endif
                if (vecs->pathvec) {
@@ -1333,6 +1543,7 @@ checkerloop (void *ap)
                if (vecs->mpvec) {
                        defered_failback_tick(vecs->mpvec);
                        retry_count_tick(vecs->mpvec);
+                       missing_uev_wait_tick(vecs);
                }
                if (count)
                        count--;
@@ -1362,7 +1573,7 @@ configure (struct vectors * vecs, int start_waiters)
        struct multipath * mpp;
        struct path * pp;
        vector mpvec;
-       int i;
+       int i, ret;
 
        if (!vecs->pathvec && !(vecs->pathvec = vector_alloc()))
                return 1;
@@ -1376,7 +1587,9 @@ configure (struct vectors * vecs, int start_waiters)
        /*
         * probe for current path (from sysfs) and map (from dm) sets
         */
-       path_discovery(vecs->pathvec, conf, DI_ALL);
+       ret = path_discovery(vecs->pathvec, conf, DI_ALL);
+       if (ret < 0)
+               return 1;
 
        vector_foreach_slot (vecs->pathvec, pp, i){
                if (filter_path(conf, pp) > 0){
@@ -1435,12 +1648,30 @@ configure (struct vectors * vecs, int start_waiters)
        return 0;
 }
 
+int
+need_to_delay_reconfig(struct vectors * vecs)
+{
+       struct multipath *mpp;
+       int i;
+
+       if (!VECTOR_SIZE(vecs->mpvec))
+               return 0;
+
+       vector_foreach_slot(vecs->mpvec, mpp, i) {
+               if (mpp->wait_for_udev)
+                       return 1;
+       }
+       return 0;
+}
+
 int
 reconfigure (struct vectors * vecs)
 {
        struct config * old = conf;
        int retval = 1;
 
+       running_state = DAEMON_CONFIGURE;
+
        /*
         * free old map and path vectors ... they use old conf state
         */
@@ -1459,12 +1690,16 @@ reconfigure (struct vectors * vecs)
        if (!load_config(DEFAULT_CONFIGFILE, udev)) {
                dm_drv_version(conf->version, TGT_MPATH);
                conf->verbosity = old->verbosity;
+               conf->bindings_read_only = old->bindings_read_only;
+               conf->ignore_new_devs = old->ignore_new_devs;
                conf->daemon = 1;
                configure(vecs, 1);
                free_config(old);
                retval = 0;
        }
 
+       running_state = DAEMON_RUNNING;
+
        return retval;
 }
 
@@ -1518,12 +1753,18 @@ void
 handle_signals(void)
 {
        if (reconfig_sig && running_state == DAEMON_RUNNING) {
-               condlog(2, "reconfigure (signal)");
                pthread_cleanup_push(cleanup_lock,
                                &gvecs->lock);
                lock(gvecs->lock);
                pthread_testcancel();
-               reconfigure(gvecs);
+               if (need_to_delay_reconfig(gvecs)) {
+                       conf->delayed_reconfig = 1;
+                       condlog(2, "delaying reconfigure (signal)");
+               }
+               else {
+                       condlog(2, "reconfigure (signal)");
+                       reconfigure(gvecs);
+               }
                lock_cleanup_pop(gvecs->lock);
        }
        if (log_reset_sig) {
@@ -1653,7 +1894,7 @@ child (void * param)
 #ifdef USE_SYSTEMD
        unsigned long checkint;
 #endif
-       int rc, pid_rc;
+       int rc;
        char *envp;
 
        mlockall(MCL_CURRENT | MCL_FUTURE);
@@ -1663,7 +1904,7 @@ child (void * param)
        udev = udev_new();
 
        setup_thread_attr(&misc_attr, 64 * 1024, 1);
-       setup_thread_attr(&uevent_attr, 128 * 1024, 1);
+       setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 1);
        setup_thread_attr(&waiter_attr, 32 * 1024, 1);
 
        if (logsink == 1) {
@@ -1671,6 +1912,12 @@ child (void * param)
                log_thread_start(&log_attr);
                pthread_attr_destroy(&log_attr);
        }
+       if (pidfile_create(DEFAULT_PIDFILE, daemon_pid)) {
+               condlog(1, "failed to create pidfile");
+               if (logsink == 1)
+                       log_thread_stop();
+               exit(1);
+       }
 
        running_state = DAEMON_START;
 
@@ -1733,7 +1980,7 @@ child (void * param)
        set_oom_adj();
 
        conf->daemon = 1;
-       udev_set_sync_support(0);
+       dm_udev_set_sync_support(0);
 #ifdef USE_SYSTEMD
        envp = getenv("WATCHDOG_USEC");
        if (envp && sscanf(envp, "%lu", &checkint) == 1) {
@@ -1746,7 +1993,7 @@ child (void * param)
                        conf->checkint = conf->max_checkint / 4;
                condlog(3, "enabling watchdog, interval %d max %d",
                        conf->checkint, conf->max_checkint);
-               conf->watchdog = conf->checkint;
+               use_watchdog = conf->checkint;
        }
 #endif
        /*
@@ -1790,10 +2037,6 @@ child (void * param)
        }
        pthread_attr_destroy(&misc_attr);
 
-       /* Startup complete, create logfile */
-       pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid);
-       /* Ignore errors, we can live without */
-
        running_state = DAEMON_RUNNING;
 #ifdef USE_SYSTEMD
        sd_notify(0, "READY=1\nSTATUS=running");
@@ -1844,10 +2087,8 @@ child (void * param)
        dm_lib_exit();
 
        /* We're done here */
-       if (!pid_rc) {
-               condlog(3, "unlink pidfile");
-               unlink(DEFAULT_PIDFILE);
-       }
+       condlog(3, "unlink pidfile");
+       unlink(DEFAULT_PIDFILE);
 
        condlog(2, "--------shut down-------");
 
@@ -1939,6 +2180,7 @@ main (int argc, char *argv[])
        extern int optind;
        int arg;
        int err;
+       int foreground = 0;
 
        logsink = 1;
        running_state = DAEMON_INIT;
@@ -1960,10 +2202,12 @@ main (int argc, char *argv[])
        if (!conf)
                exit(1);
 
-       while ((arg = getopt(argc, argv, ":dsv:k::")) != EOF ) {
+       while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
        switch(arg) {
                case 'd':
-                       logsink = 0;
+                       foreground = 1;
+                       if (logsink > 0)
+                               logsink = 0;
                        //debug=1; /* ### comment me out ### */
                        break;
                case 'v':
@@ -1977,8 +2221,16 @@ main (int argc, char *argv[])
                        logsink = -1;
                        break;
                case 'k':
-                       uxclnt(optarg);
+                       if (load_config(DEFAULT_CONFIGFILE, udev_new()))
+                               exit(1);
+                       uxclnt(optarg, conf->uxsock_timeout);
                        exit(0);
+               case 'B':
+                       conf->bindings_read_only = 1;
+                       break;
+               case 'n':
+                       conf->ignore_new_devs = 1;
+                       break;
                default:
                        ;
                }
@@ -1988,6 +2240,8 @@ main (int argc, char *argv[])
                char * s = cmd;
                char * c = s;
 
+               if (load_config(DEFAULT_CONFIGFILE, udev_new()))
+                       exit(1);
                while (optind < argc) {
                        if (strchr(argv[optind], ' '))
                                c += snprintf(c, s + CMDSIZE - c, "\"%s\" ", argv[optind]);
@@ -1996,13 +2250,16 @@ main (int argc, char *argv[])
                        optind++;
                }
                c += snprintf(c, s + CMDSIZE - c, "\n");
-               uxclnt(s);
+               uxclnt(s, conf->uxsock_timeout);
                exit(0);
        }
 
-       if (logsink < 1)
+       if (foreground) {
+               if (!isatty(fileno(stdout)))
+                       setbuf(stdout, NULL);
                err = 0;
-       else
+               daemon_pid = getpid();
+       } else
                err = daemonize();
 
        if (err < 0)
index 10378efb6025d96469381dc99d81002378e26282..2f706d20a67ef71f17e92c7e0a3d180e873da4ed 100644 (file)
@@ -18,6 +18,7 @@ extern pid_t daemon_pid;
 
 void exit_daemon(void);
 const char * daemon_status(void);
+int need_to_delay_reconfig (struct vectors *);
 int reconfigure (struct vectors *);
 int ev_add_path (struct path *, struct vectors *);
 int ev_remove_path (struct path *, struct vectors *);
index 6da9d2b7d8f48ba1fe8313b28d140816eea47bf7..77f6e72453184f0c829ecbcaef79f172bdcae6ba 100644 (file)
@@ -28,8 +28,17 @@ Suppress timestamps. Do not prefix logging messages with a timestamp.
 .B -v "level"
 Verbosity level. Print additional information while running multipathd. A  level of 0 means only print errors. A level of 3 or greater prints debugging information as well. 
 .TP
+.B -B
+Read-only bindings file. Multipathd will not write to the user_friendly_names
+bindings file. If a user_friendly_name doesn't already exist for a device, it
+will use its WWID as its alias.
+.TP
 .B -k 
 multipathd will enter interactive mode. From this mode, the available commands can be viewed by entering "help". When you are finished entering commands, press CTRL-D to quit.
+.TP
+.B -n
+ignore new devices. Multipathd will not create a multipath device unless the
+wwid for the device is already listed in the wwids file.
 
 .SH COMMANDS
 .TP
@@ -80,6 +89,9 @@ Show all available block devices by name including the information if they are b
 .B list|show status
 Show the number of path checkers in each possible state, the number of monitored paths, and whether multipathd is currently handling a uevent.
 .TP
+.B list|show daemon
+Show the current state of the multipathd daemon
+.TP
 .B add path $path
 Add a path to the list of monitored paths. $path is as listed in /sys/block (e.g. sda).
 .TP 
@@ -107,6 +119,13 @@ Sets map $map into suspend state.
 .B resume map|multipath $map
 Resumes map $map from suspend state.
 .TP
+.B reset map|multipath $map
+Reassign existing device-mapper table(s) use use the multipath device, instead
+of its path devices.
+.TP
+.B reload map|multipath $map
+Reload a multipath device.
+.TP
 .B fail path $path
 Sets path $path into failed state.
 .TP
@@ -125,8 +144,27 @@ Disable queuing on multipathed map $map
 .B restorequeueing map|multipath $map
 Restore queuing on multipahted map $map
 .TP
+.B forcequeueing daemon
+Forces multipathd into queue_without_daemon mode, so that no_path_retry queueing
+will not be disabled when the daemon stops
+.TP
+.B restorequeueing daemon
+Restores configured queue_without_daemon mode
+.TP
+.B map|multipath $map setprstatus
+Enable persistent reservation management on $map
+.TP
+.B map|multipath $map unsetprstatus
+Disable persistent reservation management on $map
+.TP
+.B map|multipath $map getprstatus
+Get the current persistent reservation management status of $map
+.TP
 .B quit|exit
 End interactive session.
+.TP
+.B shutdown
+Stop multipathd.
 
 .SH "SYSTEMD INTEGRATION"
 When compiled with systemd support two systemd service files are
index d1319b1a03be0a95571914972dc207cd642f95a4..ed699fac84839c8785e8450406591d5ca3bc04c1 100644 (file)
@@ -17,7 +17,7 @@
 
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 DAEMON=/sbin/multipathd
-PIDFILE=/var/run/multipathd.pid
+PIDFILE=/run/multipathd.pid
 MPATH_INIT_TIMEOUT=10
 ARGS=""
 
index be3ba3fbe7c178716e66035d1ebc6f3af9c3a332..d5f8606307465bb6d0163163343c60117297d916 100644 (file)
@@ -1,8 +1,10 @@
 [Unit]
 Description=Device-Mapper Multipath Device Controller
 Before=iscsi.service iscsid.service lvm2-activation-early.service
-After=syslog.target
+Before=local-fs-pre.target
+After=multipathd.socket
 DefaultDependencies=no
+Wants=local-fs-pre.target multipathd.socket blk-availability.service
 Conflicts=shutdown.target
 
 [Service]
index 3d4b6dae21bbfc9023593f0b02605ff2e7d67f20..921706d5d3337caba3f5730789fe02670b8908e4 100644 (file)
@@ -1,5 +1,7 @@
+[Unit]
+Description=multipathd control socket
+DefaultDependencies=no
+Before=sockets.target
+
 [Socket]
 ListenStream=@/org/kernel/linux/storage/multipathd
-
-[Install]
-WantedBy=sockets.target
index e86be2136bc2f759d27ec6b99438c07fd82c3e89..06c1bf8413329e518f67c0128edd562bef4473ca 100644 (file)
@@ -9,6 +9,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -17,6 +18,7 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include <mpath_cmd.h>
 #include <uxsock.h>
 #include <memory.h>
 #include <defaults.h>
@@ -63,16 +65,16 @@ static int need_quit(char *str, size_t len)
 /*
  * process the client
  */
-static void process(int fd)
+static void process(int fd, unsigned int timeout)
 {
        char *line;
        char *reply;
+       int ret;
 
        cli_init();
        rl_readline_name = "multipathd";
        rl_completion_entry_function = key_generator;
        while ((line = readline("multipathd> "))) {
-               size_t len;
                size_t llen = strlen(line);
 
                if (!llen) {
@@ -83,8 +85,9 @@ static void process(int fd)
                if (need_quit(line, llen))
                        break;
 
-               if (send_packet(fd, line, llen + 1) != 0) break;
-               if (recv_packet(fd, &reply, &len) != 0) break;
+               if (send_packet(fd, line) != 0) break;
+               ret = recv_packet(fd, &reply, timeout);
+               if (ret != 0) break;
 
                print_reply(reply);
 
@@ -96,18 +99,22 @@ static void process(int fd)
        }
 }
 
-static void process_req(int fd, char * inbuf)
+static void process_req(int fd, char * inbuf, unsigned int timeout)
 {
        char *reply;
-       size_t len;
+       int ret;
 
-       if (send_packet(fd, inbuf, strlen(inbuf) + 1) != 0) {
+       if (send_packet(fd, inbuf) != 0) {
                printf("cannot send packet\n");
                return;
        }
-       if (recv_packet(fd, &reply, &len) != 0)
-               printf("error receiving packet\n");
-       else {
+       ret = recv_packet(fd, &reply, timeout);
+       if (ret < 0) {
+               if (ret == -ETIMEDOUT)
+                       printf("timeout receiving packet\n");
+               else
+                       printf("error %d receiving packet\n", ret);
+       } else {
                printf("%s", reply);
                FREE(reply);
        }
@@ -116,18 +123,18 @@ static void process_req(int fd, char * inbuf)
 /*
  * entry point
  */
-int uxclnt(char * inbuf)
+int uxclnt(char * inbuf, unsigned int timeout)
 {
        int fd;
 
-       fd = ux_socket_connect(DEFAULT_SOCKET);
+       fd = mpath_connect();
        if (fd == -1)
                exit(1);
 
        if (inbuf)
-               process_req(fd, inbuf);
+               process_req(fd, inbuf, timeout);
        else
-               process(fd);
+               process(fd, timeout);
 
        return 0;
 }
index 0667a24e36f6c40582379ee7b967374a597b562a..8e2cdcea8c5276ed95c8bf9037e5143611d3c42a 100644 (file)
@@ -1 +1 @@
-int uxclnt(char * inbuf);
+int uxclnt(char * inbuf, unsigned int timeout);
index ed8e012fa2bc9c9d10e8ef4ce2a5333eeddcbf0d..e5c5d90717c328a45160c441197be7199b758b59 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/poll.h>
+#include <sys/time.h>
 #include <signal.h>
 #include <checkers.h>
 #include <memory.h>
@@ -29,6 +30,8 @@
 #include <structs_vec.h>
 #include <uxsock.h>
 #include <defaults.h>
+#include <config.h>
+#include <mpath_cmd.h>
 
 #include "main.h"
 #include "cli.h"
 struct timespec sleep_time = {5, 0};
 
 struct client {
+       struct list_head node;
        int fd;
-       struct client *next, *prev;
 };
 
-static struct client *clients;
-static unsigned num_clients;
+LIST_HEAD(clients);
+pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
 struct pollfd *polls;
 volatile sig_atomic_t reconfig_sig = 0;
 volatile sig_atomic_t log_reset_sig = 0;
@@ -62,14 +65,19 @@ static void new_client(int ux_sock)
        if (fd == -1)
                return;
 
-       /* put it in our linked list */
        c = (struct client *)MALLOC(sizeof(*c));
+       if (!c) {
+               close(fd);
+               return;
+       }
        memset(c, 0, sizeof(*c));
+       INIT_LIST_HEAD(&c->node);
        c->fd = fd;
-       c->next = clients;
-       if (c->next) c->next->prev = c;
-       clients = c;
-       num_clients++;
+
+       /* put it in our linked list */
+       pthread_mutex_lock(&client_lock);
+       list_add_tail(&c->node, &clients);
+       pthread_mutex_unlock(&client_lock);
 }
 
 /*
@@ -77,12 +85,12 @@ static void new_client(int ux_sock)
  */
 static void dead_client(struct client *c)
 {
+       pthread_mutex_lock(&client_lock);
+       list_del_init(&c->node);
+       pthread_mutex_unlock(&client_lock);
        close(c->fd);
-       if (c->prev) c->prev->next = c->next;
-       if (c->next) c->next->prev = c->prev;
-       if (c == clients) clients = c->next;
+       c->fd = -1;
        FREE(c);
-       num_clients--;
 }
 
 void free_polls (void)
@@ -91,6 +99,24 @@ void free_polls (void)
                FREE(polls);
 }
 
+void check_timeout(struct timeval start_time, char *inbuf,
+                  unsigned int timeout)
+{
+       struct timeval diff_time, end_time;
+
+       if (start_time.tv_sec && gettimeofday(&end_time, NULL) == 0) {
+               timersub(&end_time, &start_time, &diff_time);
+               unsigned long msecs;
+
+               msecs = diff_time.tv_sec * 1000 +
+                       diff_time.tv_usec / 1000;
+               if (msecs > timeout)
+                       condlog(2, "cli cmd '%s' timeout reached "
+                               "after %lu.%06lu secs", inbuf,
+                               diff_time.tv_sec, diff_time.tv_usec);
+       }
+}
+
 void uxsock_cleanup(void *arg)
 {
        cli_exit();
@@ -100,20 +126,27 @@ void uxsock_cleanup(void *arg)
 /*
  * entry point
  */
-void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
-                       void * trigger_data)
+void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
 {
        int ux_sock;
-       size_t len;
-       int rlen;
+       int rlen, timeout;
        char *inbuf;
        char *reply;
        sigset_t mask;
 
        ux_sock = ux_socket_listen(DEFAULT_SOCKET);
 
-       if (ux_sock == -1)
-               exit(1);
+       if (ux_sock == -1) {
+               condlog(1, "could not create uxsock: %d", errno);
+               return NULL;
+       }
+
+       if (!conf) {
+               condlog(1, "configuration changed");
+               return NULL;
+       }
+
+       timeout = conf->uxsock_timeout;
 
        pthread_cleanup_push(uxsock_cleanup, NULL);
 
@@ -122,19 +155,48 @@ void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
        sigdelset(&mask, SIGHUP);
        sigdelset(&mask, SIGUSR1);
        while (1) {
-               struct client *c;
-               int i, poll_count;
+               struct pollfd *new;
+               struct client *c, *tmp;
+               int i, poll_count, num_clients;
+
+               /*
+                * Store configuration timeout;
+                * configuration might change during
+                * the call to 'reconfigure'.
+                */
+               if (conf)
+                       timeout = conf->uxsock_timeout;
 
                /* setup for a poll */
-               polls = REALLOC(polls, (1+num_clients) * sizeof(*polls));
+               pthread_mutex_lock(&client_lock);
+               num_clients = 0;
+               list_for_each_entry(c, &clients, node) {
+                       num_clients++;
+               }
+               new = REALLOC(polls, (1+num_clients) * sizeof(*polls));
+               /* If we can't allocate poliing space for the new client,
+                * close it */
+               if (!new) {
+                       if (!num_clients) {
+                               condlog(1, "can't listen for new clients");
+                               return NULL;
+                       }
+                       dead_client(list_entry(clients.prev,
+                                              typeof(struct client), node));
+               }
+               else
+                       polls = new;
                polls[0].fd = ux_sock;
                polls[0].events = POLLIN;
 
                /* setup the clients */
-               for (i=1, c = clients; c; i++, c = c->next) {
+               i = 1;
+               list_for_each_entry(c, &clients, node) {
                        polls[i].fd = c->fd;
                        polls[i].events = POLLIN;
+                       i++;
                }
+               pthread_mutex_unlock(&client_lock);
 
                /* most of our life is spent in this call */
                poll_count = ppoll(polls, i, &sleep_time, &mask);
@@ -154,20 +216,35 @@ void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
                        continue;
 
                /* see if a client wants to speak to us */
-               for (i=1, c = clients; c; i++) {
-                       struct client *next = c->next;
-
+               for (i = 1; i < num_clients + 1; i++) {
                        if (polls[i].revents & POLLIN) {
-                               if (recv_packet(c->fd, &inbuf, &len) != 0) {
+                               struct timeval start_time;
+
+                               c = NULL;
+                               pthread_mutex_lock(&client_lock);
+                               list_for_each_entry(tmp, &clients, node) {
+                                       if (tmp->fd == polls[i].fd) {
+                                               c = tmp;
+                                               break;
+                                       }
+                               }
+                               pthread_mutex_unlock(&client_lock);
+                               if (!c) {
+                                       condlog(3, "cli%d: invalid fd %d",
+                                               i, polls[i].fd);
+                                       continue;
+                               }
+                               if (gettimeofday(&start_time, NULL) != 0)
+                                       start_time.tv_sec = 0;
+                               if (recv_packet(c->fd, &inbuf, timeout) != 0) {
                                        dead_client(c);
                                } else {
-                                       inbuf[len - 1] = 0;
                                        condlog(4, "Got request [%s]", inbuf);
                                        uxsock_trigger(inbuf, &reply, &rlen,
                                                       trigger_data);
                                        if (reply) {
-                                               if (send_packet(c->fd, reply,
-                                                               rlen) != 0) {
+                                               if (send_packet(c->fd,
+                                                               reply) != 0) {
                                                        dead_client(c);
                                                }
                                                condlog(4, "Reply [%d bytes]",
@@ -175,10 +252,11 @@ void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
                                                FREE(reply);
                                                reply = NULL;
                                        }
+                                       check_timeout(start_time, inbuf,
+                                                     timeout);
                                        FREE(inbuf);
                                }
                        }
-                       c = next;
                }
 
                /* see if we got a new client */
index 8b5a525c715950c14b5598e5477589b18718cc0f..d274b04be4abf352b8d6d87427028d621a5d94c2 100644 (file)
@@ -1,11 +1,13 @@
 #ifndef _UXLSNR_H
 #define _UXLSNR_H
 
-void * uxsock_listen(int (*uxsock_trigger)
-                       (char *, char **, int *, void *),
-                       void * trigger_data);
+typedef int (uxsock_trigger_fn)(char *, char **, int *, void *);
+
+void * uxsock_listen(uxsock_trigger_fn uxsock_trigger,
+                    void * trigger_data);
 
 extern volatile sig_atomic_t reconfig_sig;
 extern volatile sig_atomic_t log_reset_sig;
+
 #endif