forked from pool/multipath-tools
3934 lines
108 KiB
Diff
3934 lines
108 KiB
Diff
|
Makefile | 4
|
||
|
devmap_name/devmap_name.8 | 2
|
||
|
kpartx/devmapper.c | 46 ++-
|
||
|
kpartx/devmapper.h | 4
|
||
|
kpartx/kpartx.8 | 2
|
||
|
kpartx/kpartx.c | 15 -
|
||
|
libcheckers/checkers.h | 54 +++
|
||
|
libcheckers/emc_clariion.c | 13 -
|
||
|
libcheckers/hp_sw.c | 3
|
||
|
libcheckers/readsector0.c | 9
|
||
|
libcheckers/tur.c | 2
|
||
|
libmultipath/Makefile | 3
|
||
|
libmultipath/callout.c | 2
|
||
|
libmultipath/config.c | 75 +++-
|
||
|
libmultipath/config.h | 6
|
||
|
libmultipath/configure.c | 60 ++-
|
||
|
libmultipath/configure.h | 2
|
||
|
libmultipath/debug.c | 5
|
||
|
libmultipath/debug.h | 4
|
||
|
libmultipath/devmapper.c | 38 ++
|
||
|
libmultipath/discovery.c | 41 +-
|
||
|
libmultipath/discovery.h | 6
|
||
|
libmultipath/dmparser.c | 19 +
|
||
|
libmultipath/hwtable.c | 202 +++++++++--
|
||
|
libmultipath/lock.c | 8
|
||
|
libmultipath/lock.h | 22 +
|
||
|
libmultipath/parser.c | 15 +
|
||
|
libmultipath/parser.h | 1
|
||
|
libmultipath/pgpolicies.h | 2
|
||
|
libmultipath/print.c | 43 ++
|
||
|
libmultipath/propsel.c | 33 +-
|
||
|
libmultipath/structs.c | 9
|
||
|
libmultipath/structs.h | 12 -
|
||
|
libmultipath/structs_vec.c | 94 +++++
|
||
|
libmultipath/structs_vec.h | 14 -
|
||
|
libmultipath/util.c | 9
|
||
|
libmultipath/util.h | 1
|
||
|
libmultipath/version.h | 37 ++
|
||
|
libmultipath/waiter.c | 234 +++++++++++++
|
||
|
libmultipath/waiter.h | 23 +
|
||
|
multipath-tools.spec.in | 1
|
||
|
multipath.conf.annotated | 6
|
||
|
multipath/main.c | 18 +
|
||
|
multipath/main.h | 39 --
|
||
|
multipath/multipath.8 | 15 -
|
||
|
multipathd/cli.c | 3
|
||
|
multipathd/cli_handlers.c | 6
|
||
|
multipathd/main.c | 385 +--------------------
|
||
|
multipathd/multipathd.8 | 6
|
||
|
path_priority/pp_alua/main.c | 4
|
||
|
path_priority/pp_alua/mpath_prio_alua.8 | 2
|
||
|
path_priority/pp_alua/rtpg.c | 36 ++
|
||
|
path_priority/pp_alua/spc3.h | 4
|
||
|
path_priority/pp_balance_units/pp_balance_units.c | 74 ++--
|
||
|
path_priority/pp_hds_modular/Makefile | 22 +
|
||
|
path_priority/pp_hds_modular/pp_hds_modular.c | 252 ++++++++++++++
|
||
|
path_priority/pp_tpc/pp_tpc.c | 12 -
|
||
|
57 files changed, 1375 insertions(+), 684 deletions(-)
|
||
|
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index 83ae2fe..aacede3 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -22,7 +22,11 @@ export KRNLOBJ
|
||
|
|
||
|
BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib)
|
||
|
|
||
|
+ifeq ($(MULTIPATH_VERSION),)
|
||
|
VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
|
||
|
+else
|
||
|
+VERSION = $(MULTIPATH_VERSION)
|
||
|
+endif
|
||
|
|
||
|
all: recurse
|
||
|
|
||
|
diff --git a/devmap_name/devmap_name.8 b/devmap_name/devmap_name.8
|
||
|
index f4f03c3..86d0931 100644
|
||
|
--- a/devmap_name/devmap_name.8
|
||
|
+++ b/devmap_name/devmap_name.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.TH DEVMAP_NAME 8 "February 2004" "" "Linux Administrator's Manual"
|
||
|
+.TH DEVMAP_NAME 8 "July 2006" "" "Linux Administrator's Manual"
|
||
|
.SH NAME
|
||
|
devmap_name \- Query device-mapper name
|
||
|
.SH SYNOPSIS
|
||
|
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
|
||
|
index 1253941..5b27487 100644
|
||
|
--- a/kpartx/devmapper.c
|
||
|
+++ b/kpartx/devmapper.c
|
||
|
@@ -7,6 +7,10 @@ #include <string.h>
|
||
|
#include <libdevmapper.h>
|
||
|
#include <ctype.h>
|
||
|
#include <linux/kdev_t.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#define UUID_PREFIX "part%d-"
|
||
|
+#define MAX_PREFIX_LEN 8
|
||
|
|
||
|
extern int
|
||
|
dm_prereq (char * str, int x, int y, int z)
|
||
|
@@ -68,9 +72,10 @@ dm_simplecmd (int task, const char *name
|
||
|
|
||
|
extern int
|
||
|
dm_addmap (int task, const char *name, const char *target,
|
||
|
- const char *params, unsigned long size) {
|
||
|
+ const char *params, unsigned long size, const char *uuid, int part) {
|
||
|
int r = 0;
|
||
|
struct dm_task *dmt;
|
||
|
+ char *prefixed_uuid;
|
||
|
|
||
|
if (!(dmt = dm_task_create (task)))
|
||
|
return 0;
|
||
|
@@ -81,10 +86,26 @@ dm_addmap (int task, const char *name, c
|
||
|
if (!dm_task_add_target (dmt, 0, size, target, params))
|
||
|
goto addout;
|
||
|
|
||
|
+ if (task == DM_DEVICE_CREATE && uuid) {
|
||
|
+ prefixed_uuid = malloc(MAX_PREFIX_LEN + strlen(uuid) + 1);
|
||
|
+ if (!prefixed_uuid) {
|
||
|
+ fprintf(stderr, "cannot create prefixed uuid : %s\n",
|
||
|
+ strerror(errno));
|
||
|
+ goto addout;
|
||
|
+ }
|
||
|
+ sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid);
|
||
|
+ if (!dm_task_set_uuid(dmt, prefixed_uuid))
|
||
|
+ goto freeout;
|
||
|
+ }
|
||
|
+
|
||
|
dm_task_no_open_count(dmt);
|
||
|
|
||
|
r = dm_task_run (dmt);
|
||
|
|
||
|
+ freeout:
|
||
|
+ if (prefixed_uuid)
|
||
|
+ free(prefixed_uuid);
|
||
|
+
|
||
|
addout:
|
||
|
dm_task_destroy (dmt);
|
||
|
return r;
|
||
|
@@ -178,3 +199,26 @@ out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+char *
|
||
|
+dm_mapuuid(int major, int minor)
|
||
|
+{
|
||
|
+ struct dm_task *dmt;
|
||
|
+ char *tmp, *uuid = NULL;
|
||
|
+
|
||
|
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ dm_task_no_open_count(dmt);
|
||
|
+ dm_task_set_major(dmt, major);
|
||
|
+ dm_task_set_minor(dmt, minor);
|
||
|
+
|
||
|
+ if (!dm_task_run(dmt))
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ tmp = dm_task_get_uuid(dmt);
|
||
|
+ if (tmp[0] != '\0')
|
||
|
+ uuid = strdup(tmp);
|
||
|
+out:
|
||
|
+ dm_task_destroy(dmt);
|
||
|
+ return uuid;
|
||
|
+}
|
||
|
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
|
||
|
index 9607476..e20e456 100644
|
||
|
--- a/kpartx/devmapper.h
|
||
|
+++ b/kpartx/devmapper.h
|
||
|
@@ -1,6 +1,8 @@
|
||
|
int dm_prereq (char *, int, int, int);
|
||
|
int dm_simplecmd (int, const char *);
|
||
|
-int dm_addmap (int, const char *, const char *, const char *, unsigned long);
|
||
|
+int dm_addmap (int, const char *, const char *, const char *, unsigned long,
|
||
|
+ char *, int);
|
||
|
int dm_map_present (char *);
|
||
|
char * dm_mapname(int major, int minor);
|
||
|
dev_t dm_get_first_dep(char *devname);
|
||
|
+char * dm_mapuuid(int major, int minor);
|
||
|
diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8
|
||
|
index 259ce3f..87b07ce 100644
|
||
|
--- a/kpartx/kpartx.8
|
||
|
+++ b/kpartx/kpartx.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.TH KPARTX 8 "February 2004" "" "Linux Administrator's Manual"
|
||
|
+.TH KPARTX 8 "July 2006" "" "Linux Administrator's Manual"
|
||
|
.SH NAME
|
||
|
kpartx \- Create device maps from partition tables
|
||
|
.SH SYNOPSIS
|
||
|
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
||
|
index 2198302..0ee0cb3 100644
|
||
|
--- a/kpartx/kpartx.c
|
||
|
+++ b/kpartx/kpartx.c
|
||
|
@@ -192,6 +192,7 @@ main(int argc, char **argv){
|
||
|
char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
|
||
|
char * loopdev = NULL;
|
||
|
char * delim = NULL;
|
||
|
+ char *uuid = NULL;
|
||
|
int loopro = 0;
|
||
|
int hotplug = 0;
|
||
|
struct stat buf;
|
||
|
@@ -284,11 +285,6 @@ main(int argc, char **argv){
|
||
|
}
|
||
|
|
||
|
if (S_ISREG (buf.st_mode)) {
|
||
|
- loopdev = malloc(LO_NAME_SIZE * sizeof(char));
|
||
|
-
|
||
|
- if (!loopdev)
|
||
|
- exit(1);
|
||
|
-
|
||
|
/* already looped file ? */
|
||
|
loopdev = find_loop_by_file(device);
|
||
|
|
||
|
@@ -313,6 +309,13 @@ main(int argc, char **argv){
|
||
|
}
|
||
|
|
||
|
off = find_devname_offset(device);
|
||
|
+
|
||
|
+ if (!loopdev)
|
||
|
+ uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
|
||
|
+ (unsigned int)MINOR(buf.st_rdev));
|
||
|
+ if (!uuid)
|
||
|
+ uuid = device + off;
|
||
|
+
|
||
|
fd = open(device, O_RDONLY);
|
||
|
|
||
|
if (fd == -1) {
|
||
|
@@ -420,7 +423,7 @@ #endif
|
||
|
DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
|
||
|
|
||
|
dm_addmap(op, partname, DM_TARGET, params,
|
||
|
- slices[j].size);
|
||
|
+ slices[j].size, uuid, j+1);
|
||
|
|
||
|
if (op == DM_DEVICE_RELOAD)
|
||
|
dm_simplecmd(DM_DEVICE_RESUME,
|
||
|
diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h
|
||
|
index ac795ed..219dfaf 100644
|
||
|
--- a/libcheckers/checkers.h
|
||
|
+++ b/libcheckers/checkers.h
|
||
|
@@ -2,7 +2,44 @@ #ifndef _CHECKERS_H
|
||
|
#define _CHECKERS_H
|
||
|
|
||
|
/*
|
||
|
- * path states
|
||
|
+ *
|
||
|
+ * Userspace (multipath/multipathd) path states
|
||
|
+ *
|
||
|
+ * PATH_WILD:
|
||
|
+ * - Use: None of the checkers (returned if we don't have an fd)
|
||
|
+ * - Description: Corner case where "fd <= 0" for path fd (see checker_check())
|
||
|
+ *
|
||
|
+ * PATH_UNCHECKED:
|
||
|
+ * - Use: Only in directio checker
|
||
|
+ * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
|
||
|
+ * not include in flags, or O_DIRECT read fails
|
||
|
+ * - Notes:
|
||
|
+ * - multipathd: uses it to skip over paths in sync_map_state()
|
||
|
+ * - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
|
||
|
+ * pathinfo()
|
||
|
+ *
|
||
|
+ * PATH_DOWN:
|
||
|
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
|
||
|
+ * - Description: Either a) SG_IO ioctl failed, or b) check condition on some
|
||
|
+ * SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
|
||
|
+ * you shouldn't try to send commands to it
|
||
|
+ *
|
||
|
+ * PATH_UP:
|
||
|
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
|
||
|
+ * - Description: Path is up and I/O can be sent to it
|
||
|
+ *
|
||
|
+ * PATH_SHAKY:
|
||
|
+ * - Use: Only emc_clariion
|
||
|
+ * - Description: Indicates path not available for "normal" operations
|
||
|
+ *
|
||
|
+ * PATH_GHOST:
|
||
|
+ * - Use: Only hp_sw
|
||
|
+ * - Description: Indicates a "passive/standby" path on active/passive HP
|
||
|
+ * arrays. These paths will return valid answers to certain SCSI commands
|
||
|
+ * (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
|
||
|
+ * The path needs an initialization command to be sent to it in order for
|
||
|
+ * I/Os to succeed.
|
||
|
+ *
|
||
|
*/
|
||
|
#define PATH_WILD -1
|
||
|
#define PATH_UNCHECKED 0
|
||
|
@@ -20,6 +57,21 @@ #define READSECTOR0 "readsector0"
|
||
|
#define DEFAULT_CHECKER READSECTOR0
|
||
|
|
||
|
/*
|
||
|
+ * Overloaded storage response time can be very long.
|
||
|
+ * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
|
||
|
+ * as a path failure. multipathd then proactively evicts the path from the DM
|
||
|
+ * multipath table in this case.
|
||
|
+ *
|
||
|
+ * This generaly snow balls and ends up in full eviction and IO errors for end
|
||
|
+ * users. Bad. This may also cause SCSI bus resets, causing disruption for all
|
||
|
+ * local and external storage hardware users.
|
||
|
+ *
|
||
|
+ * Provision a long timeout. Longer than any real-world application would cope
|
||
|
+ * with.
|
||
|
+ */
|
||
|
+#define DEF_TIMEOUT 300000
|
||
|
+
|
||
|
+/*
|
||
|
* strings lengths
|
||
|
*/
|
||
|
#define CHECKER_NAME_LEN 16
|
||
|
diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c
|
||
|
index 1d7b684..a883e3d 100644
|
||
|
--- a/libcheckers/emc_clariion.c
|
||
|
+++ b/libcheckers/emc_clariion.c
|
||
|
@@ -57,7 +57,7 @@ int emc_clariion(struct checker * c)
|
||
|
io_hdr.dxferp = sense_buffer;
|
||
|
io_hdr.cmdp = inqCmdBlk;
|
||
|
io_hdr.sbp = sb;
|
||
|
- io_hdr.timeout = 60000;
|
||
|
+ io_hdr.timeout = DEF_TIMEOUT;
|
||
|
io_hdr.pack_id = 0;
|
||
|
if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
|
||
|
MSG(c, "emc_clariion_checker: sending query command failed");
|
||
|
@@ -89,14 +89,11 @@ int emc_clariion(struct checker * c)
|
||
|
return PATH_SHAKY;
|
||
|
}
|
||
|
|
||
|
-#if 0
|
||
|
- /* This is not actually an error as the failover to this group
|
||
|
- * _would_ bind the path */
|
||
|
- if ( /* LUN should at least be bound somewhere */
|
||
|
- sense_buffer[4] != 0x00) {
|
||
|
- return PATH_UP;
|
||
|
+ if ( /* LUN should at least be bound somewhere and not be LUNZ */
|
||
|
+ sense_buffer[4] == 0x00) {
|
||
|
+ MSG(c, "emc_clariion_checker: Logical Unit is unbound or LUNZ");
|
||
|
+ return PATH_DOWN;
|
||
|
}
|
||
|
-#endif
|
||
|
|
||
|
/*
|
||
|
* store the LUN WWN there and compare that it indeed did not
|
||
|
diff --git a/libcheckers/hp_sw.c b/libcheckers/hp_sw.c
|
||
|
index 509e9c4..b9731ff 100644
|
||
|
--- a/libcheckers/hp_sw.c
|
||
|
+++ b/libcheckers/hp_sw.c
|
||
|
@@ -19,7 +19,6 @@ #define TUR_CMD_LEN 6
|
||
|
#define INQUIRY_CMDLEN 6
|
||
|
#define INQUIRY_CMD 0x12
|
||
|
#define SENSE_BUFF_LEN 32
|
||
|
-#define DEF_TIMEOUT 60000
|
||
|
#define SCSI_CHECK_CONDITION 0x2
|
||
|
#define SCSI_COMMAND_TERMINATED 0x22
|
||
|
#define SG_ERR_DRIVER_SENSE 0x08
|
||
|
@@ -111,7 +110,7 @@ do_tur (int fd)
|
||
|
io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
|
io_hdr.cmdp = turCmdBlk;
|
||
|
io_hdr.sbp = sense_buffer;
|
||
|
- io_hdr.timeout = 20000;
|
||
|
+ io_hdr.timeout = DEF_TIMEOUT;
|
||
|
io_hdr.pack_id = 0;
|
||
|
|
||
|
if (ioctl(fd, SG_IO, &io_hdr) < 0)
|
||
|
diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c
|
||
|
index e368fb4..dd18528 100644
|
||
|
--- a/libcheckers/readsector0.c
|
||
|
+++ b/libcheckers/readsector0.c
|
||
|
@@ -16,7 +16,6 @@ #include "checkers.h"
|
||
|
#include "../libmultipath/sg_include.h"
|
||
|
|
||
|
#define SENSE_BUFF_LEN 32
|
||
|
-#define DEF_TIMEOUT 60000
|
||
|
|
||
|
#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
|
||
|
#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
|
||
|
@@ -35,8 +34,8 @@ void readsector0_free (struct checker *
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
-static int
|
||
|
-sg_read (int sg_fd, unsigned char * buff)
|
||
|
+int
|
||
|
+sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
|
||
|
{
|
||
|
/* defaults */
|
||
|
int blocks = 1;
|
||
|
@@ -46,7 +45,6 @@ sg_read (int sg_fd, unsigned char * buff
|
||
|
int * diop = NULL;
|
||
|
|
||
|
unsigned char rdCmd[cdbsz];
|
||
|
- unsigned char senseBuff[SENSE_BUFF_LEN];
|
||
|
struct sg_io_hdr io_hdr;
|
||
|
int res;
|
||
|
int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
|
||
|
@@ -98,9 +96,10 @@ extern int
|
||
|
readsector0 (struct checker * c)
|
||
|
{
|
||
|
unsigned char buf[512];
|
||
|
+ unsigned char sbuf[SENSE_BUFF_LEN];
|
||
|
int ret;
|
||
|
|
||
|
- ret = sg_read(c->fd, &buf[0]);
|
||
|
+ ret = sg_read(c->fd, &buf[0], &sbuf[0]);
|
||
|
|
||
|
switch (ret)
|
||
|
{
|
||
|
diff --git a/libcheckers/tur.c b/libcheckers/tur.c
|
||
|
index d40a273..e79bc0a 100644
|
||
|
--- a/libcheckers/tur.c
|
||
|
+++ b/libcheckers/tur.c
|
||
|
@@ -51,7 +51,7 @@ tur (struct checker * c)
|
||
|
io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
|
io_hdr.cmdp = turCmdBlk;
|
||
|
io_hdr.sbp = sense_buffer;
|
||
|
- io_hdr.timeout = 20000;
|
||
|
+ io_hdr.timeout = DEF_TIMEOUT;
|
||
|
io_hdr.pack_id = 0;
|
||
|
if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
|
||
|
MSG(c, MSG_TUR_DOWN);
|
||
|
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
|
||
|
index 8a14b04..5d8c586 100644
|
||
|
--- a/libmultipath/Makefile
|
||
|
+++ b/libmultipath/Makefile
|
||
|
@@ -6,7 +6,7 @@ BUILD = glibc
|
||
|
|
||
|
include ../Makefile.inc
|
||
|
|
||
|
-CFLAGS = -I$(checkersdir)
|
||
|
+CFLAGS += -I$(checkersdir)
|
||
|
|
||
|
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
|
||
|
hwtable.o blacklist.o util.o dmparser.o config.o \
|
||
|
@@ -18,6 +18,7 @@ OBJS = memory.o parser.o vector.o devmap
|
||
|
PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
|
||
|
|
||
|
ifeq ($(strip $(DAEMON)),1)
|
||
|
+ OBJS += lock.o waiter.o
|
||
|
CFLAGS += -DDAEMON
|
||
|
CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
|
||
|
else
|
||
|
diff --git a/libmultipath/callout.c b/libmultipath/callout.c
|
||
|
index 46b89e6..b0bc503 100644
|
||
|
--- a/libmultipath/callout.c
|
||
|
+++ b/libmultipath/callout.c
|
||
|
@@ -78,7 +78,7 @@ int execute_program(char *path, char *va
|
||
|
/* dup write side of pipe to STDOUT */
|
||
|
dup(fds[1]);
|
||
|
|
||
|
- retval = execv(argv[0], argv);
|
||
|
+ retval = execvp(argv[0], argv);
|
||
|
|
||
|
exit(-1);
|
||
|
case -1:
|
||
|
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
||
|
index 1068755..528e475 100644
|
||
|
--- a/libmultipath/config.c
|
||
|
+++ b/libmultipath/config.c
|
||
|
@@ -20,26 +20,61 @@ #include "config.h"
|
||
|
#include "blacklist.h"
|
||
|
#include "defaults.h"
|
||
|
|
||
|
+static struct hwentry *
|
||
|
+find_hwe_strmatch (vector hwtable, char * vendor, char * product, char * revision)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ struct hwentry *hwe, *ret = NULL;
|
||
|
+
|
||
|
+ vector_foreach_slot (hwtable, hwe, i) {
|
||
|
+ if (hwe->vendor && vendor && strcmp(hwe->vendor, vendor))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (hwe->product && product && strcmp(hwe->product, product))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (hwe->revision && revision && strcmp(hwe->revision, revision))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ret = hwe;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
struct hwentry *
|
||
|
-find_hwe (vector hwtable, char * vendor, char * product)
|
||
|
+find_hwe (vector hwtable, char * vendor, char * product, char * revision)
|
||
|
{
|
||
|
int i;
|
||
|
struct hwentry *hwe, *ret = NULL;
|
||
|
- regex_t vre, pre;
|
||
|
+ regex_t vre, pre, rre;
|
||
|
|
||
|
vector_foreach_slot (hwtable, hwe, i) {
|
||
|
- if (regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
|
||
|
+ if (hwe->vendor &&
|
||
|
+ regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
|
||
|
+ break;
|
||
|
+ if (hwe->product &&
|
||
|
+ regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
|
||
|
+ regfree(&vre);
|
||
|
break;
|
||
|
- if (regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
|
||
|
+ }
|
||
|
+ if (hwe->revision &&
|
||
|
+ regcomp(&rre, hwe->revision, REG_EXTENDED|REG_NOSUB)) {
|
||
|
regfree(&vre);
|
||
|
+ regfree(&pre);
|
||
|
break;
|
||
|
}
|
||
|
- if (!regexec(&vre, vendor, 0, NULL, 0) &&
|
||
|
- !regexec(&pre, product, 0, NULL, 0))
|
||
|
+ if ((!hwe->vendor || !regexec(&vre, vendor, 0, NULL, 0)) &&
|
||
|
+ (!hwe->product || !regexec(&pre, product, 0, NULL, 0)) &&
|
||
|
+ (!hwe->revision || !regexec(&rre, revision, 0, NULL, 0)))
|
||
|
ret = hwe;
|
||
|
-
|
||
|
- regfree(&pre);
|
||
|
- regfree(&vre);
|
||
|
+
|
||
|
+ if (hwe->revision)
|
||
|
+ regfree(&rre);
|
||
|
+ if (hwe->product)
|
||
|
+ regfree(&pre);
|
||
|
+ if (hwe->vendor)
|
||
|
+ regfree(&vre);
|
||
|
|
||
|
if (ret)
|
||
|
break;
|
||
|
@@ -91,6 +126,9 @@ free_hwe (struct hwentry * hwe)
|
||
|
if (hwe->product)
|
||
|
FREE(hwe->product);
|
||
|
|
||
|
+ if (hwe->revision)
|
||
|
+ FREE(hwe->revision);
|
||
|
+
|
||
|
if (hwe->selector)
|
||
|
FREE(hwe->selector);
|
||
|
|
||
|
@@ -204,23 +242,12 @@ set_param_str(char * str)
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
-static int
|
||
|
-dup_hwe (vector hwtable, char * vendor, char * product)
|
||
|
-{
|
||
|
- struct hwentry * hwe = find_hwe(hwtable, vendor, product);
|
||
|
-
|
||
|
- if (hwe)
|
||
|
- return 1;
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
|
-
|
||
|
int
|
||
|
store_hwe (vector hwtable, struct hwentry * dhwe)
|
||
|
{
|
||
|
struct hwentry * hwe;
|
||
|
|
||
|
- if (dup_hwe(hwtable, dhwe->vendor, dhwe->product))
|
||
|
+ if (find_hwe_strmatch(hwtable, dhwe->vendor, dhwe->product, dhwe->revision))
|
||
|
return 0;
|
||
|
|
||
|
if (!(hwe = alloc_hwe()))
|
||
|
@@ -232,6 +259,9 @@ store_hwe (vector hwtable, struct hwentr
|
||
|
if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
|
||
|
goto out;
|
||
|
|
||
|
+ if (dhwe->revision && !(hwe->revision = set_param_str(dhwe->revision)))
|
||
|
+ goto out;
|
||
|
+
|
||
|
if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
|
||
|
goto out;
|
||
|
|
||
|
@@ -305,7 +335,7 @@ free_config (struct config * conf)
|
||
|
free_blacklist_device(conf->blist_device);
|
||
|
free_mptable(conf->mptable);
|
||
|
free_hwtable(conf->hwtable);
|
||
|
-
|
||
|
+ free_keywords(conf->keywords);
|
||
|
FREE(conf);
|
||
|
}
|
||
|
|
||
|
@@ -332,6 +362,7 @@ load_config (char * file)
|
||
|
* read the config file
|
||
|
*/
|
||
|
if (filepresent(file)) {
|
||
|
+ set_current_keywords(&conf->keywords);
|
||
|
if (init_data(file, init_keywords)) {
|
||
|
condlog(0, "error parsing config file");
|
||
|
goto out;
|
||
|
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
||
|
index 6e5633a..0c3b640 100644
|
||
|
--- a/libmultipath/config.h
|
||
|
+++ b/libmultipath/config.h
|
||
|
@@ -11,6 +11,7 @@ enum devtypes {
|
||
|
struct hwentry {
|
||
|
char * vendor;
|
||
|
char * product;
|
||
|
+ char * revision;
|
||
|
char * getuid;
|
||
|
char * getprio;
|
||
|
char * features;
|
||
|
@@ -48,7 +49,7 @@ struct config {
|
||
|
int with_sysfs;
|
||
|
int pgpolicy;
|
||
|
struct checker * checker;
|
||
|
- int dev_type;
|
||
|
+ enum devtypes dev_type;
|
||
|
int minio;
|
||
|
int checkint;
|
||
|
int max_checkint;
|
||
|
@@ -67,6 +68,7 @@ struct config {
|
||
|
char * hwhandler;
|
||
|
char * bindings_file;
|
||
|
|
||
|
+ vector keywords;
|
||
|
vector mptable;
|
||
|
vector hwtable;
|
||
|
|
||
|
@@ -77,7 +79,7 @@ struct config {
|
||
|
|
||
|
struct config * conf;
|
||
|
|
||
|
-struct hwentry * find_hwe (vector hwtable, char * vendor, char * product);
|
||
|
+struct hwentry * find_hwe (vector hwtable, char * vendor, char * product, char *revision);
|
||
|
struct mpentry * find_mpe (char * wwid);
|
||
|
char * get_mpe_wwid (char * alias);
|
||
|
|
||
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||
|
index 1ba4356..9d17022 100644
|
||
|
--- a/libmultipath/configure.c
|
||
|
+++ b/libmultipath/configure.c
|
||
|
@@ -145,11 +145,6 @@ select_action (struct multipath * mpp, v
|
||
|
mpp->action = ACT_RENAME;
|
||
|
return;
|
||
|
}
|
||
|
- else {
|
||
|
- condlog(3, "%s: set ACT_CREATE (map does not exist)",
|
||
|
- mpp->alias);
|
||
|
- mpp->action = ACT_CREATE;
|
||
|
- }
|
||
|
mpp->action = ACT_CREATE;
|
||
|
condlog(3, "%s: set ACT_CREATE (map does not exist)",
|
||
|
mpp->alias);
|
||
|
@@ -286,11 +281,13 @@ lock_multipath (struct multipath * mpp,
|
||
|
|
||
|
/*
|
||
|
* Return value:
|
||
|
- * -1: Retry
|
||
|
- * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
|
||
|
- * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
|
||
|
- * 2: Map is already existing.
|
||
|
*/
|
||
|
+#define DOMAP_RETRY -1
|
||
|
+#define DOMAP_FAIL 0
|
||
|
+#define DOMAP_OK 1
|
||
|
+#define DOMAP_EXIST 2
|
||
|
+#define DOMAP_DRY 3
|
||
|
+
|
||
|
extern int
|
||
|
domap (struct multipath * mpp)
|
||
|
{
|
||
|
@@ -299,15 +296,15 @@ domap (struct multipath * mpp)
|
||
|
/*
|
||
|
* last chance to quit before touching the devmaps
|
||
|
*/
|
||
|
- if (conf->dry_run) {
|
||
|
+ if (conf->dry_run && mpp->action != ACT_NOTHING) {
|
||
|
print_multipath_topology(mpp, conf->verbosity);
|
||
|
- return 0;
|
||
|
+ return DOMAP_DRY;
|
||
|
}
|
||
|
|
||
|
switch (mpp->action) {
|
||
|
case ACT_REJECT:
|
||
|
case ACT_NOTHING:
|
||
|
- return 2;
|
||
|
+ return DOMAP_EXIST;
|
||
|
|
||
|
case ACT_SWITCHPG:
|
||
|
dm_switchgroup(mpp->alias, mpp->bestpg);
|
||
|
@@ -317,13 +314,13 @@ domap (struct multipath * mpp)
|
||
|
* retry.
|
||
|
*/
|
||
|
reinstate_paths(mpp);
|
||
|
- return 2;
|
||
|
+ return DOMAP_EXIST;
|
||
|
|
||
|
case ACT_CREATE:
|
||
|
if (lock_multipath(mpp, 1)) {
|
||
|
condlog(3, "%s: failed to create map (in use)",
|
||
|
mpp->alias);
|
||
|
- return -1;
|
||
|
+ return DOMAP_RETRY;
|
||
|
}
|
||
|
dm_shut_log();
|
||
|
|
||
|
@@ -377,9 +374,9 @@ #else
|
||
|
condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
|
||
|
mpp->size, DEFAULT_TARGET, mpp->params);
|
||
|
#endif
|
||
|
+ return DOMAP_OK;
|
||
|
}
|
||
|
-
|
||
|
- return r;
|
||
|
+ return DOMAP_FAIL;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
@@ -444,7 +441,7 @@ coalesce_paths (struct vectors * vecs, v
|
||
|
if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL)
|
||
|
return 1;
|
||
|
|
||
|
- if (pp1->priority < 0)
|
||
|
+ if (pp1->priority == PRIO_UNDEF)
|
||
|
mpp->action = ACT_REJECT;
|
||
|
|
||
|
if (!mpp->paths) {
|
||
|
@@ -471,7 +468,7 @@ coalesce_paths (struct vectors * vecs, v
|
||
|
mpp->size);
|
||
|
mpp->action = ACT_REJECT;
|
||
|
}
|
||
|
- if (pp2->priority < 0)
|
||
|
+ if (pp2->priority == PRIO_UNDEF)
|
||
|
mpp->action = ACT_REJECT;
|
||
|
}
|
||
|
verify_paths(mpp, vecs, NULL);
|
||
|
@@ -486,19 +483,18 @@ coalesce_paths (struct vectors * vecs, v
|
||
|
|
||
|
r = domap(mpp);
|
||
|
|
||
|
- if (!r) {
|
||
|
+ if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
|
||
|
condlog(3, "%s: domap (%u) failure "
|
||
|
"for create/reload map",
|
||
|
mpp->alias, r);
|
||
|
- remove_map(mpp, vecs, NULL, 0);
|
||
|
- continue;
|
||
|
- }
|
||
|
- else if (r < 0) {
|
||
|
- condlog(3, "%s: domap (%u) failure "
|
||
|
- "for create/reload map",
|
||
|
- mpp->alias, r);
|
||
|
- return r;
|
||
|
+ if (r == DOMAP_FAIL) {
|
||
|
+ remove_map(mpp, vecs, NULL, 0);
|
||
|
+ continue;
|
||
|
+ } else /* if (r == DOMAP_RETRY) */
|
||
|
+ return r;
|
||
|
}
|
||
|
+ if (r == DOMAP_DRY)
|
||
|
+ continue;
|
||
|
|
||
|
if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
|
||
|
if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
|
||
|
@@ -547,11 +543,11 @@ coalesce_paths (struct vectors * vecs, v
|
||
|
}
|
||
|
|
||
|
extern char *
|
||
|
-get_refwwid (char * dev, int dev_type, vector pathvec)
|
||
|
+get_refwwid (char * dev, enum devtypes dev_type, vector pathvec)
|
||
|
{
|
||
|
struct path * pp;
|
||
|
char buff[FILE_NAME_SIZE];
|
||
|
- char * refwwid;
|
||
|
+ char * refwwid = NULL, tmpwwid[WWID_SIZE];
|
||
|
|
||
|
if (dev_type == DEV_NONE)
|
||
|
return NULL;
|
||
|
@@ -606,6 +602,12 @@ get_refwwid (char * dev, int dev_type, v
|
||
|
goto out;
|
||
|
}
|
||
|
if (dev_type == DEV_DEVMAP) {
|
||
|
+
|
||
|
+ if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) {
|
||
|
+ refwwid = tmpwwid;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
/*
|
||
|
* may be a binding
|
||
|
*/
|
||
|
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
|
||
|
index 42ee9b0..1cbbe82 100644
|
||
|
--- a/libmultipath/configure.h
|
||
|
+++ b/libmultipath/configure.h
|
||
|
@@ -25,5 +25,5 @@ int setup_map (struct multipath * mpp);
|
||
|
int domap (struct multipath * mpp);
|
||
|
int reinstate_paths (struct multipath *mpp);
|
||
|
int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid);
|
||
|
-char * get_refwwid (char * dev, int dev_type, vector pathvec);
|
||
|
+char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec);
|
||
|
|
||
|
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
|
||
|
index 099ab52..fa06cbd 100644
|
||
|
--- a/libmultipath/debug.c
|
||
|
+++ b/libmultipath/debug.c
|
||
|
@@ -29,17 +29,16 @@ #if DAEMON
|
||
|
struct tm *tb = localtime(&t);
|
||
|
char buff[16];
|
||
|
|
||
|
- strftime(buff, 16, "%b %d %H:%M:%S", tb);
|
||
|
+ strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
|
||
|
+ buff[sizeof(buff)-1] = '\0';
|
||
|
|
||
|
fprintf(stdout, "%s | ", buff);
|
||
|
vfprintf(stdout, fmt, ap);
|
||
|
- fprintf(stdout, "\n");
|
||
|
}
|
||
|
else
|
||
|
log_safe(prio + 3, fmt, ap);
|
||
|
#else
|
||
|
vfprintf(stdout, fmt, ap);
|
||
|
- fprintf(stdout, "\n");
|
||
|
#endif
|
||
|
}
|
||
|
va_end(ap);
|
||
|
diff --git a/libmultipath/debug.h b/libmultipath/debug.h
|
||
|
index e7612a9..74ed531 100644
|
||
|
--- a/libmultipath/debug.h
|
||
|
+++ b/libmultipath/debug.h
|
||
|
@@ -11,11 +11,11 @@ #include "log_pthread.h"
|
||
|
int logsink;
|
||
|
|
||
|
#define condlog(prio, fmt, args...) \
|
||
|
- dlog(logsink, prio, fmt, ##args)
|
||
|
+ dlog(logsink, prio, fmt "\n", ##args)
|
||
|
|
||
|
#else /* DAEMON */
|
||
|
|
||
|
#define condlog(prio, fmt, args...) \
|
||
|
- dlog(0, prio, fmt, ##args)
|
||
|
+ dlog(0, prio, fmt "\n", ##args)
|
||
|
|
||
|
#endif /* DAEMON */
|
||
|
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||
|
index 4328036..b8571ad 100644
|
||
|
--- a/libmultipath/devmapper.c
|
||
|
+++ b/libmultipath/devmapper.c
|
||
|
@@ -11,6 +11,7 @@ #include <libdevmapper.h>
|
||
|
#include <ctype.h>
|
||
|
#include <linux/kdev_t.h>
|
||
|
#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
|
||
|
#include <checkers.h>
|
||
|
|
||
|
@@ -23,6 +24,10 @@ #include "devmapper.h"
|
||
|
#define MAX_WAIT 5
|
||
|
#define LOOPS_PER_SEC 5
|
||
|
|
||
|
+#define UUID_PREFIX "mpath-"
|
||
|
+#define UUID_PREFIX_LEN 6
|
||
|
+
|
||
|
+
|
||
|
static void
|
||
|
dm_dummy_log (int level, const char *file, int line, const char *f, ...)
|
||
|
{
|
||
|
@@ -100,6 +105,7 @@ dm_simplecmd (int task, const char *name
|
||
|
goto out;
|
||
|
|
||
|
dm_task_no_open_count(dmt);
|
||
|
+ dm_task_skip_lockfs(dmt); /* for DM_DEVICE_RESUME */
|
||
|
|
||
|
r = dm_task_run (dmt);
|
||
|
|
||
|
@@ -113,6 +119,7 @@ dm_addmap (int task, const char *name, c
|
||
|
const char *params, unsigned long long size, const char *uuid) {
|
||
|
int r = 0;
|
||
|
struct dm_task *dmt;
|
||
|
+ char *prefixed_uuid = NULL;
|
||
|
|
||
|
if (!(dmt = dm_task_create (task)))
|
||
|
return 0;
|
||
|
@@ -123,13 +130,26 @@ dm_addmap (int task, const char *name, c
|
||
|
if (!dm_task_add_target (dmt, 0, size, target, params))
|
||
|
goto addout;
|
||
|
|
||
|
- if (uuid && !dm_task_set_uuid(dmt, uuid))
|
||
|
- goto addout;
|
||
|
+ if (uuid){
|
||
|
+ prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
|
||
|
+ if (!prefixed_uuid) {
|
||
|
+ condlog(0, "cannot create prefixed uuid : %s\n",
|
||
|
+ strerror(errno));
|
||
|
+ goto addout;
|
||
|
+ }
|
||
|
+ sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
|
||
|
+ if (!dm_task_set_uuid(dmt, prefixed_uuid))
|
||
|
+ goto freeout;
|
||
|
+ }
|
||
|
|
||
|
dm_task_no_open_count(dmt);
|
||
|
|
||
|
r = dm_task_run (dmt);
|
||
|
|
||
|
+ freeout:
|
||
|
+ if (prefixed_uuid)
|
||
|
+ free(prefixed_uuid);
|
||
|
+
|
||
|
addout:
|
||
|
dm_task_destroy (dmt);
|
||
|
return r;
|
||
|
@@ -203,6 +223,7 @@ dm_get_uuid(char *name, char *uuid)
|
||
|
{
|
||
|
struct dm_task *dmt;
|
||
|
const char *uuidtmp;
|
||
|
+ int r = 1;
|
||
|
|
||
|
dmt = dm_task_create(DM_DEVICE_INFO);
|
||
|
if (!dmt)
|
||
|
@@ -215,15 +236,19 @@ dm_get_uuid(char *name, char *uuid)
|
||
|
goto uuidout;
|
||
|
|
||
|
uuidtmp = dm_task_get_uuid(dmt);
|
||
|
- if (uuidtmp)
|
||
|
- strcpy(uuid, uuidtmp);
|
||
|
+ if (uuidtmp) {
|
||
|
+ if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
|
||
|
+ strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
|
||
|
+ else
|
||
|
+ strcpy(uuid, uuidtmp);
|
||
|
+ }
|
||
|
else
|
||
|
uuid[0] = '\0';
|
||
|
|
||
|
+ r = 0;
|
||
|
uuidout:
|
||
|
dm_task_destroy(dmt);
|
||
|
-
|
||
|
- return 0;
|
||
|
+ return r;
|
||
|
}
|
||
|
|
||
|
extern int
|
||
|
@@ -591,6 +616,7 @@ dm_get_maps (vector mp, char * type)
|
||
|
goto out1;
|
||
|
|
||
|
dm_get_uuid(names->name, mpp->wwid);
|
||
|
+ dm_get_info(names->name, &mpp->dmi);
|
||
|
}
|
||
|
|
||
|
if (!vector_alloc_slot(mp))
|
||
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||
|
index cf8289c..f21e5bc 100644
|
||
|
--- a/libmultipath/discovery.c
|
||
|
+++ b/libmultipath/discovery.c
|
||
|
@@ -165,7 +165,7 @@ sysfs_get_##fname (char * sysfs_path, ch
|
||
|
goto out; \
|
||
|
\
|
||
|
strncpy(buff, attr->value, attr->len - 1); \
|
||
|
- buff[attr->len - 1] = '\0'; \
|
||
|
+ strchop(buff); \
|
||
|
sysfs_close_attribute(attr); \
|
||
|
return 0; \
|
||
|
out: \
|
||
|
@@ -237,7 +237,7 @@ devt2devname (char *devname, char *devt)
|
||
|
struct dlist * ls;
|
||
|
char attr_path[FILE_NAME_SIZE];
|
||
|
char block_path[FILE_NAME_SIZE];
|
||
|
- struct sysfs_attribute * attr;
|
||
|
+ struct sysfs_attribute * attr = NULL;
|
||
|
struct sysfs_class * class;
|
||
|
struct sysfs_class_device * dev;
|
||
|
|
||
|
@@ -295,7 +295,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u
|
||
|
{ INQUIRY_CMD, 0, 0, 0, 0, 0 };
|
||
|
unsigned char sense_b[SENSE_BUFF_LEN];
|
||
|
struct sg_io_hdr io_hdr;
|
||
|
-
|
||
|
+
|
||
|
if (cmddt)
|
||
|
inqCmdBlk[1] |= 2;
|
||
|
if (evpd)
|
||
|
@@ -313,10 +313,10 @@ do_inq(int sg_fd, int cmddt, int evpd, u
|
||
|
io_hdr.cmdp = inqCmdBlk;
|
||
|
io_hdr.sbp = sense_b;
|
||
|
io_hdr.timeout = DEF_TIMEOUT;
|
||
|
-
|
||
|
+
|
||
|
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
|
||
|
return -1;
|
||
|
-
|
||
|
+
|
||
|
/* treat SG_ERR here to get rid of sg_err.[ch] */
|
||
|
io_hdr.status &= 0x7e;
|
||
|
if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
|
||
|
@@ -339,24 +339,26 @@ do_inq(int sg_fd, int cmddt, int evpd, u
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
-int
|
||
|
-get_serial (char * str, int fd)
|
||
|
+static int
|
||
|
+get_serial (char * str, int maxlen, int fd)
|
||
|
{
|
||
|
int len = 0;
|
||
|
char buff[MX_ALLOC_LEN + 1] = {0};
|
||
|
|
||
|
if (fd < 0)
|
||
|
- return 0;
|
||
|
+ return 1;
|
||
|
|
||
|
if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
|
||
|
len = buff[3];
|
||
|
+ if (len >= maxlen)
|
||
|
+ return 1;
|
||
|
if (len > 0) {
|
||
|
memcpy(str, buff + 4, len);
|
||
|
str[len] = '\0';
|
||
|
}
|
||
|
- return 1;
|
||
|
+ return 0;
|
||
|
}
|
||
|
- return 0;
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
@@ -440,7 +442,7 @@ scsi_sysfs_pathinfo (struct path * pp)
|
||
|
/*
|
||
|
* set the hwe configlet pointer
|
||
|
*/
|
||
|
- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
|
||
|
+ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
|
||
|
|
||
|
/*
|
||
|
* host / bus / target / lun
|
||
|
@@ -524,7 +526,7 @@ ccw_sysfs_pathinfo (struct path * pp)
|
||
|
/*
|
||
|
* set the hwe configlet pointer
|
||
|
*/
|
||
|
- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
|
||
|
+ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
|
||
|
|
||
|
/*
|
||
|
* host / bus / target / lun
|
||
|
@@ -597,7 +599,7 @@ static int
|
||
|
scsi_ioctl_pathinfo (struct path * pp, int mask)
|
||
|
{
|
||
|
if (mask & DI_SERIAL) {
|
||
|
- get_serial(pp->serial, pp->fd);
|
||
|
+ get_serial(pp->serial, SERIAL_SIZE, pp->fd);
|
||
|
condlog(3, "%s: serial = %s", pp->dev, pp->serial);
|
||
|
}
|
||
|
|
||
|
@@ -636,14 +638,14 @@ get_prio (struct path * pp)
|
||
|
pp->getprio_selected = 1;
|
||
|
}
|
||
|
if (!pp->getprio) {
|
||
|
- pp->priority = 1;
|
||
|
+ pp->priority = PRIO_DEFAULT;
|
||
|
} else if (apply_format(pp->getprio, &buff[0], pp)) {
|
||
|
condlog(0, "error formatting prio callout command");
|
||
|
- pp->priority = -1;
|
||
|
+ pp->priority = PRIO_UNDEF;
|
||
|
return 1;
|
||
|
} else if (execute_program(buff, prio, 16)) {
|
||
|
condlog(0, "error calling out %s", buff);
|
||
|
- pp->priority = -1;
|
||
|
+ pp->priority = PRIO_UNDEF;
|
||
|
return 1;
|
||
|
} else
|
||
|
pp->priority = atoi(prio);
|
||
|
@@ -699,7 +701,12 @@ pathinfo (struct path *pp, vector hwtabl
|
||
|
if (mask & DI_CHECKER && get_state(pp))
|
||
|
goto blank;
|
||
|
|
||
|
- if (mask & DI_PRIO && pp->state != PATH_DOWN)
|
||
|
+ /*
|
||
|
+ * Retrieve path priority for even PATH_DOWN paths if it has never
|
||
|
+ * been successfully obtained before.
|
||
|
+ */
|
||
|
+ if (mask & DI_PRIO &&
|
||
|
+ (pp->state != PATH_DOWN || pp->priority != PRIO_UNDEF))
|
||
|
get_prio(pp);
|
||
|
|
||
|
if (mask & DI_WWID && !strlen(pp->wwid))
|
||
|
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
|
||
|
index cdc9627..ab62a59 100644
|
||
|
--- a/libmultipath/discovery.h
|
||
|
+++ b/libmultipath/discovery.h
|
||
|
@@ -5,7 +5,6 @@ #define SYSFS_PATH_SIZE 255
|
||
|
#define INQUIRY_CMDLEN 6
|
||
|
#define INQUIRY_CMD 0x12
|
||
|
#define SENSE_BUFF_LEN 32
|
||
|
-#define DEF_TIMEOUT 60000
|
||
|
#define RECOVERED_ERROR 0x01
|
||
|
#define MX_ALLOC_LEN 255
|
||
|
#define TUR_CMD_LEN 6
|
||
|
@@ -14,6 +13,10 @@ #ifndef BLKGETSIZE
|
||
|
#define BLKGETSIZE _IO(0x12,96)
|
||
|
#endif
|
||
|
|
||
|
+#ifndef DEF_TIMEOUT
|
||
|
+#define DEF_TIMEOUT 300000
|
||
|
+#endif
|
||
|
+
|
||
|
/*
|
||
|
* exerpt from sg_err.h
|
||
|
*/
|
||
|
@@ -30,7 +33,6 @@ int sysfs_get_size (char * sysfs_path, c
|
||
|
int path_discovery (vector pathvec, struct config * conf, int flag);
|
||
|
|
||
|
void basename (char *, char *);
|
||
|
-int get_serial (char * buff, int fd);
|
||
|
int do_tur (char *);
|
||
|
int devt2devname (char *, char *);
|
||
|
int pathinfo (struct path *, vector hwtable, int mask);
|
||
|
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
|
||
|
index 2b170c6..631933d 100644
|
||
|
--- a/libmultipath/dmparser.c
|
||
|
+++ b/libmultipath/dmparser.c
|
||
|
@@ -84,11 +84,14 @@ assemble_map (struct multipath * mp)
|
||
|
freechar -= shift;
|
||
|
|
||
|
vector_foreach_slot (pgp->paths, pp, j) {
|
||
|
- if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
|
||
|
- minio *= pp->priority;
|
||
|
+ int tmp_minio = minio;
|
||
|
+
|
||
|
+ if (mp->rr_weight == RR_WEIGHT_PRIO
|
||
|
+ && pp->priority > 0)
|
||
|
+ tmp_minio = minio * pp->priority;
|
||
|
|
||
|
shift = snprintf(p, freechar, " %s %d",
|
||
|
- pp->dev_t, minio);
|
||
|
+ pp->dev_t, tmp_minio);
|
||
|
if (shift >= freechar) {
|
||
|
fprintf(stderr, "mp->params too small\n");
|
||
|
return 1;
|
||
|
@@ -117,6 +120,7 @@ disassemble_map (vector pathvec, char *
|
||
|
int num_pg_args = 0;
|
||
|
int num_paths = 0;
|
||
|
int num_paths_args = 0;
|
||
|
+ int def_minio = 0;
|
||
|
struct path * pp;
|
||
|
struct pathgroup * pgp;
|
||
|
|
||
|
@@ -305,12 +309,15 @@ #endif
|
||
|
if (k == 0 && !strncmp(mpp->selector,
|
||
|
"round-robin", 11)) {
|
||
|
p += get_word(p, &word);
|
||
|
- mpp->minio = atoi(word);
|
||
|
+ def_minio = atoi(word);
|
||
|
|
||
|
- if (mpp->rr_weight)
|
||
|
- mpp->minio /= mpp->rr_weight;
|
||
|
+ if (mpp->rr_weight == RR_WEIGHT_PRIO
|
||
|
+ && pp->priority > 0)
|
||
|
+ def_minio /= pp->priority;
|
||
|
|
||
|
FREE(word);
|
||
|
+ if (def_minio != mpp->minio)
|
||
|
+ mpp->minio = def_minio;
|
||
|
}
|
||
|
else
|
||
|
p += get_word(p, NULL);
|
||
|
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
|
||
|
index 5c7d625..ac126c0 100644
|
||
|
--- a/libmultipath/hwtable.c
|
||
|
+++ b/libmultipath/hwtable.c
|
||
|
@@ -12,13 +12,34 @@ #include "pgpolicies.h"
|
||
|
* Tuning suggestions on these parameters should go to
|
||
|
* dm-devel@redhat.com
|
||
|
*
|
||
|
- * You are welcome to claim maintainership over a controler
|
||
|
+ * You are welcome to claim maintainership over a controller
|
||
|
* family. Please mail the currently enlisted maintainer and
|
||
|
* the upstream package maintainer.
|
||
|
*/
|
||
|
static struct hwentry default_hw[] = {
|
||
|
/*
|
||
|
- * StorageWorks controler family
|
||
|
+ * Apple controller family
|
||
|
+ *
|
||
|
+ * Maintainer : Shyam Sundar
|
||
|
+ * Mail : g.shyamsundar@yahoo.co.in
|
||
|
+ */
|
||
|
+ {
|
||
|
+ .vendor = "APPLE*",
|
||
|
+ .product = "Xserve RAID ",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = NULL,
|
||
|
+ .features = DEFAULT_FEATURES,
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = MULTIBUS,
|
||
|
+ .pgfailback = FAILBACK_UNDEF,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = DEFAULT_CHECKER,
|
||
|
+ },
|
||
|
+ /*
|
||
|
+ * StorageWorks controller family
|
||
|
*
|
||
|
* Maintainer : Christophe Varoqui
|
||
|
* Mail : christophe.varoqui@free.fr
|
||
|
@@ -54,14 +75,14 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = HP_SW,
|
||
|
},
|
||
|
{
|
||
|
- .vendor = "{COMPAQ,HP}",
|
||
|
- .product = "{MSA,HSV}1*",
|
||
|
+ .vendor = "(COMPAQ|HP)",
|
||
|
+ .product = "(MSA|HSV)1.*",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = "1 hp_sw",
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
- .pgpolicy = GROUP_BY_SERIAL,
|
||
|
+ .pgpolicy = MULTIBUS,
|
||
|
.pgfailback = FAILBACK_UNDEF,
|
||
|
.rr_weight = RR_WEIGHT_NONE,
|
||
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
@@ -70,7 +91,7 @@ static struct hwentry default_hw[] = {
|
||
|
},
|
||
|
{
|
||
|
.vendor = "HP",
|
||
|
- .product = "HSV2*",
|
||
|
+ .product = "A6189A",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
@@ -85,7 +106,8 @@ static struct hwentry default_hw[] = {
|
||
|
},
|
||
|
{
|
||
|
.vendor = "HP",
|
||
|
- .product = "DF[456]00",
|
||
|
+ .product = "HSV20.*",
|
||
|
+ .revision = "[123].*",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
@@ -96,10 +118,41 @@ static struct hwentry default_hw[] = {
|
||
|
.rr_weight = RR_WEIGHT_NONE,
|
||
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
.minio = DEFAULT_MINIO,
|
||
|
- .checker_name = READSECTOR0,
|
||
|
+ .checker_name = HP_SW,
|
||
|
+ },
|
||
|
+ {
|
||
|
+ .vendor = "HP",
|
||
|
+ .product = "HSV20.*",
|
||
|
+ .revision = "[^123].*",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
||
|
+ .features = DEFAULT_FEATURES,
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = MULTIBUS,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = TUR,
|
||
|
+ },
|
||
|
+ {
|
||
|
+ .vendor = "HP",
|
||
|
+ .product = "HSV21.*",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
||
|
+ .features = DEFAULT_FEATURES,
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = GROUP_BY_PRIO,
|
||
|
+ .pgfailback = FAILBACK_UNDEF,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = TUR,
|
||
|
},
|
||
|
/*
|
||
|
- * DDN controler family
|
||
|
+ * DDN controller family
|
||
|
*
|
||
|
* Maintainer : Christophe Varoqui
|
||
|
* Mail : christophe.varoqui@free.fr
|
||
|
@@ -120,7 +173,7 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = READSECTOR0,
|
||
|
},
|
||
|
/*
|
||
|
- * EMC / Clariion controler family
|
||
|
+ * EMC / Clariion controller family
|
||
|
*
|
||
|
* Maintainer : Edward Goggin, EMC
|
||
|
* Mail : egoggin@emc.com
|
||
|
@@ -128,7 +181,7 @@ static struct hwentry default_hw[] = {
|
||
|
{
|
||
|
.vendor = "EMC",
|
||
|
.product = "SYMMETRIX",
|
||
|
- .getuid = "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n",
|
||
|
+ .getuid = "scsi_id -g -u -ppre-spc3-83 -s /block/%n",
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
@@ -142,10 +195,10 @@ static struct hwentry default_hw[] = {
|
||
|
},
|
||
|
{
|
||
|
.vendor = "DGC",
|
||
|
- .product = "*",
|
||
|
+ .product = ".*",
|
||
|
.bl_product = "LUNZ",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_emc /dev/%n",
|
||
|
+ .getprio = "mpath_prio_emc /dev/%n",
|
||
|
.features = "1 queue_if_no_path",
|
||
|
.hwhandler = "1 emc",
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -157,7 +210,7 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = EMC_CLARIION,
|
||
|
},
|
||
|
/*
|
||
|
- * Fujitsu controler family
|
||
|
+ * Fujitsu controller family
|
||
|
*
|
||
|
* Maintainer : Christophe Varoqui
|
||
|
* Mail : christophe.varoqui@free.fr
|
||
|
@@ -178,14 +231,14 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = READSECTOR0,
|
||
|
},
|
||
|
/*
|
||
|
- * Hitachi controler family
|
||
|
+ * Hitachi controller family
|
||
|
*
|
||
|
- * Maintainer : Christophe Varoqui
|
||
|
- * Mail : christophe.varoqui@free.fr
|
||
|
+ * Maintainer : Matthias Rudolph
|
||
|
+ * Mail : matthias.rudolph@hds.com
|
||
|
*/
|
||
|
{
|
||
|
- .vendor = "HITACHI",
|
||
|
- .product = "{A6189A,OPEN-}",
|
||
|
+ .vendor = "(HITACHI|HP)",
|
||
|
+ .product = "OPEN-.*",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
@@ -198,10 +251,25 @@ static struct hwentry default_hw[] = {
|
||
|
.minio = DEFAULT_MINIO,
|
||
|
.checker_name = READSECTOR0,
|
||
|
},
|
||
|
+ {
|
||
|
+ .vendor = "HITACHI",
|
||
|
+ .product = "DF.*",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "mpath_prio_hds_modular %d",
|
||
|
+ .features = DEFAULT_FEATURES,
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = GROUP_BY_PRIO,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = READSECTOR0,
|
||
|
+ },
|
||
|
/*
|
||
|
- * IBM controler family
|
||
|
+ * IBM controller family
|
||
|
*
|
||
|
- * Maintainer : Hannes Reinecke, Suse
|
||
|
+ * Maintainer : Hannes Reinecke, SuSE
|
||
|
* Mail : hare@suse.de
|
||
|
*/
|
||
|
{
|
||
|
@@ -224,7 +292,23 @@ static struct hwentry default_hw[] = {
|
||
|
.vendor = "IBM",
|
||
|
.product = "1742",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_tpc /dev/%n",
|
||
|
+ .getprio = "mpath_prio_tpc /dev/%n",
|
||
|
+ .features = DEFAULT_FEATURES,
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = GROUP_BY_PRIO,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = TUR,
|
||
|
+ },
|
||
|
+ {
|
||
|
+ /* IBM Netfinity Fibre Channel RAID Controller Unit */
|
||
|
+ .vendor = "IBM",
|
||
|
+ .product = "3526",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "mpath_prio_tpc /dev/%n",
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -254,7 +338,7 @@ static struct hwentry default_hw[] = {
|
||
|
{
|
||
|
/* IBM ESS F20 aka Shark */
|
||
|
.vendor = "IBM",
|
||
|
- .product = "2105F20",
|
||
|
+ .product = "2105(800|F20)",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = "1 queue_if_no_path",
|
||
|
@@ -268,11 +352,11 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = TUR,
|
||
|
},
|
||
|
{
|
||
|
- /* IBM DS6000 / SAN Volume Controller */
|
||
|
+ /* IBM DS6000 */
|
||
|
.vendor = "IBM",
|
||
|
- .product = "{1750500,2145}",
|
||
|
+ .product = "1750500",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
||
|
+ .getprio = "mpath_prio_alua /dev/%n",
|
||
|
.features = "1 queue_if_no_path",
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -300,10 +384,27 @@ static struct hwentry default_hw[] = {
|
||
|
.checker_name = TUR,
|
||
|
},
|
||
|
{
|
||
|
+ /* IBM SAN Volume Controller */
|
||
|
+ .vendor = "IBM",
|
||
|
+ .product = "2145",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "mpath_prio_alua /dev/%n",
|
||
|
+ .features = "1 queue_if_no_path",
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = GROUP_BY_PRIO,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = DEFAULT_MINIO,
|
||
|
+ .checker_name = TUR,
|
||
|
+ },
|
||
|
+ {
|
||
|
/* IBM S/390 ECKD DASD */
|
||
|
.vendor = "IBM",
|
||
|
.product = "S/390 DASD ECKD",
|
||
|
- .getuid = "/sbin/dasdview -j /dev/%n",
|
||
|
+ .bl_product = "S/390.*",
|
||
|
+ .getuid = "dasd_id /dev/%n",
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
@@ -315,29 +416,50 @@ static struct hwentry default_hw[] = {
|
||
|
.minio = DEFAULT_MINIO,
|
||
|
.checker_name = DIRECTIO,
|
||
|
},
|
||
|
- /*
|
||
|
- * NETAPP controler family
|
||
|
+ /*
|
||
|
+ * NETAPP controller family
|
||
|
*
|
||
|
- * Maintainer : Igor Feoktistov
|
||
|
- * Mail : igorf@netapp.com
|
||
|
+ * Maintainer : Dave Wysochanski
|
||
|
+ * Mail : davidw@netapp.com
|
||
|
*/
|
||
|
{
|
||
|
.vendor = "NETAPP",
|
||
|
- .product = "LUN",
|
||
|
+ .product = "LUN.*",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_netapp /dev/%n",
|
||
|
+ .getprio = "mpath_prio_netapp /dev/%n",
|
||
|
.features = "1 queue_if_no_path",
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
.pgpolicy = GROUP_BY_PRIO,
|
||
|
- .pgfailback = FAILBACK_UNDEF,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
.rr_weight = RR_WEIGHT_NONE,
|
||
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
- .minio = DEFAULT_MINIO,
|
||
|
+ .minio = 128,
|
||
|
+ .checker_name = READSECTOR0,
|
||
|
+ },
|
||
|
+ /*
|
||
|
+ * IBM NSeries (NETAPP) controller family
|
||
|
+ *
|
||
|
+ * Maintainer : Dave Wysochanski
|
||
|
+ * Mail : davidw@netapp.com
|
||
|
+ */
|
||
|
+ {
|
||
|
+ .vendor = "IBM",
|
||
|
+ .product = "Nseries.*",
|
||
|
+ .getuid = DEFAULT_GETUID,
|
||
|
+ .getprio = "mpath_prio_netapp /dev/%n",
|
||
|
+ .features = "1 queue_if_no_path",
|
||
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
|
+ .selector = DEFAULT_SELECTOR,
|
||
|
+ .pgpolicy = GROUP_BY_PRIO,
|
||
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
|
+ .rr_weight = RR_WEIGHT_NONE,
|
||
|
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
|
+ .minio = 128,
|
||
|
.checker_name = READSECTOR0,
|
||
|
},
|
||
|
/*
|
||
|
- * Pillar Data controler family
|
||
|
+ * Pillar Data controller family
|
||
|
*
|
||
|
* Maintainer : Christophe Varoqui
|
||
|
* Mail : christophe.varoqui@free.fr
|
||
|
@@ -346,7 +468,7 @@ static struct hwentry default_hw[] = {
|
||
|
.vendor = "Pillar",
|
||
|
.product = "Axiom 500",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_alua %d",
|
||
|
+ .getprio = "mpath_prio_alua %d",
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -382,7 +504,7 @@ static struct hwentry default_hw[] = {
|
||
|
.vendor = "SGI",
|
||
|
.product = "TP9[45]00",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_tpc /dev/%n",
|
||
|
+ .getprio = "mpath_prio_tpc /dev/%n",
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -403,7 +525,7 @@ static struct hwentry default_hw[] = {
|
||
|
.vendor = "STK",
|
||
|
.product = "OPENstorage D280",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
- .getprio = "/sbin/mpath_prio_tpc /dev/%n",
|
||
|
+ .getprio = "mpath_prio_tpc /dev/%n",
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
.hwhandler = DEFAULT_HWHANDLER,
|
||
|
.selector = DEFAULT_SELECTOR,
|
||
|
@@ -422,7 +544,7 @@ static struct hwentry default_hw[] = {
|
||
|
*/
|
||
|
{
|
||
|
.vendor = "SUN",
|
||
|
- .product = "{StorEdge 3510,T4}",
|
||
|
+ .product = "(StorEdge 3510|T4)",
|
||
|
.getuid = DEFAULT_GETUID,
|
||
|
.getprio = NULL,
|
||
|
.features = DEFAULT_FEATURES,
|
||
|
diff --git a/libmultipath/lock.c b/libmultipath/lock.c
|
||
|
new file mode 100644
|
||
|
index 0000000..0ca8783
|
||
|
--- /dev/null
|
||
|
+++ b/libmultipath/lock.c
|
||
|
@@ -0,0 +1,8 @@
|
||
|
+#include <pthread.h>
|
||
|
+#include "lock.h"
|
||
|
+
|
||
|
+void cleanup_lock (void * data)
|
||
|
+{
|
||
|
+ unlock((pthread_mutex_t *)data);
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/libmultipath/lock.h b/libmultipath/lock.h
|
||
|
new file mode 100644
|
||
|
index 0000000..6afecda
|
||
|
--- /dev/null
|
||
|
+++ b/libmultipath/lock.h
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+#ifndef _LOCK_H
|
||
|
+#define _LOCK_H
|
||
|
+
|
||
|
+#ifdef LCKDBG
|
||
|
+#define lock(a) \
|
||
|
+ fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
+ pthread_mutex_lock(a)
|
||
|
+#define unlock(a) \
|
||
|
+ fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
+ pthread_mutex_unlock(a)
|
||
|
+#define lock_cleanup_pop(a) \
|
||
|
+ fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
+ pthread_cleanup_pop(1);
|
||
|
+#else
|
||
|
+#define lock(a) pthread_mutex_lock(a)
|
||
|
+#define unlock(a) pthread_mutex_unlock(a)
|
||
|
+#define lock_cleanup_pop(a) pthread_cleanup_pop(1);
|
||
|
+#endif
|
||
|
+
|
||
|
+void cleanup_lock (void * data);
|
||
|
+
|
||
|
+#endif /* _LOCK_H */
|
||
|
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
|
||
|
index 9b0b5c2..f9c555e 100644
|
||
|
--- a/libmultipath/parser.c
|
||
|
+++ b/libmultipath/parser.c
|
||
|
@@ -25,6 +25,13 @@ #include "memory.h"
|
||
|
/* local vars */
|
||
|
static int sublevel = 0;
|
||
|
vector keywords = NULL;
|
||
|
+vector *keywords_addr = NULL;
|
||
|
+
|
||
|
+void set_current_keywords (vector *k)
|
||
|
+{
|
||
|
+ keywords_addr = k;
|
||
|
+ keywords = NULL;
|
||
|
+}
|
||
|
|
||
|
int
|
||
|
keyword_alloc(vector keywords, char *string, int (*handler) (vector),
|
||
|
@@ -53,7 +60,10 @@ keyword_alloc(vector keywords, char *str
|
||
|
int
|
||
|
install_keyword_root(char *string, int (*handler) (vector))
|
||
|
{
|
||
|
- return keyword_alloc(keywords, string, handler, NULL);
|
||
|
+ int r = keyword_alloc(keywords, string, handler, NULL);
|
||
|
+ if (!r)
|
||
|
+ *keywords_addr = keywords;
|
||
|
+ return r;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
@@ -100,6 +110,9 @@ free_keywords(vector keywords)
|
||
|
struct keyword *keyword;
|
||
|
int i;
|
||
|
|
||
|
+ if (!keywords)
|
||
|
+ return;
|
||
|
+
|
||
|
for (i = 0; i < VECTOR_SIZE(keywords); i++) {
|
||
|
keyword = VECTOR_SLOT(keywords, i);
|
||
|
if (keyword->sub)
|
||
|
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
|
||
|
index f0fdd94..95d4e6f 100644
|
||
|
--- a/libmultipath/parser.h
|
||
|
+++ b/libmultipath/parser.h
|
||
|
@@ -76,6 +76,7 @@ extern void *set_value(vector strvec);
|
||
|
extern int process_stream(vector keywords);
|
||
|
extern int init_data(char *conf_file, void (*init_keywords) (void));
|
||
|
extern struct keyword * find_keyword(vector v, char * name);
|
||
|
+void set_current_keywords (vector *k);
|
||
|
int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
|
||
|
void *data);
|
||
|
|
||
|
diff --git a/libmultipath/pgpolicies.h b/libmultipath/pgpolicies.h
|
||
|
index 66c3c29..1f010a3 100644
|
||
|
--- a/libmultipath/pgpolicies.h
|
||
|
+++ b/libmultipath/pgpolicies.h
|
||
|
@@ -9,7 +9,7 @@ #endif
|
||
|
|
||
|
#define POLICY_NAME_SIZE 32
|
||
|
|
||
|
-/* Storage controlers capabilities */
|
||
|
+/* Storage controllers capabilities */
|
||
|
enum iopolicies {
|
||
|
IOPOLICY_UNDEF,
|
||
|
FAILOVER,
|
||
|
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||
|
index 6cc63e2..260aed1 100644
|
||
|
--- a/libmultipath/print.c
|
||
|
+++ b/libmultipath/print.c
|
||
|
@@ -13,8 +13,8 @@ #include "structs.h"
|
||
|
#include "structs_vec.h"
|
||
|
#include "print.h"
|
||
|
#include "dmparser.h"
|
||
|
-#include "configure.h"
|
||
|
#include "config.h"
|
||
|
+#include "configure.h"
|
||
|
#include "pgpolicies.h"
|
||
|
#include "defaults.h"
|
||
|
#include "parser.h"
|
||
|
@@ -52,16 +52,26 @@ snprint_uint (char * buff, size_t len, u
|
||
|
static int
|
||
|
snprint_size (char * buff, size_t len, unsigned long long size)
|
||
|
{
|
||
|
- if (size < (1 << 11))
|
||
|
- return snprintf(buff, len, "%llu kB", size >> 1);
|
||
|
- else if (size < (1 << 21))
|
||
|
- return snprintf(buff, len, "%llu MB", size >> 11);
|
||
|
- else if (size < (1 << 31))
|
||
|
- return snprintf(buff, len, "%llu GB", size >> 21);
|
||
|
+ float s = (float)(size >> 1); /* start with KB */
|
||
|
+ char fmt[6] = {};
|
||
|
+ char units[] = {'K','M','G','T','P'};
|
||
|
+ char *u = units;
|
||
|
+
|
||
|
+ while (s >= 1024 && *u != 'P') {
|
||
|
+ s = s / 1024;
|
||
|
+ u++;
|
||
|
+ }
|
||
|
+ if (s < 10)
|
||
|
+ snprintf(fmt, 6, "%%.1f%c", *u);
|
||
|
else
|
||
|
- return snprintf(buff, len, "%llu TB", size >> 31);
|
||
|
+ snprintf(fmt, 6, "%%.0f%c", *u);
|
||
|
+
|
||
|
+ return snprintf(buff, len, fmt, s);
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * multipath info printing functions
|
||
|
+ */
|
||
|
static int
|
||
|
snprint_name (char * buff, size_t len, struct multipath * mpp)
|
||
|
{
|
||
|
@@ -222,6 +232,9 @@ snprint_action (char * buff, size_t len,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * path info printing functions
|
||
|
+ */
|
||
|
static int
|
||
|
snprint_path_uuid (char * buff, size_t len, struct path * pp)
|
||
|
{
|
||
|
@@ -292,8 +305,8 @@ snprint_dm_path_state (char * buff, size
|
||
|
static int
|
||
|
snprint_vpr (char * buff, size_t len, struct path * pp)
|
||
|
{
|
||
|
- return snprintf(buff, len, "%s/%s/%s",
|
||
|
- pp->vendor_id, pp->product_id, pp->rev);
|
||
|
+ return snprintf(buff, len, "%s,%s",
|
||
|
+ pp->vendor_id, pp->product_id);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
@@ -496,7 +509,7 @@ snprint_multipath (char * line, int len,
|
||
|
char * f = format; /* format string cursor */
|
||
|
int fwd;
|
||
|
struct multipath_data * data;
|
||
|
- char buff[MAX_FIELD_LEN];
|
||
|
+ char buff[MAX_FIELD_LEN] = {};
|
||
|
|
||
|
do {
|
||
|
if (!TAIL)
|
||
|
@@ -515,6 +528,7 @@ snprint_multipath (char * line, int len,
|
||
|
data->snprint(buff, MAX_FIELD_LEN, mpp);
|
||
|
PRINT(c, TAIL, buff);
|
||
|
PAD(data->width);
|
||
|
+ buff[0] = '\0';
|
||
|
} while (*f++);
|
||
|
|
||
|
line[c - line - 1] = '\n';
|
||
|
@@ -631,7 +645,7 @@ snprint_pathgroup (char * line, int len,
|
||
|
extern void
|
||
|
print_multipath_topology (struct multipath * mpp, int verbosity)
|
||
|
{
|
||
|
- char buff[MAX_LINE_LEN * MAX_LINES];
|
||
|
+ char buff[MAX_LINE_LEN * MAX_LINES] = {};
|
||
|
|
||
|
snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
|
||
|
mpp, verbosity);
|
||
|
@@ -662,7 +676,10 @@ snprint_multipath_topology (char * buff,
|
||
|
c += sprintf(c, "%%n");
|
||
|
|
||
|
if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
|
||
|
- c += sprintf(c, " (%%w)");
|
||
|
+ c += sprintf(c, " (%%w) ");
|
||
|
+
|
||
|
+ c += sprintf(c, "%%d ");
|
||
|
+ c += snprint_vpr(c, 24, first_path(mpp));
|
||
|
|
||
|
fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
|
||
|
if (fwd > len)
|
||
|
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
||
|
index 79cee8b..1f0021a 100644
|
||
|
--- a/libmultipath/propsel.c
|
||
|
+++ b/libmultipath/propsel.c
|
||
|
@@ -15,6 +15,7 @@ #include "debug.h"
|
||
|
#include "pgpolicies.h"
|
||
|
#include "alias.h"
|
||
|
#include "defaults.h"
|
||
|
+#include "devmapper.h"
|
||
|
|
||
|
pgpolicyfn *pgpolicies[] = {
|
||
|
NULL,
|
||
|
@@ -41,7 +42,7 @@ select_rr_weight (struct multipath * mp)
|
||
|
}
|
||
|
if (mp->hwe && mp->hwe->rr_weight) {
|
||
|
mp->rr_weight = mp->hwe->rr_weight;
|
||
|
- condlog(3, "%s: rr_weight = %i (controler setting)",
|
||
|
+ condlog(3, "%s: rr_weight = %i (controller setting)",
|
||
|
mp->alias, mp->rr_weight);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -68,7 +69,7 @@ select_pgfailback (struct multipath * mp
|
||
|
}
|
||
|
if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
|
||
|
mp->pgfailback = mp->hwe->pgfailback;
|
||
|
- condlog(3, "%s: pgfailback = %i (controler setting)",
|
||
|
+ condlog(3, "%s: pgfailback = %i (controller setting)",
|
||
|
mp->alias, mp->pgfailback);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -112,7 +113,7 @@ select_pgpolicy (struct multipath * mp)
|
||
|
mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
|
||
|
get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
|
||
|
mp->pgpolicy);
|
||
|
- condlog(3, "%s: pgpolicy = %s (controler setting)",
|
||
|
+ condlog(3, "%s: pgpolicy = %s (controller setting)",
|
||
|
mp->alias, pgpolicy_name);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -144,7 +145,7 @@ select_selector (struct multipath * mp)
|
||
|
}
|
||
|
if (mp->hwe && mp->hwe->selector) {
|
||
|
mp->selector = mp->hwe->selector;
|
||
|
- condlog(3, "%s: selector = %s (controler setting)",
|
||
|
+ condlog(3, "%s: selector = %s (controller setting)",
|
||
|
mp->alias, mp->selector);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -164,6 +165,16 @@ select_alias (struct multipath * mp)
|
||
|
if (conf->user_friendly_names)
|
||
|
mp->alias = get_user_friendly_alias(mp->wwid,
|
||
|
conf->bindings_file);
|
||
|
+ if (mp->alias == NULL){
|
||
|
+ char *alias;
|
||
|
+ if ((alias = MALLOC(WWID_SIZE)) != NULL){
|
||
|
+ if (dm_get_name(mp->wwid, DEFAULT_TARGET,
|
||
|
+ alias) == 1)
|
||
|
+ mp->alias = alias;
|
||
|
+ else
|
||
|
+ FREE(alias);
|
||
|
+ }
|
||
|
+ }
|
||
|
if (mp->alias == NULL)
|
||
|
mp->alias = mp->wwid;
|
||
|
}
|
||
|
@@ -176,7 +187,7 @@ select_features (struct multipath * mp)
|
||
|
{
|
||
|
if (mp->hwe && mp->hwe->features) {
|
||
|
mp->features = mp->hwe->features;
|
||
|
- condlog(3, "%s: features = %s (controler setting)",
|
||
|
+ condlog(3, "%s: features = %s (controller setting)",
|
||
|
mp->alias, mp->features);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -191,7 +202,7 @@ select_hwhandler (struct multipath * mp)
|
||
|
{
|
||
|
if (mp->hwe && mp->hwe->hwhandler) {
|
||
|
mp->hwhandler = mp->hwe->hwhandler;
|
||
|
- condlog(3, "%s: hwhandler = %s (controler setting)",
|
||
|
+ condlog(3, "%s: hwhandler = %s (controller setting)",
|
||
|
mp->alias, mp->hwhandler);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -208,7 +219,7 @@ select_checker(struct path *pp)
|
||
|
|
||
|
if (pp->hwe && pp->hwe->checker) {
|
||
|
checker_get(c, pp->hwe->checker);
|
||
|
- condlog(3, "%s: path checker = %s (controler setting)",
|
||
|
+ condlog(3, "%s: path checker = %s (controller setting)",
|
||
|
pp->dev, checker_name(c));
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -229,7 +240,7 @@ select_getuid (struct path * pp)
|
||
|
{
|
||
|
if (pp->hwe && pp->hwe->getuid) {
|
||
|
pp->getuid = pp->hwe->getuid;
|
||
|
- condlog(3, "%s: getuid = %s (controler setting)",
|
||
|
+ condlog(3, "%s: getuid = %s (controller setting)",
|
||
|
pp->dev, pp->getuid);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -250,7 +261,7 @@ select_getprio (struct path * pp)
|
||
|
{
|
||
|
if (pp->hwe && pp->hwe->getprio) {
|
||
|
pp->getprio = pp->hwe->getprio;
|
||
|
- condlog(3, "%s: getprio = %s (controler setting)",
|
||
|
+ condlog(3, "%s: getprio = %s (controller setting)",
|
||
|
pp->dev, pp->getprio);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -276,7 +287,7 @@ select_no_path_retry(struct multipath *m
|
||
|
}
|
||
|
if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
|
||
|
mp->no_path_retry = mp->hwe->no_path_retry;
|
||
|
- condlog(3, "%s: no_path_retry = %i (controler setting)",
|
||
|
+ condlog(3, "%s: no_path_retry = %i (controller setting)",
|
||
|
mp->alias, mp->no_path_retry);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -303,7 +314,7 @@ select_minio (struct multipath * mp)
|
||
|
}
|
||
|
if (mp->hwe && mp->hwe->minio) {
|
||
|
mp->minio = mp->hwe->minio;
|
||
|
- condlog(3, "%s: minio = %i (controler setting)",
|
||
|
+ condlog(3, "%s: minio = %i (controller setting)",
|
||
|
mp->alias, mp->minio);
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||
|
index 024e790..db3f824 100644
|
||
|
--- a/libmultipath/structs.c
|
||
|
+++ b/libmultipath/structs.c
|
||
|
@@ -16,6 +16,7 @@ #include "config.h"
|
||
|
#include "debug.h"
|
||
|
#include "structs_vec.h"
|
||
|
#include "blacklist.h"
|
||
|
+#include "waiter.h"
|
||
|
|
||
|
struct path *
|
||
|
alloc_path (void)
|
||
|
@@ -30,6 +31,7 @@ alloc_path (void)
|
||
|
pp->sg_id.scsi_id = -1;
|
||
|
pp->sg_id.lun = -1;
|
||
|
pp->fd = -1;
|
||
|
+ pp->priority = PRIO_UNDEF;
|
||
|
}
|
||
|
return pp;
|
||
|
}
|
||
|
@@ -365,3 +367,10 @@ pathcount (struct multipath * mpp, int s
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
+
|
||
|
+struct path *
|
||
|
+first_path (struct multipath * mpp)
|
||
|
+{
|
||
|
+ struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0);
|
||
|
+ return VECTOR_SLOT(pgp->paths, 0);
|
||
|
+}
|
||
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||
|
index 2b96cfb..7db7faa 100644
|
||
|
--- a/libmultipath/structs.h
|
||
|
+++ b/libmultipath/structs.h
|
||
|
@@ -1,8 +1,8 @@
|
||
|
#ifndef _STRUCTS_H
|
||
|
#define _STRUCTS_H
|
||
|
|
||
|
-#define WWID_SIZE 64
|
||
|
-#define SERIAL_SIZE 17
|
||
|
+#define WWID_SIZE 128
|
||
|
+#define SERIAL_SIZE 64
|
||
|
#define NODE_NAME_SIZE 19
|
||
|
#define PATH_STR_SIZE 16
|
||
|
#define PARAMS_SIZE 1024
|
||
|
@@ -18,6 +18,9 @@ #define NO_PATH_RETRY_UNDEF 0
|
||
|
#define NO_PATH_RETRY_FAIL -1
|
||
|
#define NO_PATH_RETRY_QUEUE -2
|
||
|
|
||
|
+#define PRIO_UNDEF -1
|
||
|
+#define PRIO_DEFAULT 1
|
||
|
+
|
||
|
enum free_path_switch {
|
||
|
KEEP_PATHS,
|
||
|
FREE_PATHS
|
||
|
@@ -142,7 +145,7 @@ struct multipath {
|
||
|
struct mpentry * mpe;
|
||
|
struct hwentry * hwe;
|
||
|
|
||
|
- /* daemon store a data blob for DM event waiter threads */
|
||
|
+ /* threads */
|
||
|
void * waiter;
|
||
|
|
||
|
/* stats */
|
||
|
@@ -183,10 +186,11 @@ struct multipath * find_mp_by_minor (vec
|
||
|
|
||
|
struct path * find_path_by_devt (vector pathvec, char * devt);
|
||
|
struct path * find_path_by_dev (vector pathvec, char * dev);
|
||
|
+struct path * first_path (struct multipath * mpp);
|
||
|
|
||
|
int pathcountgr (struct pathgroup *, int);
|
||
|
int pathcount (struct multipath *, int);
|
||
|
|
||
|
char sysfs_path[FILE_NAME_SIZE];
|
||
|
|
||
|
-#endif
|
||
|
+#endif /* _STRUCTS_H */
|
||
|
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||
|
index 86bf2a5..1a6d8e2 100644
|
||
|
--- a/libmultipath/structs_vec.c
|
||
|
+++ b/libmultipath/structs_vec.c
|
||
|
@@ -14,6 +14,7 @@ #include "dmparser.h"
|
||
|
#include "config.h"
|
||
|
#include "propsel.h"
|
||
|
#include "discovery.h"
|
||
|
+#include "waiter.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
@@ -58,8 +59,8 @@ adopt_paths (vector pathvec, struct mult
|
||
|
|
||
|
vector_foreach_slot (pathvec, pp, i) {
|
||
|
if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
|
||
|
- condlog(3, "%s ownership set to %s",
|
||
|
- pp->dev_t, mpp->alias);
|
||
|
+ condlog(3, "%s: ownership set to %s",
|
||
|
+ pp->dev, mpp->alias);
|
||
|
pp->mpp = mpp;
|
||
|
|
||
|
if (!mpp->paths && !(mpp->paths = vector_alloc()))
|
||
|
@@ -96,7 +97,7 @@ orphan_paths (vector pathvec, struct mul
|
||
|
|
||
|
vector_foreach_slot (pathvec, pp, i) {
|
||
|
if (pp->mpp == mpp) {
|
||
|
- condlog(4, "%s is orphaned", pp->dev_t);
|
||
|
+ condlog(4, "%s: orphaned", pp->dev);
|
||
|
orphan_path(pp);
|
||
|
}
|
||
|
}
|
||
|
@@ -382,3 +383,90 @@ verify_paths(struct multipath * mpp, str
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
+int update_multipath (struct vectors *vecs, char *mapname)
|
||
|
+{
|
||
|
+ struct multipath *mpp;
|
||
|
+ struct pathgroup *pgp;
|
||
|
+ struct path *pp;
|
||
|
+ int i, j;
|
||
|
+ int r = 1;
|
||
|
+
|
||
|
+ mpp = find_mp_by_alias(vecs->mpvec, mapname);
|
||
|
+
|
||
|
+ if (!mpp)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ free_pgvec(mpp->pg, KEEP_PATHS);
|
||
|
+ mpp->pg = NULL;
|
||
|
+
|
||
|
+ if (setup_multipath(vecs, mpp))
|
||
|
+ goto out; /* mpp freed in setup_multipath */
|
||
|
+
|
||
|
+ /*
|
||
|
+ * compare checkers states with DM states
|
||
|
+ */
|
||
|
+ vector_foreach_slot (mpp->pg, pgp, i) {
|
||
|
+ vector_foreach_slot (pgp->paths, pp, j) {
|
||
|
+ if (pp->dmstate != PSTATE_FAILED)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (pp->state != PATH_DOWN) {
|
||
|
+ int oldstate = pp->state;
|
||
|
+ condlog(2, "%s: mark as failed", pp->dev_t);
|
||
|
+ mpp->stat_path_failures++;
|
||
|
+ pp->state = PATH_DOWN;
|
||
|
+ if (oldstate == PATH_UP ||
|
||
|
+ oldstate == PATH_GHOST)
|
||
|
+ update_queue_mode_del_path(mpp);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * if opportune,
|
||
|
+ * schedule the next check earlier
|
||
|
+ */
|
||
|
+ if (pp->tick > conf->checkint)
|
||
|
+ pp->tick = conf->checkint;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ r = 0;
|
||
|
+out:
|
||
|
+ if (r)
|
||
|
+ condlog(0, "failed to update multipath");
|
||
|
+ return r;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * mpp->no_path_retry:
|
||
|
+ * -2 (QUEUE) : queue_if_no_path enabled, never turned off
|
||
|
+ * -1 (FAIL) : fail_if_no_path
|
||
|
+ * 0 (UNDEF) : nothing
|
||
|
+ * >0 : queue_if_no_path enabled, turned off after polling n times
|
||
|
+ */
|
||
|
+void update_queue_mode_del_path(struct multipath *mpp)
|
||
|
+{
|
||
|
+ if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
|
||
|
+ /*
|
||
|
+ * Enter retry mode.
|
||
|
+ * meaning of +1: retry_tick may be decremented in
|
||
|
+ * checkerloop before starting retry.
|
||
|
+ */
|
||
|
+ mpp->stat_queueing_timeouts++;
|
||
|
+ mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
|
||
|
+ condlog(1, "%s: Entering recovery mode: max_retries=%d",
|
||
|
+ mpp->alias, mpp->no_path_retry);
|
||
|
+ }
|
||
|
+ condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
|
||
|
+}
|
||
|
+
|
||
|
+void update_queue_mode_add_path(struct multipath *mpp)
|
||
|
+{
|
||
|
+ if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
|
||
|
+ /* come back to normal mode from retry mode */
|
||
|
+ mpp->retry_tick = 0;
|
||
|
+ dm_queue_if_no_path(mpp->alias, 1);
|
||
|
+ condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
|
||
|
+ condlog(1, "%s: Recovered to normal mode", mpp->alias);
|
||
|
+ }
|
||
|
+ condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
|
||
|
index 348e9e5..81d9eaa 100644
|
||
|
--- a/libmultipath/structs_vec.h
|
||
|
+++ b/libmultipath/structs_vec.h
|
||
|
@@ -9,17 +9,6 @@ #endif
|
||
|
vector mpvec;
|
||
|
};
|
||
|
|
||
|
-#if DAEMON
|
||
|
-struct event_thread {
|
||
|
- struct dm_task *dmt;
|
||
|
- pthread_t thread;
|
||
|
- int event_nr;
|
||
|
- char mapname[WWID_SIZE];
|
||
|
- struct vectors *vecs;
|
||
|
- struct multipath *mpp;
|
||
|
-};
|
||
|
-#endif
|
||
|
-
|
||
|
typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
|
||
|
typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
|
||
|
|
||
|
@@ -44,5 +33,8 @@ struct multipath * add_map_without_path
|
||
|
start_waiter_thread_func *start_waiter);
|
||
|
struct multipath * add_map_with_path (struct vectors * vecs,
|
||
|
struct path * pp, int add_vec);
|
||
|
+int update_multipath (struct vectors *vecs, char *mapname);
|
||
|
+void update_queue_mode_del_path(struct multipath *mpp);
|
||
|
+void update_queue_mode_add_path(struct multipath *mpp);
|
||
|
|
||
|
#endif /* _STRUCTS_VEC_H */
|
||
|
diff --git a/libmultipath/util.c b/libmultipath/util.c
|
||
|
index 376ca04..911ec55 100644
|
||
|
--- a/libmultipath/util.c
|
||
|
+++ b/libmultipath/util.c
|
||
|
@@ -30,6 +30,15 @@ strcmp_chomp(char *str1, char *str2)
|
||
|
}
|
||
|
|
||
|
void
|
||
|
+strchop(char *str)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i=strlen(str)-1; i >=0 && isspace(str[i]); --i) ;
|
||
|
+ str[++i] = '\0';
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
basename (char * str1, char * str2)
|
||
|
{
|
||
|
char *p = str1 + (strlen(str1) - 1);
|
||
|
diff --git a/libmultipath/util.h b/libmultipath/util.h
|
||
|
index 51f052a..e86bae2 100644
|
||
|
--- a/libmultipath/util.h
|
||
|
+++ b/libmultipath/util.h
|
||
|
@@ -2,6 +2,7 @@ #ifndef _UTIL_H
|
||
|
#define _UTIL_H
|
||
|
|
||
|
int strcmp_chomp(char *, char *);
|
||
|
+void strchop(char *);
|
||
|
void basename (char * src, char * dst);
|
||
|
int filepresent (char * run);
|
||
|
int get_word (char * sentence, char ** word);
|
||
|
diff --git a/libmultipath/version.h b/libmultipath/version.h
|
||
|
new file mode 100644
|
||
|
index 0000000..d577ec9
|
||
|
--- /dev/null
|
||
|
+++ b/libmultipath/version.h
|
||
|
@@ -0,0 +1,37 @@
|
||
|
+/*
|
||
|
+ * Soft: multipath device mapper target autoconfig
|
||
|
+ *
|
||
|
+ * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
|
||
|
+ *
|
||
|
+ * Author: Christophe Varoqui
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
+ * See the GNU General Public License for more details.
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or
|
||
|
+ * modify it under the terms of the GNU General Public License
|
||
|
+ * as published by the Free Software Foundation; either version
|
||
|
+ * 2 of the License, or (at your option) any later version.
|
||
|
+ *
|
||
|
+ * Copyright (c) 2006 Christophe Varoqui
|
||
|
+ */
|
||
|
+#ifndef _VERSION_H
|
||
|
+#define _VERSION_H
|
||
|
+
|
||
|
+#define VERSION_CODE 0x000407
|
||
|
+#define DATE_CODE 0x030c06
|
||
|
+
|
||
|
+#define PROG "multipath-tools"
|
||
|
+
|
||
|
+#define MULTIPATH_VERSION(version) \
|
||
|
+ (version >> 16) & 0xFF, \
|
||
|
+ (version >> 8) & 0xFF, \
|
||
|
+ version & 0xFF
|
||
|
+
|
||
|
+#define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n", \
|
||
|
+ MULTIPATH_VERSION(VERSION_CODE), \
|
||
|
+ MULTIPATH_VERSION(DATE_CODE)
|
||
|
+
|
||
|
+#endif /* _VERSION_H */
|
||
|
diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
|
||
|
new file mode 100644
|
||
|
index 0000000..75ed90c
|
||
|
--- /dev/null
|
||
|
+++ b/libmultipath/waiter.c
|
||
|
@@ -0,0 +1,234 @@
|
||
|
+/*
|
||
|
+ * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
|
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
|
||
|
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
|
||
|
+ * Copyright (c) 2005 Edward Goggin, EMC
|
||
|
+ */
|
||
|
+#include <unistd.h>
|
||
|
+#include <libdevmapper.h>
|
||
|
+#include <sys/mman.h>
|
||
|
+#include <pthread.h>
|
||
|
+#include <signal.h>
|
||
|
+
|
||
|
+#include "vector.h"
|
||
|
+#include "memory.h"
|
||
|
+#include "checkers.h"
|
||
|
+#include "structs.h"
|
||
|
+#include "structs_vec.h"
|
||
|
+#include "devmapper.h"
|
||
|
+#include "debug.h"
|
||
|
+#include "lock.h"
|
||
|
+#include "waiter.h"
|
||
|
+
|
||
|
+struct event_thread *alloc_waiter (void)
|
||
|
+{
|
||
|
+
|
||
|
+ struct event_thread *wp;
|
||
|
+
|
||
|
+ wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
|
||
|
+
|
||
|
+ return wp;
|
||
|
+}
|
||
|
+
|
||
|
+void free_waiter (void *data)
|
||
|
+{
|
||
|
+ struct event_thread *wp = (struct event_thread *)data;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * indicate in mpp that the wp is already freed storage
|
||
|
+ */
|
||
|
+ lock(wp->vecs->lock);
|
||
|
+
|
||
|
+ if (wp->mpp)
|
||
|
+ /*
|
||
|
+ * be careful, mpp may already be freed -- null if so
|
||
|
+ */
|
||
|
+ wp->mpp->waiter = NULL;
|
||
|
+ else
|
||
|
+ condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
|
||
|
+
|
||
|
+ unlock(wp->vecs->lock);
|
||
|
+
|
||
|
+ if (wp->dmt)
|
||
|
+ dm_task_destroy(wp->dmt);
|
||
|
+
|
||
|
+ FREE(wp);
|
||
|
+}
|
||
|
+
|
||
|
+void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
|
||
|
+{
|
||
|
+ struct event_thread *wp = (struct event_thread *)mpp->waiter;
|
||
|
+
|
||
|
+ if (!wp) {
|
||
|
+ condlog(3, "%s: no waiter thread", mpp->alias);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ condlog(2, "%s: stop event checker thread", wp->mapname);
|
||
|
+ pthread_kill((pthread_t)wp->thread, SIGUSR1);
|
||
|
+}
|
||
|
+
|
||
|
+static sigset_t unblock_signals(void)
|
||
|
+{
|
||
|
+ sigset_t set, old;
|
||
|
+
|
||
|
+ sigemptyset(&set);
|
||
|
+ sigaddset(&set, SIGHUP);
|
||
|
+ sigaddset(&set, SIGUSR1);
|
||
|
+ pthread_sigmask(SIG_UNBLOCK, &set, &old);
|
||
|
+ return old;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * returns the reschedule delay
|
||
|
+ * negative means *stop*
|
||
|
+ */
|
||
|
+int waiteventloop (struct event_thread *waiter)
|
||
|
+{
|
||
|
+ sigset_t set;
|
||
|
+ int event_nr;
|
||
|
+ int r;
|
||
|
+
|
||
|
+ if (!waiter->event_nr)
|
||
|
+ waiter->event_nr = dm_geteventnr(waiter->mapname);
|
||
|
+
|
||
|
+ if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
|
||
|
+ condlog(0, "%s: devmap event #%i dm_task_create error",
|
||
|
+ waiter->mapname, waiter->event_nr);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
|
||
|
+ condlog(0, "%s: devmap event #%i dm_task_set_name error",
|
||
|
+ waiter->mapname, waiter->event_nr);
|
||
|
+ dm_task_destroy(waiter->dmt);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
|
||
|
+ waiter->event_nr)) {
|
||
|
+ condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
|
||
|
+ waiter->mapname, waiter->event_nr);
|
||
|
+ dm_task_destroy(waiter->dmt);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ dm_task_no_open_count(waiter->dmt);
|
||
|
+
|
||
|
+ /* accept wait interruption */
|
||
|
+ set = unblock_signals();
|
||
|
+
|
||
|
+ /* interruption spits messages */
|
||
|
+ dm_shut_log();
|
||
|
+
|
||
|
+ /* wait */
|
||
|
+ r = dm_task_run(waiter->dmt);
|
||
|
+
|
||
|
+ /* wait is over : event or interrupt */
|
||
|
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||
|
+ //dm_restore_log();
|
||
|
+
|
||
|
+ if (!r) /* wait interrupted by signal */
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ dm_task_destroy(waiter->dmt);
|
||
|
+ waiter->dmt = NULL;
|
||
|
+ waiter->event_nr++;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * upon event ...
|
||
|
+ */
|
||
|
+ while (1) {
|
||
|
+ condlog(3, "%s: devmap event #%i",
|
||
|
+ waiter->mapname, waiter->event_nr);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * event might be :
|
||
|
+ *
|
||
|
+ * 1) a table reload, which means our mpp structure is
|
||
|
+ * obsolete : refresh it through update_multipath()
|
||
|
+ * 2) a path failed by DM : mark as such through
|
||
|
+ * update_multipath()
|
||
|
+ * 3) map has gone away : stop the thread.
|
||
|
+ * 4) a path reinstate : nothing to do
|
||
|
+ * 5) a switch group : nothing to do
|
||
|
+ */
|
||
|
+ pthread_cleanup_push(cleanup_lock, waiter->vecs->lock);
|
||
|
+ lock(waiter->vecs->lock);
|
||
|
+ r = update_multipath(waiter->vecs, waiter->mapname);
|
||
|
+ lock_cleanup_pop(waiter->vecs->lock);
|
||
|
+
|
||
|
+ if (r)
|
||
|
+ return -1; /* stop the thread */
|
||
|
+
|
||
|
+ event_nr = dm_geteventnr(waiter->mapname);
|
||
|
+
|
||
|
+ if (waiter->event_nr == event_nr)
|
||
|
+ return 1; /* upon problem reschedule 1s later */
|
||
|
+
|
||
|
+ waiter->event_nr = event_nr;
|
||
|
+ }
|
||
|
+ return -1; /* never reach there */
|
||
|
+}
|
||
|
+
|
||
|
+void *waitevent (void *et)
|
||
|
+{
|
||
|
+ int r;
|
||
|
+ struct event_thread *waiter;
|
||
|
+
|
||
|
+ mlockall(MCL_CURRENT | MCL_FUTURE);
|
||
|
+
|
||
|
+ waiter = (struct event_thread *)et;
|
||
|
+ pthread_cleanup_push(free_waiter, et);
|
||
|
+
|
||
|
+ while (1) {
|
||
|
+ r = waiteventloop(waiter);
|
||
|
+
|
||
|
+ if (r < 0)
|
||
|
+ break;
|
||
|
+
|
||
|
+ sleep(r);
|
||
|
+ }
|
||
|
+
|
||
|
+ pthread_cleanup_pop(1);
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
|
||
|
+{
|
||
|
+ pthread_attr_t attr;
|
||
|
+ struct event_thread *wp;
|
||
|
+
|
||
|
+ if (!mpp)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (pthread_attr_init(&attr))
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ pthread_attr_setstacksize(&attr, 32 * 1024);
|
||
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||
|
+
|
||
|
+ wp = alloc_waiter();
|
||
|
+
|
||
|
+ if (!wp)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ mpp->waiter = (void *)wp;
|
||
|
+ strncpy(wp->mapname, mpp->alias, WWID_SIZE);
|
||
|
+ wp->vecs = vecs;
|
||
|
+ wp->mpp = mpp;
|
||
|
+
|
||
|
+ if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
|
||
|
+ condlog(0, "%s: cannot create event checker", wp->mapname);
|
||
|
+ goto out1;
|
||
|
+ }
|
||
|
+ condlog(2, "%s: event checker started", wp->mapname);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+out1:
|
||
|
+ free_waiter(wp);
|
||
|
+ mpp->waiter = NULL;
|
||
|
+out:
|
||
|
+ condlog(0, "failed to start waiter thread");
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
|
||
|
new file mode 100644
|
||
|
index 0000000..0223924
|
||
|
--- /dev/null
|
||
|
+++ b/libmultipath/waiter.h
|
||
|
@@ -0,0 +1,23 @@
|
||
|
+#ifndef _WAITER_H
|
||
|
+#define _WAITER_H
|
||
|
+
|
||
|
+#if DAEMON
|
||
|
+
|
||
|
+struct event_thread {
|
||
|
+ struct dm_task *dmt;
|
||
|
+ pthread_t thread;
|
||
|
+ int event_nr;
|
||
|
+ char mapname[WWID_SIZE];
|
||
|
+ struct vectors *vecs;
|
||
|
+ struct multipath *mpp;
|
||
|
+};
|
||
|
+
|
||
|
+struct event_thread * alloc_waiter (void);
|
||
|
+void free_waiter (void *data);
|
||
|
+void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
|
||
|
+int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
|
||
|
+int waiteventloop (struct event_thread *waiter);
|
||
|
+void *waitevent (void *et);
|
||
|
+
|
||
|
+#endif /* DAEMON */
|
||
|
+#endif /* _WAITER_H */
|
||
|
diff --git a/multipath-tools.spec.in b/multipath-tools.spec.in
|
||
|
index 494f09e..9d6a7ea 100644
|
||
|
--- a/multipath-tools.spec.in
|
||
|
+++ b/multipath-tools.spec.in
|
||
|
@@ -50,6 +50,7 @@ rm -rf $RPM_BUILD_ROOT
|
||
|
%{prefix}/sbin/mpath_prio_balance_units
|
||
|
%{prefix}/sbin/mpath_prio_netapp
|
||
|
%{prefix}/sbin/mpath_prio_tpc
|
||
|
+%{prefix}/sbin/mpath_prio_hds_modular
|
||
|
%{prefix}/usr/share/man/man8/devmap_name.8.gz
|
||
|
%{prefix}/usr/share/man/man8/multipath.8.gz
|
||
|
%{prefix}/usr/share/man/man8/kpartx.8.gz
|
||
|
diff --git a/multipath.conf.annotated b/multipath.conf.annotated
|
||
|
index a1f04b7..f55c367 100644
|
||
|
--- a/multipath.conf.annotated
|
||
|
+++ b/multipath.conf.annotated
|
||
|
@@ -237,7 +237,7 @@ #
|
||
|
##
|
||
|
## name : devices
|
||
|
## scope : multipath & multipathd
|
||
|
-## desc : list of per storage controler settings
|
||
|
+## desc : list of per storage controller settings
|
||
|
## overrides default settings (device_maps block)
|
||
|
## overriden by per multipath settings (multipaths block)
|
||
|
##
|
||
|
@@ -245,7 +245,7 @@ #devices {
|
||
|
# #
|
||
|
# # name : device
|
||
|
# # scope : multipath & multipathd
|
||
|
-# # desc : settings for this specific storage controler
|
||
|
+# # desc : settings for this specific storage controller
|
||
|
# #
|
||
|
# device {
|
||
|
# #
|
||
|
@@ -260,7 +260,7 @@ # #
|
||
|
# # name : path_grouping_policy
|
||
|
# # scope : multipath
|
||
|
# # desc : path grouping policy to apply to multipath hosted
|
||
|
-# # by this storage controler
|
||
|
+# # by this storage controller
|
||
|
# # values : failover = 1 path per priority group
|
||
|
# # multibus = all valid paths in 1 priority
|
||
|
# # group
|
||
|
diff --git a/multipath/main.c b/multipath/main.c
|
||
|
index 98f7207..accb230 100644
|
||
|
--- a/multipath/main.c
|
||
|
+++ b/multipath/main.c
|
||
|
@@ -46,8 +46,7 @@ #include <print.h>
|
||
|
#include <alias.h>
|
||
|
#include <configure.h>
|
||
|
#include <pgpolicies.h>
|
||
|
-
|
||
|
-#include "main.h"
|
||
|
+#include <version.h>
|
||
|
|
||
|
static int
|
||
|
filter_pathvec (vector pathvec, char * refwwid)
|
||
|
@@ -73,7 +72,7 @@ static void
|
||
|
usage (char * progname)
|
||
|
{
|
||
|
fprintf (stderr, VERSION_STRING);
|
||
|
- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
|
||
|
+ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n",
|
||
|
progname);
|
||
|
fprintf (stderr,
|
||
|
"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
|
||
|
@@ -84,6 +83,7 @@ usage (char * progname)
|
||
|
"\t 1\t\t\tprint created devmap names only\n" \
|
||
|
"\t 2\t\t\tdefault verbosity\n" \
|
||
|
"\t 3\t\t\tprint debug information\n" \
|
||
|
+ "\t-h\t\tprint this usage text\n" \
|
||
|
"\t-b file\t\tbindings file location\n" \
|
||
|
"\t-d\t\tdry run, do not create or update devmaps\n" \
|
||
|
"\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
|
||
|
@@ -134,7 +134,7 @@ update_paths (struct multipath * mpp)
|
||
|
if (pp->state == PATH_UNCHECKED)
|
||
|
pathinfo(pp, conf->hwtable, DI_CHECKER);
|
||
|
|
||
|
- if (!pp->priority)
|
||
|
+ if (pp->priority == PRIO_UNDEF)
|
||
|
pathinfo(pp, conf->hwtable, DI_PRIO);
|
||
|
}
|
||
|
}
|
||
|
@@ -281,8 +281,10 @@ configure (void)
|
||
|
|
||
|
filter_pathvec(pathvec, refwwid);
|
||
|
|
||
|
- if (conf->list)
|
||
|
+ if (conf->list) {
|
||
|
+ r = 0;
|
||
|
goto out;
|
||
|
+ }
|
||
|
|
||
|
/*
|
||
|
* core logic entry point
|
||
|
@@ -305,7 +307,7 @@ main (int argc, char *argv[])
|
||
|
int arg;
|
||
|
extern char *optarg;
|
||
|
extern int optind;
|
||
|
- int i, r;
|
||
|
+ int i, r = 1;
|
||
|
|
||
|
if (getuid() != 0) {
|
||
|
fprintf(stderr, "need to be root\n");
|
||
|
@@ -322,7 +324,7 @@ main (int argc, char *argv[])
|
||
|
if (load_config(DEFAULT_CONFIGFILE))
|
||
|
exit(1);
|
||
|
|
||
|
- while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
|
||
|
+ while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) {
|
||
|
switch(arg) {
|
||
|
case 1: printf("optarg : %s\n",optarg);
|
||
|
break;
|
||
|
@@ -365,6 +367,8 @@ #endif
|
||
|
usage(argv[0]);
|
||
|
}
|
||
|
break;
|
||
|
+ case 'h':
|
||
|
+ usage(argv[0]);
|
||
|
case ':':
|
||
|
fprintf(stderr, "Missing option arguement\n");
|
||
|
usage(argv[0]);
|
||
|
diff --git a/multipath/main.h b/multipath/main.h
|
||
|
deleted file mode 100644
|
||
|
index 8d5b285..0000000
|
||
|
--- a/multipath/main.h
|
||
|
+++ /dev/null
|
||
|
@@ -1,39 +0,0 @@
|
||
|
-/*
|
||
|
- * Soft: Description here...
|
||
|
- *
|
||
|
- * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
|
||
|
- *
|
||
|
- * Author: Copyright (C) 2003 Christophe Varoqui
|
||
|
- *
|
||
|
- * This program is distributed in the hope that it will be useful,
|
||
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
- * See the GNU General Public License for more details.
|
||
|
- *
|
||
|
- * This program is free software; you can redistribute it and/or
|
||
|
- * modify it under the terms of the GNU General Public License
|
||
|
- * as published by the Free Software Foundation; either version
|
||
|
- * 2 of the License, or (at your option) any later version.
|
||
|
- */
|
||
|
-
|
||
|
-#ifndef _MAIN_H
|
||
|
-#define _MAIN_H
|
||
|
-
|
||
|
-/*
|
||
|
- * Build version
|
||
|
- */
|
||
|
-#define PROG "multipath"
|
||
|
-
|
||
|
-#define VERSION_CODE 0x000407
|
||
|
-#define DATE_CODE 0x030c06
|
||
|
-
|
||
|
-#define MULTIPATH_VERSION(version) \
|
||
|
- (version >> 16) & 0xFF, \
|
||
|
- (version >> 8) & 0xFF, \
|
||
|
- version & 0xFF
|
||
|
-
|
||
|
-#define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n", \
|
||
|
- MULTIPATH_VERSION(VERSION_CODE), \
|
||
|
- MULTIPATH_VERSION(DATE_CODE)
|
||
|
-
|
||
|
-#endif
|
||
|
diff --git a/multipath/multipath.8 b/multipath/multipath.8
|
||
|
index 7133598..693872b 100644
|
||
|
--- a/multipath/multipath.8
|
||
|
+++ b/multipath/multipath.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.TH MULTIPATH 8 "February 2004" "" "Linux Administrator's Manual"
|
||
|
+.TH MULTIPATH 8 "July 2006" "" "Linux Administrator's Manual"
|
||
|
.SH NAME
|
||
|
multipath \- Device mapper target autoconfig
|
||
|
.SH SYNOPSIS
|
||
|
@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco
|
||
|
.RB [\| \-v\ \c
|
||
|
.IR verbosity \|]
|
||
|
.RB [\| \-d \|]
|
||
|
-.RB [\| \-l | \-ll | \-f | \-F \|]
|
||
|
+.RB [\| \-h | \-l | \-ll | \-f | \-F \|]
|
||
|
.RB [\| \-p\ \c
|
||
|
.BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
|
||
|
.RB [\| device \|]
|
||
|
@@ -29,6 +29,9 @@ print the created or updated multipath n
|
||
|
print all info : detected paths, coalesced paths (ie multipaths) and device maps
|
||
|
.RE
|
||
|
.TP
|
||
|
+.B \-h
|
||
|
+print usage text
|
||
|
+.TP
|
||
|
.B \-d
|
||
|
dry run, do not create or update devmaps
|
||
|
.TP
|
||
|
@@ -38,12 +41,6 @@ show the current multipath topology from
|
||
|
.B \-ll
|
||
|
show the current multipath topology from all available information (sysfs, the device mapper, path checkers ...)
|
||
|
.TP
|
||
|
-.TP
|
||
|
-.BI \-D " major:minor"
|
||
|
-update only the devmap the path pointed by
|
||
|
-.I major:minor
|
||
|
-is in
|
||
|
-.TP
|
||
|
.B \-f
|
||
|
flush a multipath device map specified as parameter, if unused
|
||
|
.TP
|
||
|
@@ -64,7 +61,7 @@ all paths in 1 priority group
|
||
|
1 priority group per serial
|
||
|
.TP
|
||
|
.B group_by_prio
|
||
|
-1 priority group per priority value. Priorities are determined by callout programs specified as a global, per-controler or per-multipath option in the configuration file
|
||
|
+1 priority group per priority value. Priorities are determined by callout programs specified as a global, per-controller or per-multipath option in the configuration file
|
||
|
.TP
|
||
|
.B group_by_node_name
|
||
|
1 priority group per target node name. Target node names are fetched in /sys/class/fc_transport/target*/node_name.
|
||
|
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
||
|
index 475819b..bd0d03b 100644
|
||
|
--- a/multipathd/cli.c
|
||
|
+++ b/multipathd/cli.c
|
||
|
@@ -4,6 +4,7 @@
|
||
|
#include <memory.h>
|
||
|
#include <vector.h>
|
||
|
#include <util.h>
|
||
|
+#include <version.h>
|
||
|
|
||
|
#include "cli.h"
|
||
|
|
||
|
@@ -305,6 +306,8 @@ genhelp_handler (void)
|
||
|
return NULL;
|
||
|
|
||
|
p = reply;
|
||
|
+ p += sprintf(p, VERSION_STRING);
|
||
|
+ p += sprintf(p, "CLI commands reference:\n");
|
||
|
|
||
|
vector_foreach_slot (handlers, h, i) {
|
||
|
fp = h->fingerprint;
|
||
|
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||
|
index 92d8221..b5d8e00 100644
|
||
|
--- a/multipathd/cli_handlers.c
|
||
|
+++ b/multipathd/cli_handlers.c
|
||
|
@@ -71,7 +71,7 @@ show_map_topology (char ** r, int * len,
|
||
|
|
||
|
c = reply;
|
||
|
|
||
|
- c += snprint_multipath_topology( c, reply + maxlen - c, mpp, 2);
|
||
|
+ c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
|
||
|
again = ((c - reply) == (maxlen - 1));
|
||
|
|
||
|
if (again)
|
||
|
@@ -92,7 +92,8 @@ show_maps_topology (char ** r, int * len
|
||
|
char * reply;
|
||
|
unsigned int maxlen = INITIAL_REPLY_LEN;
|
||
|
int again = 1;
|
||
|
-
|
||
|
+
|
||
|
+ get_path_layout(vecs->pathvec);
|
||
|
reply = MALLOC(maxlen);
|
||
|
|
||
|
while (again) {
|
||
|
@@ -183,6 +184,7 @@ cli_list_map_topology (void * v, char **
|
||
|
struct vectors * vecs = (struct vectors *)data;
|
||
|
char * param = get_keyparam(v, MAP);
|
||
|
|
||
|
+ get_path_layout(vecs->pathvec);
|
||
|
mpp = find_mp_by_str(vecs->mpvec, param);
|
||
|
|
||
|
if (!mpp)
|
||
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
||
|
index 55a2c49..0b70714 100644
|
||
|
--- a/multipathd/main.c
|
||
|
+++ b/multipathd/main.c
|
||
|
@@ -55,136 +55,29 @@ #include "uxlsnr.h"
|
||
|
#include "uxclnt.h"
|
||
|
#include "cli.h"
|
||
|
#include "cli_handlers.h"
|
||
|
+#include "lock.h"
|
||
|
+#include "waiter.h"
|
||
|
|
||
|
#define FILE_NAME_SIZE 256
|
||
|
#define CMDSIZE 160
|
||
|
|
||
|
#define LOG_MSG(a,b) \
|
||
|
- if (strlen(b)) condlog(a, "%s: %s", pp->dev_t, b);
|
||
|
-
|
||
|
-#ifdef LCKDBG
|
||
|
-#define lock(a) \
|
||
|
- fprintf(stderr, "%s:%s(%i) lock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
- pthread_mutex_lock(a)
|
||
|
-#define unlock(a) \
|
||
|
- fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
- pthread_mutex_unlock(a)
|
||
|
-#define lock_cleanup_pop(a) \
|
||
|
- fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
|
||
|
- pthread_cleanup_pop(1);
|
||
|
-#else
|
||
|
-#define lock(a) pthread_mutex_lock(a)
|
||
|
-#define unlock(a) pthread_mutex_unlock(a)
|
||
|
-#define lock_cleanup_pop(a) pthread_cleanup_pop(1);
|
||
|
-#endif
|
||
|
+ if (strlen(b)) condlog(a, "%s: %s", pp->dev, b);
|
||
|
|
||
|
pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
|
||
|
pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
|
||
|
/*
|
||
|
- * structs
|
||
|
+ * global copy of vecs for use in sig handlers
|
||
|
*/
|
||
|
-struct vectors * gvecs; /* global copy of vecs for use in sig handlers */
|
||
|
-
|
||
|
-static struct event_thread *
|
||
|
-alloc_waiter (void)
|
||
|
-{
|
||
|
-
|
||
|
- struct event_thread * wp;
|
||
|
-
|
||
|
- wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
|
||
|
-
|
||
|
- return wp;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-free_waiter (void * data)
|
||
|
-{
|
||
|
- struct event_thread * wp = (struct event_thread *)data;
|
||
|
-
|
||
|
- /*
|
||
|
- * indicate in mpp that the wp is already freed storage
|
||
|
- */
|
||
|
- lock(wp->vecs->lock);
|
||
|
-
|
||
|
- if (wp->mpp)
|
||
|
- /*
|
||
|
- * be careful, mpp may already be freed -- null if so
|
||
|
- */
|
||
|
- wp->mpp->waiter = NULL;
|
||
|
- else
|
||
|
- condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
|
||
|
-
|
||
|
- unlock(wp->vecs->lock);
|
||
|
-
|
||
|
- if (wp->dmt)
|
||
|
- dm_task_destroy(wp->dmt);
|
||
|
-
|
||
|
- FREE(wp);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-stop_waiter_thread (struct multipath * mpp, struct vectors * vecs)
|
||
|
-{
|
||
|
- struct event_thread * wp = (struct event_thread *)mpp->waiter;
|
||
|
-
|
||
|
- if (!wp) {
|
||
|
- condlog(3, "%s: no waiter thread", mpp->alias);
|
||
|
- return;
|
||
|
- }
|
||
|
- condlog(2, "%s: stop event checker thread", wp->mapname);
|
||
|
- pthread_kill((pthread_t)wp->thread, SIGUSR1);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-cleanup_lock (void * data)
|
||
|
-{
|
||
|
- unlock((pthread_mutex_t *)data);
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * mpp->no_path_retry:
|
||
|
- * -2 (QUEUE) : queue_if_no_path enabled, never turned off
|
||
|
- * -1 (FAIL) : fail_if_no_path
|
||
|
- * 0 (UNDEF) : nothing
|
||
|
- * >0 : queue_if_no_path enabled, turned off after polling n times
|
||
|
- */
|
||
|
-static void
|
||
|
-update_queue_mode_del_path(struct multipath *mpp)
|
||
|
-{
|
||
|
- if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
|
||
|
- /*
|
||
|
- * Enter retry mode.
|
||
|
- * meaning of +1: retry_tick may be decremented in
|
||
|
- * checkerloop before starting retry.
|
||
|
- */
|
||
|
- mpp->stat_queueing_timeouts++;
|
||
|
- mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
|
||
|
- condlog(1, "%s: Entering recovery mode: max_retries=%d",
|
||
|
- mpp->alias, mpp->no_path_retry);
|
||
|
- }
|
||
|
- condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-update_queue_mode_add_path(struct multipath *mpp)
|
||
|
-{
|
||
|
- if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
|
||
|
- /* come back to normal mode from retry mode */
|
||
|
- mpp->retry_tick = 0;
|
||
|
- dm_queue_if_no_path(mpp->alias, 1);
|
||
|
- condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
|
||
|
- condlog(1, "%s: Recovered to normal mode", mpp->alias);
|
||
|
- }
|
||
|
- condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
|
||
|
-}
|
||
|
+struct vectors * gvecs;
|
||
|
|
||
|
static int
|
||
|
need_switch_pathgroup (struct multipath * mpp, int refresh)
|
||
|
{
|
||
|
struct pathgroup * pgp;
|
||
|
struct path * pp;
|
||
|
- int i, j;
|
||
|
+ unsigned int i, j;
|
||
|
|
||
|
if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
|
||
|
return 0;
|
||
|
@@ -219,7 +112,8 @@ coalesce_maps(struct vectors *vecs, vect
|
||
|
{
|
||
|
struct multipath * ompp;
|
||
|
vector ompv = vecs->mpvec;
|
||
|
- int i, j;
|
||
|
+ unsigned int i;
|
||
|
+ int j;
|
||
|
|
||
|
vector_foreach_slot (ompv, ompp, i) {
|
||
|
if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
|
||
|
@@ -253,234 +147,12 @@ coalesce_maps(struct vectors *vecs, vect
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int
|
||
|
-update_multipath (struct vectors *vecs, char *mapname)
|
||
|
-{
|
||
|
- struct multipath *mpp;
|
||
|
- struct pathgroup *pgp;
|
||
|
- struct path *pp;
|
||
|
- int i, j;
|
||
|
- int r = 1;
|
||
|
-
|
||
|
- mpp = find_mp_by_alias(vecs->mpvec, mapname);
|
||
|
-
|
||
|
- if (!mpp)
|
||
|
- goto out;
|
||
|
-
|
||
|
- free_pgvec(mpp->pg, KEEP_PATHS);
|
||
|
- mpp->pg = NULL;
|
||
|
-
|
||
|
- if (setup_multipath(vecs, mpp))
|
||
|
- goto out; /* mpp freed in setup_multipath */
|
||
|
-
|
||
|
- /*
|
||
|
- * compare checkers states with DM states
|
||
|
- */
|
||
|
- vector_foreach_slot (mpp->pg, pgp, i) {
|
||
|
- vector_foreach_slot (pgp->paths, pp, j) {
|
||
|
- if (pp->dmstate != PSTATE_FAILED)
|
||
|
- continue;
|
||
|
-
|
||
|
- if (pp->state != PATH_DOWN) {
|
||
|
- int oldstate = pp->state;
|
||
|
- condlog(2, "%s: mark as failed", pp->dev_t);
|
||
|
- mpp->stat_path_failures++;
|
||
|
- pp->state = PATH_DOWN;
|
||
|
- if (oldstate == PATH_UP ||
|
||
|
- oldstate == PATH_GHOST)
|
||
|
- update_queue_mode_del_path(mpp);
|
||
|
-
|
||
|
- /*
|
||
|
- * if opportune,
|
||
|
- * schedule the next check earlier
|
||
|
- */
|
||
|
- if (pp->tick > conf->checkint)
|
||
|
- pp->tick = conf->checkint;
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
- r = 0;
|
||
|
-out:
|
||
|
- if (r)
|
||
|
- condlog(0, "failed to update multipath");
|
||
|
-
|
||
|
- return r;
|
||
|
-}
|
||
|
-
|
||
|
-static sigset_t unblock_signals(void)
|
||
|
-{
|
||
|
- sigset_t set, old;
|
||
|
-
|
||
|
- sigemptyset(&set);
|
||
|
- sigaddset(&set, SIGHUP);
|
||
|
- sigaddset(&set, SIGUSR1);
|
||
|
- pthread_sigmask(SIG_UNBLOCK, &set, &old);
|
||
|
- return old;
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * returns the reschedule delay
|
||
|
- * negative means *stop*
|
||
|
- */
|
||
|
-static int
|
||
|
-waiteventloop (struct event_thread * waiter)
|
||
|
-{
|
||
|
- sigset_t set;
|
||
|
- int event_nr;
|
||
|
- int r;
|
||
|
-
|
||
|
- if (!waiter->event_nr)
|
||
|
- waiter->event_nr = dm_geteventnr(waiter->mapname);
|
||
|
-
|
||
|
- if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
|
||
|
- condlog(0, "%s: devmap event #%i dm_task_create error",
|
||
|
- waiter->mapname, waiter->event_nr);
|
||
|
- return 1;
|
||
|
- }
|
||
|
-
|
||
|
- if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
|
||
|
- condlog(0, "%s: devmap event #%i dm_task_set_name error",
|
||
|
- waiter->mapname, waiter->event_nr);
|
||
|
- dm_task_destroy(waiter->dmt);
|
||
|
- return 1;
|
||
|
- }
|
||
|
-
|
||
|
- if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
|
||
|
- waiter->event_nr)) {
|
||
|
- condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
|
||
|
- waiter->mapname, waiter->event_nr);
|
||
|
- dm_task_destroy(waiter->dmt);
|
||
|
- return 1;
|
||
|
- }
|
||
|
-
|
||
|
- dm_task_no_open_count(waiter->dmt);
|
||
|
-
|
||
|
- /* accept wait interruption */
|
||
|
- set = unblock_signals();
|
||
|
-
|
||
|
- /* interruption spits messages */
|
||
|
- dm_shut_log();
|
||
|
-
|
||
|
- /* wait */
|
||
|
- r = dm_task_run(waiter->dmt);
|
||
|
-
|
||
|
- /* wait is over : event or interrupt */
|
||
|
- pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||
|
- //dm_restore_log();
|
||
|
-
|
||
|
- if (!r) /* wait interrupted by signal */
|
||
|
- return -1;
|
||
|
-
|
||
|
- dm_task_destroy(waiter->dmt);
|
||
|
- waiter->dmt = NULL;
|
||
|
- waiter->event_nr++;
|
||
|
-
|
||
|
- /*
|
||
|
- * upon event ...
|
||
|
- */
|
||
|
- while (1) {
|
||
|
- condlog(3, "%s: devmap event #%i",
|
||
|
- waiter->mapname, waiter->event_nr);
|
||
|
-
|
||
|
- /*
|
||
|
- * event might be :
|
||
|
- *
|
||
|
- * 1) a table reload, which means our mpp structure is
|
||
|
- * obsolete : refresh it through update_multipath()
|
||
|
- * 2) a path failed by DM : mark as such through
|
||
|
- * update_multipath()
|
||
|
- * 3) map has gone away : stop the thread.
|
||
|
- * 4) a path reinstate : nothing to do
|
||
|
- * 5) a switch group : nothing to do
|
||
|
- */
|
||
|
- pthread_cleanup_push(cleanup_lock, waiter->vecs->lock);
|
||
|
- lock(waiter->vecs->lock);
|
||
|
- r = update_multipath(waiter->vecs, waiter->mapname);
|
||
|
- lock_cleanup_pop(waiter->vecs->lock);
|
||
|
-
|
||
|
- if (r)
|
||
|
- return -1; /* stop the thread */
|
||
|
-
|
||
|
- event_nr = dm_geteventnr(waiter->mapname);
|
||
|
-
|
||
|
- if (waiter->event_nr == event_nr)
|
||
|
- return 1; /* upon problem reschedule 1s later */
|
||
|
-
|
||
|
- waiter->event_nr = event_nr;
|
||
|
- }
|
||
|
- return -1; /* never reach there */
|
||
|
-}
|
||
|
-
|
||
|
-static void *
|
||
|
-waitevent (void * et)
|
||
|
-{
|
||
|
- int r;
|
||
|
- struct event_thread *waiter;
|
||
|
-
|
||
|
- mlockall(MCL_CURRENT | MCL_FUTURE);
|
||
|
-
|
||
|
- waiter = (struct event_thread *)et;
|
||
|
- pthread_cleanup_push(free_waiter, et);
|
||
|
-
|
||
|
- while (1) {
|
||
|
- r = waiteventloop(waiter);
|
||
|
-
|
||
|
- if (r < 0)
|
||
|
- break;
|
||
|
-
|
||
|
- sleep(r);
|
||
|
- }
|
||
|
-
|
||
|
- pthread_cleanup_pop(1);
|
||
|
- return NULL;
|
||
|
-}
|
||
|
-
|
||
|
-static int
|
||
|
-start_waiter_thread (struct multipath * mpp, struct vectors * vecs)
|
||
|
-{
|
||
|
- pthread_attr_t attr;
|
||
|
- struct event_thread * wp;
|
||
|
-
|
||
|
- if (!mpp)
|
||
|
- return 0;
|
||
|
-
|
||
|
- if (pthread_attr_init(&attr))
|
||
|
- goto out;
|
||
|
-
|
||
|
- pthread_attr_setstacksize(&attr, 32 * 1024);
|
||
|
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||
|
-
|
||
|
- wp = alloc_waiter();
|
||
|
-
|
||
|
- if (!wp)
|
||
|
- goto out;
|
||
|
-
|
||
|
- mpp->waiter = (void *)wp;
|
||
|
- strncpy(wp->mapname, mpp->alias, WWID_SIZE);
|
||
|
- wp->vecs = vecs;
|
||
|
- wp->mpp = mpp;
|
||
|
-
|
||
|
- if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
|
||
|
- condlog(0, "%s: cannot create event checker", wp->mapname);
|
||
|
- goto out1;
|
||
|
- }
|
||
|
- condlog(2, "%s: event checker started", wp->mapname);
|
||
|
-
|
||
|
- return 0;
|
||
|
-out1:
|
||
|
- free_waiter(wp);
|
||
|
- mpp->waiter = NULL;
|
||
|
-out:
|
||
|
- condlog(0, "failed to start waiter thread");
|
||
|
- return 1;
|
||
|
-}
|
||
|
-
|
||
|
static void
|
||
|
sync_map_state(struct multipath *mpp)
|
||
|
{
|
||
|
- int i, j;
|
||
|
struct pathgroup *pgp;
|
||
|
struct path *pp;
|
||
|
+ unsigned int i, j;
|
||
|
|
||
|
vector_foreach_slot (mpp->pg, pgp, i){
|
||
|
vector_foreach_slot (pgp->paths, pp, j){
|
||
|
@@ -502,7 +174,7 @@ sync_map_state(struct multipath *mpp)
|
||
|
static void
|
||
|
sync_maps_state(vector mpvec)
|
||
|
{
|
||
|
- int i;
|
||
|
+ unsigned int i;
|
||
|
struct multipath *mpp;
|
||
|
|
||
|
vector_foreach_slot (mpvec, mpp, i)
|
||
|
@@ -863,7 +535,7 @@ ev_remove_path (char * devname, struct v
|
||
|
}
|
||
|
sync_map_state(mpp);
|
||
|
|
||
|
- condlog(3, "%s path removed from devmap %s",
|
||
|
+ condlog(3, "%s: path removed from map %s",
|
||
|
devname, mpp->alias);
|
||
|
}
|
||
|
free_pathvec(rpvec, KEEP_PATHS);
|
||
|
@@ -898,8 +570,8 @@ out:
|
||
|
static int
|
||
|
map_discovery (struct vectors * vecs)
|
||
|
{
|
||
|
- int i;
|
||
|
struct multipath * mpp;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
if (dm_get_maps(vecs->mpvec, "multipath"))
|
||
|
return 1;
|
||
|
@@ -1129,7 +801,7 @@ static void
|
||
|
mpvec_garbage_collector (struct vectors * vecs)
|
||
|
{
|
||
|
struct multipath * mpp;
|
||
|
- int i;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
vector_foreach_slot (vecs->mpvec, mpp, i) {
|
||
|
if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
|
||
|
@@ -1144,7 +816,7 @@ static void
|
||
|
defered_failback_tick (vector mpvec)
|
||
|
{
|
||
|
struct multipath * mpp;
|
||
|
- int i;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
vector_foreach_slot (mpvec, mpp, i) {
|
||
|
/*
|
||
|
@@ -1163,7 +835,7 @@ static void
|
||
|
retry_count_tick(vector mpvec)
|
||
|
{
|
||
|
struct multipath *mpp;
|
||
|
- int i;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
vector_foreach_slot (mpvec, mpp, i) {
|
||
|
if (mpp->retry_tick) {
|
||
|
@@ -1182,8 +854,9 @@ checkerloop (void *ap)
|
||
|
{
|
||
|
struct vectors *vecs;
|
||
|
struct path *pp;
|
||
|
- int i, count = 0;
|
||
|
+ int count = 0;
|
||
|
int newstate;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||
|
vecs = (struct vectors *)ap;
|
||
|
@@ -1351,10 +1024,10 @@ configure (struct vectors * vecs, int st
|
||
|
vector mpvec;
|
||
|
int i;
|
||
|
|
||
|
- if (!(vecs->pathvec = vector_alloc()))
|
||
|
+ if (!vecs->pathvec && !(vecs->pathvec = vector_alloc()))
|
||
|
return 1;
|
||
|
|
||
|
- if (!(vecs->mpvec = vector_alloc()))
|
||
|
+ if (!vecs->mpvec && !(vecs->mpvec = vector_alloc()))
|
||
|
return 1;
|
||
|
|
||
|
if (!(mpvec = vector_alloc()))
|
||
|
@@ -1406,6 +1079,7 @@ configure (struct vectors * vecs, int st
|
||
|
/*
|
||
|
* save new set of maps formed by considering current path state
|
||
|
*/
|
||
|
+ vector_free(vecs->mpvec);
|
||
|
vecs->mpvec = mpvec;
|
||
|
|
||
|
/*
|
||
|
@@ -1435,6 +1109,7 @@ reconfigure (struct vectors * vecs)
|
||
|
if (VECTOR_SIZE(vecs->pathvec))
|
||
|
free_pathvec(vecs->pathvec, FREE_PATHS);
|
||
|
|
||
|
+ vecs->pathvec = NULL;
|
||
|
conf = NULL;
|
||
|
|
||
|
if (load_config(DEFAULT_CONFIGFILE))
|
||
|
@@ -1467,24 +1142,10 @@ init_vecs (void)
|
||
|
if (!vecs->lock)
|
||
|
goto out;
|
||
|
|
||
|
- vecs->pathvec = vector_alloc();
|
||
|
-
|
||
|
- if (!vecs->pathvec)
|
||
|
- goto out1;
|
||
|
-
|
||
|
- vecs->mpvec = vector_alloc();
|
||
|
-
|
||
|
- if (!vecs->mpvec)
|
||
|
- goto out2;
|
||
|
-
|
||
|
pthread_mutex_init(vecs->lock, NULL);
|
||
|
|
||
|
return vecs;
|
||
|
|
||
|
-out2:
|
||
|
- vector_free(vecs->pathvec);
|
||
|
-out1:
|
||
|
- FREE(vecs->lock);
|
||
|
out:
|
||
|
FREE(vecs);
|
||
|
condlog(0, "failed to init paths");
|
||
|
@@ -1543,7 +1204,7 @@ signal_init(void)
|
||
|
signal_set(SIGUSR1, sigusr1);
|
||
|
signal_set(SIGINT, sigend);
|
||
|
signal_set(SIGTERM, sigend);
|
||
|
- signal_set(SIGKILL, sigend);
|
||
|
+ signal(SIGPIPE, SIG_IGN);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
@@ -1551,7 +1212,7 @@ setscheduler (void)
|
||
|
{
|
||
|
int res;
|
||
|
static struct sched_param sched_param = {
|
||
|
- sched_priority: 99
|
||
|
+ .sched_priority = 99
|
||
|
};
|
||
|
|
||
|
res = sched_setscheduler (0, SCHED_RR, &sched_param);
|
||
|
diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8
|
||
|
index 48b1b04..88ae9c6 100644
|
||
|
--- a/multipathd/multipathd.8
|
||
|
+++ b/multipathd/multipathd.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.TH MULTIPATHD 8 "October 2004" "Linux Administrator's Manual"
|
||
|
+.TH MULTIPATHD 8 "July 2006" "Linux Administrator's Manual"
|
||
|
.SH NAME
|
||
|
multipathd \- multipath daemon
|
||
|
.SH SYNOPSYS
|
||
|
@@ -6,10 +6,10 @@ multipathd \- multipath daemon
|
||
|
|
||
|
This daemon is in charge of checking for failed paths. When this happens,
|
||
|
it will reconfigure the multipath map the path belongs to, so that this map
|
||
|
-regain its maximum performance and redundancy.
|
||
|
+regains its maximum performance and redundancy.
|
||
|
|
||
|
This daemon executes the external multipath config tool when events occur.
|
||
|
-In turn, the multipath tool signals the multipathd daemon it is done with
|
||
|
+In turn, the multipath tool signals the multipathd daemon when it is done with
|
||
|
devmap reconfiguration, so that it can refresh its failed path list.
|
||
|
|
||
|
.SH "SEE ALSO"
|
||
|
diff --git a/path_priority/pp_alua/main.c b/path_priority/pp_alua/main.c
|
||
|
index 190fbdc..ba8da99 100644
|
||
|
--- a/path_priority/pp_alua/main.c
|
||
|
+++ b/path_priority/pp_alua/main.c
|
||
|
@@ -12,8 +12,6 @@
|
||
|
*
|
||
|
* This file is released under the GPL.
|
||
|
*/
|
||
|
-#include <linux/kdev_t.h>
|
||
|
-
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
@@ -241,7 +239,7 @@ main (int argc, char **argv)
|
||
|
mknod(
|
||
|
devicepath,
|
||
|
S_IFBLK|S_IRUSR|S_IWUSR,
|
||
|
- MKDEV(major, minor)
|
||
|
+ makedev(major, minor)
|
||
|
);
|
||
|
|
||
|
}
|
||
|
diff --git a/path_priority/pp_alua/mpath_prio_alua.8 b/path_priority/pp_alua/mpath_prio_alua.8
|
||
|
index 4843bcd..58568a5 100644
|
||
|
--- a/path_priority/pp_alua/mpath_prio_alua.8
|
||
|
+++ b/path_priority/pp_alua/mpath_prio_alua.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.TH MPATH_PRIO_ALUA 8 "7. June 2005" "multipath-tools" \
|
||
|
+.TH MPATH_PRIO_ALUA 8 "July 2006" "multipath-tools" \
|
||
|
"Linux Administrator's Manual"
|
||
|
.SH NAME
|
||
|
mpath_prio_alua \- Path priority tool based on Asymmetric LUn Access
|
||
|
diff --git a/path_priority/pp_alua/rtpg.c b/path_priority/pp_alua/rtpg.c
|
||
|
index 9aea560..701f9d5 100644
|
||
|
--- a/path_priority/pp_alua/rtpg.c
|
||
|
+++ b/path_priority/pp_alua/rtpg.c
|
||
|
@@ -21,6 +21,7 @@ #include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
+#include <inttypes.h>
|
||
|
|
||
|
#define __user
|
||
|
#include <scsi/sg.h>
|
||
|
@@ -28,7 +29,7 @@ #include <scsi/sg.h>
|
||
|
#include "rtpg.h"
|
||
|
|
||
|
#define SENSE_BUFF_LEN 32
|
||
|
-#define DEF_TIMEOUT 60000
|
||
|
+#define DEF_TIMEOUT 300000
|
||
|
|
||
|
/*
|
||
|
* Macro used to print debug messaged.
|
||
|
@@ -251,14 +252,38 @@ do_rtpg(int fd, void* resp, long resplen
|
||
|
int
|
||
|
get_asymmetric_access_state(int fd, unsigned int tpg)
|
||
|
{
|
||
|
- unsigned char buf[128];
|
||
|
+ unsigned char *buf;
|
||
|
struct rtpg_data * tpgd;
|
||
|
struct rtpg_tpg_dscr * dscr;
|
||
|
int rc;
|
||
|
-
|
||
|
- rc = do_rtpg(fd, buf, sizeof(buf));
|
||
|
+ int buflen;
|
||
|
+ uint32_t scsi_buflen;
|
||
|
+
|
||
|
+ buflen = 128; /* Initial value from old code */
|
||
|
+ buf = (unsigned char *)malloc(buflen);
|
||
|
+ if (!buf) {
|
||
|
+ PRINT_DEBUG ("malloc failed: could not allocate"
|
||
|
+ "%u bytes\n", buflen);
|
||
|
+ return -RTPG_RTPG_FAILED;
|
||
|
+ }
|
||
|
+ rc = do_rtpg(fd, buf, buflen);
|
||
|
if (rc < 0)
|
||
|
return rc;
|
||
|
+ scsi_buflen = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
|
||
|
+ if (buflen < (scsi_buflen + 4)) {
|
||
|
+ free(buf);
|
||
|
+ buf = (unsigned char *)malloc(scsi_buflen);
|
||
|
+ if (!buf) {
|
||
|
+ PRINT_DEBUG ("malloc failed: could not allocate"
|
||
|
+ "%u bytes\n", scsi_buflen);
|
||
|
+ return -RTPG_RTPG_FAILED;
|
||
|
+ }
|
||
|
+ buflen = scsi_buflen;
|
||
|
+ rc = do_rtpg(fd, buf, buflen);
|
||
|
+ if (rc < 0)
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
|
||
|
tpgd = (struct rtpg_data *) buf;
|
||
|
rc = -RTPG_TPG_NOT_FOUND;
|
||
|
@@ -274,7 +299,8 @@ get_asymmetric_access_state(int fd, unsi
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
+out:
|
||
|
+ free(buf);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
diff --git a/path_priority/pp_alua/spc3.h b/path_priority/pp_alua/spc3.h
|
||
|
index 11f5dbd..bddbbdd 100644
|
||
|
--- a/path_priority/pp_alua/spc3.h
|
||
|
+++ b/path_priority/pp_alua/spc3.h
|
||
|
@@ -148,10 +148,10 @@ struct inquiry_data {
|
||
|
/* ......x. = command queue support */
|
||
|
/* .......x = vs2 */
|
||
|
unsigned char vendor_identification[8];
|
||
|
- unsigned char product_identification[8];
|
||
|
+ unsigned char product_identification[16];
|
||
|
unsigned char product_revision[4];
|
||
|
unsigned char vendor_specific[20];
|
||
|
- unsigned char b48; /* xxxx.... = reserved */
|
||
|
+ unsigned char b56; /* xxxx.... = reserved */
|
||
|
/* ....xx.. = clocking */
|
||
|
/* ......x. = qas */
|
||
|
/* .......x = ius */
|
||
|
diff --git a/path_priority/pp_balance_units/pp_balance_units.c b/path_priority/pp_balance_units/pp_balance_units.c
|
||
|
index 307a959..ea70f13 100644
|
||
|
--- a/path_priority/pp_balance_units/pp_balance_units.c
|
||
|
+++ b/path_priority/pp_balance_units/pp_balance_units.c
|
||
|
@@ -3,15 +3,15 @@
|
||
|
* This code is GPLv2, see license file
|
||
|
*
|
||
|
* This path prioritizer aims to balance logical units over all
|
||
|
- * controlers available. The logic is :
|
||
|
+ * controllers available. The logic is :
|
||
|
*
|
||
|
* - list all paths in all primary path groups
|
||
|
- * - for each path, get the controler's serial
|
||
|
- * - compute the number of active paths attached to each controler
|
||
|
- * - compute the max number of paths attached to the same controler
|
||
|
+ * - for each path, get the controller's serial
|
||
|
+ * - compute the number of active paths attached to each controller
|
||
|
+ * - compute the max number of paths attached to the same controller
|
||
|
* - if sums are already balanced or if the path passed as parameter is
|
||
|
- * attached to controler with less active paths, then return
|
||
|
- * (max_path_attached_to_one_controler - number_of_paths_on_this_controler)
|
||
|
+ * attached to controller with less active paths, then return
|
||
|
+ * (max_path_attached_to_one_controller - number_of_paths_on_this_controller)
|
||
|
* - else, or if anything goes wrong, return 1 as a default prio
|
||
|
*
|
||
|
*/
|
||
|
@@ -38,7 +38,7 @@ #define FILE_NAME_SIZE 255
|
||
|
#define INQUIRY_CMDLEN 6
|
||
|
#define INQUIRY_CMD 0x12
|
||
|
#define SENSE_BUFF_LEN 32
|
||
|
-#define DEF_TIMEOUT 60000
|
||
|
+#define DEF_TIMEOUT 300000
|
||
|
#define RECOVERED_ERROR 0x01
|
||
|
#define MX_ALLOC_LEN 255
|
||
|
#define SCSI_CHECK_CONDITION 0x2
|
||
|
@@ -61,7 +61,7 @@ struct path {
|
||
|
char serial[SERIAL_SIZE];
|
||
|
};
|
||
|
|
||
|
-struct controler {
|
||
|
+struct controller {
|
||
|
char serial[SERIAL_SIZE];
|
||
|
int path_count;
|
||
|
};
|
||
|
@@ -172,7 +172,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-get_serial (char * str, char * devt)
|
||
|
+get_serial (char * str, int maxlen, char * devt)
|
||
|
{
|
||
|
int fd;
|
||
|
int len;
|
||
|
@@ -181,20 +181,22 @@ get_serial (char * str, char * devt)
|
||
|
fd = opennode(devt, O_RDONLY);
|
||
|
|
||
|
if (fd < 0)
|
||
|
- return 0;
|
||
|
+ return 1;
|
||
|
|
||
|
if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
|
||
|
len = buff[3];
|
||
|
+ if (len >= maxlen)
|
||
|
+ return 1;
|
||
|
if (len > 0) {
|
||
|
memcpy(str, buff + 4, len);
|
||
|
buff[len] = '\0';
|
||
|
}
|
||
|
close(fd);
|
||
|
- return 1;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
closenode(devt, fd);
|
||
|
- return 0;
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
@@ -358,7 +360,7 @@ get_paths (vector pathvec)
|
||
|
if (pos == BEFOREPG)
|
||
|
pos = INPG;
|
||
|
|
||
|
- get_serial(pp->serial, pp->dev_t);
|
||
|
+ get_serial(pp->serial, SERIAL_SIZE, pp->dev_t);
|
||
|
vector_alloc_slot(pathvec);
|
||
|
vector_set_slot(pathvec, pp);
|
||
|
debug("store %s [%s]",
|
||
|
@@ -370,40 +372,40 @@ get_paths (vector pathvec)
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
-find_controler (vector controlers, char * serial)
|
||
|
+find_controller (vector controllers, char * serial)
|
||
|
{
|
||
|
int i;
|
||
|
- struct controler * cp;
|
||
|
+ struct controller * cp;
|
||
|
|
||
|
- if (!controlers)
|
||
|
+ if (!controllers)
|
||
|
return NULL;
|
||
|
|
||
|
- vector_foreach_slot (controlers, cp, i)
|
||
|
+ vector_foreach_slot (controllers, cp, i)
|
||
|
if (!strncmp(cp->serial, serial, SERIAL_SIZE))
|
||
|
return cp;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-get_controlers (vector controlers, vector pathvec)
|
||
|
+get_controllers (vector controllers, vector pathvec)
|
||
|
{
|
||
|
int i;
|
||
|
struct path * pp;
|
||
|
- struct controler * cp;
|
||
|
+ struct controller * cp;
|
||
|
|
||
|
- if (!controlers)
|
||
|
+ if (!controllers)
|
||
|
return;
|
||
|
|
||
|
vector_foreach_slot (pathvec, pp, i) {
|
||
|
if (!pp || !strlen(pp->serial))
|
||
|
continue;
|
||
|
|
||
|
- cp = find_controler(controlers, pp->serial);
|
||
|
+ cp = find_controller(controllers, pp->serial);
|
||
|
|
||
|
if (!cp) {
|
||
|
- cp = zalloc(sizeof(struct controler));
|
||
|
- vector_alloc_slot(controlers);
|
||
|
- vector_set_slot(controlers, cp);
|
||
|
+ cp = zalloc(sizeof(struct controller));
|
||
|
+ vector_alloc_slot(controllers);
|
||
|
+ vector_set_slot(controllers, cp);
|
||
|
strncpy(cp->serial, pp->serial, SERIAL_SIZE);
|
||
|
}
|
||
|
cp->path_count++;
|
||
|
@@ -411,17 +413,17 @@ get_controlers (vector controlers, vecto
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-get_max_path_count (vector controlers)
|
||
|
+get_max_path_count (vector controllers)
|
||
|
{
|
||
|
int i;
|
||
|
int max = 0;
|
||
|
- struct controler * cp;
|
||
|
+ struct controller * cp;
|
||
|
|
||
|
- if (!controlers)
|
||
|
+ if (!controllers)
|
||
|
return 0;
|
||
|
|
||
|
- vector_foreach_slot (controlers, cp, i) {
|
||
|
- debug("controler %s : %i paths", cp->serial, cp->path_count);
|
||
|
+ vector_foreach_slot (controllers, cp, i) {
|
||
|
+ debug("controller %s : %i paths", cp->serial, cp->path_count);
|
||
|
if(cp->path_count > max)
|
||
|
max = cp->path_count;
|
||
|
}
|
||
|
@@ -433,9 +435,9 @@ int
|
||
|
main (int argc, char **argv)
|
||
|
{
|
||
|
vector pathvec = NULL;
|
||
|
- vector controlers = NULL;
|
||
|
+ vector controllers = NULL;
|
||
|
struct path * ref_path = NULL;
|
||
|
- struct controler * cp = NULL;
|
||
|
+ struct controller * cp = NULL;
|
||
|
int max_path_count = 0;
|
||
|
|
||
|
ref_path = zalloc(sizeof(struct path));
|
||
|
@@ -449,18 +451,18 @@ main (int argc, char **argv)
|
||
|
if (optind<argc)
|
||
|
strncpy(ref_path->dev_t, argv[optind], WORD_SIZE);
|
||
|
|
||
|
- get_serial(ref_path->serial, ref_path->dev_t);
|
||
|
+ get_serial(ref_path->serial, SERIAL_SIZE, ref_path->dev_t);
|
||
|
|
||
|
if (!ref_path->serial || !strlen(ref_path->serial))
|
||
|
exit_tool(0);
|
||
|
|
||
|
pathvec = vector_alloc();
|
||
|
- controlers = vector_alloc();
|
||
|
+ controllers = vector_alloc();
|
||
|
|
||
|
get_paths(pathvec);
|
||
|
- get_controlers(controlers, pathvec);
|
||
|
- max_path_count = get_max_path_count(controlers);
|
||
|
- cp = find_controler(controlers, ref_path->serial);
|
||
|
+ get_controllers(controllers, pathvec);
|
||
|
+ max_path_count = get_max_path_count(controllers);
|
||
|
+ cp = find_controller(controllers, ref_path->serial);
|
||
|
|
||
|
if (!cp) {
|
||
|
debug("no other active path on serial %s\n",
|
||
|
diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile
|
||
|
new file mode 100644
|
||
|
index 0000000..a0249a5
|
||
|
--- /dev/null
|
||
|
+++ b/path_priority/pp_hds_modular/Makefile
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+EXEC = mpath_prio_hds_modular
|
||
|
+BUILD = glibc
|
||
|
+OBJS = pp_hds_modular.o
|
||
|
+
|
||
|
+TOPDIR = ../..
|
||
|
+include $(TOPDIR)/Makefile.inc
|
||
|
+
|
||
|
+all: $(BUILD)
|
||
|
+
|
||
|
+glibc: $(OBJS)
|
||
|
+ $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
|
||
|
+
|
||
|
+klibc: $(OBJS)
|
||
|
+ $(CC) -static -o $(EXEC) $(OBJS)
|
||
|
+
|
||
|
+install: $(EXEC)
|
||
|
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
||
|
+
|
||
|
+uninstall:
|
||
|
+ rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
|
+clean:
|
||
|
+ rm -f *.o $(EXEC)
|
||
|
diff --git a/path_priority/pp_hds_modular/pp_hds_modular.c b/path_priority/pp_hds_modular/pp_hds_modular.c
|
||
|
new file mode 100644
|
||
|
index 0000000..f38ebcf
|
||
|
--- /dev/null
|
||
|
+++ b/path_priority/pp_hds_modular/pp_hds_modular.c
|
||
|
@@ -0,0 +1,252 @@
|
||
|
+/*
|
||
|
+ * (C) Copyright HDS GmbH 2006. All Rights Reserved.
|
||
|
+ *
|
||
|
+ * pp_hds_modular.c
|
||
|
+ * Version 1.12
|
||
|
+ *
|
||
|
+ * Prioritizer for multipath tools device mapper and HDS Storage
|
||
|
+ *
|
||
|
+ * Hitachis Modular Storage contains two controllers for redundancy. The
|
||
|
+ * Storage internal LUN (LDEV) will normally allocated via two pathes to the
|
||
|
+ * server (one path per controller). For performance reasons should the server
|
||
|
+ * access to a LDEV only via one controller. The other path to the other
|
||
|
+ * controller is stand-by. It is also possible to allocate more as one path
|
||
|
+ * for a LDEV per controller. Here is active/active access allowed. The other
|
||
|
+ * pathes via the other controller are stand-by.
|
||
|
+ *
|
||
|
+ * This prioritizer checks with inquiry commands the represented LDEV and
|
||
|
+ * Controller number and gives back a priority followed by this scheme :
|
||
|
+ *
|
||
|
+ * CONTROLLER ODD and LDEV ODD: PRIORITY 1
|
||
|
+ * CONTROLLER ODD and LDEV EVEN: PRIORITY 0
|
||
|
+ * CONTROLLER EVEN and LDEV ODD: PRIORITY 0
|
||
|
+ * CONTROLLER EVEN and LDEV EVEN: PRIORITY 1
|
||
|
+ *
|
||
|
+ * In the storage you can define for each LDEV a owner controller. If the
|
||
|
+ * server makes IOs via the other controller the storage will switch the
|
||
|
+ * ownership automatically. In this case you can see in the storage that the
|
||
|
+ * current controller is different from the default controller, but this is
|
||
|
+ * absolutely no problem.
|
||
|
+ *
|
||
|
+ * With this prioritizer it is possible to establish a static load balancing.
|
||
|
+ * Half of the LUNs are accessed via one HBA/storage controller and the other
|
||
|
+ * half via the other HBA/storage controller.
|
||
|
+ *
|
||
|
+ * In cluster environmemnts (RAC) it also guarantees that all cluster nodes
|
||
|
+ * have access to the LDEVs via the same controller.
|
||
|
+ *
|
||
|
+ * You can run the prioritizer manually in verbose mode :
|
||
|
+ * # pp_hds_modular -v 8:224
|
||
|
+ * VENDOR: HITACHI
|
||
|
+ * PRODUCT: DF600F-CM
|
||
|
+ * SERIAL: 0x0105
|
||
|
+ * LDEV: 0x00C6
|
||
|
+ * CTRL: 1
|
||
|
+ * PORT: B
|
||
|
+ * CTRL ODD, LDEV EVEN, PRIO 0
|
||
|
+ *
|
||
|
+ * The items VENDOR and PRODUCT helps you to make the correct entries in file
|
||
|
+ * /etc/multipath.conf :
|
||
|
+ * # cat /etc/multipath.conf
|
||
|
+ * ...
|
||
|
+ * devices {
|
||
|
+ * device {
|
||
|
+ * vendor "HITACHI"
|
||
|
+ * product "DF600F"
|
||
|
+ * path_grouping_policy group_by_prio
|
||
|
+ * prio_callout "/sbin/pp_hds_modular %d"
|
||
|
+ * path_checker readsector0
|
||
|
+ * getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
|
||
|
+ * failback immediate
|
||
|
+ * }
|
||
|
+ * device {
|
||
|
+ * vendor "HITACHI"
|
||
|
+ * product "DF600F-CM"
|
||
|
+ * path_grouping_policy group_by_prio
|
||
|
+ * prio_callout "/sbin/pp_hds_modular %d"
|
||
|
+ * path_checker readsector0
|
||
|
+ * getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
|
||
|
+ * failback immediate
|
||
|
+ *
|
||
|
+ *
|
||
|
+ * Author: Matthias Rudolph <matthias.rudolph@hds.com>
|
||
|
+ *
|
||
|
+ * This file is released under the GPL.
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#include <unistd.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <sys/ioctl.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <libdevmapper.h>
|
||
|
+#include <memory.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <scsi/sg.h> /* take care: fetches glibc's /usr/include/scsi/sg.h */
|
||
|
+
|
||
|
+#define INQ_REPLY_LEN 255
|
||
|
+#define INQ_CMD_CODE 0x12
|
||
|
+#define INQ_CMD_LEN 6
|
||
|
+#define FILE_NAME_SIZE 255
|
||
|
+#define safe_sprintf(var, format, args...) \
|
||
|
+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
|
||
|
+#define safe_snprintf(var, size, format, args...) \
|
||
|
+ snprintf(var, size, format, ##args) >= size
|
||
|
+
|
||
|
+int verbose;
|
||
|
+
|
||
|
+int hds_modular_prio(char * major_minor)
|
||
|
+{
|
||
|
+ int sg_fd, k, i;
|
||
|
+ char vendor[32];
|
||
|
+ char product[32];
|
||
|
+ char serial[32];
|
||
|
+ char ldev[32];
|
||
|
+ char ctrl[32];
|
||
|
+ char port[32];
|
||
|
+ char devpath[FILE_NAME_SIZE];
|
||
|
+ unsigned int major;
|
||
|
+ unsigned int minor;
|
||
|
+ unsigned char inqCmdBlk[INQ_CMD_LEN] =
|
||
|
+ {INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0};
|
||
|
+ unsigned char inqBuff[INQ_REPLY_LEN];
|
||
|
+ unsigned char sense_buffer[32];
|
||
|
+ sg_io_hdr_t io_hdr;
|
||
|
+
|
||
|
+ sscanf(major_minor, "%u:%u", &major, &minor);
|
||
|
+ memset(devpath, 0, FILE_NAME_SIZE);
|
||
|
+
|
||
|
+ if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
|
||
|
+ major, minor))
|
||
|
+ exit(1);
|
||
|
+
|
||
|
+ unlink (devpath);
|
||
|
+ mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor));
|
||
|
+
|
||
|
+ if ((sg_fd = open(devpath, O_RDONLY)) < 0) exit(1);
|
||
|
+ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
|
||
|
+ exit(1);
|
||
|
+
|
||
|
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
|
||
|
+ io_hdr.interface_id = 'S';
|
||
|
+ io_hdr.cmd_len = sizeof(inqCmdBlk);
|
||
|
+ io_hdr.mx_sb_len = sizeof(sense_buffer);
|
||
|
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
|
+ io_hdr.dxfer_len = INQ_REPLY_LEN;
|
||
|
+ io_hdr.dxferp = inqBuff;
|
||
|
+ io_hdr.cmdp = inqCmdBlk;
|
||
|
+ io_hdr.sbp = sense_buffer;
|
||
|
+ io_hdr.timeout = 2000; /* TimeOut = 2 seconds */
|
||
|
+
|
||
|
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) exit(1);
|
||
|
+ if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) exit(1);
|
||
|
+
|
||
|
+ for (i = 0; i < 8 ; i++) vendor[i] = inqBuff[i+8];
|
||
|
+ vendor[8] = 0;
|
||
|
+ for (i = 0; i < 16 ; i++) product[i] = inqBuff[i+16];
|
||
|
+ product[16] = 0;
|
||
|
+ for (i = 0; i < 4 ; i++) serial[i] = inqBuff[i+40];
|
||
|
+ serial[4] = 0;
|
||
|
+ for (i = 0; i < 4 ; i++) ldev[i] = inqBuff[i+44];
|
||
|
+ ldev[4] = 0;
|
||
|
+ ctrl[0] = inqBuff[49];
|
||
|
+ ctrl[1] = 0;
|
||
|
+ port[0] = inqBuff[50];
|
||
|
+ port[1] = 0;
|
||
|
+
|
||
|
+ close(sg_fd);
|
||
|
+
|
||
|
+ if (1 == verbose) {
|
||
|
+ printf("VENDOR: %s\n", vendor);
|
||
|
+ printf("PRODUCT: %s\n", product);
|
||
|
+ printf("SERIAL: 0x%s\n", serial);
|
||
|
+ printf("LDEV: 0x%s\n", ldev);
|
||
|
+ printf("CTRL: %s\n", ctrl);
|
||
|
+ printf("PORT: %s\n", port);
|
||
|
+ }
|
||
|
+ switch( ctrl[0] ) {
|
||
|
+ case '0': case '2': case '4': case '6': case '8':
|
||
|
+ switch( ldev[3] ) {
|
||
|
+ case '0': case '2': case '4': case '6':
|
||
|
+ case '8': case 'A': case 'C': case 'E':
|
||
|
+ if (1 == verbose)
|
||
|
+ printf("CTRL EVEN, LDEV EVEN, "
|
||
|
+ "PRIO 1\n");
|
||
|
+ return 1;
|
||
|
+ break;
|
||
|
+ case '1': case '3': case '5': case '7':
|
||
|
+ case '9': case 'B': case 'D': case 'F':
|
||
|
+ if (1 == verbose)
|
||
|
+ printf("CTRL EVEN, LDEV ODD, "
|
||
|
+ "PRIO 0\n");
|
||
|
+ return 0;
|
||
|
+ break;
|
||
|
+
|
||
|
+ }
|
||
|
+ case '1': case '3': case '5': case '7': case '9':
|
||
|
+ switch( ldev[3] ) {
|
||
|
+ case '0': case '2': case '4': case '6':
|
||
|
+ case '8': case 'A': case 'C': case 'E':
|
||
|
+ if (1 == verbose)
|
||
|
+ printf("CTRL ODD, LDEV EVEN, "
|
||
|
+ "PRIO 0\n");
|
||
|
+ return 0;
|
||
|
+ break;
|
||
|
+ case '1': case '3': case '5': case '7':
|
||
|
+ case '9': case 'B': case 'D': case 'F':
|
||
|
+ if (1 == verbose)
|
||
|
+ printf("CTRL ODD, LDEV ODD, "
|
||
|
+ "PRIO 1\n");
|
||
|
+ return 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ exit(1);
|
||
|
+}
|
||
|
+
|
||
|
+void print_help(void)
|
||
|
+{
|
||
|
+ printf("Usage: "
|
||
|
+ "pp_hds_modular [-v] <device_major:device_minor>\n");
|
||
|
+ printf("Option: "
|
||
|
+ "-v verbose mode\n");
|
||
|
+ printf("Description: "
|
||
|
+ "Prioritizer for Multipath Tools and HDS Storage\n");
|
||
|
+ printf("Version: "
|
||
|
+ "1.12\n");
|
||
|
+ printf("Author: "
|
||
|
+ "Matthias Rudolph <matthias.rudolph@hds.com>\n");
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char * argv[])
|
||
|
+{
|
||
|
+ int prio;
|
||
|
+
|
||
|
+ if (2 == argc) {
|
||
|
+ if (0 == strcmp(argv[1], "-h")) {
|
||
|
+ print_help();
|
||
|
+ exit(0);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ verbose = 0;
|
||
|
+ prio = hds_modular_prio(argv[1]);
|
||
|
+ printf("%d\n", prio);
|
||
|
+ exit(0);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((3 == argc) && (0 == strcmp(argv[1], "-v"))) {
|
||
|
+ verbose = 1;
|
||
|
+ prio = hds_modular_prio(argv[2]);
|
||
|
+ printf("%d\n", prio);
|
||
|
+ exit(0);
|
||
|
+ }
|
||
|
+ print_help();
|
||
|
+ exit(1);
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/path_priority/pp_tpc/pp_tpc.c b/path_priority/pp_tpc/pp_tpc.c
|
||
|
index 76e7c47..a7ed7ad 100644
|
||
|
--- a/path_priority/pp_tpc/pp_tpc.c
|
||
|
+++ b/path_priority/pp_tpc/pp_tpc.c
|
||
|
@@ -62,18 +62,13 @@ int sgi_tpc_prio(const char *dev)
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- if ( /* Auto-volume Transfer Enabled */
|
||
|
- (sense_buffer[8] & 0x80) != 0x80 ) {
|
||
|
- fprintf(stderr, "Auto-volume Transfer not enabled");
|
||
|
- }
|
||
|
-
|
||
|
if ( /* Current Volume Path Bit */
|
||
|
( sense_buffer[8] & 0x01) == 0x01 ) {
|
||
|
/*
|
||
|
* This volume was owned by the controller receiving
|
||
|
* the inquiry command.
|
||
|
*/
|
||
|
- ret |= 0x02;
|
||
|
+ ret |= 0x01;
|
||
|
}
|
||
|
|
||
|
/* Volume Preferred Path Priority */
|
||
|
@@ -83,7 +78,7 @@ int sgi_tpc_prio(const char *dev)
|
||
|
* Access to this volume is most preferred through
|
||
|
* this path and other paths with this value.
|
||
|
*/
|
||
|
- ret |= 0x04;
|
||
|
+ ret |= 0x02;
|
||
|
break;
|
||
|
case 0x02:
|
||
|
/*
|
||
|
@@ -91,8 +86,7 @@ int sgi_tpc_prio(const char *dev)
|
||
|
* as a secondary path. Typically this path would be used
|
||
|
* for fail-over situations.
|
||
|
*/
|
||
|
- ret |= 0x01;
|
||
|
- break;
|
||
|
+ /* Fallthrough */
|
||
|
default:
|
||
|
/* Reserved values */
|
||
|
break;
|