Imported Upstream version 0.6.3 upstream/0.6.3
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:16 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:16 +0000 (13:50 +0900)
77 files changed:
Makefile
Makefile.inc
README
kpartx/Makefile
kpartx/dasd.c
kpartx/devmapper.c
kpartx/gpt.c
kpartx/kpartx.c
kpartx/kpartx.rules
kpartx/lopart.c
kpartx/ps3.c
kpartx/solaris.c
libmpathcmd/Makefile
libmpathcmd/mpath_cmd.c
libmpathpersist/Makefile
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_pr_ioctl.c
libmpathpersist/mpath_pr_ioctl.h
libmpathpersist/mpath_updatepr.c
libmultipath/Makefile
libmultipath/blacklist.c
libmultipath/checkers.c
libmultipath/checkers.h
libmultipath/checkers/Makefile
libmultipath/checkers/cciss.h
libmultipath/checkers/cciss_tur.c
libmultipath/checkers/directio.c
libmultipath/checkers/emc_clariion.c
libmultipath/checkers/hp_sw.c
libmultipath/checkers/rbd.c [new file with mode: 0644]
libmultipath/checkers/rdac.c
libmultipath/checkers/readsector0.c
libmultipath/checkers/tur.c
libmultipath/defaults.h
libmultipath/devmapper.c
libmultipath/devmapper.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/hwtable.c
libmultipath/lock.c
libmultipath/lock.h
libmultipath/memory.c
libmultipath/memory.h
libmultipath/parser.c
libmultipath/pgpolicies.c
libmultipath/print.c
libmultipath/print.h
libmultipath/prio.h
libmultipath/prioritizers/Makefile
libmultipath/prioritizers/alua.c
libmultipath/prioritizers/hp_sw.c
libmultipath/prioritizers/ontap.c
libmultipath/prioritizers/weightedpath.c
libmultipath/prioritizers/weightedpath.h
libmultipath/propsel.c
libmultipath/structs.h
libmultipath/structs_vec.c
libmultipath/structs_vec.h
libmultipath/uevent.c
libmultipath/util.h
libmultipath/version.h
libmultipath/waiter.c
libmultipath/waiter.h
libmultipath/wwids.c
mpathpersist/Makefile
mpathpersist/main.c
multipath/Makefile
multipath/main.c
multipath/multipath.conf.5
multipathd/Makefile
multipathd/cli.c
multipathd/main.c
multipathd/main.h
multipathd/pidfile.c
multipathd/uxclnt.c
multipathd/uxlsnr.c
multipathd/uxlsnr.h

index cf1acd9..95c7dfb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,3 @@
-# Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
@@ -6,16 +5,23 @@
 #
 # Try to supply the linux kernel headers.
 #
-ifeq    ($(KRNLSRC),)
-KRNLLIB = /lib/modules/$(shell uname -r)
-ifeq    ($(shell test -r $(KRNLLIB)/source && echo 1),1)
-KRNLSRC = $(KRNLLIB)/source
-KRNLOBJ = $(KRNLLIB)/build
-else
-KRNLSRC = $(KRNLLIB)/build
-KRNLOBJ = $(KRNLLIB)/build
+ifeq ($(KRNLSRC),)
+       KRNLLIB = /lib/modules/$(shell uname -r)
+       ifeq ($(shell test -r $(KRNLLIB)/source && echo 1),1)
+               KRNLSRC = $(KRNLLIB)/source
+               KRNLOBJ = $(KRNLLIB)/build
+       else
+               KRNLSRC = $(KRNLLIB)/build
+               KRNLOBJ = $(KRNLLIB)/build
+       endif
 endif
+
+ifeq ($(MULTIPATH_VERSION),)
+       VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
+else
+       VERSION = $(MULTIPATH_VERSION)
 endif
+
 export KRNLSRC
 export KRNLOBJ
 
@@ -30,12 +36,6 @@ BUILDDIRS = \
        mpathpersist \
        kpartx
 
-ifeq   ($(MULTIPATH_VERSION),)
-VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
-else
-VERSION = $(MULTIPATH_VERSION)
-endif
-
 all: recurse
 
 recurse:
@@ -59,11 +59,11 @@ recurse_uninstall:
        $(MAKE) -C $$dir uninstall || exit $?; \
        done
 
-clean: recurse_clean
+clean: recurse_clean
 
-install:       recurse_install
+install: recurse_install
 
-uninstall:     recurse_uninstall
+uninstall: recurse_uninstall
 
 .PHONY:        TAGS
 TAGS:
index 3e8635f..0808e64 100644 (file)
@@ -1,6 +1,6 @@
-# Makefile.inc
 #
 # Copyright (C) 2004 Christophe Varoqui, <christophe.varoqui@opensvc.com>
+#
 
 #
 # Allow to force some libraries to be used statically. (Uncomment one of the
@@ -39,32 +39,32 @@ ifndef SYSTEMDPATH
        SYSTEMDPATH=usr/lib
 endif
 
-prefix      =
-exec_prefix = $(prefix)
-bindir      = $(exec_prefix)/sbin
-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
-syslibdir   = $(prefix)/$(LIB)
-incdir      = $(prefix)/usr/include
-libdir     = $(prefix)/$(LIB)/multipath
-unitdir     = $(prefix)/$(SYSTEMDPATH)/systemd/system
-mpathpersistdir = $(TOPDIR)/libmpathpersist
-mpathcmddir = $(TOPDIR)/libmpathcmd
+prefix         =
+exec_prefix    = $(prefix)
+bindir         = $(exec_prefix)/sbin
+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
+syslibdir      = $(prefix)/$(LIB)
+incdir         = $(prefix)/usr/include
+libdir         = $(prefix)/$(LIB)/multipath
+unitdir                = $(prefix)/$(SYSTEMDPATH)/systemd/system
+mpathpersistdir        = $(TOPDIR)/libmpathpersist
+mpathcmddir    = $(TOPDIR)/libmpathcmd
 
-GZIP        = gzip -9 -c
-RM          = rm -f
-LN          = ln -sf
-INSTALL_PROGRAM = install
+GZIP           = gzip -9 -c
+RM             = rm -f
+LN             = ln -sf
+INSTALL_PROGRAM        = install
 
-OPTFLAGS     = -Wunused -Wstrict-prototypes -O2 -g -pipe -Wformat-security -Wall \
-               -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
+OPTFLAGS       = -Wunused -Wstrict-prototypes -O2 -g -pipe -Wformat-security -Wall \
+                 -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
 
-CFLAGS      = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
-SHARED_FLAGS = -shared
+CFLAGS         = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
+SHARED_FLAGS   = -shared
 
 %.o:   %.c
        $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/README b/README
index c1c53fc..77b79b8 100644 (file)
--- a/README
+++ b/README
@@ -25,6 +25,5 @@ To get latest devel code: git clone http://git.opensvc.com/multipath-tools/.git
 
 Mailing list: http://www.redhat.com/mailman/listinfo/dm-devel
 Gitweb: http://git.opensvc.com/?p=multipath-tools/.git
-Patchwork: http://patchwork.kernel.org/project/dm-devel/list/
 
 Current maintainer is Christophe Varoqui <christophe.varoqui@opensvc.com>
index 5476545..75b7606 100644 (file)
@@ -1,4 +1,3 @@
-# Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
@@ -6,15 +5,17 @@ include ../Makefile.inc
 
 CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 
+LDFLAGS = -ldevmapper
+
 LIBDM_API_COOKIE = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_set_cookie' /usr/include/libdevmapper.h)
 
 ifneq ($(strip $(LIBDM_API_COOKIE)),0)
        CFLAGS += -DLIBDM_API_COOKIE
 endif
 
-LDFLAGS = -ldevmapper
 OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
-       gpt.o mac.o ps3.o crc32.o lopart.o xstrncpy.o devmapper.o
+       gpt.o mac.o ps3.o crc32.o lopart.o xstrncpy.o devmapper.o
+
 EXEC = kpartx
 
 all: $(EXEC)
index 046a08b..faf5e2e 100644 (file)
@@ -233,7 +233,7 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
                            || EBCtoASC[f1.DS1FMTID] == '5'
                            || EBCtoASC[f1.DS1FMTID] == '7'
                            || EBCtoASC[f1.DS1FMTID] == '9') {
-                               blk++;
+                               blk++;
                                continue;
                        }
 
@@ -243,7 +243,7 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
                                break;
 
                        /* OK, we got valid partition data */
-                       offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+                       offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
                        size  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) -
                                offset + geo.sectors;
                        sp[counter].start = sectors512(offset, blocksize);
@@ -280,7 +280,7 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
                retval = 1;
        }
 
- out:
+out:
        if (data != NULL)
                free(data);
        if (fd_dasd != -1 && fd_dasd != fd)
index 382f511..474d879 100644 (file)
@@ -47,7 +47,7 @@ dm_prereq (char * str, int x, int y, int z)
                target = (void *) target + target->next;
        } while (last_target != target);
 
-       out:
+out:
        dm_task_destroy(dmt);
        return r;
 }
@@ -85,7 +85,7 @@ dm_simplecmd (int task, const char *name, int no_flush, uint16_t udev_flags) {
        if (udev_wait_flag)
                        dm_udev_wait(cookie);
 #endif
-       out:
+out:
        dm_task_destroy(dmt);
        return r;
 }
index 75a1c2b..3511886 100644 (file)
@@ -592,7 +592,7 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
                return 1;
        }
 
- fail:
+fail:
        if (pgpt)  { free(pgpt);   pgpt=NULL; }
        if (agpt)  { free(agpt);   agpt=NULL; }
        if (pptes) { free(pptes); pptes=NULL; }
index b7b4047..d31fea8 100644 (file)
@@ -258,7 +258,8 @@ main(int argc, char **argv){
                exit(1);
        }
 
-       while ((arg = getopt(argc, argv, short_opts)) != EOF) switch(arg) {
+       while ((arg = getopt(argc, argv, short_opts)) != EOF)
+               switch(arg) {
                case 'r':
                        ro=1;
                        break;
@@ -295,7 +296,7 @@ main(int argc, char **argv){
                default:
                        usage();
                        exit(1);
-       }
+               }
 
 #ifdef LIBDM_API_COOKIE
        if (!udev_sync)
index 8858a60..1713f3c 100644 (file)
@@ -38,6 +38,6 @@ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", \
 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"
+       RUN+="/sbin/kpartx -u -p -part /dev/$name"
 
 LABEL="kpartx_end"
index e8e3f08..0ab1688 100644 (file)
@@ -147,7 +147,7 @@ find_loop_by_file (const char * filename)
 extern char *
 find_unused_loop_device (void)
 {
-       char dev[20], *next_loop_dev = NULL;;
+       char dev[20], *next_loop_dev = NULL;
        int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
        struct stat statbuf;
        struct loop_info loopinfo;
@@ -211,23 +211,21 @@ find_unused_loop_device (void)
                fprintf(stderr, "mount: could not find any device /dev/loop#");
 
        else if (!someloop) {
-           if (loop_known == 1)
-               fprintf(stderr,
-                   "mount: Could not find any loop device.\n"
-                   "       Maybe /dev/loop# has a wrong major number?");
-           else if (loop_known == -1)
-               fprintf(stderr,
-                   "mount: Could not find any loop device, and, according to %s,\n"
-                   "       this kernel does not know about the loop device.\n"
-                   "       (If so, then recompile or `modprobe loop'.)",
-                     PROC_DEVICES);
-
-           else
-               fprintf(stderr,
-                   "mount: Could not find any loop device. Maybe this kernel does not know\n"
-                   "       about the loop device (then recompile or `modprobe loop'), or\n"
-                   "       maybe /dev/loop# has the wrong major number?");
-
+               if (loop_known == 1)
+                       fprintf(stderr,
+                               "mount: Could not find any loop device.\n"
+                               "       Maybe /dev/loop# has a wrong major number?");
+               else if (loop_known == -1)
+                       fprintf(stderr,
+                               "mount: Could not find any loop device, and, according to %s,\n"
+                               "       this kernel does not know about the loop device.\n"
+                               "       (If so, then recompile or `modprobe loop'.)",
+                               PROC_DEVICES);
+               else
+                       fprintf(stderr,
+                               "mount: Could not find any loop device. Maybe this kernel does not know\n"
+                               "       about the loop device (then recompile or `modprobe loop'), or\n"
+                               "       maybe /dev/loop# has the wrong major number?");
        } else
                fprintf(stderr, "mount: could not find any free loop device");
        return 0;
index 2fe868d..8455097 100644 (file)
@@ -28,7 +28,7 @@ struct disklabel {
        u_int64_t d_res2;
        u_int64_t d_res3;
        struct d_partition d_partitions[MAX_PARTITIONS];
-       u_int8_t d_pad[0x600 - MAX_PARTITIONS * sizeof(struct d_partition)- 0x30];
+       u_int8_t d_pad[0x600 - MAX_PARTITIONS * sizeof(struct d_partition) - 0x30];
 };
 
 static int
index 355a6cb..01da379 100644 (file)
@@ -11,7 +11,7 @@
 struct solaris_x86_slice {
        unsigned short  s_tag;          /* ID tag of partition */
        unsigned short  s_flag;         /* permision flags */
-       daddr_t         s_start;        /* start sector no of partition */
+       long            s_start;        /* start sector no of partition */
        long            s_size;         /* # of blocks in partition */
 };
 
index 44c221d..457c4ca 100644 (file)
@@ -1,8 +1,6 @@
-# Makefile
-#
 include ../Makefile.inc
 
-SONAME=0
+SONAME = 0
 DEVLIB = libmpathcmd.so
 LIBS = $(DEVLIB).$(SONAME)
 
@@ -27,4 +25,4 @@ uninstall:
        $(RM) $(DESTDIR)$(incdir)/mpath_cmd.h
 
 clean:
-       $(RM) core *.a *.o *.gz *.so *.so.*
+       $(RM) core *.a *.o *.so *.so.* *.gz
index 2290ecb..c058479 100644 (file)
@@ -112,7 +112,7 @@ ssize_t mpath_recv_reply_len(int fd, unsigned int timeout)
                return ret;
        if (ret != sizeof(len)) {
                errno = EIO;
-               return ret;
+               return -1;
        }
        return len;
 }
index 07fcf70..1c4b2e1 100644 (file)
@@ -1,23 +1,20 @@
-# Makefile
-#
 include ../Makefile.inc
 
-SONAME=0
+SONAME = 0
 DEVLIB = libmpathpersist.so
 LIBS = $(DEVLIB).$(SONAME)
 
-
 CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
-LIBDEPS +=  -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \
-       -L$(mpathcmddir) -lmpathcmd
+
+LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \
+          -L$(mpathcmddir) -lmpathcmd
 
 OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o
 
 all: $(LIBS)
 
-
 $(LIBS):
-       $(CC) -Wall -fPIC -c $(CFLAGS) *.c
+       $(CC) -c $(CFLAGS) *.c
        $(CC) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS)
        $(LN) $(LIBS) $(DEVLIB)
        $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz
@@ -42,7 +39,4 @@ uninstall:
        $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
 
 clean:
-       $(RM) core *.a *.o
-       $(RM) libmpathpersist.so.0
-       $(RM) libmpathpersist.so
-       $(RM) mpath_persistent_reserve_in.3.gz mpath_persistent_reserve_out.3.gz
+       $(RM) core *.a *.o *.so *.so.* *.gz
index 252d6fc..7501651 100644 (file)
@@ -514,7 +514,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                        if (rc){
                                condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
                        }
-                       count = count +1;
+                       count = count + 1;
                }
        }
        for( i=0; i < active_pathcount ; i++){
@@ -642,7 +642,7 @@ int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
        struct path *pp = NULL;
        int active_pathcount = 0;
        pthread_attr_t attr;
-       int rc, found = 0;;
+       int rc, found = 0;
        int count = 0;
        int status = MPATH_PR_SUCCESS;
        struct prin_resp resp;
index cf7141a..8b9ac3d 100644 (file)
@@ -272,22 +272,22 @@ decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length)
                fdesc->trnptid.format_code = ((p[0] >> 6) & 0x3);
                fdesc->trnptid.protocol_id = (p[0] & 0xf);
                switch (fdesc->trnptid.protocol_id) {
-                       case MPATH_PROTOCOL_ID_FC:
-                               memcpy(&fdesc->trnptid.n_port_name, &p[8], 8);
-                               jump = 24;
-                               break;
-                       case MPATH_PROTOCOL_ID_ISCSI:
-                               num = ((p[2] << 8) | p[3]);
-                               memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
-                               jump = (((num + 4) < 24) ? 24 : num + 4);
-                               break;
-                       case MPATH_PROTOCOL_ID_SAS:
-                               memcpy(&fdesc->trnptid.sas_address, &p[4], 8);
-                               jump = 24;
-                               break;
-                       default:
-                               jump = 24;
-                               break;
+               case MPATH_PROTOCOL_ID_FC:
+                       memcpy(&fdesc->trnptid.n_port_name, &p[8], 8);
+                       jump = 24;
+                       break;
+               case MPATH_PROTOCOL_ID_ISCSI:
+                       num = ((p[2] << 8) | p[3]);
+                       memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
+                       jump = (((num + 4) < 24) ? 24 : num + 4);
+                       break;
+               case MPATH_PROTOCOL_ID_SAS:
+                       memcpy(&fdesc->trnptid.sas_address, &p[4], 8);
+                       jump = 24;
+                       break;
+               default:
+                       jump = 24;
+                       break;
                }
        }
 }
@@ -411,62 +411,62 @@ int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
                return MPATH_PR_SUCCESS;
 
        switch(io_hdr.status) {
-               case SAM_STAT_GOOD:
-                       break;
-               case SAM_STAT_CHECK_CONDITION:
-                       condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x",
-                               dev, Sensedata->Sense_Key,
-                               Sensedata->ASC, Sensedata->ASCQ);
-                       switch(Sensedata->Sense_Key) {
-                               case NO_SENSE:
-                                       return MPATH_PR_NO_SENSE;
-                               case RECOVERED_ERROR:
-                                       return MPATH_PR_SUCCESS;
-                               case NOT_READY:
-                                       return MPATH_PR_SENSE_NOT_READY;
-                               case MEDIUM_ERROR:
-                                       return MPATH_PR_SENSE_MEDIUM_ERROR;
-                               case BLANK_CHECK:
-                                       return MPATH_PR_OTHER;
-                               case HARDWARE_ERROR:
-                                       return MPATH_PR_SENSE_HARDWARE_ERROR;
-                               case ILLEGAL_REQUEST:
-                                       return MPATH_PR_ILLEGAL_REQ;
-                               case UNIT_ATTENTION:
-                                       return MPATH_PR_SENSE_UNIT_ATTENTION;
-                               case DATA_PROTECT:
-                               case COPY_ABORTED:
-                                       return MPATH_PR_OTHER;
-                               case ABORTED_COMMAND:
-                                       return MPATH_PR_SENSE_ABORTED_COMMAND;
-
-                               default :
-                                       return MPATH_PR_OTHER;
-                       }
-               case SAM_STAT_RESERVATION_CONFLICT:
-                       return MPATH_PR_RESERV_CONFLICT;
+       case SAM_STAT_GOOD:
+               break;
+       case SAM_STAT_CHECK_CONDITION:
+               condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x",
+                       dev, Sensedata->Sense_Key,
+                       Sensedata->ASC, Sensedata->ASCQ);
+               switch(Sensedata->Sense_Key) {
+               case NO_SENSE:
+                       return MPATH_PR_NO_SENSE;
+               case RECOVERED_ERROR:
+                       return MPATH_PR_SUCCESS;
+               case NOT_READY:
+                       return MPATH_PR_SENSE_NOT_READY;
+               case MEDIUM_ERROR:
+                       return MPATH_PR_SENSE_MEDIUM_ERROR;
+               case BLANK_CHECK:
+                       return MPATH_PR_OTHER;
+               case HARDWARE_ERROR:
+                       return MPATH_PR_SENSE_HARDWARE_ERROR;
+               case ILLEGAL_REQUEST:
+                       return MPATH_PR_ILLEGAL_REQ;
+               case UNIT_ATTENTION:
+                       return MPATH_PR_SENSE_UNIT_ATTENTION;
+               case DATA_PROTECT:
+               case COPY_ABORTED:
+                       return MPATH_PR_OTHER;
+               case ABORTED_COMMAND:
+                       return MPATH_PR_SENSE_ABORTED_COMMAND;
 
                default :
-                       return  MPATH_PR_OTHER;
+                       return MPATH_PR_OTHER;
+               }
+       case SAM_STAT_RESERVATION_CONFLICT:
+               return MPATH_PR_RESERV_CONFLICT;
+
+       default :
+               return  MPATH_PR_OTHER;
        }
 
        switch(io_hdr.host_status) {
-               case DID_OK :
-                       break;
-               default :
-                       return MPATH_PR_OTHER;
+       case DID_OK :
+               break;
+       default :
+               return MPATH_PR_OTHER;
        }
        switch(io_hdr.driver_status)
        {
-               case DRIVER_OK:
-                       break;
-               default :
-                       return MPATH_PR_OTHER;
+       case DRIVER_OK:
+               break;
+       default :
+               return MPATH_PR_OTHER;
        }
        return MPATH_PR_SUCCESS;
 }
 
-int mpath_isLittleEndian()
+int mpath_isLittleEndian(void)
 {
        int num = 1;
        if(*(char *)&num == 1)
index 7dfda5a..625490f 100644 (file)
@@ -5,17 +5,17 @@
 
 #if 0
 static const char * pr_type_strs[] = {
-    "obsolete [0]",
-    "Write Exclusive",
-    "obsolete [2]",
-    "Exclusive Access",
-    "obsolete [4]",
-    "Write Exclusive, registrants only",
-    "Exclusive Access, registrants only",
-    "Write Exclusive, all registrants",
-    "Exclusive Access, all registrants",
-    "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
-    "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
+       "obsolete [0]",
+       "Write Exclusive",
+       "obsolete [2]",
+       "Exclusive Access",
+       "obsolete [4]",
+       "Write Exclusive, registrants only",
+       "Exclusive Access, registrants only",
+       "Write Exclusive, all registrants",
+       "Exclusive Access, all registrants",
+       "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
+       "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
 };
 #endif
 
@@ -24,43 +24,43 @@ typedef unsigned char    BYTE;      /* unsigned numeric, bit patterns */
 
 typedef struct SenseData
 {
-    BYTE        Error_Code;
-    BYTE        Segment_Number; /* not applicable to DAC */
-    BYTE        Sense_Key;
-    BYTE        Information[ 4 ];
-    BYTE        Additional_Len;
-    LWORD       Command_Specific_Info;
-    BYTE        ASC;
-    BYTE        ASCQ;
-    BYTE        Field_Replaceable_Unit;
-    BYTE        Sense_Key_Specific_Info[ 3 ];
-    BYTE        Recovery_Action[ 2 ];
-    BYTE        Total_Errors;
-    BYTE        Total_Retries;
-    BYTE        ASC_Stack_1;
-    BYTE        ASCQ_Stack_1;
-    BYTE        ASC_Stack_2;
-    BYTE        ASCQ_Stack_2;
-    BYTE        Additional_FRU_Info[ 8 ];
-    BYTE        Error_Specific_Info[ 3 ];
-    BYTE        Error_Detection_Point[ 4 ];
-    BYTE        Original_CDB[10];
-    BYTE        Host_ID;
-    BYTE        Host_Descriptor[ 2 ];
-    BYTE        Serial_Number[ 16 ];
-    BYTE        Array_SW_Revision[ 4 ];
-    BYTE        Data_Xfer_Operation;
-    BYTE        LUN_Number;
-    BYTE        LUN_Status;
-    BYTE        Drive_ID;
-    BYTE        Xfer_Start_Drive_ID;
-    BYTE        Drive_SW_Revision[ 4 ];
-    BYTE        Drive_Product_ID[ 16 ];
-    BYTE        PowerUp_Status[ 2 ];
-    BYTE        RAID_Level;
-    BYTE        Drive_Sense_ID[ 2 ];
-    BYTE        Drive_Sense_Data[ 32 ];
-    BYTE        Reserved2[24];
+       BYTE        Error_Code;
+       BYTE        Segment_Number; /* not applicable to DAC */
+       BYTE        Sense_Key;
+       BYTE        Information[ 4 ];
+       BYTE        Additional_Len;
+       LWORD       Command_Specific_Info;
+       BYTE        ASC;
+       BYTE        ASCQ;
+       BYTE        Field_Replaceable_Unit;
+       BYTE        Sense_Key_Specific_Info[ 3 ];
+       BYTE        Recovery_Action[ 2 ];
+       BYTE        Total_Errors;
+       BYTE        Total_Retries;
+       BYTE        ASC_Stack_1;
+       BYTE        ASCQ_Stack_1;
+       BYTE        ASC_Stack_2;
+       BYTE        ASCQ_Stack_2;
+       BYTE        Additional_FRU_Info[ 8 ];
+       BYTE        Error_Specific_Info[ 3 ];
+       BYTE        Error_Detection_Point[ 4 ];
+       BYTE        Original_CDB[10];
+       BYTE        Host_ID;
+       BYTE        Host_Descriptor[ 2 ];
+       BYTE        Serial_Number[ 16 ];
+       BYTE        Array_SW_Revision[ 4 ];
+       BYTE        Data_Xfer_Operation;
+       BYTE        LUN_Number;
+       BYTE        LUN_Status;
+       BYTE        Drive_ID;
+       BYTE        Xfer_Start_Drive_ID;
+       BYTE        Drive_SW_Revision[ 4 ];
+       BYTE        Drive_Product_ID[ 16 ];
+       BYTE        PowerUp_Status[ 2 ];
+       BYTE        RAID_Level;
+       BYTE        Drive_Sense_ID[ 2 ];
+       BYTE        Drive_Sense_Data[ 32 ];
+       BYTE        Reserved2[24];
 } SenseData_t;
 
 #define MPATH_PRIN_CMD 0x5e
index 9ff4b30..5af2e03 100644 (file)
@@ -16,7 +16,6 @@
 #include "uxsock.h"
 #include "memory.h"
 
-unsigned long mem_allocated;    /* Total memory used in Bytes */
 
 int update_prflag(char * arg1, char * arg2, int noisy)
 {
index a14d4b3..3a20f8e 100644 (file)
@@ -1,15 +1,18 @@
-# Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
 include ../Makefile.inc
 
-SONAME=0
+SONAME = 0
 DEVLIB = libmultipath.so
 LIBS = $(DEVLIB).$(SONAME)
+
 CFLAGS += -I$(mpathcmddir)
+
 LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd
+
 ifdef SYSTEMD
+       CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
        ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1)
                LIBDEPS += -lsystemd
        else
@@ -17,14 +20,6 @@ ifdef SYSTEMD
        endif
 endif
 
-OBJS = memory.o parser.o vector.o devmapper.o callout.o \
-       hwtable.o blacklist.o util.o dmparser.o config.o \
-       structs.o discovery.o propsel.o dict.o \
-       pgpolicies.o debug.o defaults.o uevent.o \
-       switchgroup.o uxsock.o print.o alias.o log_pthread.o \
-       log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
-       lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o
-
 LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h)
 
 ifneq ($(strip $(LIBDM_API_FLUSH)),0)
@@ -43,16 +38,20 @@ ifneq ($(strip $(LIBUDEV_API_RECVBUF)),0)
        CFLAGS += -DLIBUDEV_API_RECVBUF
 endif
 
-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
 
+OBJS = memory.o parser.o vector.o devmapper.o callout.o \
+       hwtable.o blacklist.o util.o dmparser.o config.o \
+       structs.o discovery.o propsel.o dict.o \
+       pgpolicies.o debug.o defaults.o uevent.o \
+       switchgroup.o uxsock.o print.o alias.o log_pthread.o \
+       log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
+       lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o
+
 all: $(LIBS)
 
 $(LIBS): $(OBJS)
@@ -70,4 +69,4 @@ uninstall:
        $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
 
 clean:
-       $(RM) core *.a *.o *.gz *.so *.so.*
+       $(RM) core *.a *.o *.so *.so.* *.gz
index 2400eda..9687399 100644 (file)
@@ -210,7 +210,7 @@ setup_default_blist (struct config * conf)
                        if (alloc_ble_device(conf->blist_device))
                                return 1;
                        ble = VECTOR_SLOT(conf->blist_device,
-                                         VECTOR_SIZE(conf->blist_device) -1);
+                                         VECTOR_SIZE(conf->blist_device) - 1);
                        if (set_ble_device(conf->blist_device,
                                           STRDUP(hwe->vendor),
                                           STRDUP(hwe->bl_product),
index ad7d96c..fd999b0 100644 (file)
@@ -9,16 +9,16 @@
 #include "vector.h"
 
 char *checker_state_names[] = {
-      "wild",
-      "unchecked",
-      "down",
-      "up",
-      "shaky",
-      "ghost",
-      "pending",
-      "timeout",
-      "removed",
-      "delayed",
+       "wild",
+       "unchecked",
+       "down",
+       "up",
+       "shaky",
+       "ghost",
+       "pending",
+       "timeout",
+       "removed",
+       "delayed",
 };
 
 static LIST_HEAD(checkers);
@@ -138,6 +138,14 @@ struct checker * add_checker (char *multipath_dir, char * name)
        if (!c->free)
                goto out;
 
+       c->repair = (void (*)(struct checker *)) dlsym(c->handle,
+                                                      "libcheck_repair");
+       errstr = dlerror();
+       if (errstr != NULL)
+               condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+       if (!c->repair)
+               goto out;
+
        c->fd = 0;
        c->sync = 1;
        list_add(&c->node, &checkers);
@@ -203,6 +211,20 @@ void checker_put (struct checker * dst)
        free_checker(src);
 }
 
+void checker_repair (struct checker * c)
+{
+       if (!c || !checker_selected(c))
+               return;
+
+       c->message[0] = '\0';
+       if (c->disable) {
+               MSG(c, "checker disabled");
+               return;
+       }
+
+       c->repair(c);
+}
+
 int checker_check (struct checker * c)
 {
        int r;
@@ -272,6 +294,7 @@ void checker_get (char *multipath_dir, struct checker * dst, char * name)
        dst->sync = src->sync;
        strncpy(dst->name, src->name, CHECKER_NAME_LEN);
        strncpy(dst->message, src->message, CHECKER_MSG_LEN);
+       dst->repair = src->repair;
        dst->check = src->check;
        dst->init = src->init;
        dst->free = src->free;
index ac382d7..4fb97c9 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "list.h"
 #include "memory.h"
+#include "defaults.h"
 
 /*
  *
@@ -84,8 +85,7 @@ enum path_check_state {
 #define EMC_CLARIION "emc_clariion"
 #define READSECTOR0  "readsector0"
 #define CCISS_TUR    "cciss_tur"
-
-#define DEFAULT_CHECKER TUR
+#define RBD          "rbd"
 
 #define ASYNC_TIMEOUT_SEC      30
 
@@ -112,6 +112,9 @@ struct checker {
                                                multipath-wide. Use MALLOC if
                                                you want to stuff data in. */
        int (*check)(struct checker *);
+       void (*repair)(struct checker *);     /* called if check returns
+                                               PATH_DOWN to bring path into
+                                               usable state */
        int (*init)(struct checker *);       /* to allocate the context */
        void (*free)(struct checker *);      /* to free the context */
 };
@@ -131,6 +134,7 @@ void checker_set_async (struct checker *);
 void checker_set_fd (struct checker *, int);
 void checker_enable (struct checker *);
 void checker_disable (struct checker *);
+void checker_repair (struct checker *);
 int checker_check (struct checker *);
 int checker_selected (struct checker *);
 char * checker_name (struct checker *);
index fb8fff0..11ab76f 100644 (file)
@@ -1,9 +1,11 @@
-# Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
 include ../../Makefile.inc
 
+CFLAGS += -I..
+
+# If you add or remove a checker also update multipath/multipath.conf.5
 LIBS= \
        libcheckcciss_tur.so \
        libcheckreadsector0.so \
@@ -11,12 +13,14 @@ LIBS= \
        libcheckdirectio.so \
        libcheckemc_clariion.so \
        libcheckhp_sw.so \
-       libcheckrdac.so
-
-CFLAGS += -I..
+       libcheckrdac.so \
+       libcheckrbd.so
 
 all: $(LIBS)
 
+libcheckrbd.so: rbd.o
+       $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lrados -ludev
+
 libcheckdirectio.so: libsg.o directio.o
        $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio
 
index c9fa84a..cf20946 100644 (file)
 
 //Command List Structure
 typedef union _SCSI3Addr_struct {
-   struct {
-    BYTE Dev;
-    BYTE Bus:6;
-    BYTE Mode:2;        // b00
-  } PeripDev;
-   struct {
-    BYTE DevLSB;
-    BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
-  } LogDev;
-   struct {
-    BYTE Dev:5;
-    BYTE Bus:3;
-    BYTE Targ:6;
-    BYTE Mode:2;        // b10
-  } LogUnit;
+       struct {
+               BYTE Dev;
+               BYTE Bus:6;
+               BYTE Mode:2;        // b00
+       } PeripDev;
+       struct {
+               BYTE DevLSB;
+               BYTE DevMSB:6;
+               BYTE Mode:2;        // b01
+       } LogDev;
+       struct {
+               BYTE Dev:5;
+               BYTE Bus:3;
+               BYTE Targ:6;
+               BYTE Mode:2;        // b10
+       } LogUnit;
 } SCSI3Addr_struct;
 
 typedef struct _PhysDevAddr_struct {
-  DWORD             TargetId:24;
-  DWORD             Bus:6;
-  DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
+       DWORD             TargetId:24;
+       DWORD             Bus:6;
+       DWORD             Mode:2;
+       SCSI3Addr_struct  Target[2]; //2 level target device addr
 } PhysDevAddr_struct;
 
 typedef struct _LogDevAddr_struct {
-  DWORD            VolId:30;
-  DWORD            Mode:2;
-  BYTE             reserved[4];
+       DWORD            VolId:30;
+       DWORD            Mode:2;
+       BYTE             reserved[4];
 } LogDevAddr_struct;
 
 typedef union _LUNAddr_struct {
-  BYTE               LunAddrBytes[8];
-  SCSI3Addr_struct   SCSI3Lun[4];
-  PhysDevAddr_struct PhysDev;
-  LogDevAddr_struct  LogDev;
+       BYTE               LunAddrBytes[8];
+       SCSI3Addr_struct   SCSI3Lun[4];
+       PhysDevAddr_struct PhysDev;
+       LogDevAddr_struct  LogDev;
 } LUNAddr_struct;
 
 typedef struct _RequestBlock_struct {
-  BYTE   CDBLen;
-  struct {
-    BYTE Type:3;
-    BYTE Attribute:3;
-    BYTE Direction:2;
-  } Type;
-  HWORD  Timeout;
-  BYTE   CDB[16];
+       BYTE   CDBLen;
+       struct {
+               BYTE Type:3;
+               BYTE Attribute:3;
+               BYTE Direction:2;
+       } Type;
+       HWORD  Timeout;
+       BYTE   CDB[16];
 } RequestBlock_struct;
 
 typedef union _MoreErrInfo_struct{
-  struct {
-    BYTE  Reserved[3];
-    BYTE  Type;
-    DWORD ErrorInfo;
-  }Common_Info;
-  struct{
-    BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
-    DWORD offense_value;
-  }Invalid_Cmd;
-}MoreErrInfo_struct;
+       struct {
+               BYTE  Reserved[3];
+               BYTE  Type;
+               DWORD ErrorInfo;
+       } Common_Info;
+       struct{
+               BYTE  Reserved[2];
+               BYTE  offense_size;//size of offending entry
+               BYTE  offense_num; //byte # of offense 0-base
+               DWORD offense_value;
+       } Invalid_Cmd;
+} MoreErrInfo_struct;
 
 typedef struct _ErrorInfo_struct {
-  BYTE               ScsiStatus;
-  BYTE               SenseLen;
-  HWORD              CommandStatus;
-  DWORD              ResidualCnt;
-  MoreErrInfo_struct MoreErrInfo;
-  BYTE               SenseInfo[SENSEINFOBYTES];
+       BYTE               ScsiStatus;
+       BYTE               SenseLen;
+       HWORD              CommandStatus;
+       DWORD              ResidualCnt;
+       MoreErrInfo_struct MoreErrInfo;
+       BYTE               SenseInfo[SENSEINFOBYTES];
 } ErrorInfo_struct;
 
 #pragma pack()
index 81500dc..a0ffffe 100644 (file)
@@ -59,6 +59,11 @@ void libcheck_free (struct checker * c)
        return;
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 extern int
 libcheck_check (struct checker * c)
 {
index 94bf8f7..eec12d5 100644 (file)
@@ -118,6 +118,11 @@ void libcheck_free (struct checker * c)
        free(ct);
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 static int
 check_state(int fd, struct directio_context *ct, int sync, int timeout_secs)
 {
index 5e416a0..a7b9f86 100644 (file)
@@ -91,6 +91,11 @@ void libcheck_free (struct checker * c)
        free(c->context);
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 int libcheck_check (struct checker * c)
 {
        unsigned char sense_buffer[128] = { 0, };
index fe5e0f9..0cc1111 100644 (file)
@@ -44,6 +44,11 @@ void libcheck_free (struct checker * c)
        return;
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 static int
 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
        void *resp, int mx_resp_len, int noisy, unsigned int timeout)
diff --git a/libmultipath/checkers/rbd.c b/libmultipath/checkers/rbd.c
new file mode 100644 (file)
index 0000000..6f1b53a
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2016 Red Hat
+ * Copyright (c) 2004 Christophe Varoqui
+ *
+ * Code based off of tur.c and ceph's krbd.cc
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <libudev.h>
+#include <ifaddrs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include "rados/librados.h"
+
+#include "structs.h"
+#include "checkers.h"
+
+#include "../libmultipath/debug.h"
+#include "../libmultipath/uevent.h"
+
+struct rbd_checker_context;
+typedef int (thread_fn)(struct rbd_checker_context *ct, char *msg);
+
+#define RBD_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args);
+
+struct rbd_checker_context {
+       int rbd_bus_id;
+       char *client_addr;
+       char *config_info;
+       char *snap;
+       char *pool;
+       char *image;
+       char *username;
+       int remapped;
+       int blacklisted;
+
+       rados_t cluster;
+
+       int state;
+       int running;
+       time_t time;
+       thread_fn *fn;
+       pthread_t thread;
+       pthread_mutex_t lock;
+       pthread_cond_t active;
+       pthread_spinlock_t hldr_lock;
+       int holders;
+       char message[CHECKER_MSG_LEN];
+};
+
+int libcheck_init(struct checker * c)
+{
+       struct rbd_checker_context *ct;
+       struct udev_device *block_dev;
+       struct udev_device *bus_dev;
+       struct udev *udev;
+       struct stat sb;
+       const char *block_name, *addr, *config_info;
+       const char *image, *pool, *snap, *username;
+       char sysfs_path[PATH_SIZE];
+       int ret;
+
+       ct = malloc(sizeof(struct rbd_checker_context));
+       if (!ct)
+               return 1;
+       memset(ct, 0, sizeof(struct rbd_checker_context));
+       ct->holders = 1;
+       pthread_cond_init(&ct->active, NULL);
+       pthread_mutex_init(&ct->lock, NULL);
+       pthread_spin_init(&ct->hldr_lock, PTHREAD_PROCESS_PRIVATE);
+       c->context = ct;
+
+       /*
+        * The rbd block layer sysfs device is not linked to the rbd bus
+        * device that we interact with, so figure that out now.
+        */
+       if (fstat(c->fd, &sb) != 0)
+               goto free_ct;
+
+       udev = udev_new();
+       if (!udev)
+               goto free_ct;
+
+       block_dev = udev_device_new_from_devnum(udev, 'b', sb.st_rdev);
+       if (!block_dev)
+               goto free_udev;
+
+       block_name  = udev_device_get_sysname(block_dev);
+       ret = sscanf(block_name, "rbd%d", &ct->rbd_bus_id);
+
+       udev_device_unref(block_dev);
+       if (ret != 1)
+               goto free_udev;
+
+       snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d",
+                ct->rbd_bus_id);
+       bus_dev = udev_device_new_from_syspath(udev, sysfs_path);
+       if (!bus_dev)
+               goto free_udev;
+
+       addr = udev_device_get_sysattr_value(bus_dev, "client_addr");
+       if (!addr) {
+               condlog(0, "Could not find client_addr in rbd sysfs. Try "
+                       "updating kernel");
+               goto free_dev;
+       }
+
+       ct->client_addr = strdup(addr);
+       if (!ct->client_addr)
+               goto free_dev;
+
+       config_info = udev_device_get_sysattr_value(bus_dev, "config_info");
+       if (!config_info)
+               goto free_addr;
+
+       ct->config_info = strdup(config_info);
+       if (!ct->config_info)
+               goto free_addr;
+
+       username = strstr(config_info, "name=");
+       if (username) {
+               char *end;
+               int len;
+
+               username += 5;
+               end = strchr(username, ',');
+               if (!end)
+                       goto free_info;
+               len = end - username;
+
+               ct->username = malloc(len + 1);
+               if (!ct->username)
+                       goto free_info;
+               strncpy(ct->username, username, len);
+               ct->username[len] = '\0';
+       }
+
+       image = udev_device_get_sysattr_value(bus_dev, "name");
+       if (!image)
+               goto free_username;
+
+       ct->image = strdup(image);
+       if (!ct->image)
+               goto free_info;
+
+       pool = udev_device_get_sysattr_value(bus_dev, "pool");
+       if (!pool)
+               goto free_image;
+
+       ct->pool = strdup(pool);
+       if (!ct->pool)
+               goto free_image;
+
+       snap = udev_device_get_sysattr_value(bus_dev, "current_snap");
+       if (!snap)
+               goto free_pool;
+
+       if (strcmp("-", snap)) {
+               ct->snap = strdup(snap);
+               if (!ct->snap)
+                       goto free_pool;
+       }
+
+       if (rados_create(&ct->cluster, NULL) < 0) {
+               condlog(0, "Could not create rados cluster");
+               goto free_snap;
+       }
+
+       if (rados_conf_read_file(ct->cluster, NULL) < 0) {
+               condlog(0, "Could not read rados conf");
+               goto shutdown_rados;
+       }
+
+       ret = rados_connect(ct->cluster);
+       if (ret < 0) {
+               condlog(0, "Could not connect to rados cluster");
+               goto shutdown_rados;
+       }
+
+       udev_device_unref(bus_dev);
+       udev_unref(udev);
+
+       condlog(3, "rbd%d checker init %s %s/%s@%s %s", ct->rbd_bus_id,
+               ct->client_addr, ct->pool, ct->image, ct->snap ? ct->snap : "-",
+               ct->username ? ct->username : "none");
+       return 0;
+
+shutdown_rados:
+       rados_shutdown(ct->cluster);
+free_snap:
+       if (ct->snap)
+               free(ct->snap);
+free_pool:
+       free(ct->pool);
+free_image:
+       free(ct->image);
+free_username:
+       if (ct->username)
+               free(ct->username);
+free_info:
+       free(ct->config_info);
+free_addr:
+       free(ct->client_addr);
+free_dev:
+       udev_device_unref(bus_dev);
+free_udev:
+       udev_unref(udev);
+free_ct:
+       free(ct);
+       return 1;
+}
+
+void cleanup_context(struct rbd_checker_context *ct)
+{
+       pthread_mutex_destroy(&ct->lock);
+       pthread_cond_destroy(&ct->active);
+       pthread_spin_destroy(&ct->hldr_lock);
+
+       rados_shutdown(ct->cluster);
+
+       if (ct->username)
+               free(ct->username);
+       if (ct->snap)
+               free(ct->snap);
+       free(ct->pool);
+       free(ct->image);
+       free(ct->config_info);
+       free(ct->client_addr);
+       free(ct);
+}
+
+void libcheck_free(struct checker * c)
+{
+       if (c->context) {
+               struct rbd_checker_context *ct = c->context;
+               int holders;
+               pthread_t thread;
+
+               pthread_spin_lock(&ct->hldr_lock);
+               ct->holders--;
+               holders = ct->holders;
+               thread = ct->thread;
+               pthread_spin_unlock(&ct->hldr_lock);
+               if (holders)
+                       pthread_cancel(thread);
+               else
+                       cleanup_context(ct);
+               c->context = NULL;
+       }
+}
+
+static int rbd_is_blacklisted(struct rbd_checker_context *ct, char *msg)
+{
+       char *addr_tok, *start, *save;
+       char *cmd[2];
+       char *blklist, *stat;
+       size_t blklist_len, stat_len;
+       int ret;
+       char *end;
+
+       cmd[0] = "{\"prefix\": \"osd blacklist ls\"}";
+       cmd[1] = NULL;
+
+       ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0,
+                               &blklist, &blklist_len, &stat, &stat_len);
+       if (ret < 0) {
+               RBD_MSG(msg, "rbd checker failed: mon command failed %d",
+                       ret);
+               return ret;
+       }
+
+       if (!blklist || !blklist_len)
+               goto free_bufs;
+
+       /*
+        * parse list of addrs with the format
+        * ipv4:port/nonce date time\n
+        * or
+        * [ipv6]:port/nonce date time\n
+        */
+       ret = 0;
+       for (start = blklist; ; start = NULL) {
+               addr_tok = strtok_r(start, "\n", &save);
+               if (!addr_tok || !strlen(addr_tok))
+                       break;
+
+               end = strchr(addr_tok, ' ');
+               if (!end) {
+                       RBD_MSG(msg, "rbd%d checker failed: invalid blacklist %s",
+                                ct->rbd_bus_id, addr_tok);
+                       break;
+               }
+               *end = '\0';
+
+               if (!strcmp(addr_tok, ct->client_addr)) {
+                       ct->blacklisted = 1;
+                       RBD_MSG(msg, "rbd%d checker: %s is blacklisted",
+                               ct->rbd_bus_id, ct->client_addr);
+                       ret = 1;
+                       break;
+               }
+       }
+
+free_bufs:
+       rados_buffer_free(blklist);
+       rados_buffer_free(stat);
+       return ret;
+}
+
+int rbd_check(struct rbd_checker_context *ct, char *msg)
+{
+       if (ct->blacklisted || rbd_is_blacklisted(ct, msg) == 1)
+               return PATH_DOWN;
+
+       RBD_MSG(msg, "rbd checker reports path is up");
+       /*
+        * Path may have issues, but the ceph cluster is at least
+        * accepting IO, so we can attempt to do IO.
+        *
+        * TODO: in future versions, we can run other tests to
+        * verify OSDs and networks.
+        */
+       return PATH_UP;
+}
+
+int safe_write(int fd, const void *buf, size_t count)
+{
+       while (count > 0) {
+               ssize_t r = write(fd, buf, count);
+               if (r < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return -errno;
+               }
+               count -= r;
+               buf = (char *)buf + r;
+       }
+       return 0;
+}
+
+static int sysfs_write_rbd_bus(const char *which, const char *buf,
+                              size_t buf_len)
+{
+       char sysfs_path[PATH_SIZE];
+       int fd;
+       int r;
+
+       /* we require newer kernels so single_major should alwayws be there */
+       snprintf(sysfs_path, sizeof(sysfs_path),
+                "/sys/bus/rbd/%s_single_major", which);
+       fd = open(sysfs_path, O_WRONLY);
+       if (fd < 0)
+               return -errno;
+
+       r = safe_write(fd, buf, buf_len);
+       close(fd);
+       return r;
+}
+
+static int rbd_remap(struct rbd_checker_context *ct)
+{
+       char *argv[11];
+       pid_t pid;
+       int ret = 0, i = 0;
+       int status;
+
+       pid = fork();
+       switch (pid) {
+       case 0:
+               argv[i++] = "rbd";
+               argv[i++] = "map";
+               argv[i++] = "-o noshare";
+               if (ct->username) {
+                       argv[i++] = "--id";
+                       argv[i++] = ct->username;
+               }
+               argv[i++] = "--pool";
+               argv[i++] = ct->pool;
+               if (ct->snap) {
+                       argv[i++] = "--snap";
+                       argv[i++] = ct->snap;
+               }
+               argv[i++] = ct->image;
+               argv[i] = NULL;
+
+               ret = execvp(argv[0], argv);
+               condlog(0, "Error executing rbd: %s", strerror(errno));
+               exit(-1);
+       case -1:
+               condlog(0, "fork failed: %s", strerror(errno));
+               return -1;
+       default:
+               ret = -1;
+               wait(&status);
+               if (WIFEXITED(status)) {
+                       status = WEXITSTATUS(status);
+                       if (status == 0)
+                               ret = 0;
+                       else
+                               condlog(0, "rbd failed with %d", status);
+               }
+       }
+
+       return ret;
+}
+
+static int sysfs_write_rbd_remove(const char *buf, int buf_len)
+{
+       return sysfs_write_rbd_bus("remove", buf, buf_len);
+}
+
+static int rbd_rm_blacklist(struct rbd_checker_context *ct)
+{
+       char *cmd[2];
+       char *stat, *cmd_str;
+       size_t stat_len;
+       int ret;
+
+       ret = asprintf(&cmd_str, "{\"prefix\": \"osd blacklist\", \"blacklistop\": \"rm\", \"addr\": \"%s\"}",
+                      ct->client_addr);
+       if (ret == -1)
+               return -ENOMEM;
+
+       cmd[0] = cmd_str;
+       cmd[1] = NULL;
+
+       ret = rados_mon_command(ct->cluster, (const char **)cmd, 1, "", 0,
+                               NULL, 0, &stat, &stat_len);
+       if (ret < 0) {
+               condlog(1, "rbd%d repair failed to remove blacklist for %s %d",
+                       ct->rbd_bus_id, ct->client_addr, ret);
+               goto free_cmd;
+       }
+
+       condlog(1, "rbd%d repair rm blacklist for %s",
+              ct->rbd_bus_id, ct->client_addr);
+       free(stat);
+free_cmd:
+       free(cmd_str);
+       return ret;
+}
+
+static int rbd_repair(struct rbd_checker_context *ct, char *msg)
+{
+       char del[17];
+       int ret;
+
+       if (!ct->blacklisted)
+               return PATH_UP;
+
+       if (!ct->remapped) {
+               ret = rbd_remap(ct);
+               if (ret) {
+                       RBD_MSG(msg, "rbd%d repair failed to remap. Err %d",
+                               ct->rbd_bus_id, ret);
+                       return PATH_DOWN;
+               }
+       }
+       ct->remapped = 1;
+
+       snprintf(del, sizeof(del), "%d force", ct->rbd_bus_id);
+       ret = sysfs_write_rbd_remove(del, strlen(del) + 1);
+       if (ret) {
+               RBD_MSG(msg, "rbd%d repair failed to clean up. Err %d",
+                       ct->rbd_bus_id, ret);
+               return PATH_DOWN;
+       }
+
+       ret = rbd_rm_blacklist(ct);
+       if (ret) {
+               RBD_MSG(msg, "rbd%d repair could not remove blacklist entry. Err %d",
+                       ct->rbd_bus_id, ret);
+               return PATH_DOWN;
+       }
+
+       ct->remapped = 0;
+       ct->blacklisted = 0;
+
+       RBD_MSG(msg, "rbd%d has been repaired", ct->rbd_bus_id);
+       return PATH_UP;
+}
+
+#define rbd_thread_cleanup_push(ct) pthread_cleanup_push(cleanup_func, ct)
+#define rbd_thread_cleanup_pop(ct) pthread_cleanup_pop(1)
+
+void cleanup_func(void *data)
+{
+       int holders;
+       struct rbd_checker_context *ct = data;
+       pthread_spin_lock(&ct->hldr_lock);
+       ct->holders--;
+       holders = ct->holders;
+       ct->thread = 0;
+       pthread_spin_unlock(&ct->hldr_lock);
+       if (!holders)
+               cleanup_context(ct);
+}
+
+void *rbd_thread(void *ctx)
+{
+       struct rbd_checker_context *ct = ctx;
+       int state;
+
+       condlog(3, "rbd%d thread starting up", ct->rbd_bus_id);
+
+       ct->message[0] = '\0';
+       /* This thread can be canceled, so setup clean up */
+       rbd_thread_cleanup_push(ct)
+
+       /* checker start up */
+       pthread_mutex_lock(&ct->lock);
+       ct->state = PATH_PENDING;
+       pthread_mutex_unlock(&ct->lock);
+
+       state = ct->fn(ct, ct->message);
+
+       /* checker done */
+       pthread_mutex_lock(&ct->lock);
+       ct->state = state;
+       pthread_mutex_unlock(&ct->lock);
+       pthread_cond_signal(&ct->active);
+
+       condlog(3, "rbd%d thead finished, state %s", ct->rbd_bus_id,
+               checker_state_name(state));
+       rbd_thread_cleanup_pop(ct);
+       return ((void *)0);
+}
+
+static void rbd_timeout(struct timespec *tsp)
+{
+       struct timeval now;
+
+       gettimeofday(&now, NULL);
+       tsp->tv_sec = now.tv_sec;
+       tsp->tv_nsec = now.tv_usec * 1000;
+       tsp->tv_nsec += 1000000; /* 1 millisecond */
+}
+
+static int rbd_exec_fn(struct checker *c, thread_fn *fn)
+{
+       struct rbd_checker_context *ct = c->context;
+       struct timespec tsp;
+       pthread_attr_t attr;
+       int rbd_status, r;
+
+       if (c->sync)
+               return rbd_check(ct, c->message);
+       /*
+        * Async mode
+        */
+       r = pthread_mutex_lock(&ct->lock);
+       if (r != 0) {
+               condlog(2, "rbd%d mutex lock failed with %d", ct->rbd_bus_id,
+                       r);
+               MSG(c, "rbd%d thread failed to initialize", ct->rbd_bus_id);
+               return PATH_WILD;
+       }
+
+       if (ct->running) {
+               /* Check if checker is still running */
+               if (ct->thread) {
+                       condlog(3, "rbd%d thread not finished", ct->rbd_bus_id);
+                       rbd_status = PATH_PENDING;
+               } else {
+                       /* checker done */
+                       ct->running = 0;
+                       rbd_status = ct->state;
+                       strncpy(c->message, ct->message, CHECKER_MSG_LEN);
+                       c->message[CHECKER_MSG_LEN - 1] = '\0';
+               }
+               pthread_mutex_unlock(&ct->lock);
+       } else {
+               /* Start new checker */
+               ct->state = PATH_UNCHECKED;
+               ct->fn = fn;
+               pthread_spin_lock(&ct->hldr_lock);
+               ct->holders++;
+               pthread_spin_unlock(&ct->hldr_lock);
+               setup_thread_attr(&attr, 32 * 1024, 1);
+               r = pthread_create(&ct->thread, &attr, rbd_thread, ct);
+               if (r) {
+                       pthread_mutex_unlock(&ct->lock);
+                       ct->thread = 0;
+                       ct->holders--;
+                       condlog(3, "rbd%d failed to start rbd thread, using sync mode",
+                               ct->rbd_bus_id);
+                       return fn(ct, c->message);
+               }
+               pthread_attr_destroy(&attr);
+               rbd_timeout(&tsp);
+               r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp);
+               rbd_status = ct->state;
+               strncpy(c->message, ct->message,CHECKER_MSG_LEN);
+               c->message[CHECKER_MSG_LEN -1] = '\0';
+               pthread_mutex_unlock(&ct->lock);
+
+               if (ct->thread &&
+                   (rbd_status == PATH_PENDING || rbd_status == PATH_UNCHECKED)) {
+                       condlog(3, "rbd%d thread still running",
+                               ct->rbd_bus_id);
+                       ct->running = 1;
+                       rbd_status = PATH_PENDING;
+               }
+       }
+
+       return rbd_status;
+}
+
+void libcheck_repair(struct checker * c)
+{
+       struct rbd_checker_context *ct = c->context;
+
+       if (!ct || !ct->blacklisted)
+               return;
+       rbd_exec_fn(c, rbd_repair);
+}
+
+int libcheck_check(struct checker * c)
+{
+       struct rbd_checker_context *ct = c->context;
+
+       if (!ct)
+               return PATH_UNCHECKED;
+
+       if (ct->blacklisted)
+               return PATH_DOWN;
+
+       return rbd_exec_fn(c, rbd_check);
+}
index 00e3c44..68682c8 100644 (file)
@@ -139,6 +139,11 @@ void libcheck_free (struct checker * c)
        return;
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 static int
 do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len,
        unsigned int timeout)
index 1c2a868..8fccb46 100644 (file)
@@ -23,6 +23,11 @@ void libcheck_free (struct checker * c)
        return;
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 int libcheck_check (struct checker * c)
 {
        unsigned char buf[4096];
index 2edc8ad..c2ff5e9 100644 (file)
@@ -97,6 +97,11 @@ void libcheck_free (struct checker * c)
        return;
 }
 
+void libcheck_repair (struct checker * c)
+{
+       return;
+}
+
 #define TUR_MSG(msg, fmt, args...) snprintf(msg, CHECKER_MSG_LEN, fmt, ##args);
 
 int
@@ -107,7 +112,7 @@ tur_check(int fd, unsigned int timeout, char *msg)
        unsigned char sense_buffer[32];
        int retry_tur = 5;
 
- retry:
+retry:
        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
        memset(&sense_buffer, 0, 32);
        io_hdr.interface_id = 'S';
@@ -345,7 +350,7 @@ libcheck_check (struct checker * c)
                r = pthread_cond_timedwait(&ct->active, &ct->lock, &tsp);
                tur_status = ct->state;
                strncpy(c->message, ct->message,CHECKER_MSG_LEN);
-               c->message[CHECKER_MSG_LEN -1] = '\0';
+               c->message[CHECKER_MSG_LEN - 1] = '\0';
                pthread_mutex_unlock(&ct->lock);
                if (ct->thread &&
                    (tur_status == PATH_PENDING || tur_status == PATH_UNCHECKED)) {
index 9de5914..9bf27d6 100644 (file)
@@ -1,3 +1,7 @@
+/*
+ * If you add or modify a value also update multipath/multipath.conf.5
+ * and the TEMPLATE in libmultipath/hwtable.c
+ */
 #define DEFAULT_UID_ATTRIBUTE  "ID_SERIAL"
 #define DEFAULT_UDEVDIR                "/dev"
 #define DEFAULT_MULTIPATHDIR   "/" LIB_STRING "/multipath"
@@ -7,8 +11,8 @@
 #define DEFAULT_HWHANDLER      "0"
 #define DEFAULT_MINIO          1000
 #define DEFAULT_MINIO_RQ       1
-#define DEFAULT_PGPOLICY       GROUP_BY_PRIO
-#define DEFAULT_FAILBACK       -FAILBACK_IMMEDIATE
+#define DEFAULT_PGPOLICY       FAILOVER
+#define DEFAULT_FAILBACK       -FAILBACK_MANUAL
 #define DEFAULT_RR_WEIGHT      RR_WEIGHT_NONE
 #define DEFAULT_NO_PATH_RETRY  NO_PATH_RETRY_UNDEF
 #define DEFAULT_VERBOSITY      2
@@ -24,6 +28,9 @@
 #define DEFAULT_RETRIGGER_DELAY        10
 #define DEFAULT_RETRIGGER_TRIES        3
 #define DEFAULT_UEV_WAIT_TIMEOUT 30
+#define DEFAULT_PRIO           "const"
+#define DEFAULT_PRIO_ARGS      ""
+#define DEFAULT_CHECKER                TUR
 
 #define DEFAULT_CHECKINT       5
 #define MAX_CHECKINT(a)                (a << 2)
index 2c76d8b..5eb1713 100644 (file)
@@ -243,7 +243,7 @@ dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t
 
        if (udev_wait_flag)
                        dm_udev_wait(cookie);
-       out:
+out:
        dm_task_destroy (dmt);
        return r;
 }
@@ -327,11 +327,11 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
 
        if (task == DM_DEVICE_CREATE)
                        dm_udev_wait(cookie);
-       freeout:
+freeout:
        if (prefixed_uuid)
                FREE(prefixed_uuid);
 
-       addout:
+addout:
        dm_task_destroy (dmt);
 
        return r;
@@ -664,7 +664,7 @@ dm_dev_t (const char * mapname, char * dev_t, int len)
                goto out;
 
        if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
-                   goto out;
+               goto out;
 
        r = 0;
 out:
@@ -891,7 +891,7 @@ dm_flush_maps (void)
                names = (void *) names + next;
        } while (next);
 
-       out:
+out:
        dm_task_destroy (dmt);
        return r;
 }
index 4bc3b11..442d42e 100644 (file)
@@ -52,9 +52,9 @@ int dm_reassign_table(const char *name, char *old, char *new);
 int dm_setgeometry(struct multipath *mpp);
 
 #define VERSION_GE(v, minv) ( \
- (v[0] > minv[0]) || \
- ((v[0] == minv[0]) && (v[1] > minv[1])) || \
- ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])) \
      (v[0] > minv[0]) || \
      ((v[0] == minv[0]) && (v[1] > minv[1])) || \
      ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])) \
 )
 
 #endif /* _DEVMAPPER_H */
index 1933b6d..e8c6804 100644 (file)
@@ -1329,6 +1329,9 @@ snprint_deprecated (struct config *conf, char * buff, int len, void * data)
 
 #define __deprecated
 
+/*
+ * If you add or remove a keywork also update multipath/multipath.conf.5
+ */
 void
 init_keywords(vector keywords)
 {
index 1fb4db4..bb3116d 100644 (file)
@@ -491,7 +491,7 @@ sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen)
 {
        struct udev_device *parent = pp->udev;
        char value[16], *eptr;
-       unsigned int preferred;
+       unsigned long preferred;
 
        while (parent) {
                const char *subsys = udev_device_get_subsystem(parent);
@@ -1170,6 +1170,21 @@ scsi_sysfs_pathinfo (struct path * pp, vector hwtable)
 }
 
 static int
+rbd_sysfs_pathinfo (struct path * pp, vector hwtable)
+{
+       sprintf(pp->vendor_id, "Ceph");
+       sprintf(pp->product_id, "RBD");
+
+       condlog(3, "%s: vendor = %s product = %s", pp->dev, pp->vendor_id,
+               pp->product_id);
+       /*
+        * set the hwe configlet pointer
+        */
+       pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id, NULL);
+       return 0;
+}
+
+static int
 ccw_sysfs_pathinfo (struct path * pp, vector hwtable)
 {
        struct udev_device *parent;
@@ -1371,6 +1386,8 @@ sysfs_pathinfo(struct path * pp, vector hwtable)
                pp->bus = SYSFS_BUS_CCW;
        if (!strncmp(pp->dev,"sd", 2))
                pp->bus = SYSFS_BUS_SCSI;
+       if (!strncmp(pp->dev,"rbd", 3))
+               pp->bus = SYSFS_BUS_RBD;
 
        if (pp->bus == SYSFS_BUS_UNDEF)
                return 0;
@@ -1383,6 +1400,9 @@ sysfs_pathinfo(struct path * pp, vector hwtable)
        } else if (pp->bus == SYSFS_BUS_CCISS) {
                if (cciss_sysfs_pathinfo(pp, hwtable))
                        return 1;
+       } else if (pp->bus == SYSFS_BUS_RBD) {
+               if (rbd_sysfs_pathinfo(pp, hwtable))
+                       return 1;
        }
        return 0;
 }
@@ -1415,10 +1435,14 @@ scsi_ioctl_pathinfo (struct path * pp, int mask)
        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);
+       if (get_vpd_sysfs(parent, 0x80, pp->serial, SERIAL_SIZE) <= 0) {
+               if (get_serial(pp->serial, SERIAL_SIZE, pp->fd)) {
+                       condlog(2, "%s: fail to get serial", pp->dev);
+                       return 0;
+               }
+       }
 
+       condlog(3, "%s: serial = %s", pp->dev, pp->serial);
        return 0;
 }
 
@@ -1540,6 +1564,53 @@ get_udev_uid(struct path * pp, char *uid_attribute)
 }
 
 static int
+get_rbd_uid(struct path * pp)
+{
+       struct udev_device *rbd_bus_dev;
+       int ret, rbd_bus_id;
+       const char *pool, *image, *snap;
+       char sysfs_path[PATH_SIZE];
+       uint64_t snap_id, max_snap_id = -3;
+
+       ret = sscanf(pp->dev, "rbd%d", &rbd_bus_id);
+       if (ret != 1)
+               return -EINVAL;
+
+       snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/rbd/devices/%d",
+                rbd_bus_id);
+       rbd_bus_dev = udev_device_new_from_syspath(udev, sysfs_path);
+       if (!rbd_bus_dev)
+               return -ENODEV;
+
+       ret = -EINVAL;
+       pool = udev_device_get_sysattr_value(rbd_bus_dev, "pool_id");
+       if (!pool)
+               goto free_dev;
+
+       image = udev_device_get_sysattr_value(rbd_bus_dev, "image_id");
+       if (!image)
+               goto free_dev;
+
+       snap = udev_device_get_sysattr_value(rbd_bus_dev, "snap_id");
+       if (!snap)
+               goto free_dev;
+       snap_id = strtoull(snap, NULL, 19);
+       if (snap_id >= max_snap_id)
+               ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s", pool, image);
+       else
+               ret = snprintf(pp->wwid, WWID_SIZE, "%s-%s-%s", pool,
+                              image, snap);
+       if (ret >= WWID_SIZE) {
+               condlog(0, "%s: wwid overflow", pp->dev);
+               ret = -EOVERFLOW;
+       }
+
+free_dev:
+       udev_device_unref(rbd_bus_dev);
+       return ret;
+}
+
+static int
 get_vpd_uid(struct path * pp)
 {
        struct udev_device *parent = pp->udev;
@@ -1591,6 +1662,9 @@ get_uid (struct path * pp, int path_state)
                } else
                        len = strlen(pp->wwid);
                origin = "callout";
+       } else if (pp->bus == SYSFS_BUS_RBD) {
+               len = get_rbd_uid(pp);
+               origin = "sysfs";
        } else {
                int retrigger;
 
index a1fc3e8..e518d6a 100644 (file)
  */
 static struct hwentry default_hw[] = {
        /*
-        * Compellent Technologies/DELL
-        */
-       {
-               .vendor        = "COMPELNT",
-               .product       = "Compellent Vol",
-               .pgpolicy      = MULTIBUS,
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
-       },
-       /*
         * Apple
         *
         * Maintainer : Shyam Sundar
         * Mail : g.shyamsundar@yahoo.co.in
         */
        {
-               .vendor        = "APPLE.*",
+               .vendor        = "APPLE",
                .product       = "Xserve RAID",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
        },
        /*
-        * StorageWorks/HPE
+        * HPE
         */
        {
                .vendor        = "3PARdata",
                .product       = "VV",
-               .pgpolicy      = MULTIBUS,
-               .pgfailback    = FAILBACK_UNDEF,
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .hwhandler     = "1 alua",
+               .prio_name     = PRIO_ALUA,
+               .no_path_retry = 18,
        },
        {
+               /* RA8000 / ESA12000 */
                .vendor        = "DEC",
                .product       = "HSG80",
                .features      = "1 queue_if_no_path",
                .hwhandler     = "1 hp_sw",
+               .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = FAILBACK_UNDEF,
                .checker_name  = HP_SW,
                .prio_name     = PRIO_HP_SW,
        },
        {
+               /* VIRTUAL ARRAY 7400 */
                .vendor        = "HP",
                .product       = "A6189A",
                .pgpolicy      = MULTIBUS,
@@ -71,11 +68,12 @@ static struct hwentry default_hw[] = {
                .no_path_retry = 12,
        },
        {
-               /* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */
+               /* MSA 1000/1500 and EVA 3000/5000, with old firmware */
                .vendor        = "(COMPAQ|HP)",
-               .product       = "(MSA|HSV)1.0.*",
+               .product       = "(MSA|HSV)1[01]0",
                .features      = "1 queue_if_no_path",
                .hwhandler     = "1 hp_sw",
+               .pgpolicy      = GROUP_BY_PRIO,
                .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = 12,
                .minio         = 100,
@@ -86,6 +84,8 @@ static struct hwentry default_hw[] = {
                /* MSA 1000/1500 with new firmware */
                .vendor        = "(COMPAQ|HP)",
                .product       = "MSA VOLUME",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 12,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
@@ -93,62 +93,73 @@ static struct hwentry default_hw[] = {
        {
                /* EVA 3000/5000 with new firmware, EVA 4000/6000/8000 */
                .vendor        = "(COMPAQ|HP)",
-               .product       = "HSV1[01]1|HSV2[01]0|HSV3[046]0|HSV4[05]0",
+               .product       = "(HSV1[01]1|HSV2[01]0|HSV3[046]0|HSV4[05]0)",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 12,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* HP MSA2000 family with old firmware */
+               /* MSA2000 family with old firmware */
                .vendor        = "HP",
-               .product       = "MSA2[02]12fc|MSA2012i",
+               .product       = "(MSA2[02]12fc|MSA2012i)",
                .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = 18,
                .minio         = 100,
        },
        {
-               /* HP MSA2000 family with new firmware */
+               /* MSA2000 family with new firmware */
                .vendor        = "HP",
-               .product       = "MSA2012sa|MSA23(12|24)(fc|i|sa)|MSA2000s VOLUME",
+               .product       = "(MSA2012sa|MSA23(12|24)(fc|i|sa)|MSA2000s VOLUME)",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 18,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* HP MSA 1040/2040 family */
+               /* MSA 1040/2040 family */
                .vendor        = "HP",
-               .product       = "MSA (1|2)040 SA(N|S)",
+               .product       = "MSA [12]040 SA[NS]",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 18,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* HP SVSP */
+               /* SAN Virtualization Services Platform */
                .vendor        = "HP",
                .product       = "HSVX700",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 12,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* HP Smart Array */
+               /* Smart Array */
                .vendor        = "HP",
-               .product       = "LOGICAL VOLUME.*",
+               .product       = "LOGICAL VOLUME",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = 12,
        },
        {
-               /* HP P2000 family */
+               /* P2000 family */
                .vendor        = "HP",
-               .product       = "P2000 G3 FC|P2000G3 FC/iSCSI|P2000 G3 SAS|P2000 G3 iSCSI",
+               .product       = "(P2000 G3 FC|P2000G3 FC/iSCSI|P2000 G3 SAS|P2000 G3 iSCSI)",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 18,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        /*
-        * DDN
+        * DataDirect Networks
         */
        {
                .vendor        = "DDN",
@@ -157,12 +168,10 @@ static struct hwentry default_hw[] = {
                .pgfailback    = FAILBACK_UNDEF,
        },
        /*
-        * EMC/DELL
-        *
-        * Maintainer : Edward Goggin, EMC
-        * Mail : egoggin@emc.com
+        * EMC
         */
        {
+               /* Symmetrix / DMX / VMAX */
                .vendor        = "EMC",
                .product       = "SYMMETRIX",
                .pgpolicy      = MULTIBUS,
@@ -172,15 +181,18 @@ static struct hwentry default_hw[] = {
        {
                /* DGC CLARiiON CX/AX and EMC VNX */
                .vendor        = "^DGC",
-               .product       = "^RAID|^DISK|^VRAID",
+               .product       = "^(RAID|DISK|VRAID)",
                .bl_product    = "LUNZ",
                .features      = "1 queue_if_no_path",
                .hwhandler     = "1 emc",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = (300 / DEFAULT_CHECKINT),
                .checker_name  = EMC_CLARIION,
                .prio_name     = PRIO_EMC,
        },
        {
+               /* Invista / VPLEX */
                .vendor        = "EMC",
                .product       = "Invista",
                .bl_product    = "LUNZ",
@@ -196,6 +208,52 @@ static struct hwentry default_hw[] = {
                .pgfailback    = FAILBACK_UNDEF,
        },
        /*
+        * DELL
+        */
+       {
+               .vendor        = "COMPELNT",
+               .product       = "Compellent Vol",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
+               .no_path_retry = NO_PATH_RETRY_QUEUE,
+       },
+       {
+               .vendor        = "DELL",
+               .product       = "MD3000",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               .vendor        = "DELL",
+               .product       = "(MD32xx|MD36xx)",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               .vendor        = "DELL",
+               .product       = "(MD34xx|MD38xx)",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       /*
         * Fujitsu
         */
        {
@@ -208,9 +266,18 @@ static struct hwentry default_hw[] = {
                .vendor        = "FUJITSU",
                .product       = "ETERNUS_DX(H|L|M|400|8000)",
                .features      = "1 queue_if_no_path",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 10,
                .prio_name     = PRIO_ALUA,
        },
+       {
+               /* FibreCAT S80 */
+               .vendor        = "(EUROLOGC|EuroLogc)",
+               .product       = "FC2502",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
+       },
        /*
         * Hitachi
         *
@@ -218,21 +285,25 @@ static struct hwentry default_hw[] = {
         * Mail : matthias.rudolph@hds.com
         */
        {
+               /* USP-V, HUS VM, VSP, VSP G1000 and VSP GX00 families */
                .vendor        = "(HITACHI|HP)",
-               .product       = "OPEN-.*",
+               .product       = "^OPEN-",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
+               /* AMS 2000 and HUS 100 families */
                .vendor        = "HITACHI",
-               .product       = "DF.*",
+               .product       = "^DF",
                .features      = "1 queue_if_no_path",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .prio_name     = PRIO_HDS,
        },
        /*
         * IBM
         *
-        * Maintainer : Hannes Reinecke, SuSE
+        * Maintainer : Hannes Reinecke
         * Mail : hare@suse.de
         */
        {
@@ -242,130 +313,161 @@ static struct hwentry default_hw[] = {
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM FAStT 1722-600 */
+               /* DS4300 / FAStT600 */
                .vendor        = "IBM",
                .product       = "^1722-600",
                .bl_product    = "Universal Xport",
-               .features      = "1 queue_if_no_path",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 300,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS4100 */
+               /* DS4100 / FAStT100 */
                .vendor        = "IBM",
                .product       = "^1724",
                .bl_product    = "Universal Xport",
-               .features      = "1 queue_if_no_path",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 300,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS3200 / DS3300 / DS3400 */
+               /* DS3200 / DS3300 / DS3400 / Boot DS */
                .vendor        = "IBM",
                .product       = "^1726",
                .bl_product    = "Universal Xport",
-               .features      = "1 queue_if_no_path",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 300,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS4400 / DS4500 / FAStT700 */
+               /* DS4400 / DS4500 / FAStT700 / FAStT900 */
                .vendor        = "IBM",
                .product       = "^1742",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
+               /* DS3500 / DS3512 / DS3524 */
                .vendor        = "IBM",
-               .product       = "^1745|^1746",
+               .product       = "^1746",
                .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
                .features      = "2 pg_init_retries 50",
                .hwhandler     = "1 rdac",
-               .no_path_retry = 15,
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               /* DCS3860 */
+               .vendor        = "IBM",
+               .product       = "^1813",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS4700 */
+               /* DS3950 / DS4200 / DS4700 / DS5020 */
                .vendor        = "IBM",
                .product       = "^1814",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS4800 */
+               /* DS4800 */
                .vendor        = "IBM",
                .product       = "^1815",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS5000 */
+               /* DS5000 / DS5100 / DS5300 / DCS3700 */
                .vendor        = "IBM",
                .product       = "^1818",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM Netfinity Fibre Channel RAID Controller Unit */
+               /* Netfinity Fibre Channel RAID Controller Unit */
                .vendor        = "IBM",
                .product       = "^3526",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               /* IBM DS4200 / FAStT200 */
+               /* DS4200 / FAStT200 */
                .vendor        = "IBM",
                .product       = "^3542",
                .pgpolicy      = GROUP_BY_SERIAL,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM ESS F20 aka Shark */
+               /* Enterprise Storage Server / Shark family */
                .vendor        = "IBM",
-               .product       = "^2105800",
+               .product       = "^2105",
                .features      = "1 queue_if_no_path",
                .pgpolicy      = GROUP_BY_SERIAL,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM ESS F20 aka Shark */
-               .vendor        = "IBM",
-               .product       = "^2105F20",
-               .features      = "1 queue_if_no_path",
-               .pgpolicy      = GROUP_BY_SERIAL,
-               .pgfailback    = FAILBACK_UNDEF,
-       },
-       {
-               /* IBM DS6000 */
+               /* DS6000 */
                .vendor        = "IBM",
                .product       = "^1750500",
                .features      = "1 queue_if_no_path",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* IBM DS8000 */
+               /* DS8000 */
                .vendor        = "IBM",
                .product       = "^2107900",
                .features      = "1 queue_if_no_path",
@@ -373,146 +475,130 @@ static struct hwentry default_hw[] = {
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM SAN Volume Controller */
+               /* Storwize family / SAN Volume Controller / Flex System V7000 */
                .vendor        = "IBM",
                .product       = "^2145",
                .features      = "1 queue_if_no_path",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* IBM S/390 ECKD DASD */
                .vendor        = "IBM",
                .product       = "S/390 DASD ECKD",
-               .bl_product    = "S/390.*",
+               .bl_product    = "S/390",
                .uid_attribute = "ID_UID",
                .features      = "1 queue_if_no_path",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM S/390 FBA DASD */
                .vendor        = "IBM",
                .product       = "S/390 DASD FBA",
-               .bl_product    = "S/390.*",
+               .bl_product    = "S/390",
                .uid_attribute = "ID_UID",
                .features      = "1 queue_if_no_path",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
-               /* IBM IPR */
+               /* Power RAID */
                .vendor        = "IBM",
-               .product       = "^IPR.*",
+               .product       = "^IPR",
                .features      = "1 queue_if_no_path",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* IBM RSSM */
+               /* SAS RAID Controller Module (RSSM) */
                .vendor        = "IBM",
                .product       = "1820N00",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = NO_PATH_RETRY_QUEUE,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* IBM XIV Storage System */
+               /* XIV Storage System */
                .vendor        = "IBM",
                .product       = "2810XIV",
                .features      = "1 queue_if_no_path",
                .pgpolicy      = MULTIBUS,
-               .pgfailback    = 15,
+               .pgfailback    = FAILBACK_UNDEF,
                .minio         = 15,
        },
-       /*
-        * IBM Power Virtual SCSI Devices
-        *
-        * Maintainer : Brian King, IBM
-        * Mail : brking@linux.vnet.ibm.com
-        */
+               /*
+                * IBM Power Virtual SCSI Devices
+                *
+                * Maintainer : Brian King
+                * Mail : brking@linux.vnet.ibm.com
+                */
        {
-               /* AIX VDASD */
                .vendor        = "AIX",
                .product       = "VDASD",
                .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = (300 / DEFAULT_CHECKINT),
        },
        {
-               /* IBM 3303 NVDISK */
+               /* 3303 NVDISK */
                .vendor        = "IBM",
-               .product       = "3303      NVDISK",
+               .product       = "3303[ ]+NVDISK",
+               .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = (300 / DEFAULT_CHECKINT),
-               .pgpolicy      = FAILOVER,
        },
        {
-               /* AIX NVDISK */
                .vendor        = "AIX",
                .product       = "NVDISK",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = (300 / DEFAULT_CHECKINT),
                .prio_name     = PRIO_ALUA,
        },
        /*
-        * DELL
-        */
-       {
-               /* DELL MD3000 */
-               .vendor        = "DELL",
-               .product       = "MD3000",
-               .bl_product    = "Universal Xport",
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 15,
-               .checker_name  = RDAC,
-               .prio_name     = PRIO_RDAC,
-       },
-       {
-               /* DELL MD32xx/MD36xx */
-               .vendor        = "DELL",
-               .product       = "MD32xx|MD36xx",
-               .bl_product    = "Universal Xport",
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 15,
-               .checker_name  = RDAC,
-               .prio_name     = PRIO_RDAC,
-       },
-       {
-               /* DELL MD34xx/MD38xx */
-               .vendor        = "DELL",
-               .product       = "MD34xx|MD38xx",
-               .bl_product    = "Universal Xport",
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = 15,
-               .checker_name  = RDAC,
-               .prio_name     = PRIO_RDAC,
-       },
-       /*
-        * NETAPP ONTAP family
-        *
-        * Maintainer : Martin George
-        * Mail : marting@netapp.com
+        * NetApp
         */
        {
+               /*
+                * ONTAP family
+                *
+                * Maintainer : Martin George
+                * Mail : marting@netapp.com
+                */
                .vendor        = "NETAPP",
-               .product       = "LUN.*",
+               .product       = "LUN",
                .features      = "3 queue_if_no_path pg_init_retries 50",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .flush_on_last_del = FLUSH_ENABLED,
                .minio         = 128,
                .dev_loss      = MAX_DEV_LOSS_TMO,
                .prio_name     = PRIO_ONTAP,
        },
        {
-               /* IBM NSeries */
-               .vendor        = "IBM",
-               .product       = "Nseries.*",
-               .features      = "1 queue_if_no_path",
-               .minio         = 128,
-               .prio_name     = PRIO_ONTAP,
+               /*
+                * SANtricity(RDAC) family
+                *
+                * Maintainer : Sean Stewart
+                * Mail : sean.stewart@netapp.com
+                */
+               .vendor        = "(NETAPP|LSI|ENGENIO)",
+               .product       = "INF-01-00",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        /*
-        * NEXENTA
+        * Nexenta
         *
         * Maintainer : Yacine Kheddache
         * Mail : yacine@alyseo.com
@@ -522,48 +608,43 @@ static struct hwentry default_hw[] = {
                .product       = "COMSTAR",
                .features      = "1 queue_if_no_path",
                .pgpolicy      = GROUP_BY_SERIAL,
+               .pgfailback    = FAILBACK_UNDEF,
                .no_path_retry = 30,
                .minio         = 128,
        },
        /*
-        * Pillar Data/Oracle
-        *
-        * Maintainer : Srinivasan Ramani
-        * Mail : srinivas.ramani@oracle.com
-        */
-       {
-               .vendor        = "Pillar",
-               .product       = "Axiom.*",
-               .pgfailback    = FAILBACK_UNDEF,
-               .prio_name     = PRIO_ALUA,
-       },
-       /*
         * SGI
         */
        {
                .vendor        = "SGI",
-               .product       = "TP9[13]00",
+               .product       = "TP9100",
                .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
        },
        {
                .vendor        = "SGI",
-               .product       = "TP9[45]00",
+               .product       = "TP9[345]00",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
+               /* InfiniteStorage ??? */
                .vendor        = "SGI",
-               .product       = "IS.*",
+               .product       = "IS",
                .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
                .features      = "2 pg_init_retries 50",
                .hwhandler     = "1 rdac",
-               .no_path_retry = 15,
-               .checker_name  = RDAC,
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        /*
         * NEC
@@ -573,22 +654,58 @@ static struct hwentry default_hw[] = {
                .vendor        = "NEC",
                .product       = "DISK ARRAY",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .prio_name     = PRIO_ALUA,
        },
        /*
-        * STK/Oracle
+        * Oracle
         */
+               /*
+                * Pillar Data / Oracle FS
+                *
+                * Maintainer : Srinivasan Ramani
+                * Mail : srinivas.ramani@oracle.com
+                */
+       {
+               .vendor        = "^Pillar",
+               .product       = "^Axiom",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .prio_name     = PRIO_ALUA,
+       },
+       {
+               .vendor        = "^Oracle",
+               .product       = "^Oracle FS",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .prio_name     = PRIO_ALUA,
+       },
+               /* Sun - StorageTek */
        {
                .vendor        = "STK",
                .product       = "OPENstorage D280",
                .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
                .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               .vendor        = "STK",
+               .product       = "FLEXLINE 380",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
-       /*
-        * SUN/Oracle
-        */
        {
                .vendor        = "SUN",
                .product       = "(StorEdge 3510|T4)",
@@ -599,171 +716,162 @@ static struct hwentry default_hw[] = {
                .vendor        = "SUN",
                .product       = "STK6580_6780",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
        {
-               .vendor        = "EUROLOGC",
-               .product       = "FC2502",
-               .pgfailback    = FAILBACK_UNDEF,
-       },
-       /*
-        * Pivot3
-        *
-        * Maintainer : Bart Brooks, Pivot3
-        * Mail : bartb@pivot3.com
-        */
-       {
-               .vendor        = "PIVOT3",
-               .product       = "RAIGE VOLUME",
-               .features      = "1 queue_if_no_path",
-               .pgpolicy      = MULTIBUS,
-               .pgfailback    = FAILBACK_UNDEF,
-               .minio         = 100,
-       },
-       {
+               /* 6140 */
                .vendor        = "SUN",
                .product       = "CSM200_R",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
-       /* SUN/LSI 2510, 2540, 2530, 2540 */
        {
+               /* 2510 / 2530 / 2540 */
                .vendor        = "SUN",
                .product       = "LCSM100_[IEFS]",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
-       /* StorageTek 6180 */
        {
                .vendor        = "SUN",
                .product       = "SUN_6180",
                .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
+               .pgpolicy      = GROUP_BY_PRIO,
                .checker_name  = RDAC,
-               .prio_name     = PRIO_RDAC,
-       },
-       /* LSI/Engenio/NetApp RDAC
-        *
-        * Maintainer : Sean Stewart
-        * Mail : sean.stewart@netapp.com
-        */
-       {
-               .vendor        = "(NETAPP|LSI|ENGENIO)",
-               .product       = "INF-01-00",
-               .bl_product    = "Universal Xport",
                .features      = "2 pg_init_retries 50",
                .hwhandler     = "1 rdac",
-               .no_path_retry = 30,
-               .checker_name  = RDAC,
                .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
        },
+       /*
+        * Pivot3
+        *
+        * Maintainer : Bart Brooks
+        * Mail : bartb@pivot3.com
+        */
        {
-               .vendor        = "STK",
-               .product       = "FLEXLINE 380",
-               .bl_product    = "Universal Xport",
-               .hwhandler     = "1 rdac",
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
-               .checker_name  = RDAC,
-               .prio_name     = PRIO_RDAC,
+               .vendor        = "PIVOT3",
+               .product       = "RAIGE VOLUME",
+               .features      = "1 queue_if_no_path",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
+               .minio         = 100,
        },
+       /*
+        * Intel
+        */
        {
-               .vendor        = "Intel",
+               .vendor        = "(Intel|INTEL)",
                .product       = "Multi-Flex",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = NO_PATH_RETRY_QUEUE,
                .prio_name     = PRIO_ALUA,
        },
+       /*
+        * Linux-IO Target
+        */
        {
                .vendor        = "(LIO-ORG|SUSE)",
                .product       = "RBD",
                .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = 12,
                .minio         = 100,
                .prio_name     = PRIO_ALUA,
        },
+       /*
+        * DataCore
+        */
        {
                .vendor        = "DataCore",
                .product       = "SANmelody",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = NO_PATH_RETRY_QUEUE,
                .prio_name     = PRIO_ALUA,
        },
        {
                .vendor        = "DataCore",
                .product       = "Virtual Disk",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
                .no_path_retry = NO_PATH_RETRY_QUEUE,
                .prio_name     = PRIO_ALUA,
        },
+       /*
+        * Pure Storage
+        */
        {
                .vendor        = "PURE",
                .product       = "FlashArray",
                .selector      = "queue-length 0",
                .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
                .fast_io_fail  = 10,
-               .no_path_retry = 0,
                .dev_loss      = 60,
        },
-       {
-               .vendor        = "HUAWEI",
-               .product       = "XSG1",
-               .pgpolicy      = MULTIBUS,
-       },
        /*
-        * Violin Memory
+        * Huawei
         */
        {
-               .vendor        = "VIOLIN",
-               .product       = "CONCERTO ARRAY",
-               .selector      = "round-robin 0",
+               /* OceanStor V3 */
+               .vendor        = "(HUAWEI|HUASY)",
+               .product       = "XSG1",
                .pgpolicy      = MULTIBUS,
-               .prio_name     = PRIO_ALUA,
-               .minio         = 100,
-               .rr_weight     = RR_WEIGHT_PRIO,
-               .features      = "1 queue_if_no_path",
-               .no_path_retry = 300,
+               .pgfailback    = FAILBACK_UNDEF,
        },
        /*
-        * Infinidat
+        * Red Hat
+        *
+        * Maintainer: Mike Christie
+        * Mail: mchristi@redhat.com
         */
        {
-               .vendor        = "NFINIDAT",
-               .product       = "InfiniBox.*",
-               .prio_name     = PRIO_ALUA,
-               .selector      = "round-robin 0",
-               .pgfailback    = 30,
-               .rr_weight     = RR_WEIGHT_PRIO,
+               .vendor        = "Ceph",
+               .product       = "RBD",
                .no_path_retry = NO_PATH_RETRY_FAIL,
-               .flush_on_last_del = FLUSH_ENABLED,
-               .dev_loss      = 30,
+               .checker_name  = RBD,
+               .deferred_remove = DEFERRED_REMOVE_ON,
        },
        /*
-        * Tegile Systems
+        * Kove
         */
        {
-               .vendor        = "TEGILE",
-               .product       = "ZEBI-(FC|ISCSI)|INTELLIFLASH",
-               .hwhandler     = "1 alua",
-               .selector      = "round-robin 0",
-               .no_path_retry = 10,
-               .dev_loss      = 50,
-               .prio_name     = PRIO_ALUA,
-               .pgfailback    = 30,
-               .minio         = 128,
+               .vendor        = "KOVE",
+               .product       = "XPD",
+               .pgpolicy      = MULTIBUS,
+               .pgfailback    = FAILBACK_UNDEF,
        },
 #if 0
        /*
         * Copy this TEMPLATE to add new hardware.
         *
         * Keep only mandatory and modified attributes.
-        * Standard attributes must be removed.
+        * Attributes with default values must be removed.
+        * Only .vendor and .product are mandatory, all other are optional.
+        * .vendor, .product, .revision and .bl_product are POSIX Extended regex
         *
         * COMPANY_NAME
         *
@@ -771,11 +879,12 @@ static struct hwentry default_hw[] = {
         * Mail : XXX
         */
        {
-               .vendor        = "VENDOR", (Mandatory)
-               .product       = "PRODUCT", (Mandatory)
+               /* If product-ID is different from marketing name add a comment */
+               .vendor        = "VENDOR",
+               .product       = "PRODUCT",
                .revision      = "REVISION",
                .bl_product    = "BL_PRODUCT",
-               .pgpolicy      = GROUP_BY_PRIO,
+               .pgpolicy      = FAILOVER,
                .uid_attribute = "ID_SERIAL",
                .selector      = "service-time 0",
                .checker_name  = TUR,
@@ -783,7 +892,7 @@ static struct hwentry default_hw[] = {
                .hwhandler     = "0",
                .prio_name     = "const",
                .prio_args     = "",
-               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .pgfailback    = -FAILBACK_MANUAL,
                .rr_weight     = RR_WEIGHT_NONE,
                .no_path_retry = NO_PATH_RETRY_UNDEF,
                .minio         = 1000,
@@ -804,18 +913,6 @@ static struct hwentry default_hw[] = {
        {
                .vendor        = NULL,
                .product       = NULL,
-               .features      = NULL,
-               .hwhandler     = NULL,
-               .selector      = NULL,
-               .pgpolicy      = 0,
-               .pgfailback    = 0,
-               .rr_weight     = 0,
-               .no_path_retry = 0,
-               .minio         = 0,
-               .minio_rq      = 0,
-               .checker_name  = NULL,
-               .prio_name     = NULL,
-               .prio_args     = NULL,
        },
 };
 
index ec53a5e..72c70e3 100644 (file)
@@ -1,8 +1,8 @@
-#include <pthread.h>
 #include "lock.h"
-#include <stdio.h>
 
 void cleanup_lock (void * data)
 {
-       unlock ((*(struct mutex_lock *)data));
+       struct mutex_lock *lock = data;
+
+       unlock(lock);
 }
index 97af0f4..a170efe 100644 (file)
@@ -1,32 +1,28 @@
 #ifndef _LOCK_H
 #define _LOCK_H
 
-#include <signal.h>
+#include <pthread.h>
 
-/*
- * Wrapper for the mutex. Includes a ref-count to keep
- * track of how many there are out-standing threads blocking
- * on a mutex. */
 struct mutex_lock {
-       pthread_mutex_t *mutex;
-       int depth;
+       pthread_mutex_t mutex;
 };
 
-#ifdef LCKDBG
-#define lock(a) \
-               fprintf(stderr, "%s:%s(%i) lock %p depth: %d (%ld)\n", __FILE__, __FUNCTION__, __LINE__, a.mutex, a.depth, pthread_self()); \
-               a.depth++; pthread_mutex_lock(a.mutex)
-#define unlock(a) \
-               fprintf(stderr, "%s:%s(%i) unlock %p depth: %d (%ld)\n", __FILE__, __FUNCTION__, __LINE__, a.mutex, a.depth, pthread_self()); \
-       a.depth--; pthread_mutex_unlock(a.mutex)
-#define lock_cleanup_pop(a) \
-               fprintf(stderr, "%s:%s(%i) unlock %p depth: %d (%ld)\n", __FILE__, __FUNCTION__, __LINE__, a.mutex, a.depth, pthread_self()); \
-       pthread_cleanup_pop(1)
-#else
-#define lock(a) a.depth++; pthread_mutex_lock(a.mutex)
-#define unlock(a) a.depth--; pthread_mutex_unlock(a.mutex)
+static inline void lock(struct mutex_lock *a)
+{
+       pthread_mutex_lock(&a->mutex);
+}
+
+static inline int timedlock(struct mutex_lock *a, struct timespec *tmo)
+{
+       return pthread_mutex_timedlock(&a->mutex, tmo);
+}
+
+static inline void unlock(struct mutex_lock *a)
+{
+       pthread_mutex_unlock(&a->mutex);
+}
+
 #define lock_cleanup_pop(a) pthread_cleanup_pop(1)
-#endif
 
 void cleanup_lock (void * data);
 
index 1366f45..5441e6a 100644 (file)
 
 #include "memory.h"
 
-/* Global var */
-unsigned long mem_allocated;   /* Total memory used in Bytes */
-
-void *
-xalloc(unsigned long size)
-{
-       void *mem;
-       if ((mem = malloc(size)))
-               mem_allocated += size;
-       return mem;
-}
-
-void *
-zalloc(unsigned long size)
-{
-       void *mem;
-       if ((mem = malloc(size))) {
-               memset(mem, 0, size);
-               mem_allocated += size;
-       }
-       return mem;
-}
-
-void
-xfree(void *p)
-{
-       mem_allocated -= sizeof (p);
-       free(p);
-       p = NULL;
-}
-
 /*
  * Memory management. in debug mode,
  * help finding eventual memory leak.
index 8573f6f..29a75ed 100644 (file)
 #include <string.h>
 #include <assert.h>
 
-/* extern types */
-extern unsigned long mem_allocated;
-extern void *xalloc(unsigned long size);
-extern void *zalloc(unsigned long size);
-extern void xfree(void *p);
-
-/* Global alloc macro */
-#define ALLOC(n) (xalloc(n))
-
 /* Local defines */
 #ifdef _DEBUG_
 
@@ -63,8 +54,8 @@ extern void dbg_free_final(char *);
 
 #else
 
-#define MALLOC(n)    (zalloc(n))
-#define FREE(p)      (xfree(p))
+#define MALLOC(n)    (calloc(1,(n)))
+#define FREE(p)      do { free(p); p = NULL; } while(0)
 #define REALLOC(p,n) (realloc((p),(n)))
 #define STRDUP(n)    (strdup(n))
 
index dd955f3..c47d891 100644 (file)
@@ -171,7 +171,7 @@ snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
                        r = kw->print(conf, buff + fwd, len - fwd, data);
                        put_multipath_config(conf);
                        if (!r) { /* no output if no value */
-                               buff = '\0';
+                               buff[0] = '\0';
                                return 0;
                        }
                        fwd += r;
index f440441..3064aab 100644 (file)
@@ -123,11 +123,11 @@ group_by_node_name (struct multipath * mp) {
                        goto out1;
 
                if (store_pathgroup(mp->pg, pgp))
-                       goto out1;
+                       goto out2;
 
                /* feed the first path */
                if (store_path(pgp->paths, pp))
-                       goto out1;
+                       goto out2;
 
                bitmap[i] = 1;
 
@@ -141,7 +141,7 @@ group_by_node_name (struct multipath * mp) {
                        if (!strncmp(pp->tgt_node_name, pp2->tgt_node_name,
                                        NODE_NAME_SIZE)) {
                                if (store_path(pgp->paths, pp2))
-                                       goto out1;
+                                       goto out2;
 
                                bitmap[j] = 1;
                        }
@@ -152,6 +152,8 @@ group_by_node_name (struct multipath * mp) {
        free_pathvec(mp->paths, KEEP_PATHS);
        mp->paths = NULL;
        return 0;
+out2:
+       free_pathgroup(pgp, KEEP_PATHS);
 out1:
        FREE(bitmap);
 out:
@@ -197,11 +199,11 @@ group_by_serial (struct multipath * mp) {
                        goto out1;
 
                if (store_pathgroup(mp->pg, pgp))
-                       goto out1;
+                       goto out2;
 
                /* feed the first path */
                if (store_path(pgp->paths, pp))
-                       goto out1;
+                       goto out2;
 
                bitmap[i] = 1;
 
@@ -214,7 +216,7 @@ group_by_serial (struct multipath * mp) {
 
                        if (0 == strcmp(pp->serial, pp2->serial)) {
                                if (store_path(pgp->paths, pp2))
-                                       goto out1;
+                                       goto out2;
 
                                bitmap[j] = 1;
                        }
@@ -225,6 +227,8 @@ group_by_serial (struct multipath * mp) {
        free_pathvec(mp->paths, KEEP_PATHS);
        mp->paths = NULL;
        return 0;
+out2:
+       free_pathgroup(pgp, KEEP_PATHS);
 out1:
        FREE(bitmap);
 out:
@@ -254,15 +258,17 @@ one_path_per_group (struct multipath * mp)
                        goto out;
 
                if (store_pathgroup(mp->pg, pgp))
-                       goto out;
+                       goto out1;
 
                if (store_path(pgp->paths, pp))
-                       goto out;
+                       goto out1;
        }
        sort_pathgroups(mp);
        free_pathvec(mp->paths, KEEP_PATHS);
        mp->paths = NULL;
        return 0;
+out1:
+       free_pathgroup(pgp, KEEP_PATHS);
 out:
        free_pgvec(mp->pg, KEEP_PATHS);
        mp->pg = NULL;
@@ -290,14 +296,17 @@ one_group (struct multipath * mp) /* aka multibus */
                        goto out;
 
                vector_free(pgp->paths);
-               pgp->paths = mp->paths;
-               mp->paths = NULL;
 
                if (store_pathgroup(mp->pg, pgp))
-                       goto out;
+                       goto out1;
+
+               pgp->paths = mp->paths;
+               mp->paths = NULL;
        }
 
        return 0;
+out1:
+       free_pathgroup(pgp, KEEP_PATHS);
 out:
        free_pgvec(mp->pg, KEEP_PATHS);
        mp->pg = NULL;
@@ -311,6 +320,7 @@ group_by_prio (struct multipath * mp)
        unsigned int prio;
        struct path * pp;
        struct pathgroup * pgp;
+       vector pathvec = NULL;
 
        if (!mp->pg)
                mp->pg = vector_alloc();
@@ -318,8 +328,18 @@ group_by_prio (struct multipath * mp)
        if (!mp->pg)
                return 1;
 
-       while (VECTOR_SIZE(mp->paths) > 0) {
-               pp = VECTOR_SLOT(mp->paths, 0);
+       pathvec = vector_alloc();
+       if (!pathvec)
+               goto out;
+
+       vector_foreach_slot(mp->paths, pp, i) {
+               if (!vector_alloc_slot(pathvec))
+                       goto out1;
+               vector_set_slot(pathvec, pp);
+       }
+
+       while (VECTOR_SIZE(pathvec) > 0) {
+               pp = VECTOR_SLOT(pathvec, 0);
                prio = pp->priority;
 
                /*
@@ -339,46 +359,45 @@ group_by_prio (struct multipath * mp)
                pgp = alloc_pathgroup();
 
                if (!pgp)
-                       goto out;
+                       goto out1;
 
-               if (store_path(pgp->paths, VECTOR_SLOT(mp->paths, 0))) {
-                       free_pathgroup(pgp, KEEP_PATHS);
-                       goto out;
-               }
+               if (store_path(pgp->paths, VECTOR_SLOT(pathvec, 0)))
+                       goto out2;
 
-               vector_del_slot(mp->paths, 0);
+               vector_del_slot(pathvec, 0);
 
                /*
                 * Store the new path group into the vector.
                 */
                if (i < VECTOR_SIZE(mp->pg)) {
-                       if (!vector_insert_slot(mp->pg, i, pgp)) {
-                               free_pathgroup(pgp, KEEP_PATHS);
-                               goto out;
-                       }
+                       if (!vector_insert_slot(mp->pg, i, pgp))
+                               goto out2;
                } else {
-                       if (store_pathgroup(mp->pg, pgp)) {
-                               free_pathgroup(pgp, KEEP_PATHS);
-                               goto out;
-                       }
+                       if (store_pathgroup(mp->pg, pgp))
+                               goto out2;
                }
 
                /*
                 * add the other paths with the same prio
                 */
-               vector_foreach_slot(mp->paths, pp, i) {
+               vector_foreach_slot(pathvec, pp, i) {
                        if (pp->priority == prio) {
                                if (store_path(pgp->paths, pp))
-                                       goto out;
+                                       goto out2;
 
-                               vector_del_slot(mp->paths, i);
+                               vector_del_slot(pathvec, i);
                                i--;
                        }
                }
        }
+       free_pathvec(pathvec, KEEP_PATHS);
        free_pathvec(mp->paths, KEEP_PATHS);
        mp->paths = NULL;
        return 0;
+out2:
+       free_pathgroup(pgp, KEEP_PATHS);
+out1:
+       free_pathvec(pathvec, KEEP_PATHS);
 out:
        free_pgvec(mp->pg, KEEP_PATHS);
        mp->pg = NULL;
index 7c556b3..94d6384 100644 (file)
@@ -503,7 +503,7 @@ snprint_path_size (char * buff, size_t len, struct path * pp)
        return snprint_size(buff, len, pp->size);
 }
 
-static int
+int
 snprint_path_serial (char * buff, size_t len, struct path * pp)
 {
        return snprint_str(buff, len, pp->serial);
index 9306e50..6839fc7 100644 (file)
@@ -112,6 +112,7 @@ int snprint_devices (struct config *, char *, int, struct vectors *);
 int snprint_hwtable (struct config *, char *, int, vector);
 int snprint_mptable (struct config *, char *, int, vector);
 int snprint_overrides (struct config *, char *, int, struct hwentry *);
+int snprint_path_serial (char *, size_t, struct path *);
 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 *);
index 032028e..261105b 100644 (file)
@@ -12,9 +12,7 @@ struct path;
 
 #include "list.h"
 #include "memory.h"
-
-#define DEFAULT_PRIO "const"
-#define DEFAULT_PRIO_ARGS ""
+#include "defaults.h"
 
 /*
  * Known prioritizers for use in hwtable.c
index bb76700..36b42e4 100644 (file)
@@ -1,9 +1,11 @@
-# Makefile
 #
 # Copyright (C) 2007 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
 include ../../Makefile.inc
 
+CFLAGS += -I..
+
+# If you add or remove a prioritizer also update multipath/multipath.conf.5
 LIBS = \
        libprioalua.so \
        libprioconst.so \
@@ -18,8 +20,6 @@ LIBS = \
        libprioweightedpath.so \
        libpriosysfs.so
 
-CFLAGS += -I..
-
 all: $(LIBS)
 
 libprioalua.so: alua.o alua_rtpg.o
index a1c59fd..5636974 100644 (file)
@@ -107,37 +107,37 @@ int getprio (struct path * pp, char * args, unsigned int timeout)
                aas = (rc & 0x0f);
                priopath = (rc & 0x80);
                switch(aas) {
-                       case AAS_OPTIMIZED:
-                               rc = 50;
-                               break;
-                       case AAS_NON_OPTIMIZED:
-                               rc = 10;
-                               break;
-                       case AAS_LBA_DEPENDENT:
-                               rc = 5;
-                               break;
-                       case AAS_STANDBY:
-                               rc = 1;
-                               break;
-                       default:
-                               rc = 0;
+               case AAS_OPTIMIZED:
+                       rc = 50;
+                       break;
+               case AAS_NON_OPTIMIZED:
+                       rc = 10;
+                       break;
+               case AAS_LBA_DEPENDENT:
+                       rc = 5;
+                       break;
+               case AAS_STANDBY:
+                       rc = 1;
+                       break;
+               default:
+                       rc = 0;
                }
                if (priopath && (aas != AAS_OPTIMIZED || exclusive_pref))
                        rc += 80;
        } else {
                switch(-rc) {
-                       case ALUA_PRIO_NOT_SUPPORTED:
-                               condlog(0, "%s: alua not supported", pp->dev);
-                               break;
-                       case ALUA_PRIO_RTPG_FAILED:
-                               condlog(0, "%s: couldn't get target port group", pp->dev);
-                               break;
-                       case ALUA_PRIO_GETAAS_FAILED:
-                               condlog(0, "%s: couldn't get asymmetric access state", pp->dev);
-                               break;
-                       case ALUA_PRIO_TPGS_FAILED:
-                               condlog(3, "%s: couldn't get supported alua states", pp->dev);
-                               break;
+               case ALUA_PRIO_NOT_SUPPORTED:
+                       condlog(0, "%s: alua not supported", pp->dev);
+                       break;
+               case ALUA_PRIO_RTPG_FAILED:
+                       condlog(0, "%s: couldn't get target port group", pp->dev);
+                       break;
+               case ALUA_PRIO_GETAAS_FAILED:
+                       condlog(0, "%s: couldn't get asymmetric access state", pp->dev);
+                       break;
+               case ALUA_PRIO_TPGS_FAILED:
+                       condlog(3, "%s: couldn't get supported alua states", pp->dev);
+                       break;
                }
        }
        return rc;
index 253fd51..6b0ed39 100644 (file)
@@ -48,7 +48,7 @@ int hp_sw_prio(const char *dev, int fd, unsigned int timeout)
        io_hdr.sbp = sb;
        io_hdr.timeout = get_prio_timeout(timeout, 60000);
        io_hdr.pack_id = 0;
- retry:
+retry:
        if (ioctl(fd, SG_IO, &io_hdr) < 0) {
                pp_hp_sw_log(0, "sending tur command failed");
                goto out;
index 747dfb5..4084c65 100644 (file)
@@ -113,7 +113,7 @@ static int send_gva(const char *dev, int fd, unsigned char pg,
                goto out;
        }
        ret = 0;
- out:
+out:
        return(ret);
 }
 
@@ -171,7 +171,7 @@ static int get_proxy(const char *dev, int fd, unsigned int timeout)
        }
        ret = (results[19] & 0x02) >> 1;
 
- out:
+out:
        return(ret);
 }
 
@@ -221,13 +221,13 @@ static int ontap_prio(const char *dev, int fd, unsigned int timeout)
                return 0;
        }
 
- try_fcp_proxy:
+try_fcp_proxy:
        rc = get_proxy(dev, fd, timeout);
        if (rc >= 0) {
                is_proxy = rc;
        }
 
- prio_select:
+prio_select:
        if (is_iscsi_hardware) {
                return 3;
        } else if (is_iscsi_software) {
index e8168fe..a62b86e 100644 (file)
@@ -53,6 +53,16 @@ do { \
 } while(0)
 
 static int
+build_serial_path(struct path *pp, char *str, int len)
+{
+       char *p = str;
+
+       p += snprint_path_serial(p, str + len - p, pp);
+       CHECK_LEN;
+       return 0;
+}
+
+static int
 build_wwn_path(struct path *pp, char *str, int len)
 {
        char *p = str;
@@ -103,6 +113,11 @@ int prio_path_weight(struct path *pp, char *prio_args)
                        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, SERIAL)) {
+               if (build_serial_path(pp, path, FILE_NAME_SIZE) != 0) {
+                       FREE(arg);
+                       return priority;
+               }
        } else if (!strcmp(regex, WWN)) {
                if (build_wwn_path(pp, path, FILE_NAME_SIZE) != 0) {
                        FREE(arg);
index 93d8c43..a1b268f 100644 (file)
@@ -4,6 +4,7 @@
 #define PRIO_WEIGHTED_PATH "weightedpath"
 #define HBTL "hbtl"
 #define DEV_NAME "devname"
+#define SERIAL "serial"
 #define WWN "wwn"
 #define DEFAULT_PRIORITY 0
 
index 0caf269..1625990 100644 (file)
@@ -459,7 +459,7 @@ out:
                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)",
+               condlog(3, "%s: no_path_retry = %s (inherited setting)",
                        mp->alias, buff);
        else
                condlog(3, "%s: no_path_retry = undef (internal default)",
index 9f216df..cb5d532 100644 (file)
@@ -52,6 +52,7 @@ enum sysfs_buses {
        SYSFS_BUS_IDE,
        SYSFS_BUS_CCW,
        SYSFS_BUS_CCISS,
+       SYSFS_BUS_RBD,
 };
 
 enum pathstates {
@@ -167,10 +168,10 @@ struct sg_id {
 #  define HDIO_GETGEO  0x0301  /* get device geometry */
 
 struct hd_geometry {
-      unsigned char heads;
-      unsigned char sectors;
-      unsigned short cylinders;
-      unsigned long start;
+       unsigned char heads;
+       unsigned char sectors;
+       unsigned short cylinders;
+       unsigned long start;
 };
 #endif
 
index adb1911..a0c8869 100644 (file)
@@ -409,10 +409,12 @@ __setup_multipath (struct vectors * vecs, struct multipath * mpp,
                        mpp->alias);
        }
        if (reset) {
+               conf = get_multipath_config();
                select_rr_weight(conf, mpp);
                select_pgfailback(conf, mpp);
                set_no_path_retry(conf, mpp);
                select_flush_on_last_del(conf, mpp);
+               put_multipath_config(conf);
                if (VECTOR_SIZE(mpp->paths) != 0)
                        dm_cancel_deferred_remove(mpp);
        }
index 8ef547d..46f30af 100644 (file)
@@ -4,11 +4,7 @@
 #include "vector.h"
 #include "config.h"
 #include "lock.h"
-/*
-struct mutex_lock {
-       pthread_mutex_t *mutex;
-       int depth;
-}; */
+
 struct vectors {
        struct mutex_lock lock; /* defined in lock.h */
        vector pathvec;
index 5f3204b..6247898 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/types.h>
 #include <linux/netlink.h>
 #include <pthread.h>
-#include <signal.h>
 #include <limits.h>
 #include <sys/mman.h>
 #include <libudev.h>
index 257912c..8861085 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _UTIL_H
 #define _UTIL_H
 
+#include <sys/types.h>
+
 size_t strchop(char *);
 int basenamecpy (const char * src, char * dst, int);
 int filepresent (char * run);
index 09d725d..dea59fe 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef _VERSION_H
 #define _VERSION_H
 
-#define VERSION_CODE 0x000602
-#define DATE_CODE    0x071610
+#define VERSION_CODE 0x000603
+#define DATE_CODE    0x080f10
 
 #define PROG    "multipath-tools"
 
index 06995b6..995ea1a 100644 (file)
@@ -24,7 +24,7 @@
 
 pthread_attr_t waiter_attr;
 
-struct event_thread *alloc_waiter (void)
+static struct event_thread *alloc_waiter (void)
 {
 
        struct event_thread *wp;
@@ -35,7 +35,7 @@ struct event_thread *alloc_waiter (void)
        return wp;
 }
 
-void free_waiter (void *data)
+static void free_waiter (void *data)
 {
        struct event_thread *wp = (struct event_thread *)data;
 
@@ -67,7 +67,7 @@ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
  * returns the reschedule delay
  * negative means *stop*
  */
-int waiteventloop (struct event_thread *waiter)
+static int waiteventloop (struct event_thread *waiter)
 {
        sigset_t set, oldset;
        int event_nr;
@@ -138,7 +138,7 @@ int waiteventloop (struct event_thread *waiter)
                 * 5) a switch group : nothing to do
                 */
                pthread_cleanup_push(cleanup_lock, &waiter->vecs->lock);
-               lock(waiter->vecs->lock);
+               lock(&waiter->vecs->lock);
                pthread_testcancel();
                r = update_multipath(waiter->vecs, waiter->mapname, 1);
                lock_cleanup_pop(waiter->vecs->lock);
@@ -159,7 +159,7 @@ int waiteventloop (struct event_thread *waiter)
        return -1; /* never reach there */
 }
 
-void *waitevent (void *et)
+static void *waitevent (void *et)
 {
        int r;
        struct event_thread *waiter;
index a1f57fb..0cfae46 100644 (file)
@@ -11,11 +11,7 @@ struct event_thread {
        struct vectors *vecs;
 };
 
-struct event_thread * alloc_waiter (void);
-void free_waiter (void *data);
 void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
 int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
-int waiteventloop (struct event_thread *waiter);
-void *waitevent (void *et);
 
 #endif /* _WAITER_H */
index a7c3249..babf149 100644 (file)
@@ -273,7 +273,7 @@ out:
 int
 should_multipath(struct path *pp1, vector pathvec)
 {
-       int i, ignore_new_devs;;
+       int i, ignore_new_devs;
        struct path *pp2;
        struct config *conf;
 
index a458c4d..d545514 100644 (file)
@@ -1,14 +1,14 @@
-# Makefile
-#
 include ../Makefile.inc
 
-OBJS = main.o
-
 CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
-LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev
+
+LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist \
+          -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev
 
 EXEC = mpathpersist
 
+OBJS = main.o
+
 all: $(EXEC)
 
 $(EXEC): $(OBJS)
@@ -22,8 +22,7 @@ install:
        $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 
 clean:
-       $(RM) *.o $(EXEC)
-       $(RM) mpathpersist.8.gz
+       $(RM) core *.o $(EXEC) *.gz
 
 uninstall:
        $(RM) $(DESTDIR)$(bindir)/$(EXEC)
index bf9c721..a55865f 100644 (file)
@@ -662,7 +662,7 @@ void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
 
                if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
                        printf("      << Reservation holder >>\n");
-                       j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type>> 4) & 0xf);
+                       j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type >> 4) & 0xf);
                        if (0 == j)
                                printf("      scope: LU_SCOPE, ");
                        else
@@ -675,7 +675,7 @@ void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
        }
 }
 
-static void usage()
+static void usage(void)
 {
        fprintf(stderr,
                        "Usage: mpathpersist [OPTIONS] [DEVICE]\n"
@@ -720,37 +720,37 @@ void
 mpath_print_transport_id(struct prin_fulldescr *fdesc)
 {
        switch (fdesc->trnptid.protocol_id) {
-               case MPATH_PROTOCOL_ID_FC:
-                       printf("   FCP-2 ");
-                       if (0 != fdesc->trnptid.format_code)
-                               printf(" [Unexpected format code: %d]\n",
-                                               fdesc->trnptid.format_code);
-                       dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
-                       break;
-               case MPATH_PROTOCOL_ID_ISCSI:
-                       printf("   iSCSI ");
-                       if (0 == fdesc->trnptid.format_code) {
-                               printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
+       case MPATH_PROTOCOL_ID_FC:
+               printf("   FCP-2 ");
+               if (0 != fdesc->trnptid.format_code)
+                       printf(" [Unexpected format code: %d]\n",
+                                       fdesc->trnptid.format_code);
+               dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
+               break;
+       case MPATH_PROTOCOL_ID_ISCSI:
+               printf("   iSCSI ");
+               if (0 == fdesc->trnptid.format_code) {
+                       printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
+                               fdesc->trnptid.iscsi_name);
+               }else if (1 == fdesc->trnptid.format_code){
+                       printf("world wide unique port id: %.*s\n",
+                                       (int)sizeof(fdesc->trnptid.iscsi_name),
                                        fdesc->trnptid.iscsi_name);
-                       }else if (1 == fdesc->trnptid.format_code){
-                               printf("world wide unique port id: %.*s\n",
-                                               (int)sizeof(fdesc->trnptid.iscsi_name),
-                                               fdesc->trnptid.iscsi_name);
-                       }else {
-                               printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
-                               dumpHex((const char *)fdesc->trnptid.iscsi_name,
-                                        (int)sizeof(fdesc->trnptid.iscsi_name), 0);
-                       }
-                       break;
-               case MPATH_PROTOCOL_ID_SAS:
-                       printf("   SAS ");
-                        if (0 != fdesc->trnptid.format_code)
-                               printf(" [Unexpected format code: %d]\n",
-                                               fdesc->trnptid.format_code);
-                       dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
-                       break;
-               default:
-                       return;
+               }else {
+                       printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
+                       dumpHex((const char *)fdesc->trnptid.iscsi_name,
+                                (int)sizeof(fdesc->trnptid.iscsi_name), 0);
+               }
+               break;
+       case MPATH_PROTOCOL_ID_SAS:
+               printf("   SAS ");
+               if (0 != fdesc->trnptid.format_code)
+                       printf(" [Unexpected format code: %d]\n",
+                                       fdesc->trnptid.format_code);
+               dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
+               break;
+       default:
+               return;
        }
 }
 
index 9c57d3b..b125ae3 100644 (file)
@@ -1,17 +1,17 @@
-# Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@opensvc.com>
 #
 include ../Makefile.inc
 
-OBJS = main.o
-
 CFLAGS += -I$(multipathdir) -I$(mpathcmddir)
+
 LDFLAGS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -ludev \
-       -L$(mpathcmddir) -lmpathcmd
+          -L$(mpathcmddir) -lmpathcmd
 
 EXEC = multipath
 
+OBJS = main.o
+
 all: $(EXEC)
 
 $(EXEC): $(OBJS)
index 6ccece7..ee00fdb 100644 (file)
@@ -212,7 +212,7 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
                /*
                 * discard out of scope maps
                 */
-               if (mpp->wwid && refwwid &&
+               if (refwwid && strlen(refwwid) &&
                    strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
                        condlog(3, "skip map %s: out of scope", mpp->alias);
                        free_multipath(mpp, KEEP_PATHS);
@@ -511,7 +511,7 @@ main (int argc, char *argv[])
        extern int optind;
        int r = 1;
        enum mpath_cmds cmd = CMD_CREATE;
-       enum devtypes dev_type;
+       enum devtypes dev_type = DEV_NONE;
        char *dev = NULL;
        struct config *conf;
 
index f542d3f..55fde22 100644 (file)
@@ -1,13 +1,37 @@
-.TH MULTIPATH.CONF 5 2016-07-08 "Linux"
+.\" ----------------------------------------------------------------------------
+.\" Update the date below if you make any significant change.
+.\" Make sure there are no errors with:
+.\" groff -z -wall -b -e -t multipath/multipath.conf.5
+.\"
+.\" TODO: Look for XXX
+.\"
+.\" ----------------------------------------------------------------------------
+.
+.TH MULTIPATH.CONF 5 2016-08-07 "Linux"
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH NAME
+.\" ----------------------------------------------------------------------------
+.
 multipath.conf \- multipath daemon configuration file.
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH DESCRIPTION
+.\" ----------------------------------------------------------------------------
+.
 .B "/etc/multipath.conf"
 is the configuration file for the multipath daemon. It is used to
 overwrite the built-in configuration table of \fBmultipathd\fP.
 Any line whose first non-white-space character is a '#' is considered
 a comment line. Empty lines are ignored.
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH SYNTAX
+.\" ----------------------------------------------------------------------------
+.
 The configuration file contains entries of the form:
 .RS
 .nf
@@ -38,6 +62,8 @@ Each \fIsection\fP contains one or more attributes or subsections. The
 recognized keywords for attributes or subsections depend on the
 section in which they occur.
 .LP
+.
+.
 The following \fIsection\fP keywords are recognized:
 .TP 17
 .B defaults
@@ -52,8 +78,7 @@ multipath topology discovery.
 .B blacklist_exceptions
 This section defines which devices should be included in the
 multipath topology discovery, despite being listed in the
-.I blacklist
-section.
+\fIblacklist\fR section.
 .TP
 .B multipaths
 This section defines the multipath topologies. They are indexed by a
@@ -68,10 +93,15 @@ This section defines values for attributes that should override the
 device-specific settings for all devices.
 .RE
 .LP
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH "defaults section"
-The
-.I defaults
-section recognizes the following keywords:
+.\" ----------------------------------------------------------------------------
+.
+The \fIdefaults\fR section recognizes the following keywords:
+.
+.
 .TP 17
 .B verbosity
 Default verbosity. Higher values increase the verbosity level. Valid
@@ -80,18 +110,20 @@ levels are between 0 and 6.
 .TP
 Default value is: \fB2\fR
 .RE
+.
+.
 .TP
 .B polling_interval
 Interval between two path checks in seconds. For properly functioning paths,
-the interval between checks will gradually increase to
-.I max_polling_interval.
-This value will be overridden by the
-.I WatchdogSec
+the interval between checks will gradually increase to \fImax_polling_interval\fR.
+This value will be overridden by the \fIWatchdogSec\fR
 setting in the multipathd.service definition if systemd is used.
 .RS
 .TP
 Default value is: \fB5\fR
 .RE
+.
+.
 .TP
 .B max_polling_interval
 Maximal interval between two path checks in seconds.
@@ -99,6 +131,8 @@ Maximal interval between two path checks in seconds.
 .TP
 Default value is: \fB4 * polling_interval\fR
 .RE
+.
+.
 .TP
 .B reassign_maps
 Enable reassigning of device-mapper maps. With this option multipathd
@@ -109,13 +143,18 @@ device, not the underlying block devices. Possible values are
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B multipath_dir
 Directory where the dynamic shared objects are stored.
 .RS
 .TP
-Default value is: \fB<system dependent>\fR, commonly \fI/lib64/multipath/\fR
+Default value is: \fB<system dependent>\fR. Defined at compile time, commonly
+\fI/lib64/multipath/\fR.
 .RE
+.
+.
 .TP
 .B path_selector
 The default path selector algorithm to use; they are offered by the
@@ -135,6 +174,8 @@ to the path and its relative throughput.
 .TP
 Default value is: \fBservice-time 0\fR
 .RE
+.
+.
 .TP
 .B path_grouping_policy
 The default path grouping policy to apply to unspecified
@@ -159,28 +200,33 @@ per-multipath option in the configuration file.
 One priority group per target node name. Target node names are fetched
 in \fI/sys/class/fc_transport/target*/node_name\fR.
 .TP
-Default value is: \fBgroup_by_prio\fR
+Default value is: \fBfailover\fR
 .RE
+.
+.
 .TP
 .B uid_attribute
 The udev attribute providing a unique path identifier.
 .RS
 .TP
-Default value is: \fBID_SERIAL\fR for SCSI devices
+Default value is: for SCSI devices \fBID_SERIAL\fR
 .TP
-Default value is: \fBID_UID\fR for DASD devices
+Default value is: for DASD devices \fBID_UID\fR
 .RE
+.
+.
 .TP
 .B getuid_callout
-(Deprecated) The default program and args to callout to obtain a unique path
-identifier. Should be specified with an absolute path.
+(Superseded by \fIuid_attribute\fR) The default program and args to callout
+to obtain a unique path identifier. Should be specified with an absolute path.
 .TP
+.
+.
 .B prio
 The name of the path priority routine. The specified routine
 should return a numeric value specifying the relative priority
 of this path. Higher number have a higher priority.
-.I "none"
-is a valid value. Currently the following path priority routines
+\fI"none"\fR is a valid value. Currently the following path priority routines
 are implemented:
 .RS
 .TP 12
@@ -190,7 +236,7 @@ Return a constant priority of \fI1\fR.
 .I sysfs
 Use the sysfs attributes \fIaccess_state\fR and \fIpreferred_path\fR to
 generate the path priority. This prioritizer accepts the optional prio_arg
-.I exclusive_pref_bit
+\fIexclusive_pref_bit\fR
 .TP
 .I emc
 (Hardware-dependent)
@@ -208,8 +254,8 @@ Generate the path priority for NetApp ONTAP class and OEM arrays as IBM NSeries.
 .TP
 .I rdac
 (Hardware-dependent)
-Generate the path priority for LSI/Engenio/NetApp RDAC class as NetApp E/EF
-Series, and OEM arrays from IBM DELL SGI STK and SUN.
+Generate the path priority for LSI/Engenio/NetApp RDAC class as NetApp SANtricity
+E/EF Series, and OEM arrays from IBM DELL SGI STK and SUN.
 .TP
 .I hp_sw
 (Hardware-dependent)
@@ -218,23 +264,27 @@ Active/Standby mode exclusively.
 .TP
 .I hds
 (Hardware-dependent)
-Generate the path priority for Hitachi HDS Modular storage arrays.
+Generate the path priority for Hitachi AMS 2000 and HUS 100 families of arrays.
 .TP
 .I random
 Generate a random priority between 1 and 10.
-.TP 12
+.TP
 .I weightedpath
 Generate the path priority based on the regular expression and the
 priority provided as argument. Requires prio_args keyword.
 .TP
 .I datacore
+.\" XXX
 ???. Requires prio_args keyword.
 .TP
 .I iet
+.\" XXX
 ???. Requires prio_args keyword.
 .TP
 Default value is: \fBconst\fR
 .RE
+.
+.
 .TP
 .B prio_args
 Arguments to pass to to the prio function. This only applies to certain
@@ -243,48 +293,52 @@ prioritizers:
 .TP 12
 .I weighted
 Needs a value of the form
-.I "<hbtl|devname|wwn> <regex1> <prio1> <regex2> <prio2> ..."
+\fI"<hbtl|devname|serial|wwn> <regex1> <prio1> <regex2> <prio2> ..."\fR
+.RS
+.TP 8
 .I hbtl
-regex can be of SCSI H:B:T:L format  Ex: 1:0:.:. , *:0:0:.
+regex can be of SCSI H:B:T:L format. For example: 1:0:.:. , *:0:0:.
+.TP
 .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:.*
+regex can be of device name format. For example: sda , sd.e
+.TP
+.I serial
+regex can be of serial number format. For example: .*J1FR.*324 . The serial can
+be looked up through sysfs or by running multipathd show paths format "%z". For
+example: 0395J1FR904324
 .TP
+.I wwn
+regex can be of the form \fI"host_wwnn:host_wwpn:target_wwnn:target_wwpn"\fR
+these values can be looked up through sysfs or by running \fImultipathd show paths format
+"%N:%R:%n:%r"\fR. For example: 0x200100e08ba0aea0:0x210100e08ba0aea0:.*:.* , .*:.*:iqn.2009-10.com.redhat.msp.lab.ask-06:.*
+.RE
+.TP 12
 .I alua
-If
-.I exclusive_pref_bit
-is set, paths with the \fIpreferred path\fR bit set will always
-be in their own path group.
+If \fIexclusive_pref_bit\fR is set, paths with the \fIpreferred path\fR bit
+set will always be in their own path group.
 .TP
 .I datacore
-.I preferredsds
-???.
+.\" XXX
+\fIpreferredsds\fR ???.
 .TP
 .I iet
-.I preferredip
-???.
+.\" XXX
+\fIpreferredip\fR ???.
 .TP
 Default value is: \fB<unset>\fR
 .RE
+.
+.
 .TP
 .B features
-Specify any device-mapper features to be used. Syntax is
-.I num list
-where
-.I num
-is the number, between 0 and 6, of features in
-.I list.
+Specify any device-mapper features to be used. Syntax is \fInum list\fR
+where \fInum\fR is the number, between 0 and 6, of features in \fIlist\fR.
 Possible values for the feature list are:
 .RS
 .TP 12
 .I queue_if_no_path
-Queue IO if no path is active; identical to the
-.I no_path_retry
-keyword.
+(Superseded by \fIno_path_retry\fR) Queue IO if no path is active. Identical to
+the \fIno_path_retry\fR with \fIqueue\fR value. See KNOWN ISSUES.
 .TP
 .I no_partitions
 Disable automatic partitions generation via kpartx.
@@ -297,6 +351,8 @@ Number of msecs before pg_init retry, it must be between 0 and 60000.
 .TP
 Default value is: \fB0\fR
 .RE
+.
+.
 .TP
 .B path_checker
 The default method used to determine the paths state. Possible values
@@ -308,9 +364,7 @@ are:
 deprecated, please use \fItur\fR instead.
 .TP
 .I tur
-Issue a
-.I TEST UNIT READY
-command to the device.
+Issue a \fITEST UNIT READY\fR command to the device.
 .TP
 .I emc_clariion
 (Hardware-dependent)
@@ -324,7 +378,7 @@ Active/Standby mode exclusively.
 .TP
 .I rdac
 (Hardware-dependent)
-Check the path state for LSI/Engenio/NetApp RDAC class as NetApp E/EF
+Check the path state for LSI/Engenio/NetApp RDAC class as NetApp SANtricity E/EF
 Series, and OEM arrays from IBM DELL SGI STK and SUN.
 .TP
 .I directio
@@ -336,8 +390,13 @@ Please use \fItur\fR instead.
 (Hardware-dependent)
 Check the path state for HP/COMPAQ Smart Array(CCISS) controllers.
 .TP
+.I rbd
+Check if the path is in the Ceph blacklist and remap the path if it is.
+.TP
 Default value is: \fBtur\fR
 .RE
+.
+.
 .TP
 .B alias_prefix
 The \fIuser_friendly_names\fR prefix.
@@ -345,6 +404,8 @@ The \fIuser_friendly_names\fR prefix.
 .TP
 Default value is: \fBmpath\fR
 .RE
+.
+.
 .TP
 .B failback
 Tell multipathd how to manage path group failback.
@@ -358,15 +419,18 @@ active paths.
 Do not perform automatic failback.
 .TP
 .I followover
-Only perform automatic failback when the first path of a pathgroup
-becomes active. This keeps a node from automatically failing back when
+Used to deal with multiple computers accessing the same Active/Passive storage
+devices. Only perform automatic failback when the first path of a pathgroup
+becomes active. This keeps a cluster node from automatically failing back when
 another node requested the failover.
 .TP
 .I values > 0
 Deferred failback (time to defer in seconds).
 .TP
-Default value is: \fBimmediate\fR
+Default value is: \fBmanual\fR
 .RE
+.
+.
 .TP
 .B  rr_min_io
 The number of IO to route to a path before switching to the next in
@@ -375,6 +439,8 @@ the same path group. This is only for BIO based multipath.
 .TP
 Default value is: \fB1000\fR
 .RE
+.
+.
 .TP
 .B rr_min_io_rq
 The number of IO requests to route to a path before switching to the
@@ -383,10 +449,12 @@ next in the same path group. This is only for request based multipath.
 .TP
 Default value is: \fB1\fR
 .RE
+.
+.
 .TP
 .B max_fds
 Specify the maximum number of file descriptors that can be opened by multipath
-and multipathd.  This is equivalent to ulimit \-n. A value of \fImax\fR will set
+and multipathd. This is equivalent to ulimit \-n. A value of \fImax\fR will set
 this to the system limit from \fI/proc/sys/fs/nr_open\fR. If this is not set, the
 maximum number of open fds is taken from the calling process. It is usually
 1024. To be safe, this should be set to the maximum number of paths plus 32,
@@ -395,34 +463,40 @@ if that number is greated than 1024.
 .TP
 Default value is: \fBmax\fR
 .RE
+.
+.
 .TP
 .B rr_weight
 If set to \fIpriorities\fR the multipath configurator will assign
 path weights as "path prio * rr_min_io". Possible values are
 .I priorities
 or
-.IR uniform .
+.I uniform .
 .RS
 .TP
 Default value is: \fBuniform\fR
 .RE
+.
+.
 .TP
 .B no_path_retry
 Specify the number of retries until disable queueing, or
 .I fail
 for immediate failure (no queueing),
 .I queue
-for never stop queueing. If unset no queueing is attempted.
+for never stop queueing. If unset no queueing is attempted. See KNOWN ISSUES.
 .RS
 .TP
 Default value is: \fB<unset>\fR
 .RE
+.
+.
 .TP
 .B queue_without_daemon
 If set to
 .I no
 , when multipathd stops, queueing will be turned off for all devices.
-This is useful for devices that set no_path_retry.  If a machine is
+This is useful for devices that set no_path_retry. If a machine is
 shut down while all paths to a device are down, it is possible to hang waiting
 for IO to return from the device after multipathd has been stopped. Without
 multipathd running, access to the paths cannot be restored, and the kernel
@@ -433,6 +507,8 @@ cannot be told to stop queueing IO. Setting queue_without_daemon to
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B checker_timeout
 Specify the timeout to use for path checkers and prioritizers that issue SCSI
@@ -441,6 +517,8 @@ commands with an explicit timeout, in seconds.
 .TP
 Default value is: in \fB/sys/block/sd<x>/device/timeout\fR
 .RE
+.
+.
 .TP
 .B flush_on_last_del
 If set to
@@ -451,14 +529,14 @@ deleted.
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B user_friendly_names
 If set to
 .I yes
-, using the bindings file
-.I /etc/multipath/bindings
-to assign a persistent and unique alias to the multipath, in the form of mpath<n>.
-If set to
+, using the bindings file \fI/etc/multipath/bindings\fR to assign a persistent
+and unique alias to the multipath, in the form of mpath<n>. If set to
 .I no
 use the WWID as the alias. In either case this be will
 be overridden by any specific aliases in the \fImultipaths\fR section.
@@ -466,6 +544,8 @@ be overridden by any specific aliases in the \fImultipaths\fR section.
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B fast_io_fail_tmo
 Specify the number of seconds the SCSI layer will wait after a problem has been
@@ -477,29 +557,35 @@ will disable the timeout.
 .TP
 Default value is: in \fB5\fR
 .RE
+.
+.
 .TP
 .B dev_loss_tmo
 Specify the number of seconds the SCSI layer will wait after a problem has
 been detected on a FC remote port before removing it from the system. This
 can be set to "infinity" which sets it to the max value of 2147483647
 seconds, or 68 years. It will be automatically adjusted to the overall
-retry interval
-\fIno_path_retry\fR * \fIpolling_interval\fR
+retry interval \fIno_path_retry\fR * \fIpolling_interval\fR
 if a number of retries is given with \fIno_path_retry\fR and the
 overall retry interval is longer than the specified \fIdev_loss_tmo\fR value.
 The Linux kernel will cap this value to \fI300\fR if \fIfast_io_fail_tmo\fR
-is not set.
+is not set. See KNOWN ISSUES.
 .RS
 .TP
 Default value is: \fB600\fR
 .RE
+.
+.
 .TP
 .B bindings_file
-The full pathname of the binding file to be used when the user_friendly_names option is set.
+The full pathname of the binding file to be used when the user_friendly_names
+option is set.
 .RS
 .TP
 Default value is: \fB/etc/multipath/bindings\fR
 .RE
+.
+.
 .TP
 .B wwids_file
 The full pathname of the WWIDs file, which is used by multipath to keep track
@@ -508,6 +594,8 @@ of the WWIDs for LUNs it has created multipath devices on in the past.
 .TP
 Default value is: \fB/etc/multipath/wwids\fR
 .RE
+.
+.
 .TP
 .B log_checker_err
 If set to
@@ -520,9 +608,11 @@ errors are logged at level 3 until the device is restored. If set to
 .TP
 Default value is: \fBalways\fR
 .RE
+.
+.
 .TP
 .B reservation_key
-This is the service action reservation key used by mpathpersist.  It must be
+This is the service action reservation key used by mpathpersist. It must be
 set for all multipath devices using persistent reservations, and it must be
 the same as the RESERVATION KEY field of the PERSISTENT RESERVE OUT parameter
 list which contains an 8-byte value provided by the application client to the
@@ -531,6 +621,8 @@ device server to identify the I_T nexus.
 .TP
 Default value is: \fB<unset>\fR
 .RE
+.
+.
 .TP
 .B retain_attached_hw_handler
 If set to
@@ -543,26 +635,24 @@ multipath will continue to use its configured hardware handler.
 .TP
 Default value is: \fByes\fR
 .RE
+.
+.
 .TP
 .B detect_prio
 If set to
 .I yes
 , multipath will try to detect if the device supports SCSI-3 ALUA. If so, the
-device will automatically use the
-.I sysfs
-prioritizer if the required sysfs attributes
-.I access_state
-and
-.I preferred_path
-are supported, or the
-.I alua
-prioritizer if not. If set to
+device will automatically use the \fIsysfs\fR prioritizer if the required sysf
+attributes \fIaccess_state\fR and \fIpreferred_path\fR are supported, or the
+\fIalua\fR prioritizer if not. If set to
 .I no
 , the prioritizer will be selected as usual.
 .RS
 .TP
 Default value is: \fByes\fR
 .RE
+.
+.
 .TP
 .B force_sync
 If set to
@@ -574,22 +664,24 @@ multipathd checkers running in parallel causes significant CPU pressure.
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B strict_timinig
 If set to
 .I yes
 , multipathd will start a new path checker loop after exactly one second,
-so that each path check will occur at exactly
-.I polling_interval
+so that each path check will occur at exactly \fIpolling_interval\fR
 seconds. On busy systems path checks might take longer than one second;
 here the missing ticks will be accounted for on the next round.
-A warning will be printed if path checks take longer than
-.I polling_interval
+A warning will be printed if path checks take longer than \fIpolling_interval\fR
 seconds.
 .RS
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B deferred_remove
 If set to
@@ -603,6 +695,8 @@ will be canceled.
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B partition_delimiter
 If this value is not set, when multipath renames a device, it will act just
@@ -613,6 +707,8 @@ the \fI-p\fR option is used, and always add delimiter.
 .TP
 Default value is: \fB<unset>\fR
 .RE
+.
+.
 .TP
 .B config_dir
 If set to anything other than "", multipath will search this directory
@@ -623,31 +719,32 @@ config_dir must either be "" or a fully qualified directory name.
 .TP
 Default value is: \fB/etc/multipath/conf.d/\fR
 .RE
+.
+.
 .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
+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.
+have stayed up for \fIdelay_wait_checks\fR checks.
 .RS
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .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.
+online fails again within \fIdelay_watch_checks\fR checks, the next time it
+comes back online, it will marked and delayed, and not used until it has passed
+\fIdelay_wait_checks\fR checks.
 .RS
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B find_multipaths
 If set to
@@ -673,6 +770,8 @@ multipath devices, without having to edit the blacklist.
 .TP
 Default value is: \fBno\fR
 .RE
+.
+.
 .TP
 .B uxsock_timeout
 CLI receive timeout in milliseconds. For larger systems CLI commands
@@ -685,6 +784,8 @@ those issues.
 .TP
 Default value is: \fB1000\fR
 .RE
+.
+.
 .TP
 .B retrigger_tries
 Sets the number of times multipathd will try to retrigger a uevent to get the
@@ -693,6 +794,8 @@ WWID.
 .TP
 Default value is: \fB3\fR
 .RE
+.
+.
 .TP
 .B retrigger_delay
 Sets the amount of time, in seconds, to wait between retriggers.
@@ -700,6 +803,8 @@ Sets the amount of time, in seconds, to wait between retriggers.
 .TP
 Default value is: \fB10\fR
 .RE
+.
+.
 .TP
 .B missing_uev_wait_timeout
 Controls how many seconds multipathd will wait, after a new multipath device
@@ -711,13 +816,17 @@ on a device until it receives a change uevent from the initial table load.
 Default value is: \fB30\fR
 .RE
 .
+.
+.\" ----------------------------------------------------------------------------
 .SH "blacklist section"
-The
-.I blacklist
-section is used to exclude specific device from inclusion in the
-multipath topology. It is most commonly used to exclude local disks or
-LUNs for the array controller.
+.\" ----------------------------------------------------------------------------
+.
+The \fIblacklist\fR section is used to exclude specific device from inclusion in
+the multipath topology. It is most commonly used to exclude local disks or LUNs
+for the array controller.
 .LP
+.
+.
 The following keywords are recognized:
 .TP 17
 .B devnode
@@ -735,19 +844,20 @@ Subsection for the device description. This subsection recognizes the
 and
 .B product
 keywords. For a full description of these keywords please see the
-.I devices
-section description.
+\fIdevices\fR section description.
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH "blacklist_exceptions section"
-The
-.I blacklist_exceptions
-section is used to revert the actions of the
-.I blacklist
-section, for example to include specific device in the
+.\" ----------------------------------------------------------------------------
+.
+The \fIblacklist_exceptions\fR section is used to revert the actions of the
+\fIblacklist\fR section. For example to include specific device in the
 multipath topology. This allows one to selectively include devices which
-would normally be excluded via the
-.I blacklist
-section.
+would normally be excluded via the \fIblacklist\fR section.
 .LP
+.
+.
 The following keywords are recognized:
 .TP 17
 .B devnode
@@ -768,42 +878,36 @@ Subsection for the device description. This subsection recognizes the
 .B vendor
 and
 .B product
-keywords. For a full description of these keywords please see the
-.I devices
+keywords. For a full description of these keywords please see the \fIdevices\fR
 section description.
 .LP
-The
-.I property
-blacklist and whitelist handling is different from the usual handling
-in the sense that the whitelist
-.I has
-to be set, otherwise the device will be blacklisted.
-In these cases the message
-.I blacklisted, udev property missing
-will be displayed.
+The \fIproperty\fR blacklist and whitelist handling is different from the usual
+handling in the sense that the whitelist \fIhas\fR to be set, otherwise the
+device will be blacklisted. In these cases the message \fIblacklisted, udev
+property missing\fR will be displayed.
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH "multipaths section"
-The only recognized attribute for the
-.I multipaths
-section is the
-.I multipath
-subsection.
+.\" ----------------------------------------------------------------------------
+.
+The only recognized attribute for the \fImultipaths\fR section is the
+\fImultipath\fR subsection.
 .LP
-The
-.I multipath
-subsection recognizes the following attributes:
+.
+.
+The \fImultipath\fR subsection recognizes the following attributes:
 .TP 17
 .B wwid
 (Mandatory) Index of the container.
 .TP
 .B alias
-(Optional) Symbolic name for the multipath map.
+Symbolic name for the multipath map.
 .LP
+.
+.
 The following attributes are optional; if not set the default values
-are taken from the
-.I defaults
-or
-.I devices
-section:
+are taken from the \fIdefaults\fR or \fIdevices\fR section:
 .sp 1
 .PD .1v
 .RS
@@ -842,16 +946,20 @@ section:
 .RE
 .PD
 .LP
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH "devices section"
-The only recognized attribute for the
-.I devices
-section is the
-.I device
+.\" ----------------------------------------------------------------------------
+.
+The only recognized attribute for the \fIdevices\fR section is the \fIdevice\fR
 subsection.
 .LP
-The
-.I device
-subsection recognizes the following attributes:
+.
+.
+The \fIdevice\fR subsection recognizes the following attributes:
+.TP
+vendor, product, revision and product_blacklist are POSIX Extended regex.
 .TP 17
 .B vendor
 (Mandatory) Vendor identifier.
@@ -860,17 +968,17 @@ subsection recognizes the following attributes:
 (Mandatory) Product identifier.
 .TP
 .B revision
-(Optional) Revision identfier.
+Revision identfier.
 .TP
 .B product_blacklist
-(Optional) Product strings to blacklist for this vendor.
+Product strings to blacklist for this vendor.
 .TP
 .B alias_prefix
-(Optional) The user_friendly_names prefix to use for this
+The user_friendly_names prefix to use for this
 device type, instead of the default "mpath".
 .TP
 .B hardware_handler
-(Optional) The hardware handler to use for this device type.
+The hardware handler to use for this device type.
 The following hardware handler are implemented:
 .RS
 .TP 12
@@ -880,7 +988,7 @@ Hardware handler for DGC class arrays as CLARiiON CX/AX and EMC VNX families.
 .TP
 .I 1 rdac
 (Hardware-dependent)
-Hardware handler for LSI/Engenio/NetApp RDAC class as NetApp E/EF
+Hardware handler for LSI/Engenio/NetApp RDAC class as NetApp SANtricity E/EF
 Series, and OEM arrays from IBM DELL SGI STK and SUN.
 .TP
 .I 1 hp_sw
@@ -894,10 +1002,11 @@ Hardware handler for SCSI-3 ALUA compatible arrays.
 .TP
 Default value is: \fB<unset>\fR
 .RE
+.
+.
 .LP
 The following attributes are optional; if not set the default values
-are taken from the
-.I defaults
+are taken from the \fIdefaults\fR
 section:
 .sp 1
 .PD .1v
@@ -945,13 +1054,14 @@ section:
 .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:
+the values are taken from the \fIdevices\fR or \fIdefaults\fR sections:
 .sp 1
 .PD .1v
 .RS
@@ -1004,7 +1114,12 @@ sections:
 .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.
@@ -1028,35 +1143,37 @@ variable.
 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
-.I queue_if_no_path
-option can lead to
-.I D state
-processes being hung and not killable in situations where all the paths to the LUN go offline.
-It is advisable to use the
-.I no_path_retry
-option instead.
+.\" ----------------------------------------------------------------------------
+.
+The usage of \fIqueue_if_no_path\fR option can lead to \fID state\fR
+processes being hung and not killable in situations where all the paths to the
+LUN go offline. It is advisable to use the \fIno_path_retry\fR option instead.
 .P
-The use of
-.I queue_if_no_path
-or
-.I no_path_retry
-might lead to a deadlock if the
-.I dev_loss_tmo
-setting results in a device being removed while I/O is still queued.
-The multipath daemon will update the
-.I dev_loss_tmo
+The use of \fIqueue_if_no_path\fR or \fIno_path_retry\fR might lead to a
+deadlock if the \fIdev_loss_tmo\fR setting results in a device being removed
+while I/O is still queued. The multipath daemon will update the \fIdev_loss_tmo\fR
 setting accordingly to avoid this deadlock. Hence if both values are
-specified the order of precedence is
-.I no_path_retry, queue_if_no_path, dev_loss_tmo.
-
+specified the order of precedence is \fIno_path_retry, queue_if_no_path, dev_loss_tmo\fR.
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH "SEE ALSO"
+.\" ----------------------------------------------------------------------------
+.
 .BR udev (8),
 .BR dmsetup (8),
 .BR multipath (8),
 .BR multipathd (8).
-
+.
+.
+.\" ----------------------------------------------------------------------------
 .SH AUTHORS
-.I multipath-tools
-was developed by Christophe Varoqui, <christophe.varoqui@opensvc.com> and others.
+.\" ----------------------------------------------------------------------------
+.
+\fImultipath-tools\fR was developed by Christophe Varoqui, <christophe.varoqui@opensvc.com>
+and others.
+.\" EOF
index 092b74b..03d7815 100644 (file)
@@ -1,42 +1,30 @@
-EXEC = multipathd
-
 include ../Makefile.inc
 
 #
-# basic flags setting
+# debuging stuff
 #
+#CFLAGS += -DLCKDBG
+#CFLAGS += -D_DEBUG_
+#CFLAGS += -DLOGDBG
 CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
+
+LDFLAGS += -ludev -ldl -L$(multipathdir) -lmultipath -L$(mpathpersistdir) \
+          -lmpathpersist -L$(mpathcmddir) -lmpathcmd -lurcu -lpthread \
+          -ldevmapper -lreadline
+
 ifdef SYSTEMD
        CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
-endif
-LDFLAGS += -lurcu -lpthread -ldevmapper -lreadline
-ifdef SYSTEMD
        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$(mpathcmddir) -lmpathcmd
-
-#
-# debuging stuff
-#
-#CFLAGS += -DLCKDBG
-#CFLAGS += -D_DEBUG_
-#CFLAGS += -DLOGDBG
 
-#
-# object files
-#
 OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
 
+EXEC = multipathd
 
-#
-# directives
-#
 all : $(EXEC)
 
 $(EXEC): $(OBJS)
index 3663c0a..9a19728 100644 (file)
@@ -487,10 +487,9 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data, int timeout )
 
                pthread_cleanup_push(cleanup_lock, &vecs->lock);
                if (tmo.tv_sec) {
-                       vecs->lock.depth++;
-                       r = pthread_mutex_timedlock(vecs->lock.mutex, &tmo);
+                       r = timedlock(&vecs->lock, &tmo);
                } else {
-                       lock(vecs->lock);
+                       lock(&vecs->lock);
                        r = 0;
                }
                if (r == 0) {
index 8784307..001eb8c 100644 (file)
@@ -117,6 +117,11 @@ struct udev * udev;
 
 struct config *multipath_conf;
 
+/* Local variables */
+static volatile sig_atomic_t exit_sig;
+static volatile sig_atomic_t reconfig_sig;
+static volatile sig_atomic_t log_reset_sig;
+
 const char *
 daemon_status(void)
 {
@@ -446,7 +451,7 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
                }
        }
        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
+       lock(&vecs->lock);
        pthread_testcancel();
        rc = ev_add_map(uev->kernel, alias, vecs);
        lock_cleanup_pop(vecs->lock);
@@ -552,7 +557,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
        minor = uevent_get_minor(uev);
 
        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
+       lock(&vecs->lock);
        pthread_testcancel();
        mpp = find_mp_by_minor(vecs->mpvec, minor);
 
@@ -613,7 +618,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs)
        }
 
        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
+       lock(&vecs->lock);
        pthread_testcancel();
        pp = find_path_by_dev(vecs->pathvec, uev->kernel);
        if (pp) {
@@ -663,7 +668,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs)
                return 1;
        }
        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
+       lock(&vecs->lock);
        pthread_testcancel();
        ret = store_path(vecs->pathvec, pp);
        if (!ret) {
@@ -826,7 +831,7 @@ uev_remove_path (struct uevent *uev, struct vectors * vecs)
 
        condlog(2, "%s: remove path (uevent)", uev->kernel);
        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-       lock(vecs->lock);
+       lock(&vecs->lock);
        pthread_testcancel();
        pp = find_path_by_dev(vecs->pathvec, uev->kernel);
        if (pp)
@@ -952,7 +957,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
                condlog(2, "%s: update path write_protect to '%d' (uevent)",
                        uev->kernel, ro);
                pthread_cleanup_push(cleanup_lock, &vecs->lock);
-               lock(vecs->lock);
+               lock(&vecs->lock);
                pthread_testcancel();
                /*
                 * pthread_mutex_lock() and pthread_mutex_unlock()
@@ -1126,10 +1131,9 @@ out:
        return r;
 }
 
-static void *rcu_unregister(void *param)
+static void rcu_unregister(void *param)
 {
        rcu_unregister_thread();
-       return NULL;
 }
 
 static void *
@@ -1438,6 +1442,16 @@ int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh)
        return 0;
 }
 
+void repair_path(struct path * pp)
+{
+       if (pp->state != PATH_DOWN)
+               return;
+
+       checker_repair(&pp->checker);
+       if (strlen(checker_message(&pp->checker)))
+               LOG_MSG(1, checker_message(&pp->checker));
+}
+
 /*
  * Returns '1' if the path has been checked, '-1' if it was blacklisted
  * and '0' otherwise
@@ -1602,6 +1616,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
                        pp->mpp->failback_tick = 0;
 
                        pp->mpp->stat_path_failures++;
+                       repair_path(pp);
                        return 1;
                }
 
@@ -1696,7 +1711,7 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
        }
 
        pp->state = newstate;
-
+       repair_path(pp);
 
        if (pp->mpp->wait_for_udev)
                return 1;
@@ -1782,7 +1797,7 @@ checkerloop (void *ap)
                }
                if (vecs->pathvec) {
                        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-                       lock(vecs->lock);
+                       lock(&vecs->lock);
                        pthread_testcancel();
                        vector_foreach_slot (vecs->pathvec, pp, i) {
                                rc = check_path(vecs, pp, ticks);
@@ -1797,7 +1812,7 @@ checkerloop (void *ap)
                }
                if (vecs->mpvec) {
                        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-                       lock(vecs->lock);
+                       lock(&vecs->lock);
                        pthread_testcancel();
                        defered_failback_tick(vecs->mpvec);
                        retry_count_tick(vecs->mpvec);
@@ -1808,7 +1823,7 @@ checkerloop (void *ap)
                        count--;
                else {
                        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-                       lock(vecs->lock);
+                       lock(&vecs->lock);
                        pthread_testcancel();
                        condlog(4, "map garbage collection");
                        mpvec_garbage_collector(vecs);
@@ -2032,21 +2047,9 @@ init_vecs (void)
        if (!vecs)
                return NULL;
 
-       vecs->lock.mutex =
-               (pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t));
-
-       if (!vecs->lock.mutex)
-               goto out;
-
-       pthread_mutex_init(vecs->lock.mutex, NULL);
-       vecs->lock.depth = 0;
+       pthread_mutex_init(&vecs->lock.mutex, NULL);
 
        return vecs;
-
-out:
-       FREE(vecs);
-       condlog(0, "failed to init paths");
-       return NULL;
 }
 
 static void *
@@ -2071,6 +2074,10 @@ signal_set(int signo, void (*func) (int))
 void
 handle_signals(void)
 {
+       if (exit_sig) {
+               condlog(2, "exit (signal)");
+               exit_daemon();
+       }
        if (reconfig_sig) {
                condlog(2, "reconfigure (signal)");
                set_config_state(DAEMON_CONFIGURE);
@@ -2081,6 +2088,7 @@ handle_signals(void)
                log_reset("multipathd");
                pthread_mutex_unlock(&logq_lock);
        }
+       exit_sig = 0;
        reconfig_sig = 0;
        log_reset_sig = 0;
 }
@@ -2094,7 +2102,7 @@ sighup (int sig)
 static void
 sigend (int sig)
 {
-       exit_daemon();
+       exit_sig = 1;
 }
 
 static void
@@ -2115,11 +2123,8 @@ signal_init(void)
        sigset_t set;
 
        sigemptyset(&set);
-       sigaddset(&set, SIGHUP);
-       sigaddset(&set, SIGUSR1);
-       sigaddset(&set, SIGUSR2);
-       sigaddset(&set, SIGALRM);
-       pthread_sigmask(SIG_BLOCK, &set, NULL);
+       sigaddset(&set, SIGPIPE);
+       pthread_sigmask(SIG_SETMASK, &set, NULL);
 
        signal_set(SIGHUP, sighup);
        signal_set(SIGUSR1, sigusr1);
@@ -2245,7 +2250,7 @@ child (void * param)
        if (ignore_new_devs)
                conf->ignore_new_devs = ignore_new_devs;
        uxsock_timeout = conf->uxsock_timeout;
-       multipath_conf = conf;
+       rcu_assign_pointer(multipath_conf, conf);
        dm_init(conf->verbosity);
        dm_drv_version(conf->version, TGT_MPATH);
        if (init_checkers(conf->multipath_dir)) {
@@ -2313,6 +2318,11 @@ child (void * param)
        }
 #endif
        /*
+        * Startup done, invalidate configuration
+        */
+       conf = NULL;
+
+       /*
         * Signal start of configuration
         */
        post_config_state(DAEMON_CONFIGURE);
@@ -2357,44 +2367,45 @@ child (void * param)
                pthread_cleanup_pop(1);
                if (running_state == DAEMON_CONFIGURE) {
                        pthread_cleanup_push(cleanup_lock, &vecs->lock);
-                       lock(vecs->lock);
+                       lock(&vecs->lock);
                        pthread_testcancel();
                        if (!need_to_delay_reconfig(vecs)) {
                                reconfigure(vecs);
                        } else {
+                               conf = get_multipath_config();
                                conf->delayed_reconfig = 1;
+                               put_multipath_config(conf);
                        }
                        lock_cleanup_pop(vecs->lock);
                        post_config_state(DAEMON_IDLE);
                }
        }
 
-       lock(vecs->lock);
+       lock(&vecs->lock);
+       conf = get_multipath_config();
        if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
                vector_foreach_slot(vecs->mpvec, mpp, i)
                        dm_queue_if_no_path(mpp->alias, 0);
+       put_multipath_config(conf);
        remove_maps_and_stop_waiters(vecs);
-       unlock(vecs->lock);
+       unlock(&vecs->lock);
 
        pthread_cancel(check_thr);
        pthread_cancel(uevent_thr);
        pthread_cancel(uxlsnr_thr);
        pthread_cancel(uevq_thr);
 
-       lock(vecs->lock);
+       pthread_join(check_thr, NULL);
+       pthread_join(uevent_thr, NULL);
+       pthread_join(uxlsnr_thr, NULL);
+       pthread_join(uevq_thr, NULL);
+
+       lock(&vecs->lock);
        free_pathvec(vecs->pathvec, FREE_PATHS);
        vecs->pathvec = NULL;
-       unlock(vecs->lock);
-       /* Now all the waitevent threads will start rushing in. */
-       while (vecs->lock.depth > 0) {
-               sleep (1); /* This is weak. */
-               condlog(3, "Have %d wait event checkers threads to de-alloc,"
-                       " waiting...", vecs->lock.depth);
-       }
-       pthread_mutex_destroy(vecs->lock.mutex);
-       FREE(vecs->lock.mutex);
-       vecs->lock.depth = 0;
-       vecs->lock.mutex = NULL;
+       unlock(&vecs->lock);
+
+       pthread_mutex_destroy(&vecs->lock.mutex);
        FREE(vecs);
        vecs = NULL;
 
@@ -2418,8 +2429,9 @@ child (void * param)
         * because logging functions like dlog() and dm_write_log()
         * reference the config.
         */
-       free_config(conf);
-       conf = NULL;
+       conf = rcu_dereference(multipath_conf);
+       rcu_assign_pointer(multipath_conf, NULL);
+       call_rcu(&conf->rcu, rcu_free_config);
        udev_unref(udev);
        udev = NULL;
        pthread_attr_destroy(&waiter_attr);
@@ -2520,7 +2532,7 @@ main (int argc, char *argv[])
        udev = udev_new();
 
        while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
-       switch(arg) {
+               switch(arg) {
                case 'd':
                        foreground = 1;
                        if (logsink > 0)
index 10b3a6d..f72580d 100644 (file)
@@ -4,12 +4,12 @@
 #define MAPGCINT 5
 
 enum daemon_status {
-    DAEMON_INIT,
-    DAEMON_START,
-    DAEMON_CONFIGURE,
-    DAEMON_IDLE,
-    DAEMON_RUNNING,
-    DAEMON_SHUTDOWN,
+       DAEMON_INIT,
+       DAEMON_START,
+       DAEMON_CONFIGURE,
+       DAEMON_IDLE,
+       DAEMON_RUNNING,
+       DAEMON_SHUTDOWN,
 };
 
 struct prout_param_descriptor;
index 9bac1dd..47d18e2 100644 (file)
@@ -1,11 +1,9 @@
 #include <sys/types.h> /* for pid_t */
 #include <sys/stat.h>  /* for open */
-#include <signal.h>    /* for kill() */
-#include <errno.h>     /* for ESHRC */
-#include <stdio.h>     /* for f...() */
+#include <errno.h>     /* for EACCESS and EAGAIN */
+#include <stdio.h>     /* for snprintf() */
 #include <string.h>    /* for memset() */
-#include <stdlib.h>    /* for atoi() */
-#include <unistd.h>    /* for unlink() */
+#include <unistd.h>    /* for ftruncate() */
 #include <fcntl.h>     /* for fcntl() */
 
 #include "debug.h"
index 62ff6f4..c5c32ea 100644 (file)
@@ -28,6 +28,9 @@
 
 static void print_reply(char *s)
 {
+       if (!s)
+               return;
+
        if (isatty(1)) {
                printf("%s", s);
                return;
index 0159648..7a9faf3 100644 (file)
@@ -49,8 +49,6 @@ struct client {
 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;
 
 /*
  * handle a new client joining
@@ -147,14 +145,16 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
        pthread_cleanup_push(uxsock_cleanup, NULL);
 
        condlog(3, "uxsock: startup listener");
-       polls = (struct pollfd *)MALLOC(MIN_POLLS + 1);
+       polls = (struct pollfd *)MALLOC((MIN_POLLS + 1) * sizeof(struct pollfd));
        if (!polls) {
                condlog(0, "uxsock: failed to allocate poll fds");
                return NULL;
        }
-       pthread_sigmask(SIG_SETMASK, NULL, &mask);
-       sigdelset(&mask, SIGHUP);
-       sigdelset(&mask, SIGUSR1);
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGHUP);
+       sigaddset(&mask, SIGUSR1);
        while (1) {
                struct client *c, *tmp;
                int i, poll_count, num_clients;
@@ -167,9 +167,11 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
                }
                if (num_clients != old_clients) {
                        struct pollfd *new;
-                       if (num_clients < MIN_POLLS) {
+                       if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) {
                                new = REALLOC(polls, (1 + MIN_POLLS) *
                                                sizeof(struct pollfd));
+                       } else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) {
+                               new = polls;
                        } else {
                                new = REALLOC(polls, (1+num_clients) *
                                                sizeof(struct pollfd));
@@ -181,7 +183,7 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
                                pthread_yield();
                                continue;
                        }
-                       num_clients = old_clients;
+                       old_clients = num_clients;
                        polls = new;
                }
                polls[0].fd = ux_sock;
@@ -210,8 +212,10 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
                        break;
                }
 
-               if (poll_count == 0)
+               if (poll_count == 0) {
+                       handle_signals();
                        continue;
+               }
 
                /* see if a client wants to speak to us */
                for (i = 1; i < num_clients + 1; i++) {
@@ -239,6 +243,10 @@ void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
                                        dead_client(c);
                                        continue;
                                }
+                               if (!inbuf) {
+                                       condlog(4, "recv_packet get null request");
+                                       continue;
+                               }
                                condlog(4, "cli[%d]: Got request [%s]",
                                        i, inbuf);
                                uxsock_trigger(inbuf, &reply, &rlen,
index 7839fce..4ef47d5 100644 (file)
@@ -6,7 +6,4 @@ 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