Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
authorHannes Reinecke <hare@suse.de>
Tue, 5 Dec 2006 08:11:27 +0000 (09:11 +0100)
committerHannes Reinecke <hare@suse.de>
Tue, 5 Dec 2006 08:11:27 +0000 (09:11 +0100)
14 files changed:
libcheckers/Makefile
libcheckers/checkers.c
libcheckers/checkers.h
libcheckers/emc_clariion.c
libcheckers/libsg.c [new file with mode: 0644]
libcheckers/libsg.h [new file with mode: 0644]
libcheckers/readsector0.c
libmultipath/alias.c
libmultipath/discovery.c
libmultipath/hwtable.c
libmultipath/structs.c
libmultipath/structs.h
multipath/main.c
multipathd/multipathd.8

index ec8c10d..bcdc6de 100644 (file)
@@ -6,7 +6,7 @@ BUILD = glibc
 
 include ../Makefile.inc
 
-OBJS = checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o
+OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o
 
 all: $(BUILD)
 
index 53770a6..4f6928f 100644 (file)
@@ -75,8 +75,9 @@ struct checker * checker_lookup (char * name)
        return NULL;
 }
 
-int checker_init (struct checker * c)
+int checker_init (struct checker * c, void ** mpctxt_addr)
 {
+       c->mpcontext = mpctxt_addr;
        return c->init(c);
 }
 
index 219dfaf..5589fc7 100644 (file)
@@ -83,14 +83,16 @@ struct checker {
        char name[CHECKER_NAME_LEN];
        char message[CHECKER_MSG_LEN];       /* comm with callers */
        void * context;                      /* store for persistent data */
+       void ** mpcontext;                   /* store for persistent data
+                                               shared multipath-wide */
        int (*check)(struct checker *);
        int (*init)(struct checker *);       /* to allocate the context */
        void (*free)(struct checker *);      /* to free the context */
 };
 
-#define MSG(c, a) snprintf((c)->message, CHECKER_MSG_LEN, a);
+#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
 
-int checker_init (struct checker *);
+int checker_init (struct checker *, void **);
 void checker_put (struct checker *);
 void checker_reset (struct checker * c);
 void checker_set_fd (struct checker *, int);
index a883e3d..384a943 100644 (file)
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "checkers.h"
-
 #include "../libmultipath/sg_include.h"
+#include "libsg.h"
+#include "checkers.h"
 
 #define INQUIRY_CMD     0x12
 #define INQUIRY_CMDLEN  6
 #define HEAVY_CHECK_COUNT       10
 
-struct emc_clariion_checker_context {
+/*
+ * Mechanism to track CLARiiON inactive snapshot LUs.
+ * This is done so that we can fail passive paths
+ * to an inactive snapshot LU even though since a
+ * simple read test would return 02/04/03 instead
+ * of 05/25/01 sensekey/ASC/ASCQ data.
+ */
+#define        IS_INACTIVE_SNAP(c)   (c->mpcontext ?                              \
+                              ((struct emc_clariion_checker_LU_context *) \
+                                       (*c->mpcontext))->inactive_snap    \
+                                           : 0)
+
+#define        SET_INACTIVE_SNAP(c)  if (c->mpcontext)                            \
+                               ((struct emc_clariion_checker_LU_context *)\
+                                       (*c->mpcontext))->inactive_snap = 1
+
+#define        CLR_INACTIVE_SNAP(c)  if (c->mpcontext)                            \
+                               ((struct emc_clariion_checker_LU_context *)\
+                                       (*c->mpcontext))->inactive_snap = 0
+
+struct emc_clariion_checker_path_context {
        char wwn[16];
        unsigned wwn_set;
 };
 
+struct emc_clariion_checker_LU_context {
+       int inactive_snap;
+};
+
+extern void
+hexadecimal_to_ascii(char * wwn, char *wwnstr)
+{
+       int i,j, nbl;
+
+       for (i=0,j=0;i<16;i++) {
+               wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
+                                       '0' + nbl : 'a' + (nbl - 10);
+               wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
+                                       '0' + nbl : 'a' + (nbl - 10);
+       }
+       wwnstr[32]=0;
+}
+
 int emc_clariion_init (struct checker * c)
 {
-       c->context = malloc(sizeof(struct emc_clariion_checker_context));
+       /*
+        * Allocate and initialize the path specific context.
+        */
+       c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
        if (!c->context)
                return 1;
-       ((struct emc_clariion_checker_context *)c->context)->wwn_set = 0;
+       ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
+
+       /*
+        * Allocate and initialize the multi-path global context.
+        */
+       if (c->mpcontext) {
+               void * mpctxt = malloc(sizeof(int));
+               *c->mpcontext = mpctxt;
+               CLR_INACTIVE_SNAP(c);
+       }
+
        return 0;
 }
 
@@ -40,13 +91,15 @@ void emc_clariion_free (struct checker * c)
 
 int emc_clariion(struct checker * c)
 {
-       unsigned char sense_buffer[256] = { 0, };
-       unsigned char sb[128] = { 0, };
+       unsigned char sense_buffer[128] = { 0, };
+       unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
        unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
-                                               sizeof(sb), 0};
+                                               sizeof(sense_buffer), 0};
        struct sg_io_hdr io_hdr;
-       struct emc_clariion_checker_context * ct =
-               (struct emc_clariion_checker_context *)c->context;
+       struct emc_clariion_checker_path_context * ct =
+               (struct emc_clariion_checker_path_context *)c->context;
+       char wwnstr[33];
+       int ret;
 
        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
        io_hdr.interface_id = 'S';
@@ -69,7 +122,8 @@ int emc_clariion(struct checker * c)
        }
        if (/* Verify the code page - right page & revision */
            sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
-               MSG(c, "emc_clariion_checker: Path unit report page in unknown format");
+               MSG(c, "emc_clariion_checker: Path unit report page in "
+                   "unknown format");
                return PATH_DOWN;
        }
 
@@ -79,19 +133,22 @@ int emc_clariion(struct checker * c)
                || (sense_buffer[28] & 0x07) != 0x04
                /* Arraycommpath should be set to 1 */
                || (sense_buffer[30] & 0x04) != 0x04) {
-               MSG(c, "emc_clariion_checker: Path not correctly configured for failover");
+               MSG(c, "emc_clariion_checker: Path not correctly configured "
+                   "for failover");
                return PATH_DOWN;
        }
 
        if ( /* LUN operations should indicate normal operations */
                sense_buffer[48] != 0x00) {
-               MSG(c, "emc_clariion_checker: Path not available for normal operations");
+               MSG(c, "emc_clariion_checker: Path not available for normal "
+                   "operations");
                return PATH_SHAKY;
        }
 
        if ( /* LUN should at least be bound somewhere and not be LUNZ */
                sense_buffer[4] == 0x00) {
-               MSG(c, "emc_clariion_checker: Logical Unit is unbound or LUNZ");
+               MSG(c, "emc_clariion_checker: Logical Unit is unbound "
+                   "or LUNZ");
                return PATH_DOWN;
        }
        
@@ -102,7 +159,8 @@ int emc_clariion(struct checker * c)
         */
        if (ct->wwn_set) {
                if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
-                       MSG(c, "emc_clariion_checker: Logical Unit WWN has changed!");
+                       MSG(c, "emc_clariion_checker: Logical Unit WWN "
+                           "has changed!");
                        return PATH_DOWN;
                }
        } else {
@@ -110,7 +168,59 @@ int emc_clariion(struct checker * c)
                ct->wwn_set = 1;
        }
        
-       
-       MSG(c, "emc_clariion_checker: Path healthy");
-        return PATH_UP;
+       /*
+        * Issue read on active path to determine if inactive snapshot.
+        */
+       if (sense_buffer[4] == 2) {/* if active path */
+               unsigned char buf[512];
+
+               ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
+               if (ret == PATH_DOWN) {
+                       hexadecimal_to_ascii(ct->wwn, wwnstr);
+
+                       /*
+                        * Check for inactive snapshot LU this way.  Must
+                        * fail these.
+                        */
+                       if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
+                           (sbb[13]==1)) {
+                               /*
+                                * Do this so that we can fail even the
+                                * passive paths which will return
+                                * 02/04/03 not 05/25/01 on read.
+                                */
+                               SET_INACTIVE_SNAP(c);
+                               MSG(c, "emc_clariion_checker: Active "
+                                       "path to inactive snapshot WWN %s.",
+                                       wwnstr);
+                       } else
+                               MSG(c, "emc_clariion_checker: Read "
+                                       "error for WWN %s.  Sense data are "
+                                       "0x%x/0x%x/0x%x.", wwnstr,
+                                       sbb[2]&0xf, sbb[12], sbb[13]);
+               } else {
+                       MSG(c, "emc_clariion_checker: Active path is "
+                           "healthy.");
+                       /*
+                        * Remove the path from the set of paths to inactive
+                        * snapshot LUs if it was in this list since the
+                        * snapshot is no longer inactive.
+                        */
+                       CLR_INACTIVE_SNAP(c);
+               }
+       } else {
+               if (IS_INACTIVE_SNAP(c)) {
+                       hexadecimal_to_ascii(ct->wwn, wwnstr);
+                       MSG(c, "emc_clariion_checker: Passive "
+                               "path to inactive snapshot WWN %s.",
+                               wwnstr);
+                       ret = PATH_DOWN;
+               } else {
+                       MSG(c,
+                           "emc_clariion_checker: Passive path is healthy.");
+                       ret = PATH_UP;  /* not ghost */
+               }
+       }
+
+       return ret;
 }
diff --git a/libcheckers/libsg.c b/libcheckers/libsg.c
new file mode 100644 (file)
index 0000000..f426aaf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+#include "libsg.h"
+#include "../libmultipath/sg_include.h"
+
+int
+sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
+{
+       /* defaults */
+       int blocks = 1;
+       long long start_block = 0;
+       int bs = 512;
+       int cdbsz = 10;
+       int * diop = NULL;
+
+       unsigned char rdCmd[cdbsz];
+       unsigned char *sbb = senseBuff;
+       struct sg_io_hdr io_hdr;
+       int res;
+       int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
+       int sz_ind;
+       int retry_count = 3;
+       
+       memset(rdCmd, 0, cdbsz);
+       sz_ind = 1;
+       rdCmd[0] = rd_opcode[sz_ind];
+       rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
+       rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
+       rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
+       rdCmd[5] = (unsigned char)(start_block & 0xff);
+       rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
+       rdCmd[8] = (unsigned char)(blocks & 0xff);
+
+       memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+       io_hdr.interface_id = 'S';
+       io_hdr.cmd_len = cdbsz;
+       io_hdr.cmdp = rdCmd;
+       io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+       io_hdr.dxfer_len = bs * blocks;
+       io_hdr.dxferp = buff;
+       io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+       io_hdr.sbp = senseBuff;
+       io_hdr.timeout = DEF_TIMEOUT;
+       io_hdr.pack_id = (int)start_block;
+       if (diop && *diop)
+       io_hdr.flags |= SG_FLAG_DIRECT_IO;
+
+retry: 
+       memset(senseBuff, 0, SENSE_BUFF_LEN);
+       while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
+
+       if (res < 0) {
+               if (ENOMEM == errno) {
+                       return PATH_UP;
+               }
+               return PATH_DOWN;
+       }
+
+       if ((0 == io_hdr.status) &&
+           (0 == io_hdr.host_status) &&
+           (0 == io_hdr.driver_status)) {
+               return PATH_UP;
+       } else {
+               /*
+                * Retry if UNIT_ATTENTION check condition.
+                */
+               if ((sbb[2]&0xf) == 6) {
+                       if (--retry_count)
+                               goto retry;
+               }
+               return PATH_DOWN;
+       }
+}
diff --git a/libcheckers/libsg.h b/libcheckers/libsg.h
new file mode 100644 (file)
index 0000000..97c4491
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LIBSG_H
+#define _LIBSG_H
+
+#define SENSE_BUFF_LEN 32
+
+int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
+
+#endif /* _LIBSG_H */
index dd18528..3cddfa8 100644 (file)
@@ -2,20 +2,9 @@
  * Copyright (c) 2004, 2005 Christophe Varoqui
  */
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
 
 #include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define SENSE_BUFF_LEN 32
+#include "libsg.h"
 
 #define MSG_READSECTOR0_UP     "readsector0 checker reports path is up"
 #define MSG_READSECTOR0_DOWN   "readsector0 checker reports path is down"
@@ -34,64 +23,6 @@ void readsector0_free (struct checker * c)
        return;
 }
 
-int
-sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
-{
-       /* defaults */
-       int blocks = 1;
-       long long start_block = 0;
-       int bs = 512;
-       int cdbsz = 10;
-       int * diop = NULL;
-
-       unsigned char rdCmd[cdbsz];
-       struct sg_io_hdr io_hdr;
-       int res;
-       int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
-       int sz_ind;
-       
-       memset(rdCmd, 0, cdbsz);
-       sz_ind = 1;
-       rdCmd[0] = rd_opcode[sz_ind];
-       rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
-       rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
-       rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
-       rdCmd[5] = (unsigned char)(start_block & 0xff);
-       rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
-       rdCmd[8] = (unsigned char)(blocks & 0xff);
-
-       memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
-       io_hdr.interface_id = 'S';
-       io_hdr.cmd_len = cdbsz;
-       io_hdr.cmdp = rdCmd;
-       io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-       io_hdr.dxfer_len = bs * blocks;
-       io_hdr.dxferp = buff;
-       io_hdr.mx_sb_len = SENSE_BUFF_LEN;
-       io_hdr.sbp = senseBuff;
-       io_hdr.timeout = DEF_TIMEOUT;
-       io_hdr.pack_id = (int)start_block;
-       if (diop && *diop)
-       io_hdr.flags |= SG_FLAG_DIRECT_IO;
-
-       while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
-
-       if (res < 0) {
-               if (ENOMEM == errno) {
-                       return PATH_UP;
-               }
-               return PATH_DOWN;
-       }
-
-       if ((0 == io_hdr.status) &&
-           (0 == io_hdr.host_status) &&
-           (0 == io_hdr.driver_status)) {
-               return PATH_UP;
-       } else {
-               return PATH_DOWN;
-       }
-}
-
 extern int
 readsector0 (struct checker * c)
 {
index 6d103d7..86cae9b 100644 (file)
@@ -166,28 +166,14 @@ fail:
 
 
 static int
-lookup_binding(int fd, char *map_wwid, char **map_alias)
+lookup_binding(FILE *f, char *map_wwid, char **map_alias)
 {
        char buf[LINE_MAX];
-       FILE *f;
        unsigned int line_nr = 0;
-       int scan_fd;
        int id = 0;
 
        *map_alias = NULL;
-       scan_fd = dup(fd);
-       if (scan_fd < 0) {
-               condlog(0, "Cannot dup bindings file descriptor : %s",
-                       strerror(errno));
-               return -1;
-       }
-       f = fdopen(scan_fd, "r");
-       if (!f) {
-               condlog(0, "cannot fdopen on bindings file descriptor : %s",
-                       strerror(errno));
-               close(scan_fd);
-               return -1;
-       }
+
        while (fgets(buf, LINE_MAX, f)) {
                char *c, *alias, *wwid;
                int curr_id;
@@ -215,38 +201,22 @@ lookup_binding(int fd, char *map_wwid, char **map_alias)
                        if (*map_alias == NULL)
                                condlog(0, "Cannot copy alias from bindings "
                                        "file : %s", strerror(errno));
-                       fclose(f);
                        return id;
                }
        }
        condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
-       fclose(f);
        return id;
 }      
 
 static int
-rlookup_binding(int fd, char **map_wwid, char *map_alias)
+rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
 {
        char buf[LINE_MAX];
-       FILE *f;
        unsigned int line_nr = 0;
-       int scan_fd;
        int id = 0;
 
        *map_wwid = NULL;
-       scan_fd = dup(fd);
-       if (scan_fd < 0) {
-               condlog(0, "Cannot dup bindings file descriptor : %s",
-                       strerror(errno));
-               return -1;
-       }
-       f = fdopen(scan_fd, "r");
-       if (!f) {
-               condlog(0, "cannot fdopen on bindings file descriptor : %s",
-                       strerror(errno));
-               close(scan_fd);
-               return -1;
-       }
+
        while (fgets(buf, LINE_MAX, f)) {
                char *c, *alias, *wwid;
                int curr_id;
@@ -274,12 +244,10 @@ rlookup_binding(int fd, char **map_wwid, char *map_alias)
                        if (*map_wwid == NULL)
                                condlog(0, "Cannot copy alias from bindings "
                                        "file : %s", strerror(errno));
-                       fclose(f);
                        return id;
                }
        }
        condlog(3, "No matching alias [%s] in bindings file.", map_alias);
-       fclose(f);
        return id;
 }      
 
@@ -327,7 +295,8 @@ char *
 get_user_friendly_alias(char *wwid, char *file)
 {
        char *alias;
-       int fd, id;
+       int fd, scan_fd, id;
+       FILE *f;
 
        if (!wwid || *wwid == '\0') {
                condlog(3, "Cannot find binding for empty WWID");
@@ -337,14 +306,37 @@ get_user_friendly_alias(char *wwid, char *file)
        fd = open_bindings_file(file);
        if (fd < 0)
                return NULL;
-       id = lookup_binding(fd, wwid, &alias);
+
+       scan_fd = dup(fd);
+       if (scan_fd < 0) {
+               condlog(0, "Cannot dup bindings file descriptor : %s",
+                       strerror(errno));
+               close(fd);
+               return NULL;
+       }
+
+       f = fdopen(scan_fd, "r");
+       if (!f) {
+               condlog(0, "cannot fdopen on bindings file descriptor : %s",
+                       strerror(errno));
+               close(scan_fd);
+               close(fd);
+               return NULL;
+       }
+
+       id = lookup_binding(f, wwid, &alias);
        if (id < 0) {
+               fclose(f);
+               close(scan_fd);
                close(fd);
                return NULL;
        }
+
        if (!alias)
                alias = allocate_binding(fd, wwid, id);
 
+       fclose(f);
+       close(scan_fd);
        close(fd);
        return alias;
 }
@@ -353,7 +345,8 @@ char *
 get_user_friendly_wwid(char *alias, char *file)
 {
        char *wwid;
-       int fd, id;
+       int fd, scan_fd, id;
+       FILE *f;
 
        if (!alias || *alias == '\0') {
                condlog(3, "Cannot find binding for empty alias");
@@ -363,12 +356,34 @@ get_user_friendly_wwid(char *alias, char *file)
        fd = open_bindings_file(file);
        if (fd < 0)
                return NULL;
-       id = rlookup_binding(fd, &wwid, alias);
+
+       scan_fd = dup(fd);
+       if (scan_fd < 0) {
+               condlog(0, "Cannot dup bindings file descriptor : %s",
+                       strerror(errno));
+               close(fd);
+               return NULL;
+       }
+
+       f = fdopen(scan_fd, "r");
+       if (!f) {
+               condlog(0, "cannot fdopen on bindings file descriptor : %s",
+                       strerror(errno));
+               close(scan_fd);
+               close(fd);
+               return NULL;
+       }
+
+       id = rlookup_binding(f, &wwid, alias);
        if (id < 0) {
+               fclose(f);
+               close(scan_fd);
                close(fd);
                return NULL;
        }
 
+       fclose(f);
+       close(scan_fd);
        close(fd);
        return wwid;
 }
index f21e5bc..a4a7997 100644 (file)
@@ -611,12 +611,15 @@ get_state (struct path * pp)
 {
        struct checker * c = &pp->checker;
 
+       if (!pp->mpp)
+               return 0;
+
        if (!checker_selected(c)) {
                select_checker(pp);
                if (!checker_selected(c))
                        return 1;
                checker_set_fd(c, pp->fd);
-               if (checker_init(c))
+               if (checker_init(c, &pp->mpp->mpcontext))
                        return 1;
        }
        pp->state = checker_check(c);
@@ -706,7 +709,7 @@ pathinfo (struct path *pp, vector hwtable, int mask)
          * been successfully obtained before.
          */
        if (mask & DI_PRIO &&
-           (pp->state != PATH_DOWN || pp->priority != PRIO_UNDEF))
+           (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF))
                get_prio(pp);
 
        if (mask & DI_WWID && !strlen(pp->wwid))
index ac126c0..f1dc611 100644 (file)
@@ -170,7 +170,7 @@ static struct hwentry default_hw[] = {
                .rr_weight     = RR_WEIGHT_NONE,
                .no_path_retry = NO_PATH_RETRY_UNDEF,
                .minio         = DEFAULT_MINIO,
-               .checker_name  = READSECTOR0,
+               .checker_name  = DIRECTIO,
        },
        /*
         * EMC / Clariion controller family
@@ -376,7 +376,7 @@ static struct hwentry default_hw[] = {
                .features      = "1 queue_if_no_path",
                .hwhandler     = DEFAULT_HWHANDLER,
                .selector      = DEFAULT_SELECTOR,
-               .pgpolicy      = GROUP_BY_SERIAL,
+               .pgpolicy      = MULTIBUS,
                .pgfailback    = FAILBACK_UNDEF,
                .rr_weight     = RR_WEIGHT_NONE,
                .no_path_retry = NO_PATH_RETRY_UNDEF,
index db3f824..d36eaef 100644 (file)
@@ -117,9 +117,10 @@ alloc_multipath (void)
 
        mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
 
-       if (mpp)
+       if (mpp) {
                mpp->bestpg = 1;
-
+               mpp->mpcontext = NULL;
+       }
        return mpp;
 }
 
@@ -180,6 +181,7 @@ free_multipath (struct multipath * mpp, int free_paths)
 
        free_pathvec(mpp->paths, free_paths);
        free_pgvec(mpp->pg, free_paths);
+       FREE_PTR(mpp->mpcontext);
        FREE(mpp);
 }
 
index 7db7faa..77dd4af 100644 (file)
@@ -154,6 +154,9 @@ struct multipath {
        unsigned int stat_map_loads;
        unsigned int stat_total_queueing_time;
        unsigned int stat_queueing_timeouts;
+
+       /* checkers shared data */
+       void * mpcontext;
 };
 
 struct pathgroup {
index accb230..7de89a7 100644 (file)
@@ -128,6 +128,7 @@ update_paths (struct multipath * mpp)
                                        pp->state = PATH_DOWN;
                                        continue;
                                }
+                               pp->mpp = mpp;
                                pathinfo(pp, conf->hwtable, DI_ALL);
                                continue;
                        }
index 88ae9c6..596bbf3 100644 (file)
@@ -1,10 +1,15 @@
-.TH MULTIPATHD 8 "July 2006" "Linux Administrator's Manual"
+.TH MULTIPATHD 8 "November 2006" "Linux Administrator's Manual"
 .SH NAME
 multipathd \- multipath daemon
-.SH SYNOPSYS
+
+.SH SYNOPSIS
 .B multipathd
+.RB [\| options \|]
 
-This daemon is in charge of checking for failed paths. When this happens,
+.SH DESCRIPTION
+The 
+.B multipathd 
+daemon is in charge of checking for failed paths. When this happens,
 it will reconfigure the multipath map the path belongs to, so that this map 
 regains its maximum performance and redundancy.
 
@@ -12,11 +17,80 @@ This daemon executes the external multipath config tool when events occur.
 In turn, the multipath tool signals the multipathd daemon when it is done with 
 devmap reconfiguration, so that it can refresh its failed path list.
 
+.SH OPTIONS
+.TP
+.B \-d
+Forground Mode. Don't daemonize, and print all messages to stdout and stderr.
+.TP 
+.B -v "level"
+Verbosity level. Print additional information while running multipathd. A  level of 0 means only print errors. A level of 3 or greater prints debugging information as well. 
+.TP
+.B -k 
+multipathd will enter interactive mode. From this mode, the available commands can be viewed by entering "help". When you are finished entering commands, press CTRL-D to quit.
+
+.SH COMMANDS
+.TP
+The following commands can be used in interactive mode:
+.TP
+.B list|show paths
+Show the paths that multipathd is monitoring, and their state. 
+.TP
+.B list|show maps|multipaths
+Show the multipath devices that the multipathd is monitoring. 
+.TP
+.B list|show maps|multipaths status
+Show the status of all multipath devices that the multipathd is monitoring.
+.TP
+.B list|show maps|multipaths stats
+Show some statistics of all multipath devices that the multipathd is monitoring.
+.TP
+.B list|show maps|multipaths topology
+Show the current multipath topology. Same as "multipath -ll".
+.TP
+.B list|show topology
+Show the current multipath topology. Same as "multipath -ll".
+.TP
+.B list|show map|multipath $map topology
+Show topology of a single multipath device specified by $map, e.g. 36005076303ffc56200000000000010aa.
+This map could be obtained from "list maps".
+.TP
+.B list|show config
+Show the currently used configuration, derived from default values and values specified within the configuration file /etc/multipath.conf.
+.TP
+.B add path $path
+Add a path to the list of monitored paths. $path is as listed in /sys/block (e.g. sda).
+.TP 
+.B remove|del path $path
+Stop monitoring a path. $path is as listed in /sys/block (e.g. sda).
+.TP
+.B add map $map
+Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa). 
+.TP
+.B remove|del map $map
+Stop monitoring a multipath device.
+.TP 
+.B switch|switchgroup map $map group $group
+Force a multipath device to switch to a specific path group. $group is the path group index, starting with 1.
+.TP
+.B reconfigure
+Reconfigures the multipaths. This should be triggered automatically after any hotplug event.
+.TP
+.B suspend map|multipath $map
+Sets map $map into suspend state.
+.TP
+.B resume map|multipath $map
+Resumes map $map from suspend state.
+.TP
+.B fail path $path
+Sets path $path into failed state.
+.TP
+.B reinstate path $path
+Resumes path $path from failed state.
+
 .SH "SEE ALSO"
 .BR multipath (8)
 .BR kpartx (8)
 .BR hotplug (8)
 .SH "AUTHORS"
-This man page was assembled by Patrick Caulfield 
-for the Debian project. From documentation provided
-by the multipath author Christophe Varoqui, <christophe.varoqui@free.fr> and others.
+.B multipathd
+was developed by Christophe Varoqui, <christophe.varoqui@free.fr> and others.