1
0
multipath-tools/multipath-tools-git-update.patch

6913 lines
183 KiB
Diff

Makefile | 4 +
devmap_name/devmap_name.8 | 2 +-
kpartx/dasd.c | 28 +-
kpartx/devmapper.c | 46 +++-
kpartx/devmapper.h | 4 +-
kpartx/kpartx.8 | 2 +-
kpartx/kpartx.c | 15 +-
libcheckers/Makefile | 2 +-
libcheckers/checkers.c | 13 +-
libcheckers/checkers.h | 61 +++-
libcheckers/emc_clariion.c | 157 ++++++--
libcheckers/hp_sw.c | 3 +-
libcheckers/libsg.c | 79 ++++
libcheckers/libsg.h | 8 +
libcheckers/rdac.c | 109 +++++
libcheckers/rdac.h | 8 +
libcheckers/readsector0.c | 76 +----
libcheckers/tur.c | 2 +-
libmultipath/Makefile | 9 +-
libmultipath/alias.c | 97 +++--
libmultipath/blacklist.c | 179 ++++++++--
libmultipath/blacklist.h | 21 +-
libmultipath/config.c | 100 ++++-
libmultipath/config.h | 15 +-
libmultipath/configure.c | 74 ++--
libmultipath/configure.h | 2 +-
libmultipath/debug.c | 5 +-
libmultipath/debug.h | 4 +-
libmultipath/defaults.h | 1 +
libmultipath/devmapper.c | 111 +++++-
libmultipath/devmapper.h | 3 +-
libmultipath/dict.c | 229 +++++++++++-
libmultipath/discovery.c | 51 ++-
libmultipath/discovery.h | 6 +-
libmultipath/dmparser.c | 19 +-
libmultipath/hwtable.c | 198 ++++++++--
libmultipath/lock.c | 8 +
libmultipath/lock.h | 22 +
libmultipath/parser.c | 15 +-
libmultipath/parser.h | 1 +
libmultipath/pgpolicies.h | 2 +-
libmultipath/print.c | 266 ++++++++++++-
libmultipath/print.h | 3 +
libmultipath/propsel.c | 71 +++-
libmultipath/propsel.h | 1 +
libmultipath/structs.c | 15 +-
libmultipath/structs.h | 21 +-
libmultipath/structs_vec.c | 95 +++++-
libmultipath/structs_vec.h | 14 +-
libmultipath/switchgroup.c | 2 +-
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 | 22 +-
multipath.conf.synthetic | 6 +-
multipath/main.c | 36 ++-
multipath/main.h | 39 --
multipath/multipath.8 | 15 +-
multipathd/cli.c | 232 ++++++++++--
multipathd/cli.h | 7 +
multipathd/cli_handlers.c | 94 +++++-
multipathd/cli_handlers.h | 2 +
multipathd/main.c | 439 +++------------------
multipathd/multipathd.8 | 96 ++++-
multipathd/uxclnt.c | 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 +-
76 files changed, 3026 insertions(+), 958 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/dasd.c b/kpartx/dasd.c
index 69b9807..f31111f 100644
--- a/kpartx/dasd.c
+++ b/kpartx/dasd.c
@@ -40,14 +40,20 @@
#include "byteorder.h"
#include "dasd.h"
+unsigned long sectors512(unsigned long sectors, int blocksize)
+{
+ return sectors * (blocksize >> 9);
+}
+
/*
*/
int
read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
{
int retval = -1;
- int blocksize, offset, size;
+ int blocksize;
long disksize;
+ unsigned long offset, size;
dasd_information_t info;
struct hd_geometry geo;
char type[5] = {0,};
@@ -172,13 +178,13 @@ read_dasd_pt(int fd, struct slice all, s
/* disk is reserved minidisk */
blocksize = label[3];
offset = label[13];
- size = (label[7] - 1)*(blocksize >> 9);
+ size = sectors512(label[7] - 1, blocksize);
} else {
- offset = (info.label_block + 1) * (blocksize >> 9);
- size = disksize - offset;
+ offset = info.label_block + 1;
+ size = disksize;
}
- sp[0].start = offset * (blocksize >> 9);
- sp[0].size = size - offset * (blocksize >> 9);
+ sp[0].start = sectors512(offset, blocksize);
+ sp[0].size = size - sp[0].start;
retval = 1;
} else if ((strncmp(type, "VOL1", 4) == 0) &&
(!info.FBA_layout) && (!strcmp(info.type, "ECKD"))) {
@@ -214,8 +220,8 @@ read_dasd_pt(int fd, struct slice all, s
offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
size = cchh2blk(&f1.DS1EXT1.ulimit, &geo) -
offset + geo.sectors;
- sp[counter].start = offset * (blocksize >> 9);
- sp[counter].size = size * (blocksize >> 9);
+ sp[counter].start = sectors512(offset, blocksize);
+ sp[counter].size = sectors512(size, blocksize);
counter++;
blk++;
}
@@ -224,10 +230,8 @@ read_dasd_pt(int fd, struct slice all, s
/*
* Old style LNX1 or unlabeled disk
*/
- offset = (info.label_block + 1) * (blocksize >> 9);
- size = disksize - offset;
- sp[0].start = offset * (blocksize >> 9);
- sp[0].size = size - offset * (blocksize >> 9);
+ sp[0].start = sectors512(info.label_block + 1, blocksize);
+ sp[0].size = disksize - sp[0].start;
retval = 1;
}
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 <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 @@ main(int argc, char **argv){
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/Makefile b/libcheckers/Makefile
index ec8c10d..6340a68 100644
--- a/libcheckers/Makefile
+++ b/libcheckers/Makefile
@@ -6,7 +6,7 @@ BUILD = glibc
include ../Makefile.inc
-OBJS = checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o
+OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o
all: $(BUILD)
diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c
index 53770a6..a49ad59 100644
--- a/libcheckers/checkers.c
+++ b/libcheckers/checkers.c
@@ -7,6 +7,7 @@
#include "tur.h"
#include "hp_sw.h"
#include "emc_clariion.h"
+#include "rdac.h"
#include "readsector0.h"
static struct checker checkers[] = {
@@ -48,6 +49,15 @@ static struct checker checkers[] = {
},
{
.fd = 0,
+ .name = RDAC,
+ .message = "",
+ .context = NULL,
+ .check = rdac,
+ .init = rdac_init,
+ .free = rdac_free
+ },
+ {
+ .fd = 0,
.name = READSECTOR0,
.message = "",
.context = NULL,
@@ -75,8 +85,9 @@ struct checker * checker_lookup (char *
return NULL;
}
-int checker_init (struct checker * c)
+int checker_init (struct checker * c, void ** mpctxt_addr)
{
+ c->mpcontext = mpctxt_addr;
return c->init(c);
}
diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h
index ac795ed..d4dad9c 100644
--- a/libcheckers/checkers.h
+++ b/libcheckers/checkers.h
@@ -2,7 +2,44 @@
#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
@@ -14,12 +51,28 @@
#define DIRECTIO "directio"
#define TUR "tur"
#define HP_SW "hp_sw"
+#define RDAC "rdac"
#define EMC_CLARIION "emc_clariion"
#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
@@ -31,14 +84,16 @@ struct checker {
char name[CHECKER_NAME_LEN];
char message[CHECKER_MSG_LEN]; /* comm with callers */
void * context; /* store for persistent data */
+ void ** mpcontext; /* store for persistent data
+ shared multipath-wide */
int (*check)(struct checker *);
int (*init)(struct checker *); /* to allocate the context */
void (*free)(struct checker *); /* to free the context */
};
-#define MSG(c, a) snprintf((c)->message, CHECKER_MSG_LEN, a);
+#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
-int checker_init (struct checker *);
+int checker_init (struct checker *, void **);
void checker_put (struct checker *);
void checker_reset (struct checker * c);
void checker_set_fd (struct checker *, int);
diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c
index 1d7b684..384a943 100644
--- a/libcheckers/emc_clariion.c
+++ b/libcheckers/emc_clariion.c
@@ -11,25 +11,76 @@
#include <sys/ioctl.h>
#include <errno.h>
-#include "checkers.h"
-
#include "../libmultipath/sg_include.h"
+#include "libsg.h"
+#include "checkers.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
#define HEAVY_CHECK_COUNT 10
-struct emc_clariion_checker_context {
+/*
+ * Mechanism to track CLARiiON inactive snapshot LUs.
+ * This is done so that we can fail passive paths
+ * to an inactive snapshot LU even though since a
+ * simple read test would return 02/04/03 instead
+ * of 05/25/01 sensekey/ASC/ASCQ data.
+ */
+#define IS_INACTIVE_SNAP(c) (c->mpcontext ? \
+ ((struct emc_clariion_checker_LU_context *) \
+ (*c->mpcontext))->inactive_snap \
+ : 0)
+
+#define SET_INACTIVE_SNAP(c) if (c->mpcontext) \
+ ((struct emc_clariion_checker_LU_context *)\
+ (*c->mpcontext))->inactive_snap = 1
+
+#define CLR_INACTIVE_SNAP(c) if (c->mpcontext) \
+ ((struct emc_clariion_checker_LU_context *)\
+ (*c->mpcontext))->inactive_snap = 0
+
+struct emc_clariion_checker_path_context {
char wwn[16];
unsigned wwn_set;
};
+struct emc_clariion_checker_LU_context {
+ int inactive_snap;
+};
+
+extern void
+hexadecimal_to_ascii(char * wwn, char *wwnstr)
+{
+ int i,j, nbl;
+
+ for (i=0,j=0;i<16;i++) {
+ wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
+ '0' + nbl : 'a' + (nbl - 10);
+ wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
+ '0' + nbl : 'a' + (nbl - 10);
+ }
+ wwnstr[32]=0;
+}
+
int emc_clariion_init (struct checker * c)
{
- c->context = malloc(sizeof(struct emc_clariion_checker_context));
+ /*
+ * Allocate and initialize the path specific context.
+ */
+ c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
if (!c->context)
return 1;
- ((struct emc_clariion_checker_context *)c->context)->wwn_set = 0;
+ ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
+
+ /*
+ * Allocate and initialize the multi-path global context.
+ */
+ if (c->mpcontext) {
+ void * mpctxt = malloc(sizeof(int));
+ *c->mpcontext = mpctxt;
+ CLR_INACTIVE_SNAP(c);
+ }
+
return 0;
}
@@ -40,13 +91,15 @@ void emc_clariion_free (struct checker *
int emc_clariion(struct checker * c)
{
- unsigned char sense_buffer[256] = { 0, };
- unsigned char sb[128] = { 0, };
+ unsigned char sense_buffer[128] = { 0, };
+ unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
- sizeof(sb), 0};
+ sizeof(sense_buffer), 0};
struct sg_io_hdr io_hdr;
- struct emc_clariion_checker_context * ct =
- (struct emc_clariion_checker_context *)c->context;
+ struct emc_clariion_checker_path_context * ct =
+ (struct emc_clariion_checker_path_context *)c->context;
+ char wwnstr[33];
+ int ret;
memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
io_hdr.interface_id = 'S';
@@ -57,7 +110,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");
@@ -69,7 +122,8 @@ int emc_clariion(struct checker * c)
}
if (/* Verify the code page - right page & revision */
sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
- MSG(c, "emc_clariion_checker: Path unit report page in unknown format");
+ MSG(c, "emc_clariion_checker: Path unit report page in "
+ "unknown format");
return PATH_DOWN;
}
@@ -79,24 +133,24 @@ int emc_clariion(struct checker * c)
|| (sense_buffer[28] & 0x07) != 0x04
/* Arraycommpath should be set to 1 */
|| (sense_buffer[30] & 0x04) != 0x04) {
- MSG(c, "emc_clariion_checker: Path not correctly configured for failover");
+ MSG(c, "emc_clariion_checker: Path not correctly configured "
+ "for failover");
return PATH_DOWN;
}
if ( /* LUN operations should indicate normal operations */
sense_buffer[48] != 0x00) {
- MSG(c, "emc_clariion_checker: Path not available for normal operations");
+ MSG(c, "emc_clariion_checker: Path not available for normal "
+ "operations");
return PATH_SHAKY;
}
-#if 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
@@ -105,7 +159,8 @@ int emc_clariion(struct checker * c)
*/
if (ct->wwn_set) {
if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
- MSG(c, "emc_clariion_checker: Logical Unit WWN has changed!");
+ MSG(c, "emc_clariion_checker: Logical Unit WWN "
+ "has changed!");
return PATH_DOWN;
}
} else {
@@ -113,7 +168,59 @@ int emc_clariion(struct checker * c)
ct->wwn_set = 1;
}
-
- MSG(c, "emc_clariion_checker: Path healthy");
- return PATH_UP;
+ /*
+ * Issue read on active path to determine if inactive snapshot.
+ */
+ if (sense_buffer[4] == 2) {/* if active path */
+ unsigned char buf[512];
+
+ ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
+ if (ret == PATH_DOWN) {
+ hexadecimal_to_ascii(ct->wwn, wwnstr);
+
+ /*
+ * Check for inactive snapshot LU this way. Must
+ * fail these.
+ */
+ if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
+ (sbb[13]==1)) {
+ /*
+ * Do this so that we can fail even the
+ * passive paths which will return
+ * 02/04/03 not 05/25/01 on read.
+ */
+ SET_INACTIVE_SNAP(c);
+ MSG(c, "emc_clariion_checker: Active "
+ "path to inactive snapshot WWN %s.",
+ wwnstr);
+ } else
+ MSG(c, "emc_clariion_checker: Read "
+ "error for WWN %s. Sense data are "
+ "0x%x/0x%x/0x%x.", wwnstr,
+ sbb[2]&0xf, sbb[12], sbb[13]);
+ } else {
+ MSG(c, "emc_clariion_checker: Active path is "
+ "healthy.");
+ /*
+ * Remove the path from the set of paths to inactive
+ * snapshot LUs if it was in this list since the
+ * snapshot is no longer inactive.
+ */
+ CLR_INACTIVE_SNAP(c);
+ }
+ } else {
+ if (IS_INACTIVE_SNAP(c)) {
+ hexadecimal_to_ascii(ct->wwn, wwnstr);
+ MSG(c, "emc_clariion_checker: Passive "
+ "path to inactive snapshot WWN %s.",
+ wwnstr);
+ ret = PATH_DOWN;
+ } else {
+ MSG(c,
+ "emc_clariion_checker: Passive path is healthy.");
+ ret = PATH_UP; /* not ghost */
+ }
+ }
+
+ return ret;
}
diff --git a/libcheckers/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 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/libsg.c b/libcheckers/libsg.c
new file mode 100644
index 0000000..f426aaf
--- /dev/null
+++ b/libcheckers/libsg.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+#include "libsg.h"
+#include "../libmultipath/sg_include.h"
+
+int
+sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
+{
+ /* defaults */
+ int blocks = 1;
+ long long start_block = 0;
+ int bs = 512;
+ int cdbsz = 10;
+ int * diop = NULL;
+
+ unsigned char rdCmd[cdbsz];
+ unsigned char *sbb = senseBuff;
+ struct sg_io_hdr io_hdr;
+ int res;
+ int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
+ int sz_ind;
+ int retry_count = 3;
+
+ memset(rdCmd, 0, cdbsz);
+ sz_ind = 1;
+ rdCmd[0] = rd_opcode[sz_ind];
+ rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
+ rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
+ rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
+ rdCmd[5] = (unsigned char)(start_block & 0xff);
+ rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
+ rdCmd[8] = (unsigned char)(blocks & 0xff);
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = cdbsz;
+ io_hdr.cmdp = rdCmd;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = bs * blocks;
+ io_hdr.dxferp = buff;
+ io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+ io_hdr.sbp = senseBuff;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = (int)start_block;
+ if (diop && *diop)
+ io_hdr.flags |= SG_FLAG_DIRECT_IO;
+
+retry:
+ memset(senseBuff, 0, SENSE_BUFF_LEN);
+ while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
+
+ if (res < 0) {
+ if (ENOMEM == errno) {
+ return PATH_UP;
+ }
+ return PATH_DOWN;
+ }
+
+ if ((0 == io_hdr.status) &&
+ (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status)) {
+ return PATH_UP;
+ } else {
+ /*
+ * Retry if UNIT_ATTENTION check condition.
+ */
+ if ((sbb[2]&0xf) == 6) {
+ if (--retry_count)
+ goto retry;
+ }
+ return PATH_DOWN;
+ }
+}
diff --git a/libcheckers/libsg.h b/libcheckers/libsg.h
new file mode 100644
index 0000000..97c4491
--- /dev/null
+++ b/libcheckers/libsg.h
@@ -0,0 +1,8 @@
+#ifndef _LIBSG_H
+#define _LIBSG_H
+
+#define SENSE_BUFF_LEN 32
+
+int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
+
+#endif /* _LIBSG_H */
diff --git a/libcheckers/rdac.c b/libcheckers/rdac.c
new file mode 100644
index 0000000..f430488
--- /dev/null
+++ b/libcheckers/rdac.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_CMD 0x12
+#define SENSE_BUFF_LEN 32
+#define RDAC_DEF_TIMEOUT 60000
+#define SCSI_CHECK_CONDITION 0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE 0x08
+#define RECOVERED_ERROR 0x01
+
+#define MSG_RDAC_UP "rdac checker reports path is up"
+#define MSG_RDAC_DOWN "rdac checker reports path is down"
+#define MSG_RDAC_GHOST "rdac checker reports path is ghost"
+
+struct rdac_checker_context {
+ void * dummy;
+};
+
+int rdac_init (struct checker * c)
+{
+ return 0;
+}
+
+void rdac_free (struct checker * c)
+{
+ return;
+}
+
+static int
+do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
+{
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ inqCmdBlk[2] = (unsigned char) pg_op;
+ inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = RDAC_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) &&
+ (0 == io_hdr.driver_status))
+ return 0;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2)
+ sense_key = sense_buffer[1] & 0xf;
+ else
+ sense_key = sense_buffer[2] & 0xf;
+ if (RECOVERED_ERROR == sense_key)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+struct volume_access_inq
+{
+ char dontcare0[8];
+ char avtcvp;
+ char dontcare1[39];
+};
+
+extern int
+rdac(struct checker * c)
+{
+ struct volume_access_inq inq;
+
+ if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
+ MSG(c, MSG_RDAC_DOWN);
+ return PATH_DOWN;
+ }
+
+ return ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST);
+}
diff --git a/libcheckers/rdac.h b/libcheckers/rdac.h
new file mode 100644
index 0000000..d7bf812
--- /dev/null
+++ b/libcheckers/rdac.h
@@ -0,0 +1,8 @@
+#ifndef _RDAC_H
+#define _RDAC_H
+
+int rdac(struct checker *);
+int rdac_init(struct checker *);
+void rdac_free(struct checker *);
+
+#endif /* _RDAC_H */
diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c
index e368fb4..3cddfa8 100644
--- a/libcheckers/readsector0.c
+++ b/libcheckers/readsector0.c
@@ -2,21 +2,9 @@
* Copyright (c) 2004, 2005 Christophe Varoqui
*/
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define SENSE_BUFF_LEN 32
-#define DEF_TIMEOUT 60000
+#include "libsg.h"
#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
@@ -35,72 +23,14 @@ void readsector0_free (struct checker *
return;
}
-static int
-sg_read (int sg_fd, unsigned char * buff)
-{
- /* defaults */
- int blocks = 1;
- long long start_block = 0;
- int bs = 512;
- int cdbsz = 10;
- 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};
- int sz_ind;
-
- memset(rdCmd, 0, cdbsz);
- sz_ind = 1;
- rdCmd[0] = rd_opcode[sz_ind];
- rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
- rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
- rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
- rdCmd[5] = (unsigned char)(start_block & 0xff);
- rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
- rdCmd[8] = (unsigned char)(blocks & 0xff);
-
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = cdbsz;
- io_hdr.cmdp = rdCmd;
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = bs * blocks;
- io_hdr.dxferp = buff;
- io_hdr.mx_sb_len = SENSE_BUFF_LEN;
- io_hdr.sbp = senseBuff;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = (int)start_block;
- if (diop && *diop)
- io_hdr.flags |= SG_FLAG_DIRECT_IO;
-
- while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
-
- if (res < 0) {
- if (ENOMEM == errno) {
- return PATH_UP;
- }
- return PATH_DOWN;
- }
-
- if ((0 == io_hdr.status) &&
- (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status)) {
- return PATH_UP;
- } else {
- return PATH_DOWN;
- }
-}
-
extern int
readsector0 (struct checker * c)
{
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..ef561a8 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,12 +18,19 @@ 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
CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
endif
+LIBDM_API_FLUSH = $(shell objdump -T /lib/libdevmapper.so.* | grep -c dm_task_no_flush)
+
+ifeq ($(strip $(LIBDM_API_FLUSH)),1)
+ CFLAGS += -DLIBDM_API_FLUSH
+endif
+
all: $(BUILD)
prepare: $(CLEAN)
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 6d103d7..02ca087 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -166,28 +166,14 @@ fail:
static int
-lookup_binding(int fd, char *map_wwid, char **map_alias)
+lookup_binding(FILE *f, char *map_wwid, char **map_alias)
{
char buf[LINE_MAX];
- FILE *f;
unsigned int line_nr = 0;
- int scan_fd;
int id = 0;
*map_alias = NULL;
- scan_fd = dup(fd);
- if (scan_fd < 0) {
- condlog(0, "Cannot dup bindings file descriptor : %s",
- strerror(errno));
- return -1;
- }
- f = fdopen(scan_fd, "r");
- if (!f) {
- condlog(0, "cannot fdopen on bindings file descriptor : %s",
- strerror(errno));
- close(scan_fd);
- return -1;
- }
+
while (fgets(buf, LINE_MAX, f)) {
char *c, *alias, *wwid;
int curr_id;
@@ -210,43 +196,27 @@ lookup_binding(int fd, char *map_wwid, c
}
if (strcmp(wwid, map_wwid) == 0){
condlog(3, "Found matching wwid [%s] in bindings file."
- "\nSetting alias to %s", wwid, alias);
+ " Setting alias to %s", wwid, alias);
*map_alias = strdup(alias);
if (*map_alias == NULL)
condlog(0, "Cannot copy alias from bindings "
"file : %s", strerror(errno));
- fclose(f);
return id;
}
}
condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
- fclose(f);
return id;
}
static int
-rlookup_binding(int fd, char **map_wwid, char *map_alias)
+rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
{
char buf[LINE_MAX];
- FILE *f;
unsigned int line_nr = 0;
- int scan_fd;
int id = 0;
*map_wwid = NULL;
- scan_fd = dup(fd);
- if (scan_fd < 0) {
- condlog(0, "Cannot dup bindings file descriptor : %s",
- strerror(errno));
- return -1;
- }
- f = fdopen(scan_fd, "r");
- if (!f) {
- condlog(0, "cannot fdopen on bindings file descriptor : %s",
- strerror(errno));
- close(scan_fd);
- return -1;
- }
+
while (fgets(buf, LINE_MAX, f)) {
char *c, *alias, *wwid;
int curr_id;
@@ -274,12 +244,10 @@ rlookup_binding(int fd, char **map_wwid,
if (*map_wwid == NULL)
condlog(0, "Cannot copy alias from bindings "
"file : %s", strerror(errno));
- fclose(f);
return id;
}
}
condlog(3, "No matching alias [%s] in bindings file.", map_alias);
- fclose(f);
return id;
}
@@ -327,7 +295,8 @@ char *
get_user_friendly_alias(char *wwid, char *file)
{
char *alias;
- int fd, id;
+ int fd, scan_fd, id;
+ FILE *f;
if (!wwid || *wwid == '\0') {
condlog(3, "Cannot find binding for empty WWID");
@@ -337,14 +306,37 @@ get_user_friendly_alias(char *wwid, char
fd = open_bindings_file(file);
if (fd < 0)
return NULL;
- id = lookup_binding(fd, wwid, &alias);
+
+ scan_fd = dup(fd);
+ if (scan_fd < 0) {
+ condlog(0, "Cannot dup bindings file descriptor : %s",
+ strerror(errno));
+ close(fd);
+ return NULL;
+ }
+
+ f = fdopen(scan_fd, "r");
+ if (!f) {
+ condlog(0, "cannot fdopen on bindings file descriptor : %s",
+ strerror(errno));
+ close(scan_fd);
+ close(fd);
+ return NULL;
+ }
+
+ id = lookup_binding(f, wwid, &alias);
if (id < 0) {
+ fclose(f);
+ close(scan_fd);
close(fd);
return NULL;
}
+
if (!alias)
alias = allocate_binding(fd, wwid, id);
+ fclose(f);
+ close(scan_fd);
close(fd);
return alias;
}
@@ -353,7 +345,8 @@ char *
get_user_friendly_wwid(char *alias, char *file)
{
char *wwid;
- int fd, id;
+ int fd, scan_fd, id;
+ FILE *f;
if (!alias || *alias == '\0') {
condlog(3, "Cannot find binding for empty alias");
@@ -363,12 +356,34 @@ get_user_friendly_wwid(char *alias, char
fd = open_bindings_file(file);
if (fd < 0)
return NULL;
- id = rlookup_binding(fd, &wwid, alias);
+
+ scan_fd = dup(fd);
+ if (scan_fd < 0) {
+ condlog(0, "Cannot dup bindings file descriptor : %s",
+ strerror(errno));
+ close(fd);
+ return NULL;
+ }
+
+ f = fdopen(scan_fd, "r");
+ if (!f) {
+ condlog(0, "cannot fdopen on bindings file descriptor : %s",
+ strerror(errno));
+ close(scan_fd);
+ close(fd);
+ return NULL;
+ }
+
+ id = rlookup_binding(f, &wwid, alias);
if (id < 0) {
+ fclose(f);
+ close(scan_fd);
close(fd);
return NULL;
}
+ fclose(f);
+ close(scan_fd);
close(fd);
return wwid;
}
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index 6a8a681..5f7b2f5 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -2,7 +2,6 @@
* Copyright (c) 2004, 2005 Christophe Varoqui
*/
#include <stdio.h>
-
#include <checkers.h>
#include "memory.h"
@@ -14,7 +13,7 @@
#include "blacklist.h"
extern int
-store_ble (vector blist, char * str)
+store_ble (vector blist, char * str, int origin)
{
struct blentry * ble;
@@ -36,6 +35,7 @@ store_ble (vector blist, char * str)
goto out1;
ble->str = str;
+ ble->origin = origin;
vector_set_slot(blist, ble);
return 0;
out1:
@@ -63,7 +63,7 @@ alloc_ble_device (vector blist)
}
extern int
-set_ble_device (vector blist, char * vendor, char * product)
+set_ble_device (vector blist, char * vendor, char * product, int origin)
{
struct blentry_device * ble;
@@ -91,6 +91,7 @@ set_ble_device (vector blist, char * ven
}
ble->product = product;
}
+ ble->origin = origin;
return 0;
}
@@ -105,19 +106,19 @@ setup_default_blist (struct config * con
str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
if (!str)
return 1;
- if (store_ble(conf->blist_devnode, str))
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
str = STRDUP("^hd[a-z]");
if (!str)
return 1;
- if (store_ble(conf->blist_devnode, str))
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
str = STRDUP("^cciss!c[0-9]d[0-9]*");
if (!str)
return 1;
- if (store_ble(conf->blist_devnode, str))
+ if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
return 1;
vector_foreach_slot (conf->hwtable, hwe, i) {
@@ -128,7 +129,8 @@ setup_default_blist (struct config * con
VECTOR_SIZE(conf->blist_device) -1);
if (set_ble_device(conf->blist_device,
STRDUP(hwe->vendor),
- STRDUP(hwe->bl_product))) {
+ STRDUP(hwe->bl_product),
+ ORIGIN_DEFAULT)) {
FREE(ble);
return 1;
}
@@ -139,52 +141,183 @@ setup_default_blist (struct config * con
}
int
-blacklist (vector blist, char * str)
+_blacklist_exceptions (vector elist, char * str)
+{
+ int i;
+ struct blentry * ele;
+
+ vector_foreach_slot (elist, ele, i) {
+ if (!regexec(&ele->regex, str, 0, NULL, 0))
+ return 1;
+ }
+ return 0;
+}
+
+int
+_blacklist (vector blist, char * str)
{
int i;
struct blentry * ble;
vector_foreach_slot (blist, ble, i) {
- if (!regexec(&ble->regex, str, 0, NULL, 0)) {
- condlog(3, "%s: blacklisted", str);
+ if (!regexec(&ble->regex, str, 0, NULL, 0))
return 1;
- }
}
return 0;
}
int
-blacklist_device (vector blist, char * vendor, char * product)
+_blacklist_exceptions_device(vector elist, char * vendor, char * product)
+{
+ int i;
+ struct blentry_device * ble;
+
+ vector_foreach_slot (elist, ble, i) {
+ if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
+ !regexec(&ble->product_reg, product, 0, NULL, 0))
+ return 1;
+ }
+ return 0;
+}
+
+int
+_blacklist_device (vector blist, char * vendor, char * product)
{
int i;
struct blentry_device * ble;
vector_foreach_slot (blist, ble, i) {
if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
- !regexec(&ble->product_reg, product, 0, NULL, 0)) {
- condlog(3, "%s:%s: blacklisted", vendor, product);
+ !regexec(&ble->product_reg, product, 0, NULL, 0))
return 1;
- }
}
return 0;
}
+#define LOG_BLIST(M) \
+ if (vendor && product) \
+ condlog(3, "%s: (%s:%s) %s", dev, vendor, product, (M)); \
+ else if (wwid) \
+ condlog(3, "%s: (%s) %s", dev, wwid, (M)); \
+ else \
+ condlog(3, "%s: %s", dev, (M))
+
+void
+log_filter (char *dev, char *vendor, char *product, char *wwid, int r)
+{
+ /*
+ * Try to sort from most likely to least.
+ */
+ switch (r) {
+ case MATCH_NOTHING:
+ break;
+ case MATCH_DEVICE_BLIST:
+ LOG_BLIST("vendor/product blacklisted");
+ break;
+ case MATCH_WWID_BLIST:
+ LOG_BLIST("wwid blacklisted");
+ break;
+ case MATCH_DEVNODE_BLIST:
+ LOG_BLIST("device node name blacklisted");
+ break;
+ case MATCH_DEVICE_BLIST_EXCEPT:
+ LOG_BLIST("vendor/product whitelisted");
+ break;
+ case MATCH_WWID_BLIST_EXCEPT:
+ LOG_BLIST("wwid whitelisted");
+ break;
+ case MATCH_DEVNODE_BLIST_EXCEPT:
+ LOG_BLIST("device node name whitelisted");
+ break;
+ }
+}
+
int
-blacklist_path (struct config * conf, struct path * pp)
+_filter_device (vector blist, vector elist, char * vendor, char * product)
{
- if (blacklist(conf->blist_devnode, pp->dev))
- return 1;
+ if (!vendor || !product)
+ return 0;
+ if (_blacklist_exceptions_device(elist, vendor, product))
+ return MATCH_DEVICE_BLIST_EXCEPT;
+ if (_blacklist_device(blist, vendor, product))
+ return MATCH_DEVICE_BLIST;
+ return 0;
+}
- if (blacklist(conf->blist_wwid, pp->wwid))
- return 1;
+int
+filter_device (vector blist, vector elist, char * vendor, char * product)
+{
+ int r = _filter_device(blist, elist, vendor, product);
+ log_filter(NULL, vendor, product, NULL, r);
+ return r;
+}
- if (pp->vendor_id && pp->product_id &&
- blacklist_device(conf->blist_device, pp->vendor_id, pp->product_id))
- return 1;
+int
+_filter_devnode (vector blist, vector elist, char * dev)
+{
+ if (!dev)
+ return 0;
+ if (_blacklist_exceptions(elist, dev))
+ return MATCH_DEVNODE_BLIST_EXCEPT;
+ if (_blacklist(blist, dev))
+ return MATCH_DEVNODE_BLIST;
+ return 0;
+}
+
+int
+filter_devnode (vector blist, vector elist, char * dev)
+{
+ int r = _filter_devnode(blist, elist, dev);
+ log_filter(dev, NULL, NULL, NULL, r);
+ return r;
+}
+
+int
+_filter_wwid (vector blist, vector elist, char * wwid)
+{
+ if (!wwid)
+ return 0;
+ if (_blacklist_exceptions(elist, wwid))
+ return MATCH_WWID_BLIST_EXCEPT;
+ if (_blacklist(blist, wwid))
+ return MATCH_WWID_BLIST;
+ return 0;
+}
+int
+filter_wwid (vector blist, vector elist, char * wwid)
+{
+ int r = _filter_wwid(blist, elist, wwid);
+ log_filter(NULL, NULL, NULL, wwid, r);
+ return r;
+}
+
+int
+_filter_path (struct config * conf, struct path * pp)
+{
+ int r;
+
+ r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
+ if (r)
+ return r;
+ r = _filter_wwid(conf->blist_devnode, conf->elist_devnode, pp->wwid);
+ if (r)
+ return r;
+ r = _filter_device(conf->blist_device, conf->elist_device,
+ pp->vendor_id, pp->product_id);
+ if (r)
+ return r;
return 0;
}
+int
+filter_path (struct config * conf, struct path * pp)
+{
+ int r=_filter_path(conf, pp);
+ log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, r);
+ return r;
+}
+
void
free_blacklist (vector blist)
{
diff --git a/libmultipath/blacklist.h b/libmultipath/blacklist.h
index 9e2b63c..cdbebef 100644
--- a/libmultipath/blacklist.h
+++ b/libmultipath/blacklist.h
@@ -3,9 +3,18 @@
#include "regex.h"
+#define MATCH_NOTHING 0
+#define MATCH_WWID_BLIST 1
+#define MATCH_DEVICE_BLIST 2
+#define MATCH_DEVNODE_BLIST 3
+#define MATCH_WWID_BLIST_EXCEPT -MATCH_WWID_BLIST
+#define MATCH_DEVICE_BLIST_EXCEPT -MATCH_DEVICE_BLIST
+#define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST
+
struct blentry {
char * str;
regex_t regex;
+ int origin;
};
struct blentry_device {
@@ -13,15 +22,17 @@ struct blentry_device {
char * product;
regex_t vendor_reg;
regex_t product_reg;
+ int origin;
};
int setup_default_blist (struct config *);
int alloc_ble_device (vector);
-int blacklist (vector, char *);
-int blacklist_device (vector, char *, char *);
-int blacklist_path (struct config *, struct path *);
-int store_ble (vector, char *);
-int set_ble_device (vector, char *, char *);
+int filter_devnode (vector, vector, char *);
+int filter_wwid (vector, vector, char *);
+int filter_device (vector, vector, char *, char *);
+int filter_path (struct config *, struct path *);
+int store_ble (vector, char *, int);
+int set_ble_device (vector, char *, char *, int);
void free_blacklist (vector);
void free_blacklist_device (vector);
diff --git a/libmultipath/config.c b/libmultipath/config.c
index 1068755..a39af8a 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -20,26 +20,61 @@
#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;
@@ -303,9 +333,14 @@ free_config (struct config * conf)
free_blacklist(conf->blist_devnode);
free_blacklist(conf->blist_wwid);
free_blacklist_device(conf->blist_device);
+
+ free_blacklist(conf->elist_devnode);
+ free_blacklist(conf->elist_wwid);
+ free_blacklist_device(conf->elist_device);
+
free_mptable(conf->mptable);
free_hwtable(conf->hwtable);
-
+ free_keywords(conf->keywords);
FREE(conf);
}
@@ -332,6 +367,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;
@@ -372,6 +408,26 @@ load_config (char * file)
if (setup_default_blist(conf))
goto out;
+ if (conf->elist_devnode == NULL) {
+ conf->elist_devnode = vector_alloc();
+
+ if (!conf->elist_devnode)
+ goto out;
+ }
+ if (conf->elist_wwid == NULL) {
+ conf->elist_wwid = vector_alloc();
+
+ if (!conf->elist_wwid)
+ goto out;
+ }
+
+ if (conf->elist_device == NULL) {
+ conf->elist_device = vector_alloc();
+
+ if (!conf->elist_device)
+ goto out;
+ }
+
if (conf->mptable == NULL) {
conf->mptable = vector_alloc();
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 6e5633a..7caa11d 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -1,6 +1,9 @@
#ifndef _CONFIG_H
#define _CONFIG_H
+#define ORIGIN_DEFAULT 0
+#define ORIGIN_CONFIG 1
+
enum devtypes {
DEV_NONE,
DEV_DEVT,
@@ -11,6 +14,7 @@ enum devtypes {
struct hwentry {
char * vendor;
char * product;
+ char * revision;
char * getuid;
char * getprio;
char * features;
@@ -23,6 +27,7 @@ struct hwentry {
int rr_weight;
int no_path_retry;
int minio;
+ int pg_timeout;
struct checker * checker;
char * bl_product;
};
@@ -38,6 +43,7 @@ struct mpentry {
int rr_weight;
int no_path_retry;
int minio;
+ int pg_timeout;
};
struct config {
@@ -48,7 +54,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;
@@ -57,6 +63,7 @@ struct config {
int rr_weight;
int no_path_retry;
int user_friendly_names;
+ int pg_timeout;
char * dev;
char * udev_dir;
@@ -67,17 +74,21 @@ struct config {
char * hwhandler;
char * bindings_file;
+ vector keywords;
vector mptable;
vector hwtable;
vector blist_devnode;
vector blist_wwid;
vector blist_device;
+ vector elist_devnode;
+ vector elist_wwid;
+ vector elist_device;
};
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..9632fb4 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -60,6 +60,7 @@ setup_map (struct multipath * mpp)
select_rr_weight(mpp);
select_minio(mpp);
select_no_path_retry(mpp);
+ select_pg_timeout(mpp);
/*
* assign paths to path groups -- start with no groups and all paths
@@ -145,11 +146,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);
@@ -179,8 +175,9 @@ select_action (struct multipath * mpp, v
mpp->alias);
return;
}
- if (!mpp->no_path_retry && /* let features be handled by the daemon */
- strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
+ if (!mpp->no_path_retry && !mpp->pg_timeout &&
+ (strlen(cmpp->features) != strlen(mpp->features) ||
+ strcmp(cmpp->features, mpp->features))) {
mpp->action = ACT_RELOAD;
condlog(3, "%s: set ACT_RELOAD (features change)",
mpp->alias);
@@ -286,11 +283,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 +298,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 +316,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 +376,9 @@ domap (struct multipath * mpp)
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
@@ -423,7 +422,7 @@ coalesce_paths (struct vectors * vecs, v
/* 1. if path has no unique id or wwid blacklisted */
if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
- blacklist_path(conf, pp1))
+ filter_path(conf, pp1) > 0)
continue;
/* 2. if path already coalesced */
@@ -444,7 +443,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 +470,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 +485,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)
@@ -506,6 +504,12 @@ coalesce_paths (struct vectors * vecs, v
else
dm_queue_if_no_path(mpp->alias, 1);
}
+ if (mpp->pg_timeout != PGTIMEOUT_UNDEF) {
+ if (mpp->pg_timeout == -PGTIMEOUT_NONE)
+ dm_set_pg_timeout(mpp->alias, 0);
+ else
+ dm_set_pg_timeout(mpp->alias, mpp->pg_timeout);
+ }
if (newmp) {
if (mpp->action != ACT_REJECT) {
@@ -547,11 +551,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 +610,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 @@ void dlog (int sink, int prio, char * fm
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 @@ void dlog (int sink, int prio, char * fm
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/defaults.h b/libmultipath/defaults.h
index ab65492..8deeb0f 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -9,6 +9,7 @@
#define DEFAULT_FAILBACK -FAILBACK_MANUAL
#define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE
#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
+#define DEFAULT_PGTIMEOUT -PGTIMEOUT_NONE
#define DEFAULT_USER_FRIENDLY_NAMES 0
#define DEFAULT_CHECKINT 5
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 4328036..dece079 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -11,6 +11,7 @@
#include <ctype.h>
#include <linux/kdev_t.h>
#include <unistd.h>
+#include <errno.h>
#include <checkers.h>
@@ -23,6 +24,9 @@
#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, ...)
{
@@ -41,13 +45,35 @@ dm_shut_log (void)
dm_log_init(&dm_dummy_log);
}
-extern int
-dm_prereq (char * str, int x, int y, int z)
+static int
+dm_libprereq (void)
+{
+ char version[64];
+ int v[3];
+ int minv[3] = {1, 2, 11};
+
+ dm_get_library_version(version, sizeof(version));
+ condlog(3, "libdevmapper version %s", version);
+ sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]);
+
+ if ((v[0] > minv[0]) ||
+ ((v[0] == minv[0]) && (v[1] > minv[1])) ||
+ ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])))
+ return 0;
+ condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d",
+ minv[0], minv[1], minv[2]);
+ return 1;
+}
+
+static int
+dm_drvprereq (char * str)
{
int r = 2;
struct dm_task *dmt;
struct dm_versions *target;
struct dm_versions *last_target;
+ int minv[3] = {1, 0, 3};
+ unsigned int *v;
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
return 3;
@@ -58,37 +84,44 @@ dm_prereq (char * str, int x, int y, int
condlog(0, "Can not communicate with kernel DM");
goto out;
}
-
target = dm_task_get_versions(dmt);
do {
last_target = target;
-
if (!strncmp(str, target->name, strlen(str))) {
- r--;
-
- if (target->version[0] >= x &&
- target->version[1] >= y &&
- target->version[2] >= z)
- r--;
-
+ r = 1;
break;
}
-
target = (void *) target + target->next;
} while (last_target != target);
- if (r == 2)
+ if (r == 2) {
condlog(0, "DM multipath kernel driver not loaded");
- else if (r == 1)
- condlog(0, "DM multipath kernel driver version too old");
-
+ goto out;
+ }
+ v = target->version;
+ if ((v[0] > minv[0]) ||
+ ((v[0] == minv[0]) && (v[1] > minv[1])) ||
+ ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2]))) {
+ r = 0;
+ goto out;
+ }
+ condlog(0, "DM multipath kernel driver must be >= %u.%.2u.%.2u",
+ minv[0], minv[1], minv[2]);
out:
dm_task_destroy(dmt);
return r;
}
extern int
+dm_prereq (char * str)
+{
+ if (dm_libprereq())
+ return 1;
+ return dm_drvprereq(str);
+}
+
+extern int
dm_simplecmd (int task, const char *name) {
int r = 0;
struct dm_task *dmt;
@@ -100,6 +133,10 @@ dm_simplecmd (int task, const char *name
goto out;
dm_task_no_open_count(dmt);
+ dm_task_skip_lockfs(dmt); /* for DM_DEVICE_RESUME */
+#ifdef LIBDM_API_FLUSH
+ dm_task_no_flush(dmt); /* for DM_DEVICE_SUSPEND/RESUME */
+#endif
r = dm_task_run (dmt);
@@ -113,6 +150,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 +161,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 +254,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 +267,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
@@ -509,6 +565,16 @@ dm_queue_if_no_path(char *mapname, int e
return dm_message(mapname, message);
}
+int
+dm_set_pg_timeout(char *mapname, int timeout_val)
+{
+ char message[24];
+
+ if (snprintf(message, 24, "set_pg_timeout %d", timeout_val) >= 24)
+ return 1;
+ return dm_message(mapname, message);
+}
+
static int
dm_groupmsg (char * msg, char * mapname, int index)
{
@@ -591,6 +657,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/devmapper.h b/libmultipath/devmapper.h
index c7879a7..59afd01 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -1,6 +1,6 @@
void dm_shut_log(void);
void dm_restore_log(void);
-int dm_prereq (char *, int, int, int);
+int dm_prereq (char *);
int dm_simplecmd (int, const char *);
int dm_addmap (int, const char *, const char *, const char *,
unsigned long long, const char *uuid);
@@ -13,6 +13,7 @@ int dm_flush_maps (char *);
int dm_fail_path(char * mapname, char * path);
int dm_reinstate_path(char * mapname, char * path);
int dm_queue_if_no_path(char *mapname, int enable);
+int dm_set_pg_timeout(char *mapname, int timeout_val);
int dm_switchgroup(char * mapname, int index);
int dm_enablegroup(char * mapname, int index);
int dm_disablegroup(char * mapname, int index);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 9ca228a..c705cc6 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -201,6 +201,32 @@ def_no_path_retry_handler(vector strvec)
}
static int
+def_pg_timeout_handler(vector strvec)
+{
+ int pg_timeout;
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ if (strlen(buff) == 4 && !strcmp(buff, "none"))
+ conf->pg_timeout = -PGTIMEOUT_NONE;
+ else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+ if (pg_timeout == 0)
+ conf->pg_timeout = -PGTIMEOUT_NONE;
+ else
+ conf->pg_timeout = pg_timeout;
+ }
+ else
+ conf->pg_timeout = PGTIMEOUT_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
+static int
names_handler(vector strvec)
{
char * buff;
@@ -238,6 +264,19 @@ blacklist_handler(vector strvec)
}
static int
+blacklist_exceptions_handler(vector strvec)
+{
+ conf->elist_devnode = vector_alloc();
+ conf->elist_wwid = vector_alloc();
+ conf->elist_device = vector_alloc();
+
+ if (!conf->elist_devnode || !conf->elist_wwid || !conf->blist_device)
+ return 1;
+
+ return 0;
+}
+
+static int
ble_devnode_handler(vector strvec)
{
char * buff;
@@ -247,7 +286,20 @@ ble_devnode_handler(vector strvec)
if (!buff)
return 1;
- return store_ble(conf->blist_devnode, buff);
+ return store_ble(conf->blist_devnode, buff, ORIGIN_CONFIG);
+}
+
+static int
+ble_except_devnode_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return store_ble(conf->elist_devnode, buff, ORIGIN_CONFIG);
}
static int
@@ -260,7 +312,20 @@ ble_wwid_handler(vector strvec)
if (!buff)
return 1;
- return store_ble(conf->blist_wwid, buff);
+ return store_ble(conf->blist_wwid, buff, ORIGIN_CONFIG);
+}
+
+static int
+ble_except_wwid_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return store_ble(conf->elist_wwid, buff, ORIGIN_CONFIG);
}
static int
@@ -270,6 +335,12 @@ ble_device_handler(vector strvec)
}
static int
+ble_except_device_handler(vector strvec)
+{
+ return alloc_ble_device(conf->elist_device);
+}
+
+static int
ble_vendor_handler(vector strvec)
{
char * buff;
@@ -279,7 +350,20 @@ ble_vendor_handler(vector strvec)
if (!buff)
return 1;
- return set_ble_device(conf->blist_device, buff, NULL);
+ return set_ble_device(conf->blist_device, buff, NULL, ORIGIN_CONFIG);
+}
+
+static int
+ble_except_vendor_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return set_ble_device(conf->elist_device, buff, NULL, ORIGIN_CONFIG);
}
static int
@@ -292,7 +376,20 @@ ble_product_handler(vector strvec)
if (!buff)
return 1;
- return set_ble_device(conf->blist_device, NULL, buff);
+ return set_ble_device(conf->blist_device, NULL, buff, ORIGIN_CONFIG);
+}
+
+static int
+ble_except_product_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return set_ble_device(conf->elist_device, NULL, buff, ORIGIN_CONFIG);
}
/*
@@ -585,6 +682,36 @@ hw_minio_handler(vector strvec)
return 0;
}
+static int
+hw_pg_timeout_handler(vector strvec)
+{
+ int pg_timeout;
+ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+ char *buff;
+
+ if (!hwe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ if (strlen(buff) == 4 && !strcmp(buff, "none"))
+ hwe->pg_timeout = -PGTIMEOUT_NONE;
+ else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+ if (pg_timeout == 0)
+ hwe->pg_timeout = -PGTIMEOUT_NONE;
+ else
+ hwe->pg_timeout = pg_timeout;
+ }
+ else
+ hwe->pg_timeout = PGTIMEOUT_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
/*
* multipaths block handlers
*/
@@ -777,6 +904,35 @@ mp_minio_handler(vector strvec)
return 0;
}
+static int
+mp_pg_timeout_handler(vector strvec)
+{
+ int pg_timeout;
+ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+ char *buff;
+
+ if (!mpe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+ if (strlen(buff) == 4 && !strcmp(buff, "none"))
+ mpe->pg_timeout = -PGTIMEOUT_NONE;
+ else if (sscanf(buff, "%d", &pg_timeout) == 1 && pg_timeout >= 0) {
+ if (pg_timeout == 0)
+ mpe->pg_timeout = -PGTIMEOUT_NONE;
+ else
+ mpe->pg_timeout = pg_timeout;
+ }
+ else
+ mpe->pg_timeout = PGTIMEOUT_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
/*
* config file keywords printing
*/
@@ -896,6 +1052,22 @@ snprint_mp_rr_min_io (char * buff, int l
}
static int
+snprint_mp_pg_timeout (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ switch (mpe->pg_timeout) {
+ case PGTIMEOUT_UNDEF:
+ break;
+ case -PGTIMEOUT_NONE:
+ return snprintf(buff, len, "none");
+ default:
+ return snprintf(buff, len, "%i", mpe->pg_timeout);
+ }
+ return 0;
+}
+
+static int
snprint_hw_vendor (char * buff, int len, void * data)
{
struct hwentry * hwe = (struct hwentry *)data;
@@ -1097,6 +1269,27 @@ snprint_hw_rr_min_io (char * buff, int l
}
static int
+snprint_hw_pg_timeout (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->pg_timeout)
+ return 0;
+ if (hwe->pg_timeout == conf->pg_timeout)
+ return 0;
+
+ switch (hwe->pg_timeout) {
+ case PGTIMEOUT_UNDEF:
+ break;
+ case -PGTIMEOUT_NONE:
+ return snprintf(buff, len, "none");
+ default:
+ return snprintf(buff, len, "%i", hwe->pg_timeout);
+ }
+ return 0;
+}
+
+static int
snprint_hw_path_checker (char * buff, int len, void * data)
{
struct hwentry * hwe = (struct hwentry *)data;
@@ -1268,6 +1461,23 @@ snprint_def_no_path_retry (char * buff,
}
static int
+snprint_def_pg_timeout (char * buff, int len, void * data)
+{
+ if (conf->pg_timeout == DEFAULT_PGTIMEOUT)
+ return 0;
+
+ switch (conf->pg_timeout) {
+ case PGTIMEOUT_UNDEF:
+ break;
+ case -PGTIMEOUT_NONE:
+ return snprintf(buff, len, "none");
+ default:
+ return snprintf(buff, len, "%i", conf->pg_timeout);
+ }
+ return 0;
+}
+
+static int
snprint_def_user_friendly_names (char * buff, int len, void * data)
{
if (conf->user_friendly_names == DEFAULT_USER_FRIENDLY_NAMES)
@@ -1320,6 +1530,7 @@ init_keywords(void)
install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
+ install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout);
install_keyword("user_friendly_names", &names_handler, &snprint_def_user_friendly_names);
__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
@@ -1336,6 +1547,14 @@ init_keywords(void)
install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
install_keyword("product", &ble_product_handler, &snprint_bled_product);
install_sublevel_end();
+ install_keyword_root("blacklist_exceptions", &blacklist_exceptions_handler);
+ install_keyword("devnode", &ble_except_devnode_handler, &snprint_ble_simple);
+ install_keyword("wwid", &ble_except_wwid_handler, &snprint_ble_simple);
+ install_keyword("device", &ble_except_device_handler, NULL);
+ install_sublevel();
+ install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor);
+ install_keyword("product", &ble_except_product_handler, &snprint_bled_product);
+ install_sublevel_end();
#if 0
__deprecated install_keyword_root("devnode_blacklist", &blacklist_handler);
@@ -1365,6 +1584,7 @@ init_keywords(void)
install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
+ install_keyword("pg_timeout", &hw_pg_timeout_handler, &snprint_hw_pg_timeout);
install_sublevel_end();
install_keyword_root("multipaths", &multipaths_handler);
@@ -1378,5 +1598,6 @@ init_keywords(void)
install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_rr_min_io);
+ install_keyword("pg_timeout", &mp_pg_timeout_handler, &snprint_mp_pg_timeout);
install_sublevel_end();
}
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index cf8289c..a196583 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -61,7 +61,8 @@ path_discover (vector pathvec, struct co
if (!devname)
return 0;
- if (blacklist(conf->blist_devnode, devname))
+ if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
+ devname) > 0)
return 0;
if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
@@ -112,7 +113,7 @@ out:
* not multipath(8), ran by udev
*/
#if DAEMON
-#define WAIT_MAX_SECONDS 5
+#define WAIT_MAX_SECONDS 60
#define WAIT_LOOP_PER_SECOND 5
static int
@@ -165,7 +166,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 +238,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 +296,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 +314,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 +340,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 +443,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 +527,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 +600,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);
}
@@ -609,12 +612,15 @@ get_state (struct path * pp)
{
struct checker * c = &pp->checker;
+ if (!pp->mpp)
+ return 0;
+
if (!checker_selected(c)) {
select_checker(pp);
if (!checker_selected(c))
return 1;
checker_set_fd(c, pp->fd);
- if (checker_init(c))
+ if (checker_init(c, &pp->mpp->mpcontext))
return 1;
}
pp->state = checker_check(c);
@@ -636,14 +642,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 +705,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 even for not PATH_UP paths if it has never
+ * been successfully obtained before.
+ */
+ if (mask & DI_PRIO &&
+ (pp->state == PATH_UP || 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 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 @@
#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 @@ disassemble_map (vector pathvec, char *
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..df6f5aa 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -12,13 +12,34 @@
* 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
@@ -117,10 +170,10 @@ static struct hwentry default_hw[] = {
.rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_UNDEF,
.minio = DEFAULT_MINIO,
- .checker_name = READSECTOR0,
+ .checker_name = DIRECTIO,
},
/*
- * EMC / Clariion controler family
+ * EMC / Clariion controller family
*
* Maintainer : Edward Goggin, EMC
* Mail : egoggin@emc.com
@@ -142,7 +195,7 @@ static struct hwentry default_hw[] = {
},
{
.vendor = "DGC",
- .product = "*",
+ .product = ".*",
.bl_product = "LUNZ",
.getuid = DEFAULT_GETUID,
.getprio = "/sbin/mpath_prio_emc /dev/%n",
@@ -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 = "/sbin/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
*/
{
@@ -236,6 +304,22 @@ static struct hwentry default_hw[] = {
.checker_name = TUR,
},
{
+ /* IBM Netfinity Fibre Channel RAID Controller Unit */
+ .vendor = "IBM",
+ .product = "3526",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/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 DS4200 / FAStT200 */
.vendor = "IBM",
.product = "3542",
@@ -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,9 +352,9 @@ 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",
.features = "1 queue_if_no_path",
@@ -292,7 +376,7 @@ static struct hwentry default_hw[] = {
.features = "1 queue_if_no_path",
.hwhandler = DEFAULT_HWHANDLER,
.selector = DEFAULT_SELECTOR,
- .pgpolicy = GROUP_BY_SERIAL,
+ .pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
.rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_UNDEF,
@@ -300,10 +384,27 @@ static struct hwentry default_hw[] = {
.checker_name = TUR,
},
{
+ /* IBM SAN Volume Controller */
+ .vendor = "IBM",
+ .product = "2145",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/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 = "/sbin/dasd_id /dev/%n",
.getprio = NULL,
.features = DEFAULT_FEATURES,
.hwhandler = DEFAULT_HWHANDLER,
@@ -315,38 +416,59 @@ 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",
.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 = "/sbin/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
+ * Maintainer : Srinivasan Ramani
+ * Mail : sramani@pillardata.com
*/
{
.vendor = "Pillar",
- .product = "Axiom 500",
+ .product = "Axiom.*",
.getuid = DEFAULT_GETUID,
- .getprio = "/sbin/mpath_prio_alua %d",
+ .getprio = "/sbin/mpath_prio_alua %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 @@
/* 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 @@
#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..e50f37d 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -5,6 +5,8 @@
#include <string.h>
#include <libdevmapper.h>
#include <stdarg.h>
+#include <sysfs/dlist.h>
+#include <sysfs/libsysfs.h>
#include <checkers.h>
@@ -13,11 +15,12 @@
#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"
+#include "blacklist.h"
#define MAX(x,y) (x > y) ? x : y
#define TAIL (line + len - 1 - c)
@@ -52,16 +55,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 +235,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 +308,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 +512,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 +531,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 +648,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 +679,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)
@@ -833,6 +853,110 @@ snprint_defaults (char * buff, int len)
}
+static int
+snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
+{
+ int threshold = MAX_LINE_LEN;
+ struct blentry * ble;
+ int pos;
+ int i;
+
+ pos = *fwd;
+ if (!VECTOR_SIZE(*vec)) {
+ if ((len - pos - threshold) <= 0)
+ return 0;
+ pos += snprintf(buff + pos, len - pos, " <empty>\n");
+ } else vector_foreach_slot (*vec, ble, i) {
+ if ((len - pos - threshold) <= 0)
+ return 0;
+ if (ble->origin == ORIGIN_CONFIG)
+ pos += snprintf(buff + pos, len - pos, " (config file rule) ");
+ else if (ble->origin == ORIGIN_DEFAULT)
+ pos += snprintf(buff + pos, len - pos, " (default rule) ");
+ pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
+ }
+
+ *fwd = pos;
+ return pos;
+}
+
+static int
+snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
+{
+ int threshold = MAX_LINE_LEN;
+ struct blentry_device * bled;
+ int pos;
+ int i;
+
+ pos = *fwd;
+ if (!VECTOR_SIZE(*vec)) {
+ if ((len - pos - threshold) <= 0)
+ return 0;
+ pos += snprintf(buff + pos, len - pos, " <empty>\n");
+ } else vector_foreach_slot (*vec, bled, i) {
+ if ((len - pos - threshold) <= 0)
+ return 0;
+ if (bled->origin == ORIGIN_CONFIG)
+ pos += snprintf(buff + pos, len - pos, " (config file rule) ");
+ else if (bled->origin == ORIGIN_DEFAULT)
+ pos += snprintf(buff + pos, len - pos, " (default rule) ");
+ pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
+ }
+
+ *fwd = pos;
+ return pos;
+}
+
+extern int
+snprint_blacklist_report (char * buff, int len)
+{
+ int threshold = MAX_LINE_LEN;
+ int fwd = 0;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
+ "- blacklist:\n");
+ if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
+ return len;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+ if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
+ return len;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
+ "- blacklist:\n");
+ if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
+ return len;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+ if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
+ return len;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
+ "- blacklist:\n");
+ if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
+ return len;
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+ if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
+ return len;
+
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
extern int
snprint_blacklist (char * buff, int len)
{
@@ -895,12 +1019,126 @@ snprint_blacklist (char * buff, int len)
if (fwd > len)
return len;
}
+ fwd += snprintf(buff + fwd, len - fwd, "}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+extern int
+snprint_blacklist_except (char * buff, int len)
+{
+ int i;
+ struct blentry * ele;
+ struct blentry_device * eled;
+ int fwd = 0;
+ struct keyword *rootkw;
+ struct keyword *kw;
+
+ rootkw = find_keyword(NULL, "blacklist_exceptions");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
+ if (fwd > len)
+ return len;
+
+ vector_foreach_slot (conf->elist_devnode, ele, i) {
+ kw = find_keyword(rootkw->sub, "devnode");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+ kw, ele);
+ if (fwd > len)
+ return len;
+ }
+ vector_foreach_slot (conf->elist_wwid, ele, i) {
+ kw = find_keyword(rootkw->sub, "wwid");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+ kw, ele);
+ if (fwd > len)
+ return len;
+ }
+ rootkw = find_keyword(rootkw->sub, "device");
+ if (!rootkw)
+ return 0;
+ vector_foreach_slot (conf->elist_device, eled, i) {
+ fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
+ if (fwd > len)
+ return len;
+ kw = find_keyword(rootkw->sub, "vendor");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, eled);
+ if (fwd > len)
+ return len;
+ kw = find_keyword(rootkw->sub, "product");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, eled);
+ if (fwd > len)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+ if (fwd > len)
+ return len;
+ }
fwd += snprintf(buff + fwd, len - fwd, "}\n");
if (fwd > len)
return len;
return fwd;
-
+}
+
+extern int
+snprint_devices (char * buff, int len, struct vectors *vecs)
+{
+ struct dlist * ls;
+ struct sysfs_class * class;
+ struct sysfs_class_device * dev;
+ int threshold = MAX_LINE_LEN;
+ int fwd = 0;
+ int r;
+
+ struct path * pp;
+
+ if (!(class = sysfs_open_class("block")))
+ return 0;
+
+ if (!(ls = sysfs_get_class_devices(class))) {
+ sysfs_close_class(class);
+ return 0;
+ }
+
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
+
+ dlist_for_each_data(ls, dev, struct sysfs_class_device) {
+ if ((len - fwd - threshold) <= 0)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, " %s", dev->name);
+ pp = find_path_by_dev(vecs->pathvec, dev->name);
+ if (!pp) {
+ r = filter_devnode(conf->blist_devnode,
+ conf->elist_devnode, dev->name);
+ if (r > 0)
+ fwd += snprintf(buff + fwd, len - fwd,
+ " (blacklisted)");
+ else if (r < 0)
+ fwd += snprintf(buff + fwd, len - fwd,
+ " (whitelisted)");
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "\n");
+ }
+ sysfs_close_class(class);
+
+ if (fwd > len)
+ return len;
+ return fwd;
}
extern int
diff --git a/libmultipath/print.h b/libmultipath/print.h
index 3dde45d..73c2f63 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -42,6 +42,9 @@ int snprint_multipath_topology (char *,
int verbosity);
int snprint_defaults (char *, int);
int snprint_blacklist (char *, int);
+int snprint_blacklist_except (char *, int);
+int snprint_blacklist_report (char *, int);
+int snprint_devices (char *, int, struct vectors *);
int snprint_hwtable (char *, int, vector);
int snprint_mptable (char *, int, vector);
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 79cee8b..45a3728 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -15,6 +15,7 @@
#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;
}
@@ -319,3 +330,41 @@ select_minio (struct multipath * mp)
return 0;
}
+extern int
+select_pg_timeout(struct multipath *mp)
+{
+ if (mp->mpe && mp->mpe->pg_timeout != PGTIMEOUT_UNDEF) {
+ mp->pg_timeout = mp->mpe->pg_timeout;
+ if (mp->pg_timeout > 0)
+ condlog(3, "%s: pg_timeout = %d (multipath setting)",
+ mp->alias, mp->pg_timeout);
+ else
+ condlog(3, "%s: pg_timeout = NONE (multipath setting)",
+ mp->alias);
+ return 0;
+ }
+ if (mp->hwe && mp->hwe->pg_timeout != PGTIMEOUT_UNDEF) {
+ mp->pg_timeout = mp->hwe->pg_timeout;
+ if (mp->pg_timeout > 0)
+ condlog(3, "%s: pg_timeout = %d (controller setting)",
+ mp->alias, mp->pg_timeout);
+ else
+ condlog(3, "%s: pg_timeout = NONE (controller setting)",
+ mp->alias);
+ return 0;
+ }
+ if (conf->pg_timeout != PGTIMEOUT_UNDEF) {
+ mp->pg_timeout = conf->pg_timeout;
+ if (mp->pg_timeout > 0)
+ condlog(3, "%s: pg_timeout = %d (config file default)",
+ mp->alias, mp->pg_timeout);
+ else
+ condlog(3,
+ "%s: pg_timeout = NONE (config file default)",
+ mp->alias);
+ return 0;
+ }
+ mp->pg_timeout = PGTIMEOUT_UNDEF;
+ condlog(3, "pg_timeout = NONE (internal default)");
+ return 0;
+}
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index f66a598..afd1f88 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -9,4 +9,5 @@ int select_checker(struct path *pp);
int select_getuid (struct path * pp);
int select_getprio (struct path * pp);
int select_no_path_retry(struct multipath *mp);
+int select_pg_timeout(struct multipath *mp);
int select_minio(struct multipath *mp);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 024e790..d36eaef 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -16,6 +16,7 @@
#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;
}
@@ -115,9 +117,10 @@ alloc_multipath (void)
mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
- if (mpp)
+ if (mpp) {
mpp->bestpg = 1;
-
+ mpp->mpcontext = NULL;
+ }
return mpp;
}
@@ -178,6 +181,7 @@ free_multipath (struct multipath * mpp,
free_pathvec(mpp->paths, free_paths);
free_pgvec(mpp->pg, free_paths);
+ FREE_PTR(mpp->mpcontext);
FREE(mpp);
}
@@ -365,3 +369,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..46dcdee 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_FAIL -1
#define NO_PATH_RETRY_QUEUE -2
+#define PRIO_UNDEF -1
+#define PRIO_DEFAULT 1
+
enum free_path_switch {
KEEP_PATHS,
FREE_PATHS
@@ -55,6 +58,11 @@ enum pgstates {
PGSTATE_ACTIVE
};
+enum pgtimeouts {
+ PGTIMEOUT_UNDEF,
+ PGTIMEOUT_NONE
+};
+
struct scsi_idlun {
int dev_id;
int host_unique_id;
@@ -127,6 +135,7 @@ struct multipath {
int no_path_retry; /* number of retries after all paths are down */
int retry_tick; /* remaining times for retries */
int minio;
+ int pg_timeout;
unsigned long long size;
vector paths;
vector pg;
@@ -142,7 +151,7 @@ struct multipath {
struct mpentry * mpe;
struct hwentry * hwe;
- /* daemon store a data blob for DM event waiter threads */
+ /* threads */
void * waiter;
/* stats */
@@ -151,6 +160,9 @@ struct multipath {
unsigned int stat_map_loads;
unsigned int stat_total_queueing_time;
unsigned int stat_queueing_timeouts;
+
+ /* checkers shared data */
+ void * mpcontext;
};
struct pathgroup {
@@ -183,10 +195,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..53b7e17 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -14,6 +14,7 @@
#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);
}
}
@@ -277,6 +278,7 @@ retry:
select_rr_weight(mpp);
select_pgfailback(mpp);
set_no_path_retry(mpp);
+ select_pg_timeout(mpp);
return 0;
out:
@@ -382,3 +384,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 @@ struct vectors {
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/switchgroup.c b/libmultipath/switchgroup.c
index 757543f..9b84bc2 100644
--- a/libmultipath/switchgroup.c
+++ b/libmultipath/switchgroup.c
@@ -28,7 +28,7 @@ select_path_group (struct multipath * mp
priority = 0;
vector_foreach_slot (pgp->paths, pp, j) {
- if (pp->state != PATH_DOWN)
+ if (pp->state == PATH_UP)
priority += pp->priority;
}
pgp->priority = priority;
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 @@
#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..649ff8c 100644
--- a/multipath.conf.annotated
+++ b/multipath.conf.annotated
@@ -142,6 +142,22 @@
# product MSA[15]00
# }
#}
+##
+## name : blacklist_exceptions
+## scope : multipath & multipathd
+## desc : list of device names to be treated as multipath candidates
+## even if they are on the blacklist.
+## Note: blacklist exceptions are only valid in the same class.
+## It is not possible to blacklist devices using the devnode keyword
+## and to exclude some devices of them using the wwid keyword.
+## default : -
+##
+#blacklist_exceptions {
+# devnode "^dasd[c-d]+[0-9]*"
+# wwid "IBM.75000000092461.4d00.34"
+# wwid "IBM.75000000092461.4d00.35"
+# wwid "IBM.75000000092461.4d00.36"
+#}
#
##
## name : multipaths
@@ -237,7 +253,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 +261,7 @@
# #
# # name : device
# # scope : multipath & multipathd
-# # desc : settings for this specific storage controler
+# # desc : settings for this specific storage controller
# #
# device {
# #
@@ -260,7 +276,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.conf.synthetic b/multipath.conf.synthetic
index 4a1f5a4..e5e6cd0 100644
--- a/multipath.conf.synthetic
+++ b/multipath.conf.synthetic
@@ -16,7 +16,7 @@
# no_path_retry fail
# user_friendly_names no
#}
-#devnode_blacklist {
+#blacklist {
# wwid 26353900f02796769
# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
# devnode "^hd[a-z][[0-9]*]"
@@ -26,6 +26,10 @@
# product MSA[15]00
# }
#}
+#blacklist_exceptions {
+# devnode "^dasd[c-d]+[0-9]*"
+# wwid "IBM.75000000092461.4d00.34"
+#}
#multipaths {
# multipath {
# wwid 3600508b4000156d700012000000b0000
diff --git a/multipath/main.c b/multipath/main.c
index 98f7207..67076db 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -46,8 +46,7 @@
#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" \
@@ -128,13 +128,15 @@ update_paths (struct multipath * mpp)
pp->state = PATH_DOWN;
continue;
}
+ pp->mpp = mpp;
pathinfo(pp, conf->hwtable, DI_ALL);
continue;
}
+ pp->mpp = 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);
}
}
@@ -222,7 +224,7 @@ configure (void)
vecs.mpvec = curmp;
/*
- * if we have a blacklisted device parameter, exit early
+ * dev is "/dev/" . "sysfs block dev"
*/
if (conf->dev) {
if (!strncmp(conf->dev, "/dev/", 5) &&
@@ -232,8 +234,12 @@ configure (void)
dev = conf->dev;
}
- if (dev && blacklist(conf->blist_devnode, dev))
- goto out;
+ /*
+ * if we have a blacklisted device parameter, exit early
+ */
+ if (dev &&
+ (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0))
+ goto out;
/*
* scope limiting must be translated into a wwid
@@ -247,8 +253,8 @@ configure (void)
goto out;
}
condlog(3, "scope limited to %s", refwwid);
-
- if (blacklist(conf->blist_wwid, refwwid))
+ if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
+ refwwid) > 0)
goto out;
}
@@ -281,8 +287,10 @@ configure (void)
filter_pathvec(pathvec, refwwid);
- if (conf->list)
+ if (conf->list) {
+ r = 0;
goto out;
+ }
/*
* core logic entry point
@@ -305,14 +313,14 @@ 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");
exit(1);
}
- if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
+ if (dm_prereq(DEFAULT_TARGET))
exit(1);
if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
@@ -322,7 +330,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 +373,8 @@ main (int argc, char *argv[])
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..d786eef 100644
--- a/multipathd/cli.c
+++ b/multipathd/cli.c
@@ -4,6 +4,8 @@
#include <memory.h>
#include <vector.h>
#include <util.h>
+#include <version.h>
+#include <readline/readline.h>
#include "cli.h"
@@ -72,6 +74,30 @@ add_handler (int fp, int (*fn)(void *, c
return 0;
}
+static struct handler *
+find_handler (int fp)
+{
+ int i;
+ struct handler *h;
+
+ vector_foreach_slot (handlers, h, i)
+ if (h->fingerprint == fp)
+ return h;
+
+ return NULL;
+}
+
+int
+set_handler_callback (int fp, int (*fn)(void *, char **, int *, void *))
+{
+ struct handler * h = find_handler(fp);
+
+ if (!h)
+ return 1;
+ h->fn = fn;
+ return 0;
+}
+
static void
free_key (struct key * kw)
{
@@ -140,33 +166,34 @@ load_keys (void)
r += add_key(keys, "stats", STATS, 0);
r += add_key(keys, "topology", TOPOLOGY, 0);
r += add_key(keys, "config", CONFIG, 0);
+ r += add_key(keys, "blacklist", BLACKLIST, 0);
+ r += add_key(keys, "devices", DEVICES, 0);
if (r) {
free_keys(keys);
keys = NULL;
return 1;
}
-
return 0;
}
static struct key *
-find_key (char * str)
+find_key (const char * str)
{
int i;
int len, klen;
struct key * kw = NULL;
struct key * foundkw = NULL;
- vector_foreach_slot (keys, kw, i) {
- len = strlen(str);
- klen = strlen(kw->str);
+ len = strlen(str);
+ vector_foreach_slot (keys, kw, i) {
if (strncmp(kw->str, str, len))
continue;
- else if (len == klen)
+ klen = strlen(kw->str);
+ if (len == klen)
return kw; /* exact match */
- else if (len < klen) {
+ if (len < klen) {
if (!foundkw)
foundkw = kw; /* shortcut match */
else
@@ -175,24 +202,16 @@ find_key (char * str)
}
return foundkw;
}
-
-static struct handler *
-find_handler (int fp)
-{
- int i;
- struct handler *h;
-
- vector_foreach_slot (handlers, h, i)
- if (h->fingerprint == fp)
- return h;
- return NULL;
-}
+#define E_SYNTAX 1
+#define E_NOPARM 2
+#define E_NOMEM 3
-static vector
-get_cmdvec (char * cmd)
+static int
+get_cmdvec (char * cmd, vector *v)
{
int fwd = 1;
+ int r = 0;
char * p = cmd;
char * buff;
struct key * kw = NULL;
@@ -200,9 +219,10 @@ get_cmdvec (char * cmd)
vector cmdvec;
cmdvec = vector_alloc();
+ *v = cmdvec;
if (!cmdvec)
- return NULL;
+ return E_NOMEM;
while (fwd) {
fwd = get_word(p, &buff);
@@ -215,18 +235,19 @@ get_cmdvec (char * cmd)
FREE(buff);
if (!kw)
- goto out; /* synthax error */
+ return E_SYNTAX;
cmdkw = alloc_key();
- if (!cmdkw)
+ if (!cmdkw) {
+ r = E_NOMEM;
goto out;
-
+ }
if (!vector_alloc_slot(cmdvec)) {
FREE(cmdkw);
+ r = E_NOMEM;
goto out;
}
-
vector_set_slot(cmdvec, cmdkw);
cmdkw->code = kw->code;
cmdkw->has_param = kw->has_param;
@@ -238,18 +259,18 @@ get_cmdvec (char * cmd)
fwd = get_word(p, &buff);
if (!buff)
- goto out;
+ return E_NOPARM;
p += fwd;
cmdkw->param = buff;
}
}
-
- return cmdvec;
+ return 0;
out:
free_keys(cmdvec);
- return NULL;
+ *v = NULL;
+ return r;
}
static int
@@ -259,6 +280,9 @@ fingerprint(vector vec)
int fp = 0;
struct key * kw;
+ if (!vec)
+ return 0;
+
vector_foreach_slot(vec, kw, i)
fp += kw->code;
@@ -305,6 +329,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;
@@ -329,9 +355,13 @@ parse_cmd (char * cmd, char ** reply, in
{
int r;
struct handler * h;
- vector cmdvec = get_cmdvec(cmd);
+ vector cmdvec;
+
+ r = get_cmdvec(cmd, &cmdvec);
- if (!cmdvec) {
+ if (r) {
+ if (cmdvec)
+ free_keys(cmdvec);
*reply = genhelp_handler();
*len = strlen(*reply) + 1;
return 0;
@@ -366,3 +396,141 @@ get_keyparam (vector v, int code)
return NULL;
}
+
+int
+cli_init (void) {
+ if (load_keys())
+ return 1;
+
+ if (alloc_handlers())
+ return 1;
+
+ add_handler(LIST+PATHS, NULL);
+ add_handler(LIST+MAPS, NULL);
+ add_handler(LIST+MAPS+STATUS, NULL);
+ add_handler(LIST+MAPS+STATS, NULL);
+ add_handler(LIST+MAPS+TOPOLOGY, NULL);
+ add_handler(LIST+TOPOLOGY, NULL);
+ add_handler(LIST+MAP+TOPOLOGY, NULL);
+ add_handler(LIST+CONFIG, NULL);
+ add_handler(LIST+BLACKLIST, NULL);
+ add_handler(LIST+DEVICES, NULL);
+ add_handler(ADD+PATH, NULL);
+ add_handler(DEL+PATH, NULL);
+ add_handler(ADD+MAP, NULL);
+ add_handler(DEL+MAP, NULL);
+ add_handler(SWITCH+MAP+GROUP, NULL);
+ add_handler(RECONFIGURE, NULL);
+ add_handler(SUSPEND+MAP, NULL);
+ add_handler(RESUME+MAP, NULL);
+ add_handler(REINSTATE+PATH, NULL);
+ add_handler(FAIL+PATH, NULL);
+
+ return 0;
+}
+
+static int
+key_match_fingerprint (struct key * kw, int fp)
+{
+ if (!fp)
+ return 0;
+
+ return ((fp & kw->code) == kw->code);
+}
+
+/*
+ * This is the readline completion handler
+ */
+char *
+key_generator (const char * str, int state)
+{
+ static int index, len, rlfp, has_param;
+ struct key * kw;
+ int i;
+ struct handler *h;
+ vector v;
+
+ if (!state) {
+ index = 0;
+ has_param = 0;
+ rlfp = 0;
+ len = strlen(str);
+ int r = get_cmdvec(rl_line_buffer, &v);
+ /*
+ * If a word completion is in progess, we don't want
+ * to take an exact keyword match in the fingerprint.
+ * For ex "show map[tab]" would validate "map" and discard
+ * "maps" as a valid candidate.
+ */
+ if (v && len)
+ vector_del_slot(v, VECTOR_SIZE(v) - 1);
+ /*
+ * Clean up the mess if we dropped the last slot of a 1-slot
+ * vector
+ */
+ if (v && !VECTOR_SIZE(v)) {
+ vector_free(v);
+ v = NULL;
+ }
+ /*
+ * If last keyword takes a param, don't even try to guess
+ */
+ if (r == E_NOPARM) {
+ has_param = 1;
+ return (strdup("(value)"));
+ }
+ /*
+ * Compute a command fingerprint to find out possible completions.
+ * Once done, the vector is useless. Free it.
+ */
+ if (v) {
+ rlfp = fingerprint(v);
+ free_keys(v);
+ }
+ }
+ /*
+ * No more completions for parameter placeholder.
+ * Brave souls might try to add parameter completion by walking paths and
+ * multipaths vectors.
+ */
+ if (has_param)
+ return ((char *)NULL);
+ /*
+ * Loop through keywords for completion candidates
+ */
+ vector_foreach_slot_after (keys, kw, index) {
+ if (!strncmp(kw->str, str, len)) {
+ /*
+ * Discard keywords already in the command line
+ */
+ if (key_match_fingerprint(kw, rlfp)) {
+ struct key * curkw = find_key(str);
+ if (!curkw || (curkw != kw))
+ continue;
+ }
+ /*
+ * Discard keywords making syntax errors.
+ *
+ * nfp is the candidate fingerprint we try to
+ * validate against all known command fingerprints.
+ */
+ int nfp = rlfp | kw->code;
+ vector_foreach_slot(handlers, h, i) {
+ if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
+ /*
+ * At least one full command is
+ * possible with this keyword :
+ * Consider it validated
+ */
+ index++;
+ return (strdup(kw->str));
+ }
+ }
+ }
+ }
+ /*
+ * No more candidates
+ */
+ return ((char *)NULL);
+}
+
diff --git a/multipathd/cli.h b/multipathd/cli.h
index ef1e3b8..a2397df 100644
--- a/multipathd/cli.h
+++ b/multipathd/cli.h
@@ -17,6 +17,8 @@ enum {
__STATS,
__TOPOLOGY,
__CONFIG,
+ __BLACKLIST,
+ __DEVICES,
};
#define LIST (1 << __LIST)
@@ -37,6 +39,8 @@ enum {
#define STATS (1 << __STATS)
#define TOPOLOGY (1 << __TOPOLOGY)
#define CONFIG (1 << __CONFIG)
+#define BLACKLIST (1 << __BLACKLIST)
+#define DEVICES (1 << __DEVICES)
#define INITIAL_REPLY_LEN 1000
@@ -57,8 +61,11 @@ vector handlers;
int alloc_handlers (void);
int add_handler (int fp, int (*fn)(void *, char **, int *, void *));
+int set_handler_callback (int fp, int (*fn)(void *, char **, int *, void *));
int parse_cmd (char * cmd, char ** reply, int * len, void *);
int load_keys (void);
char * get_keyparam (vector v, int code);
void free_keys (vector vec);
void free_handlers (vector vec);
+int cli_init (void);
+char * key_generator (const char * str, int state);
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 92d8221..4938e84 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) {
@@ -142,6 +143,12 @@ show_config (char ** r, int * len)
reply = REALLOC(reply, maxlen *= 2);
continue;
}
+ c += snprint_blacklist_except(c, reply + maxlen - c);
+ again = ((c - reply) == maxlen);
+ if (again) {
+ reply = REALLOC(reply, maxlen *= 2);
+ continue;
+ }
c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
again = ((c - reply) == maxlen);
if (again) {
@@ -183,6 +190,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)
@@ -278,8 +286,8 @@ cli_add_path (void * v, char ** reply, i
condlog(2, "%s: add path (operator)", param);
- if (blacklist(conf->blist_devnode, param) ||
- (r = ev_add_path(param, vecs)) == 2) {
+ if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
+ param) > 0 || (r = ev_add_path(param, vecs)) == 2) {
*reply = strdup("blacklisted");
*len = strlen(*reply) + 1;
condlog(2, "%s: path blacklisted", param);
@@ -307,7 +315,7 @@ cli_add_map (void * v, char ** reply, in
condlog(2, "%s: add map (operator)", param);
- if (blacklist(conf->blist_wwid, param)) {
+ if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param) > 0) {
*reply = strdup("blacklisted");
*len = strlen(*reply) + 1;
condlog(2, "%s: map blacklisted", param);
@@ -431,3 +439,79 @@ cli_fail(void * v, char ** reply, int *
return dm_fail_path(pp->mpp->alias, pp->dev_t);
}
+
+int
+show_blacklist (char ** r, int * len)
+{
+ char *c = NULL;
+ char *reply = NULL;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ while (again) {
+ reply = MALLOC(maxlen);
+ if (!reply)
+ return 1;
+
+ c = reply;
+ c += snprint_blacklist_report(c, maxlen);
+ again = ((c - reply) == maxlen);
+ if (again) {
+ maxlen *= 2;
+ FREE(reply);
+ continue;
+ }
+ }
+
+ *r = reply;
+ *len = (int)(c - reply + 1);
+
+ return 0;
+}
+
+int
+cli_list_blacklist (void * v, char ** reply, int * len, void * data)
+{
+ condlog(3, "list blacklist (operator)");
+
+ return show_blacklist(reply, len);
+}
+
+int
+show_devices (char ** r, int * len, struct vectors *vecs)
+{
+ char *c = NULL;
+ char *reply = NULL;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ while (again) {
+ reply = MALLOC(maxlen);
+ if (!reply)
+ return 1;
+
+ c = reply;
+ c += snprint_devices(c, maxlen, vecs);
+ again = ((c - reply) == maxlen);
+ if (again) {
+ maxlen *= 2;
+ FREE(reply);
+ continue;
+ }
+ }
+
+ *r = reply;
+ *len = (int)(c - reply + 1);
+
+ return 0;
+}
+
+int
+cli_list_devices (void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+
+ condlog(3, "list devices (operator)");
+
+ return show_devices(reply, len, vecs);
+}
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
index 8768724..863694b 100644
--- a/multipathd/cli_handlers.h
+++ b/multipathd/cli_handlers.h
@@ -5,6 +5,8 @@ int cli_list_maps_stats (void * v, char
int cli_list_map_topology (void * v, char ** reply, int * len, void * data);
int cli_list_maps_topology (void * v, char ** reply, int * len, void * data);
int cli_list_config (void * v, char ** reply, int * len, void * data);
+int cli_list_blacklist (void * v, char ** reply, int * len, void * data);
+int cli_list_devices (void * v, char ** reply, int * len, void * data);
int cli_add_path (void * v, char ** reply, int * len, void * data);
int cli_del_path (void * v, char ** reply, int * len, void * data);
int cli_add_map (void * v, char ** reply, int * len, void * data);
diff --git a/multipathd/main.c b/multipathd/main.c
index 55a2c49..f2f9a96 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -55,136 +55,29 @@
#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
- */
-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
+ * global copy of vecs for use in sig handlers
*/
-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)
@@ -704,7 +376,7 @@ ev_add_path (char * devname, struct vect
condlog(0, "%s: failed to get path uid", devname);
return 1; /* leave path added to pathvec */
}
- if (blacklist_path(conf, pp)){
+ if (filter_path(conf, pp)){
int i = find_slot(vecs->pathvec, (void *)pp);
if (i != -1)
vector_del_slot(vecs->pathvec, 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;
@@ -995,7 +667,8 @@ uev_trigger (struct uevent * uev, void *
/*
* path add/remove event
*/
- if (blacklist(conf->blist_devnode, devname))
+ if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
+ devname) > 0)
goto out;
if (!strncmp(uev->action, "add", 3)) {
@@ -1024,30 +697,29 @@ ueventloop (void * ap)
static void *
uxlsnrloop (void * ap)
{
- if (load_keys())
- return NULL;
-
- if (alloc_handlers())
+ if (cli_init())
return NULL;
- add_handler(LIST+PATHS, cli_list_paths);
- add_handler(LIST+MAPS, cli_list_maps);
- add_handler(LIST+MAPS+STATUS, cli_list_maps_status);
- add_handler(LIST+MAPS+STATS, cli_list_maps_stats);
- add_handler(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
- add_handler(LIST+TOPOLOGY, cli_list_maps_topology);
- add_handler(LIST+MAP+TOPOLOGY, cli_list_map_topology);
- add_handler(LIST+CONFIG, cli_list_config);
- add_handler(ADD+PATH, cli_add_path);
- add_handler(DEL+PATH, cli_del_path);
- add_handler(ADD+MAP, cli_add_map);
- add_handler(DEL+MAP, cli_del_map);
- add_handler(SWITCH+MAP+GROUP, cli_switch_group);
- add_handler(RECONFIGURE, cli_reconfigure);
- add_handler(SUSPEND+MAP, cli_suspend);
- add_handler(RESUME+MAP, cli_resume);
- add_handler(REINSTATE+PATH, cli_reinstate);
- add_handler(FAIL+PATH, cli_fail);
+ set_handler_callback(LIST+PATHS, cli_list_paths);
+ set_handler_callback(LIST+MAPS, cli_list_maps);
+ set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
+ set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
+ set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
+ set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
+ set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
+ set_handler_callback(LIST+CONFIG, cli_list_config);
+ set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
+ set_handler_callback(LIST+DEVICES, cli_list_devices);
+ set_handler_callback(ADD+PATH, cli_add_path);
+ set_handler_callback(DEL+PATH, cli_del_path);
+ set_handler_callback(ADD+MAP, cli_add_map);
+ set_handler_callback(DEL+MAP, cli_del_map);
+ set_handler_callback(SWITCH+MAP+GROUP, cli_switch_group);
+ set_handler_callback(RECONFIGURE, cli_reconfigure);
+ set_handler_callback(SUSPEND+MAP, cli_suspend);
+ set_handler_callback(RESUME+MAP, cli_resume);
+ set_handler_callback(REINSTATE+PATH, cli_reinstate);
+ set_handler_callback(FAIL+PATH, cli_fail);
uxsock_listen(&uxsock_trigger, ap);
@@ -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()))
@@ -1366,7 +1039,7 @@ configure (struct vectors * vecs, int st
path_discovery(vecs->pathvec, conf, DI_ALL);
vector_foreach_slot (vecs->pathvec, pp, i){
- if (blacklist_path(conf, pp)){
+ if (filter_path(conf, pp)){
vector_del_slot(vecs->pathvec, i);
free_path(pp);
i--;
@@ -1394,10 +1067,6 @@ configure (struct vectors * vecs, int st
sync_maps_state(mpvec);
- if (conf->verbosity > 2)
- vector_foreach_slot(mpvec, mpp, i)
- print_map(mpp);
-
/*
* purge dm of old maps
*/
@@ -1406,6 +1075,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 +1105,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 +1138,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 +1200,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 +1208,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..480b8ed 100644
--- a/multipathd/multipathd.8
+++ b/multipathd/multipathd.8
@@ -1,22 +1,102 @@
-.TH MULTIPATHD 8 "October 2004" "Linux Administrator's Manual"
+.TH MULTIPATHD 8 "November 2006" "Linux Administrator's Manual"
.SH NAME
multipathd \- multipath daemon
-.SH SYNOPSYS
+
+.SH SYNOPSIS
.B multipathd
+.RB [\| options \|]
-This daemon is in charge of checking for failed paths. When this happens,
+.SH DESCRIPTION
+The
+.B multipathd
+daemon is in charge of checking for failed paths. When this happens,
it will reconfigure the multipath map the path belongs to, so that this map
-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 OPTIONS
+.TP
+.B \-d
+Forground Mode. Don't daemonize, and print all messages to stdout and stderr.
+.TP
+.B -v "level"
+Verbosity level. Print additional information while running multipathd. A level of 0 means only print errors. A level of 3 or greater prints debugging information as well.
+.TP
+.B -k
+multipathd will enter interactive mode. From this mode, the available commands can be viewed by entering "help". When you are finished entering commands, press CTRL-D to quit.
+
+.SH COMMANDS
+.TP
+The following commands can be used in interactive mode:
+.TP
+.B list|show paths
+Show the paths that multipathd is monitoring, and their state.
+.TP
+.B list|show maps|multipaths
+Show the multipath devices that the multipathd is monitoring.
+.TP
+.B list|show maps|multipaths status
+Show the status of all multipath devices that the multipathd is monitoring.
+.TP
+.B list|show maps|multipaths stats
+Show some statistics of all multipath devices that the multipathd is monitoring.
+.TP
+.B list|show maps|multipaths topology
+Show the current multipath topology. Same as "multipath -ll".
+.TP
+.B list|show topology
+Show the current multipath topology. Same as "multipath -ll".
+.TP
+.B list|show map|multipath $map topology
+Show topology of a single multipath device specified by $map, e.g. 36005076303ffc56200000000000010aa.
+This map could be obtained from "list maps".
+.TP
+.B list|show config
+Show the currently used configuration, derived from default values and values specified within the configuration file /etc/multipath.conf.
+.TP
+.B list|show blacklist
+Show the currently used blacklist rules, derived from default values and values specified within the configuration file /etc/multipath.conf.
+.TP
+.B list|show devices
+Show all available block devices by name including the information if they are blacklisted or not.
+.TP
+.B add path $path
+Add a path to the list of monitored paths. $path is as listed in /sys/block (e.g. sda).
+.TP
+.B remove|del path $path
+Stop monitoring a path. $path is as listed in /sys/block (e.g. sda).
+.TP
+.B add map $map
+Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa).
+.TP
+.B remove|del map $map
+Stop monitoring a multipath device.
+.TP
+.B switch|switchgroup map $map group $group
+Force a multipath device to switch to a specific path group. $group is the path group index, starting with 1.
+.TP
+.B reconfigure
+Reconfigures the multipaths. This should be triggered automatically after any hotplug event.
+.TP
+.B suspend map|multipath $map
+Sets map $map into suspend state.
+.TP
+.B resume map|multipath $map
+Resumes map $map from suspend state.
+.TP
+.B fail path $path
+Sets path $path into failed state.
+.TP
+.B reinstate path $path
+Resumes path $path from failed state.
+
.SH "SEE ALSO"
.BR multipath (8)
.BR kpartx (8)
.BR hotplug (8)
.SH "AUTHORS"
-This man page was assembled by Patrick Caulfield
-for the Debian project. From documentation provided
-by the multipath author Christophe Varoqui, <christophe.varoqui@free.fr> and others.
+.B multipathd
+was developed by Christophe Varoqui, <christophe.varoqui@free.fr> and others.
diff --git a/multipathd/uxclnt.c b/multipathd/uxclnt.c
index ff7b578..009e5cb 100644
--- a/multipathd/uxclnt.c
+++ b/multipathd/uxclnt.c
@@ -21,6 +21,9 @@
#include <memory.h>
#include <defaults.h>
+#include <vector.h>
+#include "cli.h"
+
/*
* process the client
*/
@@ -29,6 +32,9 @@ static void process(int fd)
char *line;
char *reply;
+ cli_init();
+ rl_readline_name = "multipathd";
+ rl_completion_entry_function = key_generator;
while ((line = readline("multipathd> "))) {
size_t len;
size_t llen = strlen(line);
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/stat.h>
#include <unistd.h>
#include <errno.h>
+#include <inttypes.h>
#define __user
#include <scsi/sg.h>
@@ -28,7 +29,7 @@
#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 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;