2037 lines
54 KiB
Plaintext
2037 lines
54 KiB
Plaintext
Makefile.inc | 1 +
|
|
devmap_name/Makefile | 10 +-
|
|
kpartx/Makefile | 8 +-
|
|
kpartx/devmapper.c | 7 +-
|
|
kpartx/kpartx.c | 16 ++-
|
|
libcheckers/directio.c | 119 ++++++++----
|
|
libcheckers/emc_clariion.c | 8 +-
|
|
libcheckers/libaio.h | 222 +++++++++++++++++++++
|
|
libmultipath/config.c | 5 +-
|
|
libmultipath/configure.c | 2 -
|
|
libmultipath/debug.c | 2 +-
|
|
libmultipath/debug.h | 2 +-
|
|
libmultipath/devmapper.c | 60 +++++--
|
|
libmultipath/devmapper.h | 3 +-
|
|
libmultipath/dict.c | 2 +-
|
|
libmultipath/hwtable.c | 81 +++++---
|
|
libmultipath/log.c | 5 +
|
|
libmultipath/log_pthread.c | 2 +-
|
|
libmultipath/log_pthread.h | 2 +-
|
|
libmultipath/parser.c | 15 +-
|
|
libmultipath/parser.h | 1 +
|
|
libmultipath/print.c | 2 +-
|
|
libmultipath/structs_vec.c | 32 ++--
|
|
libmultipath/waiter.c | 9 +-
|
|
multipath/Makefile | 7 +-
|
|
multipath/main.c | 58 ++++++-
|
|
multipath/multipath.8 | 8 +-
|
|
multipath/multipath.conf.5 | 384 +++++++++++++++++++++++++++++++++++++
|
|
multipathd/Makefile | 5 +-
|
|
multipathd/cli.c | 2 +-
|
|
multipathd/main.c | 9 +-
|
|
path_priority/pp_alua/Makefile | 9 +-
|
|
path_priority/pp_emc/pp_emc.c | 8 +-
|
|
path_priority/pp_hp_sw/Makefile | 25 +++
|
|
path_priority/pp_hp_sw/pp_hp_sw.c | 119 ++++++++++++
|
|
35 files changed, 1092 insertions(+), 158 deletions(-)
|
|
|
|
diff --git a/Makefile.inc b/Makefile.inc
|
|
index 4a705aa..fe6cbdf 100644
|
|
--- a/Makefile.inc
|
|
+++ b/Makefile.inc
|
|
@@ -26,6 +26,7 @@ bindir = $(exec_prefix)/sbin
|
|
checkersdir = $(TOPDIR)/libcheckers
|
|
multipathdir = $(TOPDIR)/libmultipath
|
|
mandir = $(prefix)/usr/share/man/man8
|
|
+man5dir = $(prefix)/usr/share/man/man5
|
|
rcdir = $(prefix)/etc/init.d
|
|
|
|
GZIP = /bin/gzip -9 -c
|
|
diff --git a/devmap_name/Makefile b/devmap_name/Makefile
|
|
index 380c85b..8b0c678 100644
|
|
--- a/devmap_name/Makefile
|
|
+++ b/devmap_name/Makefile
|
|
@@ -22,21 +22,19 @@ prepare:
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
klibc: prepare $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
-install:
|
|
+install: $(EXEC) $(EXEC).8
|
|
install -d $(DESTDIR)$(bindir)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
install -d $(DESTDIR)$(mandir)
|
|
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
|
+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
+ rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
rm -f core *.o $(EXEC) *.gz
|
|
diff --git a/kpartx/Makefile b/kpartx/Makefile
|
|
index bf6e6c1..522a6a0 100644
|
|
--- a/kpartx/Makefile
|
|
+++ b/kpartx/Makefile
|
|
@@ -27,20 +27,18 @@ prepare:
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
-
|
|
+
|
|
klibc: prepare $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
$(MULTIPATHLIB)-$(BUILD).a:
|
|
make -C $(multipathdir) BUILD=$(BUILD)
|
|
|
|
-install:
|
|
+install: $(EXEC) $(EXEC).8
|
|
install -d $(DESTDIR)$(bindir)
|
|
install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
install -d $(DESTDIR)$(mandir)
|
|
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
|
+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
|
|
uninstall:
|
|
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
|
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
|
|
index 5b27487..4b228ed 100644
|
|
--- a/kpartx/devmapper.c
|
|
+++ b/kpartx/devmapper.c
|
|
@@ -95,19 +95,16 @@ dm_addmap (int task, const char *name, c
|
|
}
|
|
sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid);
|
|
if (!dm_task_set_uuid(dmt, prefixed_uuid))
|
|
- goto freeout;
|
|
+ goto addout;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
|
index 0ee0cb3..b406b95 100644
|
|
--- a/kpartx/kpartx.c
|
|
+++ b/kpartx/kpartx.c
|
|
@@ -193,6 +193,7 @@ main(int argc, char **argv){
|
|
char * loopdev = NULL;
|
|
char * delim = NULL;
|
|
char *uuid = NULL;
|
|
+ char *mapname = NULL;
|
|
int loopro = 0;
|
|
int hotplug = 0;
|
|
struct stat buf;
|
|
@@ -310,12 +311,19 @@ main(int argc, char **argv){
|
|
|
|
off = find_devname_offset(device);
|
|
|
|
- if (!loopdev)
|
|
+ if (!loopdev) {
|
|
uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
|
|
(unsigned int)MINOR(buf.st_rdev));
|
|
+ mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev),
|
|
+ (unsigned int)MINOR(buf.st_rdev));
|
|
+ }
|
|
+
|
|
if (!uuid)
|
|
uuid = device + off;
|
|
|
|
+ if (!mapname)
|
|
+ mapname = device + off;
|
|
+
|
|
fd = open(device, O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
@@ -365,7 +373,7 @@ main(int argc, char **argv){
|
|
continue;
|
|
|
|
printf("%s%s%d : 0 %lu %s %lu\n",
|
|
- device + off, delim, j+1,
|
|
+ mapname, delim, j+1,
|
|
(unsigned long) slices[j].size, device,
|
|
(unsigned long) slices[j].start);
|
|
}
|
|
@@ -374,7 +382,7 @@ main(int argc, char **argv){
|
|
case DELETE:
|
|
for (j = 0; j < n; j++) {
|
|
if (safe_sprintf(partname, "%s%s%d",
|
|
- device + off , delim, j+1)) {
|
|
+ mapname, delim, j+1)) {
|
|
fprintf(stderr, "partname too small\n");
|
|
exit(1);
|
|
}
|
|
@@ -407,7 +415,7 @@ main(int argc, char **argv){
|
|
continue;
|
|
|
|
if (safe_sprintf(partname, "%s%s%d",
|
|
- device + off , delim, j+1)) {
|
|
+ mapname, delim, j+1)) {
|
|
fprintf(stderr, "partname too small\n");
|
|
exit(1);
|
|
}
|
|
diff --git a/libcheckers/directio.c b/libcheckers/directio.c
|
|
index b53c1c3..2251515 100644
|
|
--- a/libcheckers/directio.c
|
|
+++ b/libcheckers/directio.c
|
|
@@ -12,28 +12,44 @@
|
|
#include <sys/ioctl.h>
|
|
#include <linux/fs.h>
|
|
#include <errno.h>
|
|
+#include <linux/kdev_t.h>
|
|
+#include <asm/unistd.h>
|
|
|
|
+#include "libaio.h"
|
|
#include "checkers.h"
|
|
+#include "../libmultipath/debug.h"
|
|
|
|
#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
|
|
#define MSG_DIRECTIO_UP "directio checker reports path is up"
|
|
#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
|
|
|
|
struct directio_context {
|
|
- int blksize;
|
|
- unsigned char *buf;
|
|
- unsigned char *ptr;
|
|
+ int running;
|
|
+ int reset_flags;
|
|
+ int blksize;
|
|
+ unsigned char * buf;
|
|
+ unsigned char * ptr;
|
|
+ io_context_t ioctx;
|
|
+ struct iocb io;
|
|
};
|
|
|
|
+
|
|
int directio_init (struct checker * c)
|
|
{
|
|
unsigned long pgsize = getpagesize();
|
|
struct directio_context * ct;
|
|
+ long flags;
|
|
|
|
ct = malloc(sizeof(struct directio_context));
|
|
if (!ct)
|
|
return 1;
|
|
- c->context = (void *)ct;
|
|
+ memset(ct, 0, sizeof(struct directio_context));
|
|
+
|
|
+ if (syscall(__NR_io_setup, 1, &ct->ioctx) != 0) {
|
|
+ condlog(1, "io_setup failed");
|
|
+ free(ct);
|
|
+ return 1;
|
|
+ }
|
|
|
|
if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
|
|
MSG(c, "cannot get blocksize, set default");
|
|
@@ -50,11 +66,28 @@ int directio_init (struct checker * c)
|
|
ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
|
|
if (!ct->buf)
|
|
goto out;
|
|
- ct->ptr = (unsigned char *)(((unsigned long)ct->buf + pgsize - 1) &
|
|
- (~(pgsize - 1)));
|
|
|
|
+ flags = fcntl(c->fd, F_GETFL);
|
|
+ if (flags < 0)
|
|
+ goto out;
|
|
+ if (!(flags & O_DIRECT)) {
|
|
+ flags |= O_DIRECT;
|
|
+ if (fcntl(c->fd, F_SETFL, flags) < 0)
|
|
+ goto out;
|
|
+ ct->reset_flags = 1;
|
|
+ }
|
|
+
|
|
+ ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
|
|
+ (~(pgsize - 1)));
|
|
+
|
|
+ /* Sucessfully initialized, return the context. */
|
|
+ c->context = (void *) ct;
|
|
return 0;
|
|
+
|
|
out:
|
|
+ if (ct->buf)
|
|
+ free(ct->buf);
|
|
+ syscall(__NR_io_destroy, ct->ioctx);
|
|
free(ct);
|
|
return 1;
|
|
}
|
|
@@ -62,56 +95,63 @@ out:
|
|
void directio_free (struct checker * c)
|
|
{
|
|
struct directio_context * ct = (struct directio_context *)c->context;
|
|
+ long flags;
|
|
|
|
if (!ct)
|
|
return;
|
|
+
|
|
+ if (ct->reset_flags) {
|
|
+ if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
|
|
+ flags &= ~O_DIRECT;
|
|
+ /* No point in checking for errors */
|
|
+ fcntl(c->fd, F_SETFL, flags);
|
|
+ }
|
|
+ }
|
|
+
|
|
if (ct->buf)
|
|
free(ct->buf);
|
|
+ syscall(__NR_io_destroy, ct->ioctx);
|
|
free(ct);
|
|
}
|
|
|
|
static int
|
|
-direct_read (int fd, unsigned char * buff, int size)
|
|
+check_state(int fd, struct directio_context *ct)
|
|
{
|
|
- long flags;
|
|
- int reset_flags = 0;
|
|
- int res, retval;
|
|
-
|
|
- flags = fcntl(fd,F_GETFL);
|
|
-
|
|
- if (flags < 0) {
|
|
- return PATH_UNCHECKED;
|
|
+ struct timespec timeout = { .tv_sec = 2 };
|
|
+ struct io_event event;
|
|
+ struct stat sb;
|
|
+ int rc = PATH_UNCHECKED;
|
|
+ long r;
|
|
+
|
|
+ if (fstat(fd, &sb) == 0) {
|
|
+ condlog(4, "directio: called for %x", (unsigned) sb.st_rdev);
|
|
}
|
|
|
|
- if (!(flags & O_DIRECT)) {
|
|
- flags |= O_DIRECT;
|
|
- if (fcntl(fd,F_SETFL,flags) < 0) {
|
|
+ if (!ct->running) {
|
|
+ struct iocb *ios[1] = { &ct->io };
|
|
+
|
|
+ condlog(3, "directio: starting new request");
|
|
+ memset(&ct->io, 0, sizeof(struct iocb));
|
|
+ io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
|
|
+ if (syscall(__NR_io_submit, ct->ioctx, 1, ios) != 1) {
|
|
+ condlog(3, "directio: io_submit error %i", errno);
|
|
return PATH_UNCHECKED;
|
|
}
|
|
- reset_flags = 1;
|
|
}
|
|
+ ct->running = 1;
|
|
|
|
- while ( (res = read(fd,buff,size)) < 0 && errno == EINTR );
|
|
- if (res < 0) {
|
|
- if (errno == EINVAL) {
|
|
- /* O_DIRECT is not available */
|
|
- retval = PATH_UNCHECKED;
|
|
- } else if (errno == ENOMEM) {
|
|
- retval = PATH_UP;
|
|
- } else {
|
|
- retval = PATH_DOWN;
|
|
- }
|
|
+ r = syscall(__NR_io_getevents, ct->ioctx, 1L, 1L, &event, &timeout);
|
|
+ if (r < 1L) {
|
|
+ condlog(3, "directio: timeout r=%li errno=%i", r, errno);
|
|
+ rc = PATH_DOWN;
|
|
} else {
|
|
- retval = PATH_UP;
|
|
- }
|
|
-
|
|
- if (reset_flags) {
|
|
- flags &= ~O_DIRECT;
|
|
- /* No point in checking for errors */
|
|
- fcntl(fd,F_SETFL,flags);
|
|
+ condlog(3, "directio: io finished %lu/%lu", event.res,
|
|
+ event.res2);
|
|
+ ct->running = 0;
|
|
+ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
|
|
}
|
|
|
|
- return retval;
|
|
+ return rc;
|
|
}
|
|
|
|
int directio (struct checker * c)
|
|
@@ -119,7 +159,10 @@ int directio (struct checker * c)
|
|
int ret;
|
|
struct directio_context * ct = (struct directio_context *)c->context;
|
|
|
|
- ret = direct_read(c->fd, ct->ptr, ct->blksize);
|
|
+ if (!ct)
|
|
+ return PATH_UNCHECKED;
|
|
+
|
|
+ ret = check_state(c->fd, ct);
|
|
|
|
switch (ret)
|
|
{
|
|
diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c
|
|
index 384a943..d801b42 100644
|
|
--- a/libcheckers/emc_clariion.c
|
|
+++ b/libcheckers/emc_clariion.c
|
|
@@ -129,8 +129,12 @@ int emc_clariion(struct checker * c)
|
|
|
|
if ( /* Effective initiator type */
|
|
sense_buffer[27] != 0x03
|
|
- /* Failover mode should be set to 1 */
|
|
- || (sense_buffer[28] & 0x07) != 0x04
|
|
+ /*
|
|
+ * Failover mode should be set to 1 (PNR failover mode)
|
|
+ * or 4 (ALUA failover mode).
|
|
+ */
|
|
+ || (((sense_buffer[28] & 0x07) != 0x04) &&
|
|
+ ((sense_buffer[28] & 0x07) != 0x06))
|
|
/* Arraycommpath should be set to 1 */
|
|
|| (sense_buffer[30] & 0x04) != 0x04) {
|
|
MSG(c, "emc_clariion_checker: Path not correctly configured "
|
|
diff --git a/libcheckers/libaio.h b/libcheckers/libaio.h
|
|
new file mode 100644
|
|
index 0000000..6574601
|
|
--- /dev/null
|
|
+++ b/libcheckers/libaio.h
|
|
@@ -0,0 +1,222 @@
|
|
+/* /usr/include/libaio.h
|
|
+ *
|
|
+ * Copyright 2000,2001,2002 Red Hat, Inc.
|
|
+ *
|
|
+ * Written by Benjamin LaHaise <bcrl@redhat.com>
|
|
+ *
|
|
+ * libaio Linux async I/O interface
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+ */
|
|
+#ifndef __LIBAIO_H
|
|
+#define __LIBAIO_H
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <string.h>
|
|
+
|
|
+struct timespec;
|
|
+struct sockaddr;
|
|
+struct iovec;
|
|
+struct iocb;
|
|
+
|
|
+typedef struct io_context *io_context_t;
|
|
+
|
|
+typedef enum io_iocb_cmd {
|
|
+ IO_CMD_PREAD = 0,
|
|
+ IO_CMD_PWRITE = 1,
|
|
+
|
|
+ IO_CMD_FSYNC = 2,
|
|
+ IO_CMD_FDSYNC = 3,
|
|
+
|
|
+ IO_CMD_POLL = 5,
|
|
+ IO_CMD_NOOP = 6,
|
|
+} io_iocb_cmd_t;
|
|
+
|
|
+#if defined(__i386__) /* little endian, 32 bits */
|
|
+#define PADDED(x, y) x; unsigned y
|
|
+#define PADDEDptr(x, y) x; unsigned y
|
|
+#define PADDEDul(x, y) unsigned long x; unsigned y
|
|
+#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__)
|
|
+#define PADDED(x, y) x, y
|
|
+#define PADDEDptr(x, y) x
|
|
+#define PADDEDul(x, y) unsigned long x
|
|
+#elif defined(__powerpc64__) /* big endian, 64 bits */
|
|
+#define PADDED(x, y) unsigned y; x
|
|
+#define PADDEDptr(x,y) x
|
|
+#define PADDEDul(x, y) unsigned long x
|
|
+#elif defined(__PPC__) /* big endian, 32 bits */
|
|
+#define PADDED(x, y) unsigned y; x
|
|
+#define PADDEDptr(x, y) unsigned y; x
|
|
+#define PADDEDul(x, y) unsigned y; unsigned long x
|
|
+#elif defined(__s390x__) /* big endian, 64 bits */
|
|
+#define PADDED(x, y) unsigned y; x
|
|
+#define PADDEDptr(x,y) x
|
|
+#define PADDEDul(x, y) unsigned long x
|
|
+#elif defined(__s390__) /* big endian, 32 bits */
|
|
+#define PADDED(x, y) unsigned y; x
|
|
+#define PADDEDptr(x, y) unsigned y; x
|
|
+#define PADDEDul(x, y) unsigned y; unsigned long x
|
|
+#else
|
|
+#error endian?
|
|
+#endif
|
|
+
|
|
+struct io_iocb_poll {
|
|
+ PADDED(int events, __pad1);
|
|
+}; /* result code is the set of result flags or -'ve errno */
|
|
+
|
|
+struct io_iocb_sockaddr {
|
|
+ struct sockaddr *addr;
|
|
+ int len;
|
|
+}; /* result code is the length of the sockaddr, or -'ve errno */
|
|
+
|
|
+struct io_iocb_common {
|
|
+ PADDEDptr(void *buf, __pad1);
|
|
+ PADDEDul(nbytes, __pad2);
|
|
+ long long offset;
|
|
+ long long __pad3, __pad4;
|
|
+}; /* result code is the amount read or -'ve errno */
|
|
+
|
|
+struct io_iocb_vector {
|
|
+ const struct iovec *vec;
|
|
+ int nr;
|
|
+ long long offset;
|
|
+}; /* result code is the amount read or -'ve errno */
|
|
+
|
|
+struct iocb {
|
|
+ PADDEDptr(void *data, __pad1); /* Return in the io completion event */
|
|
+ PADDED(unsigned key, __pad2); /* For use in identifying io requests */
|
|
+
|
|
+ short aio_lio_opcode;
|
|
+ short aio_reqprio;
|
|
+ int aio_fildes;
|
|
+
|
|
+ union {
|
|
+ struct io_iocb_common c;
|
|
+ struct io_iocb_vector v;
|
|
+ struct io_iocb_poll poll;
|
|
+ struct io_iocb_sockaddr saddr;
|
|
+ } u;
|
|
+};
|
|
+
|
|
+struct io_event {
|
|
+ PADDEDptr(void *data, __pad1);
|
|
+ PADDEDptr(struct iocb *obj, __pad2);
|
|
+ PADDEDul(res, __pad3);
|
|
+ PADDEDul(res2, __pad4);
|
|
+};
|
|
+
|
|
+#undef PADDED
|
|
+#undef PADDEDptr
|
|
+#undef PADDEDul
|
|
+
|
|
+typedef void (*io_callback_t)(io_context_t ctx, struct iocb *iocb, long res, long res2);
|
|
+
|
|
+/* library wrappers */
|
|
+extern int io_queue_init(int maxevents, io_context_t *ctxp);
|
|
+/*extern int io_queue_grow(io_context_t ctx, int new_maxevents);*/
|
|
+extern int io_queue_release(io_context_t ctx);
|
|
+/*extern int io_queue_wait(io_context_t ctx, struct timespec *timeout);*/
|
|
+extern int io_queue_run(io_context_t ctx);
|
|
+
|
|
+/* Actual syscalls */
|
|
+extern int io_setup(int maxevents, io_context_t *ctxp);
|
|
+extern int io_destroy(io_context_t ctx);
|
|
+extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
|
|
+extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
|
|
+extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
|
|
+
|
|
+
|
|
+static inline void io_set_callback(struct iocb *iocb, io_callback_t cb)
|
|
+{
|
|
+ iocb->data = (void *)cb;
|
|
+}
|
|
+
|
|
+static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
|
|
+{
|
|
+ memset(iocb, 0, sizeof(*iocb));
|
|
+ iocb->aio_fildes = fd;
|
|
+ iocb->aio_lio_opcode = IO_CMD_PREAD;
|
|
+ iocb->aio_reqprio = 0;
|
|
+ iocb->u.c.buf = buf;
|
|
+ iocb->u.c.nbytes = count;
|
|
+ iocb->u.c.offset = offset;
|
|
+}
|
|
+
|
|
+static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
|
|
+{
|
|
+ memset(iocb, 0, sizeof(*iocb));
|
|
+ iocb->aio_fildes = fd;
|
|
+ iocb->aio_lio_opcode = IO_CMD_PWRITE;
|
|
+ iocb->aio_reqprio = 0;
|
|
+ iocb->u.c.buf = buf;
|
|
+ iocb->u.c.nbytes = count;
|
|
+ iocb->u.c.offset = offset;
|
|
+}
|
|
+
|
|
+static inline void io_prep_poll(struct iocb *iocb, int fd, int events)
|
|
+{
|
|
+ memset(iocb, 0, sizeof(*iocb));
|
|
+ iocb->aio_fildes = fd;
|
|
+ iocb->aio_lio_opcode = IO_CMD_POLL;
|
|
+ iocb->aio_reqprio = 0;
|
|
+ iocb->u.poll.events = events;
|
|
+}
|
|
+
|
|
+static inline int io_poll(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd, int events)
|
|
+{
|
|
+ io_prep_poll(iocb, fd, events);
|
|
+ io_set_callback(iocb, cb);
|
|
+ return io_submit(ctx, 1, &iocb);
|
|
+}
|
|
+
|
|
+static inline void io_prep_fsync(struct iocb *iocb, int fd)
|
|
+{
|
|
+ memset(iocb, 0, sizeof(*iocb));
|
|
+ iocb->aio_fildes = fd;
|
|
+ iocb->aio_lio_opcode = IO_CMD_FSYNC;
|
|
+ iocb->aio_reqprio = 0;
|
|
+}
|
|
+
|
|
+static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
|
|
+{
|
|
+ io_prep_fsync(iocb, fd);
|
|
+ io_set_callback(iocb, cb);
|
|
+ return io_submit(ctx, 1, &iocb);
|
|
+}
|
|
+
|
|
+static inline void io_prep_fdsync(struct iocb *iocb, int fd)
|
|
+{
|
|
+ memset(iocb, 0, sizeof(*iocb));
|
|
+ iocb->aio_fildes = fd;
|
|
+ iocb->aio_lio_opcode = IO_CMD_FDSYNC;
|
|
+ iocb->aio_reqprio = 0;
|
|
+}
|
|
+
|
|
+static inline int io_fdsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
|
|
+{
|
|
+ io_prep_fdsync(iocb, fd);
|
|
+ io_set_callback(iocb, cb);
|
|
+ return io_submit(ctx, 1, &iocb);
|
|
+}
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* __LIBAIO_H */
|
|
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
|
index a39af8a..1dfc18c 100644
|
|
--- a/libmultipath/config.c
|
|
+++ b/libmultipath/config.c
|
|
@@ -366,12 +366,15 @@ load_config (char * file)
|
|
/*
|
|
* read the config file
|
|
*/
|
|
+ set_current_keywords(&conf->keywords);
|
|
+ alloc_keywords();
|
|
if (filepresent(file)) {
|
|
- set_current_keywords(&conf->keywords);
|
|
if (init_data(file, init_keywords)) {
|
|
condlog(0, "error parsing config file");
|
|
goto out;
|
|
}
|
|
+ } else {
|
|
+ init_keywords();
|
|
}
|
|
|
|
/*
|
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
|
index 9632fb4..a5bad4c 100644
|
|
--- a/libmultipath/configure.c
|
|
+++ b/libmultipath/configure.c
|
|
@@ -324,7 +324,6 @@ domap (struct multipath * mpp)
|
|
mpp->alias);
|
|
return DOMAP_RETRY;
|
|
}
|
|
- dm_shut_log();
|
|
|
|
if (dm_map_present(mpp->alias))
|
|
break;
|
|
@@ -345,7 +344,6 @@ domap (struct multipath * mpp)
|
|
}
|
|
|
|
lock_multipath(mpp, 0);
|
|
- dm_restore_log();
|
|
break;
|
|
|
|
case ACT_RELOAD:
|
|
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
|
|
index fa06cbd..05dfb06 100644
|
|
--- a/libmultipath/debug.c
|
|
+++ b/libmultipath/debug.c
|
|
@@ -14,7 +14,7 @@
|
|
#include "vector.h"
|
|
#include "config.h"
|
|
|
|
-void dlog (int sink, int prio, char * fmt, ...)
|
|
+void dlog (int sink, int prio, const char * fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int thres;
|
|
diff --git a/libmultipath/debug.h b/libmultipath/debug.h
|
|
index 74ed531..082fff1 100644
|
|
--- a/libmultipath/debug.h
|
|
+++ b/libmultipath/debug.h
|
|
@@ -1,4 +1,4 @@
|
|
-void dlog (int sink, int prio, char * fmt, ...)
|
|
+void dlog (int sink, int prio, const char * fmt, ...)
|
|
__attribute__((format(printf, 3, 4)));
|
|
|
|
#if DAEMON
|
|
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
|
index dece079..d762cc1 100644
|
|
--- a/libmultipath/devmapper.c
|
|
+++ b/libmultipath/devmapper.c
|
|
@@ -20,6 +20,13 @@
|
|
#include "debug.h"
|
|
#include "memory.h"
|
|
#include "devmapper.h"
|
|
+#include "config.h"
|
|
+
|
|
+#if DAEMON
|
|
+#include "log_pthread.h"
|
|
+#include <sys/types.h>
|
|
+#include <time.h>
|
|
+#endif
|
|
|
|
#define MAX_WAIT 5
|
|
#define LOOPS_PER_SEC 5
|
|
@@ -28,21 +35,50 @@
|
|
#define UUID_PREFIX_LEN 6
|
|
|
|
static void
|
|
-dm_dummy_log (int level, const char *file, int line, const char *f, ...)
|
|
+dm_write_log (int level, const char *file, int line, const char *f, ...)
|
|
{
|
|
- return;
|
|
-}
|
|
+ va_list ap;
|
|
+ int thres;
|
|
+
|
|
+ if (level > 6)
|
|
+ level = 6;
|
|
+
|
|
+ thres = (conf) ? conf->verbosity : 0;
|
|
+ if (thres <= 3 || level > thres)
|
|
+ return;
|
|
+
|
|
+ va_start(ap, f);
|
|
+#if DAEMON
|
|
+ if (!logsink) {
|
|
+ time_t t = time(NULL);
|
|
+ struct tm *tb = localtime(&t);
|
|
+ char buff[16];
|
|
+
|
|
+ strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
|
|
+ buff[sizeof(buff)-1] = '\0';
|
|
+
|
|
+ fprintf(stdout, "%s | ", buff);
|
|
+ fprintf(stdout, "libdevmapper: %s(%i): ", file, line);
|
|
+ vfprintf(stdout, f, ap);
|
|
+ fprintf(stdout, "\n");
|
|
+ } else {
|
|
+ condlog(level, "libdevmapper: %s(%i): ", file, line);
|
|
+ log_safe(level + 3, f, ap);
|
|
+ }
|
|
+#else
|
|
+ fprintf(stdout, "libdevmapper: %s(%i): ", file, line);
|
|
+ vfprintf(stdout, f, ap);
|
|
+ fprintf(stdout, "\n");
|
|
+#endif
|
|
+ va_end(ap);
|
|
|
|
-void
|
|
-dm_restore_log (void)
|
|
-{
|
|
- dm_log_init(NULL);
|
|
+ return;
|
|
}
|
|
|
|
-void
|
|
-dm_shut_log (void)
|
|
-{
|
|
- dm_log_init(&dm_dummy_log);
|
|
+extern void
|
|
+dm_init(void) {
|
|
+ dm_log_init(&dm_write_log);
|
|
+ dm_log_init_verbose(conf ? conf->verbosity + 3 : 0);
|
|
}
|
|
|
|
static int
|
|
@@ -764,9 +800,7 @@ dm_mapname(int major, int minor)
|
|
* daemon uev_trigger -> uev_add_map
|
|
*/
|
|
while (--loop) {
|
|
- dm_shut_log();
|
|
r = dm_task_run(dmt);
|
|
- dm_restore_log();
|
|
|
|
if (r)
|
|
break;
|
|
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
|
|
index 59afd01..8438034 100644
|
|
--- a/libmultipath/devmapper.h
|
|
+++ b/libmultipath/devmapper.h
|
|
@@ -1,5 +1,4 @@
|
|
-void dm_shut_log(void);
|
|
-void dm_restore_log(void);
|
|
+void dm_init(void);
|
|
int dm_prereq (char *);
|
|
int dm_simplecmd (int, const char *);
|
|
int dm_addmap (int, const char *, const char *, const char *,
|
|
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
|
index c705cc6..4572a7d 100644
|
|
--- a/libmultipath/dict.c
|
|
+++ b/libmultipath/dict.c
|
|
@@ -270,7 +270,7 @@ blacklist_exceptions_handler(vector strv
|
|
conf->elist_wwid = vector_alloc();
|
|
conf->elist_device = vector_alloc();
|
|
|
|
- if (!conf->elist_devnode || !conf->elist_wwid || !conf->blist_device)
|
|
+ if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device)
|
|
return 1;
|
|
|
|
return 0;
|
|
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
|
|
index df6f5aa..d5b227f 100644
|
|
--- a/libmultipath/hwtable.c
|
|
+++ b/libmultipath/hwtable.c
|
|
@@ -63,11 +63,11 @@ static struct hwentry default_hw[] = {
|
|
.vendor = "DEC",
|
|
.product = "HSG80",
|
|
.getuid = DEFAULT_GETUID,
|
|
- .getprio = NULL,
|
|
- .features = DEFAULT_FEATURES,
|
|
- .hwhandler = "1 hp_sw",
|
|
+ .getprio = "mpath_prio_hp_sw /dev/%n",
|
|
+ .features = "1 queue_if_no_path",
|
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
|
.selector = DEFAULT_SELECTOR,
|
|
- .pgpolicy = GROUP_BY_SERIAL,
|
|
+ .pgpolicy = GROUP_BY_PRIO,
|
|
.pgfailback = FAILBACK_UNDEF,
|
|
.rr_weight = RR_WEIGHT_NONE,
|
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
|
@@ -75,61 +75,62 @@ static struct hwentry default_hw[] = {
|
|
.checker_name = HP_SW,
|
|
},
|
|
{
|
|
- .vendor = "(COMPAQ|HP)",
|
|
- .product = "(MSA|HSV)1.*",
|
|
+ .vendor = "HP",
|
|
+ .product = "A6189A",
|
|
.getuid = DEFAULT_GETUID,
|
|
.getprio = NULL,
|
|
.features = DEFAULT_FEATURES,
|
|
- .hwhandler = "1 hp_sw",
|
|
+ .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 = HP_SW,
|
|
+ .checker_name = READSECTOR0,
|
|
},
|
|
{
|
|
- .vendor = "HP",
|
|
- .product = "A6189A",
|
|
+ /* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */
|
|
+ .vendor = "(COMPAQ|HP)",
|
|
+ .product = "(MSA|HSV)1.0.*",
|
|
.getuid = DEFAULT_GETUID,
|
|
- .getprio = NULL,
|
|
- .features = DEFAULT_FEATURES,
|
|
+ .getprio = "mpath_prio_hp_sw /dev/%n",
|
|
+ .features = "1 queue_if_no_path",
|
|
.hwhandler = DEFAULT_HWHANDLER,
|
|
.selector = DEFAULT_SELECTOR,
|
|
- .pgpolicy = MULTIBUS,
|
|
+ .pgpolicy = GROUP_BY_PRIO,
|
|
.pgfailback = FAILBACK_UNDEF,
|
|
.rr_weight = RR_WEIGHT_NONE,
|
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
|
.minio = DEFAULT_MINIO,
|
|
- .checker_name = READSECTOR0,
|
|
+ .checker_name = HP_SW,
|
|
},
|
|
{
|
|
+ /* MSA 1000/1500 with new firmware */
|
|
.vendor = "HP",
|
|
- .product = "HSV20.*",
|
|
- .revision = "[123].*",
|
|
+ .product = "MSA VOLUME",
|
|
.getuid = DEFAULT_GETUID,
|
|
- .getprio = NULL,
|
|
+ .getprio = "mpath_prio_alua /dev/%n",
|
|
.features = DEFAULT_FEATURES,
|
|
.hwhandler = DEFAULT_HWHANDLER,
|
|
.selector = DEFAULT_SELECTOR,
|
|
- .pgpolicy = MULTIBUS,
|
|
- .pgfailback = FAILBACK_UNDEF,
|
|
+ .pgpolicy = GROUP_BY_PRIO,
|
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
|
.rr_weight = RR_WEIGHT_NONE,
|
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
|
.minio = DEFAULT_MINIO,
|
|
- .checker_name = HP_SW,
|
|
+ .checker_name = TUR,
|
|
},
|
|
{
|
|
- .vendor = "HP",
|
|
- .product = "HSV20.*",
|
|
- .revision = "[^123].*",
|
|
+ /* EVA 3000/5000 with new firmware */
|
|
+ .vendor = "(COMPAQ|HP)",
|
|
+ .product = "(MSA|HSV)1.1.*",
|
|
.getuid = DEFAULT_GETUID,
|
|
- .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
|
+ .getprio = "mpath_prio_alua /dev/%n",
|
|
.features = DEFAULT_FEATURES,
|
|
.hwhandler = DEFAULT_HWHANDLER,
|
|
.selector = DEFAULT_SELECTOR,
|
|
- .pgpolicy = MULTIBUS,
|
|
+ .pgpolicy = GROUP_BY_PRIO,
|
|
.pgfailback = -FAILBACK_IMMEDIATE,
|
|
.rr_weight = RR_WEIGHT_NONE,
|
|
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
|
@@ -137,15 +138,16 @@ static struct hwentry default_hw[] = {
|
|
.checker_name = TUR,
|
|
},
|
|
{
|
|
+ /* EVA 4000/6000/8000 */
|
|
.vendor = "HP",
|
|
- .product = "HSV21.*",
|
|
+ .product = "HSV2.*",
|
|
.getuid = DEFAULT_GETUID,
|
|
- .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
|
+ .getprio = "mpath_prio_alua /dev/%n",
|
|
.features = DEFAULT_FEATURES,
|
|
.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,
|
|
@@ -404,9 +406,9 @@ static struct hwentry default_hw[] = {
|
|
.vendor = "IBM",
|
|
.product = "S/390 DASD ECKD",
|
|
.bl_product = "S/390.*",
|
|
- .getuid = "/sbin/dasd_id /dev/%n",
|
|
+ .getuid = "dasdinfo -u -b %n",
|
|
.getprio = NULL,
|
|
- .features = DEFAULT_FEATURES,
|
|
+ .features = "1 queue_if_no_path",
|
|
.hwhandler = DEFAULT_HWHANDLER,
|
|
.selector = DEFAULT_SELECTOR,
|
|
.pgpolicy = MULTIBUS,
|
|
@@ -511,9 +513,24 @@ static struct hwentry default_hw[] = {
|
|
.pgpolicy = GROUP_BY_PRIO,
|
|
.pgfailback = -FAILBACK_IMMEDIATE,
|
|
.rr_weight = RR_WEIGHT_NONE,
|
|
- .no_path_retry = NO_PATH_RETRY_UNDEF,
|
|
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
|
|
.minio = DEFAULT_MINIO,
|
|
- .checker_name = TUR,
|
|
+ .checker_name = RDAC,
|
|
+ },
|
|
+ {
|
|
+ .vendor = "SGI",
|
|
+ .product = "IS.*",
|
|
+ .getuid = DEFAULT_GETUID,
|
|
+ .getprio = "mpath_prio_tpc /dev/%n",
|
|
+ .features = DEFAULT_FEATURES,
|
|
+ .hwhandler = DEFAULT_HWHANDLER,
|
|
+ .selector = DEFAULT_SELECTOR,
|
|
+ .pgpolicy = GROUP_BY_PRIO,
|
|
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
|
+ .rr_weight = RR_WEIGHT_NONE,
|
|
+ .no_path_retry = NO_PATH_RETRY_QUEUE,
|
|
+ .minio = DEFAULT_MINIO,
|
|
+ .checker_name = RDAC,
|
|
},
|
|
/*
|
|
* STK arrays
|
|
diff --git a/libmultipath/log.c b/libmultipath/log.c
|
|
index 8b339d7..90e4d1f 100644
|
|
--- a/libmultipath/log.c
|
|
+++ b/libmultipath/log.c
|
|
@@ -118,6 +118,11 @@ int log_enqueue (int prio, const char *
|
|
/* not enough space on tail : rewind */
|
|
if (la->head <= la->tail && len > (la->end - la->tail)) {
|
|
logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
|
|
+ if (la->head == la->start ) {
|
|
+ logdbg(stderr, "enqueue: can not rewind tail, drop msg\n");
|
|
+ la->tail = lastmsg;
|
|
+ return 1; /* can't reuse */
|
|
+ }
|
|
la->tail = la->start;
|
|
|
|
if (la->empty)
|
|
diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c
|
|
index f98cfa4..5a82b6a 100644
|
|
--- a/libmultipath/log_pthread.c
|
|
+++ b/libmultipath/log_pthread.c
|
|
@@ -12,7 +12,7 @@
|
|
#include "log_pthread.h"
|
|
#include "log.h"
|
|
|
|
-void log_safe (int prio, char * fmt, va_list ap)
|
|
+void log_safe (int prio, const char * fmt, va_list ap)
|
|
{
|
|
pthread_mutex_lock(logq_lock);
|
|
//va_start(ap, fmt);
|
|
diff --git a/libmultipath/log_pthread.h b/libmultipath/log_pthread.h
|
|
index 7c902c7..2b18f59 100644
|
|
--- a/libmultipath/log_pthread.h
|
|
+++ b/libmultipath/log_pthread.h
|
|
@@ -7,7 +7,7 @@ pthread_mutex_t *logq_lock;
|
|
pthread_mutex_t *logev_lock;
|
|
pthread_cond_t *logev_cond;
|
|
|
|
-void log_safe(int prio, char * fmt, va_list ap);
|
|
+void log_safe(int prio, const char * fmt, va_list ap);
|
|
void log_thread_start(void);
|
|
void log_thread_stop(void);
|
|
|
|
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
|
|
index f9c555e..5302970 100644
|
|
--- a/libmultipath/parser.c
|
|
+++ b/libmultipath/parser.c
|
|
@@ -455,16 +455,23 @@ process_stream(vector keywords)
|
|
return r;
|
|
}
|
|
|
|
+int alloc_keywords(void)
|
|
+{
|
|
+ if (!keywords)
|
|
+ keywords = vector_alloc();
|
|
+
|
|
+ if (!keywords)
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Data initialization */
|
|
int
|
|
init_data(char *conf_file, void (*init_keywords) (void))
|
|
{
|
|
int r;
|
|
|
|
- if (!keywords)
|
|
- keywords = vector_alloc();
|
|
- if (!keywords)
|
|
- return 1;
|
|
stream = fopen(conf_file, "r");
|
|
if (!stream) {
|
|
syslog(LOG_WARNING, "Configuration file open problem");
|
|
diff --git a/libmultipath/parser.h b/libmultipath/parser.h
|
|
index 95d4e6f..8496684 100644
|
|
--- a/libmultipath/parser.h
|
|
+++ b/libmultipath/parser.h
|
|
@@ -74,6 +74,7 @@ extern vector read_value_block(void);
|
|
extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
|
|
extern void *set_value(vector strvec);
|
|
extern int process_stream(vector keywords);
|
|
+extern int alloc_keywords(void);
|
|
extern int init_data(char *conf_file, void (*init_keywords) (void));
|
|
extern struct keyword * find_keyword(vector v, char * name);
|
|
void set_current_keywords (vector *k);
|
|
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
|
index e50f37d..dc8af48 100644
|
|
--- a/libmultipath/print.c
|
|
+++ b/libmultipath/print.c
|
|
@@ -734,7 +734,7 @@ snprint_hwentry (char * buff, int len, s
|
|
if (fwd > len)
|
|
return len;
|
|
iterate_sub_keywords(rootkw, kw, i) {
|
|
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
|
|
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k \"%v\"\n",
|
|
kw, hwe);
|
|
if (fwd > len)
|
|
return len;
|
|
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
|
index 53b7e17..a4a996a 100644
|
|
--- a/libmultipath/structs_vec.c
|
|
+++ b/libmultipath/structs_vec.c
|
|
@@ -16,7 +16,6 @@
|
|
#include "discovery.h"
|
|
#include "waiter.h"
|
|
|
|
-
|
|
/*
|
|
* creates or updates mpp->paths reading mpp->pg
|
|
*/
|
|
@@ -118,6 +117,8 @@ remove_map (struct multipath * mpp, stru
|
|
{
|
|
int i;
|
|
|
|
+ condlog(4, "%s: remove multipath map", mpp->alias);
|
|
+
|
|
/*
|
|
* stop the DM event waiter thread
|
|
*/
|
|
@@ -245,8 +246,17 @@ extern int
|
|
setup_multipath (struct vectors * vecs, struct multipath * mpp)
|
|
{
|
|
retry:
|
|
- if (dm_get_info(mpp->alias, &mpp->dmi))
|
|
+ if (dm_get_info(mpp->alias, &mpp->dmi)) {
|
|
+ /* Error accessing table */
|
|
+ condlog(3, "%s: cannot access table", mpp->alias);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!dm_map_present(mpp->alias)) {
|
|
+ /* Table has been removed */
|
|
+ condlog(3, "%s: table does not exist", mpp->alias);
|
|
goto out;
|
|
+ }
|
|
|
|
set_multipath_wwid(mpp);
|
|
mpp->mpe = find_mpe(mpp->wwid);
|
|
@@ -270,6 +280,7 @@ retry:
|
|
#endif
|
|
goto retry;
|
|
}
|
|
+ condlog(0, "%s: failed to setup multipath", mpp->alias);
|
|
goto out;
|
|
}
|
|
|
|
@@ -282,7 +293,6 @@ retry:
|
|
|
|
return 0;
|
|
out:
|
|
- condlog(0, "%s: failed to setup multipath", mpp->alias);
|
|
remove_map(mpp, vecs, NULL, 1);
|
|
return 1;
|
|
}
|
|
@@ -390,18 +400,19 @@ int update_multipath (struct vectors *ve
|
|
struct pathgroup *pgp;
|
|
struct path *pp;
|
|
int i, j;
|
|
- int r = 1;
|
|
|
|
mpp = find_mp_by_alias(vecs->mpvec, mapname);
|
|
|
|
- if (!mpp)
|
|
- goto out;
|
|
+ if (!mpp) {
|
|
+ condlog(3, "%s: multipath map not found\n", mapname);
|
|
+ return 2;
|
|
+ }
|
|
|
|
free_pgvec(mpp->pg, KEEP_PATHS);
|
|
mpp->pg = NULL;
|
|
|
|
if (setup_multipath(vecs, mpp))
|
|
- goto out; /* mpp freed in setup_multipath */
|
|
+ return 1; /* mpp freed in setup_multipath */
|
|
|
|
/*
|
|
* compare checkers states with DM states
|
|
@@ -429,11 +440,8 @@ int update_multipath (struct vectors *ve
|
|
}
|
|
}
|
|
}
|
|
- r = 0;
|
|
-out:
|
|
- if (r)
|
|
- condlog(0, "failed to update multipath");
|
|
- return r;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
|
|
index 75ed90c..d7af0d1 100644
|
|
--- a/libmultipath/waiter.c
|
|
+++ b/libmultipath/waiter.c
|
|
@@ -117,15 +117,11 @@ int waiteventloop (struct event_thread *
|
|
/* 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;
|
|
@@ -157,8 +153,11 @@ int waiteventloop (struct event_thread *
|
|
r = update_multipath(waiter->vecs, waiter->mapname);
|
|
lock_cleanup_pop(waiter->vecs->lock);
|
|
|
|
- if (r)
|
|
+ if (r) {
|
|
+ condlog(2, "%s: event checker exit",
|
|
+ waiter->mapname);
|
|
return -1; /* stop the thread */
|
|
+ }
|
|
|
|
event_nr = dm_geteventnr(waiter->mapname);
|
|
|
|
diff --git a/multipath/Makefile b/multipath/Makefile
|
|
index 646dfc2..947d481 100644
|
|
--- a/multipath/Makefile
|
|
+++ b/multipath/Makefile
|
|
@@ -25,11 +25,9 @@ prepare:
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
klibc: prepare $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
$(CHECKERSLIB)-$(BUILD).a:
|
|
make -C $(checkersdir) BUILD=$(BUILD) $(BUILD)
|
|
@@ -43,12 +41,13 @@ install:
|
|
install -d $(DESTDIR)/etc/udev/rules.d
|
|
install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
|
|
install -d $(DESTDIR)$(mandir)
|
|
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
|
+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
+ install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
+ rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
rm -f core *.o $(EXEC) *.gz
|
|
diff --git a/multipath/main.c b/multipath/main.c
|
|
index 67076db..c3d0dac 100644
|
|
--- a/multipath/main.c
|
|
+++ b/multipath/main.c
|
|
@@ -72,7 +72,7 @@ static void
|
|
usage (char * progname)
|
|
{
|
|
fprintf (stderr, VERSION_STRING);
|
|
- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n",
|
|
+ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F|-t]\n",
|
|
progname);
|
|
fprintf (stderr,
|
|
"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
|
|
@@ -90,6 +90,7 @@ usage (char * progname)
|
|
"\t-ll\t\tshow multipath topology (maximum info)\n" \
|
|
"\t-f\t\tflush a multipath device map\n" \
|
|
"\t-F\t\tflush all multipath device maps\n" \
|
|
+ "\t-t\t\tprint internal hardware table\n" \
|
|
"\t-p policy\tforce all maps to specified policy :\n" \
|
|
"\t failover\t\t1 path per priority group\n" \
|
|
"\t multibus\t\tall paths in 1 priority group\n" \
|
|
@@ -307,6 +308,55 @@ out:
|
|
return r;
|
|
}
|
|
|
|
+static int
|
|
+dump_config (void)
|
|
+{
|
|
+ char * c;
|
|
+ char * reply;
|
|
+ unsigned int maxlen = 256;
|
|
+ int again = 1;
|
|
+
|
|
+ reply = MALLOC(maxlen);
|
|
+
|
|
+ while (again) {
|
|
+ if (!reply)
|
|
+ return 1;
|
|
+ c = reply;
|
|
+ c += snprint_defaults(c, reply + maxlen - c);
|
|
+ again = ((c - reply) == maxlen);
|
|
+ if (again) {
|
|
+ reply = REALLOC(reply, maxlen *= 2);
|
|
+ continue;
|
|
+ }
|
|
+ c += snprint_blacklist(c, reply + maxlen - c);
|
|
+ again = ((c - reply) == maxlen);
|
|
+ if (again) {
|
|
+ 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) {
|
|
+ reply = REALLOC(reply, maxlen *= 2);
|
|
+ continue;
|
|
+ }
|
|
+ c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
|
|
+ again = ((c - reply) == maxlen);
|
|
+ if (again)
|
|
+ reply = REALLOC(reply, maxlen *= 2);
|
|
+ }
|
|
+
|
|
+ printf("%s", reply);
|
|
+ FREE(reply);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
@@ -330,7 +380,7 @@ main (int argc, char *argv[])
|
|
if (load_config(DEFAULT_CONFIGFILE))
|
|
exit(1);
|
|
|
|
- while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) {
|
|
+ while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:t")) != EOF ) {
|
|
switch(arg) {
|
|
case 1: printf("optarg : %s\n",optarg);
|
|
break;
|
|
@@ -373,6 +423,9 @@ main (int argc, char *argv[])
|
|
usage(argv[0]);
|
|
}
|
|
break;
|
|
+ case 't':
|
|
+ dump_config();
|
|
+ goto out;
|
|
case 'h':
|
|
usage(argv[0]);
|
|
case ':':
|
|
@@ -401,6 +454,7 @@ main (int argc, char *argv[])
|
|
conf->dev_type = DEV_DEVMAP;
|
|
|
|
}
|
|
+ dm_init();
|
|
|
|
if (conf->remove == FLUSH_ONE) {
|
|
if (conf->dev_type == DEV_DEVMAP)
|
|
diff --git a/multipath/multipath.8 b/multipath/multipath.8
|
|
index 693872b..e72cc45 100644
|
|
--- a/multipath/multipath.8
|
|
+++ b/multipath/multipath.8
|
|
@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco
|
|
.RB [\| \-v\ \c
|
|
.IR verbosity \|]
|
|
.RB [\| \-d \|]
|
|
-.RB [\| \-h | \-l | \-ll | \-f | \-F \|]
|
|
+.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F \|]
|
|
.RB [\| \-p\ \c
|
|
.BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
|
|
.RB [\| device \|]
|
|
@@ -47,6 +47,9 @@ flush a multipath device map specified a
|
|
.B \-F
|
|
flush all unused multipath device maps
|
|
.TP
|
|
+.B \-t
|
|
+print internal hardware table to stdout
|
|
+.TP
|
|
.BI \-p " policy"
|
|
force maps to specified policy:
|
|
.RS 1.2i
|
|
@@ -76,6 +79,9 @@ is in the /dev/sdb (as shown by udev in
|
|
.I device
|
|
may alternatively be a multipath mapname
|
|
.SH "SEE ALSO"
|
|
+.BR multipathd (8),
|
|
+.BR multipath.conf (5),
|
|
+.BR kpartx (8),
|
|
.BR udev (8),
|
|
.BR dmsetup (8)
|
|
.BR hotplug (8)
|
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
|
new file mode 100644
|
|
index 0000000..1c1c0db
|
|
--- /dev/null
|
|
+++ b/multipath/multipath.conf.5
|
|
@@ -0,0 +1,384 @@
|
|
+.TH MULTIPATH.CONF 5 "30 November 2006"
|
|
+.SH NAME
|
|
+multipath.conf \- multipath daemon configuration file
|
|
+.SH DESCRIPTION
|
|
+.B "multipath.conf"
|
|
+is the configuration file for the multipath daemon. It is used to
|
|
+overwrite the built-in configuration table of \fBmultipathd\fP.
|
|
+Any line whose first non-white-space character is a '#' is considered
|
|
+a comment line. Empty lines are ignored.
|
|
+.SH SYNTAX
|
|
+The configuration file contains entries of the form:
|
|
+.RS
|
|
+.nf
|
|
+.ft B
|
|
+.sp
|
|
+<section> {
|
|
+.RS
|
|
+.ft B
|
|
+<attribute> <value>
|
|
+.I "..."
|
|
+.ft B
|
|
+<subsection> {
|
|
+.RS
|
|
+.ft B
|
|
+<attribute> <value>
|
|
+.I "..."
|
|
+.RE
|
|
+}
|
|
+.RE
|
|
+}
|
|
+.ft R
|
|
+.fi
|
|
+.RE
|
|
+.LP
|
|
+Each \fIsection\fP contains one or more attributes or subsections. The
|
|
+recognized keywords for attributes or subsections depend on the
|
|
+section in which they occor.
|
|
+.LP
|
|
+The following \fIsection\fP keywords are recognized:
|
|
+.TP 17
|
|
+.B defaults
|
|
+This section defines default values for attributes which are used
|
|
+whenever no specific setting is given.
|
|
+.TP
|
|
+.B blacklist
|
|
+This section defines which devices should be excluded from the
|
|
+multipath topology discovery.
|
|
+.TP
|
|
+.B blacklist_exceptions
|
|
+This section defines which devices should be included in the
|
|
+multipath topology discovery, despite being listed in the
|
|
+.I blacklist
|
|
+section.
|
|
+.TP
|
|
+.B multipaths
|
|
+This section defines the multipath topologies. They are indexed by a
|
|
+\fIWorld Wide Identifier\fR(wwid), which is the result of the
|
|
+\fIgetuid_callout\fR program.
|
|
+.TP
|
|
+.B devices
|
|
+This section defines the device-specific settings.
|
|
+.RE
|
|
+.LP
|
|
+.SH "defaults section"
|
|
+The
|
|
+.B defaults
|
|
+section recognizes the following keywords:
|
|
+.TP 17
|
|
+.B polling_interval
|
|
+interval between two path checks in seconds; default is
|
|
+.I 5
|
|
+.TP
|
|
+.B udev_dir
|
|
+directory where udev creates its device nodes; default is
|
|
+.I /dev
|
|
+.TP
|
|
+.B selector
|
|
+The default path selector algorithm to use; they are offered by the
|
|
+kernel multipath target. The only currently implemented is
|
|
+.I "round-robin 0"
|
|
+.TP
|
|
+.B path_grouping_policy
|
|
+The default path grouping policy to apply to unspecified
|
|
+multipaths. Possible values are
|
|
+.RS
|
|
+.TP 12
|
|
+.B failover
|
|
+1 path per priority group
|
|
+.TP
|
|
+.B multibus
|
|
+all paths in 1 priority group
|
|
+.TP
|
|
+.B group_by_serial
|
|
+1 priority group per serial number
|
|
+.TP
|
|
+.B group_by_prio
|
|
+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.
|
|
+.TP
|
|
+Default value is \fImultibus\fR.
|
|
+.RE
|
|
+.TP
|
|
+.B getuid_callout
|
|
+The default program and args to callout to obtain a unique path
|
|
+identifier. Should be specified with an absolute path. Default value
|
|
+is
|
|
+.I /sbin/scsi_id -g -u -s
|
|
+.TP
|
|
+.B prio_callout
|
|
+The default program and args to callout to obtain a path priority
|
|
+value. The specified program will be executed and should return a
|
|
+numeric value specifying the relative priority of this path. Higher
|
|
+number have a higher priority. A '%n' in the command line will be expanded
|
|
+to the device name, a '%b' will be expanded to the device number in
|
|
+.I major:minor
|
|
+format.
|
|
+.I "none"
|
|
+is a valid value. Currently the following path priority programs are
|
|
+implemented:
|
|
+.RS
|
|
+.TP 12
|
|
+.B mpath_prio_emc /dev/%n
|
|
+Generate the path priority for EMC arrays
|
|
+.TP
|
|
+.B mpath_prio_alua /dev/%n
|
|
+Generate the path priority based on the SCSI-3 ALUA settings.
|
|
+.TP
|
|
+.B mpath_prio_netapp /dev/%n
|
|
+Generate the path priority for NetApp arrays.
|
|
+.TP
|
|
+.B mpath_prio_tpc /dev/%n
|
|
+Generate the path priority for LSI/Engenio RDAC controller.
|
|
+.TP
|
|
+.B mpath_prio_hp_sw /dev/%n
|
|
+Generate the path priority for Compaq/HP controller in
|
|
+active/standby mode.
|
|
+.TP
|
|
+.B mpath_prio_hds_modular %b
|
|
+Generate the path priority for Hitachi HDS Modular storage arrays.
|
|
+.TP
|
|
+Default value is \fBnone\fR.
|
|
+.RE
|
|
+.TP
|
|
+.B features
|
|
+Specify any device-mapper features to be used. The most common of
|
|
+these features is
|
|
+.I "1 queue_if_no_path"
|
|
+Note that this can also be set via the
|
|
+.I no_path_retry
|
|
+keyword.
|
|
+.TP
|
|
+.B path_checker
|
|
+The default method used to determine the paths' state. Possible values
|
|
+are
|
|
+.RS
|
|
+.TP 12
|
|
+.B readsector0
|
|
+Read the first sector of the device
|
|
+.TP
|
|
+.B tur
|
|
+Issue a
|
|
+.I TEST UNIT READY
|
|
+command to the device.
|
|
+.TP
|
|
+.B emc_clariion
|
|
+Query the EMC Clariion specific EVPD page 0xC0 to determine the path
|
|
+state.
|
|
+.TP
|
|
+.B hp_sw
|
|
+Check the path state for HP storage arrays with Active/Standby firmware.
|
|
+.TP
|
|
+.B rdac
|
|
+Check the path state for LSI/Engenio RDAC storage controller.
|
|
+.TP
|
|
+.B directio
|
|
+Read the first sector with direct I/O.
|
|
+.TP
|
|
+Default value is \fIreadsector0\fR.
|
|
+.RE
|
|
+.TP
|
|
+.B failback
|
|
+Tell the daemon to manage path group failback, or not to. 0 or
|
|
+.I immediate
|
|
+means immediate failback, values >0 means deferred failback (in
|
|
+seconds).
|
|
+.I manual
|
|
+means no failback. Default value is
|
|
+.I manual
|
|
+.TP
|
|
+.B rr_min_io
|
|
+The number of IO to route to a path before switching to the next in
|
|
+the same path group. Default is
|
|
+.I 1000
|
|
+.TP
|
|
+.B rr_weight
|
|
+If set to \fIpriorities\fR the multipath configurator will assign
|
|
+path weights as "path prio * rr_min_io". Possible values are
|
|
+.I priorities
|
|
+or
|
|
+.I uniform
|
|
+. Default is
|
|
+.I uniform
|
|
+.TP
|
|
+.B no_path_retry
|
|
+Specify the number of retries until disable queueing, or
|
|
+.I fail
|
|
+for immediate failure (no queueing),
|
|
+.I queue
|
|
+for never stop queueing. Default is 0.
|
|
+.TP
|
|
+.B user_friendly_names
|
|
+If set to
|
|
+.I yes
|
|
+, using the bindings file
|
|
+.I /var/lib/multipath/bindings
|
|
+to assign a persistent and unique alias to the multipath, in the form of mpath<n>.
|
|
+If set to
|
|
+.I no
|
|
+use the WWID as the alias. In either case this be will
|
|
+be overriden by any specific aliases in the \fImultipaths\fR section.
|
|
+Default is
|
|
+.I no
|
|
+.
|
|
+.SH "blacklist section"
|
|
+The
|
|
+.I blacklist
|
|
+section is used to exclude specific device from inclusion in the
|
|
+multipath topology. It is most commonly used to exclude local disks or
|
|
+LUNs for the array controller.
|
|
+.LP
|
|
+The following keywords are recognized:
|
|
+.TP 17
|
|
+.B wwid
|
|
+The \fIWorld Wide Identification\fR of a device.
|
|
+.TP
|
|
+.B devnode
|
|
+Regular expression of the device nodes to be excluded.
|
|
+.TP
|
|
+.B device
|
|
+Subsection for the device description. This subsection recognizes the
|
|
+.I vendor
|
|
+and
|
|
+.I product
|
|
+keywords. For a full description of these keywords please see the
|
|
+.I devices
|
|
+section description.
|
|
+.SH "blacklist_exceptions section"
|
|
+The
|
|
+.I blacklist_exceptions
|
|
+section is used to revert the actions of the
|
|
+.I blacklist
|
|
+section, ie to include specific device in the
|
|
+multipath topology. This allows to selectively include devices which
|
|
+would normally be excluded via the
|
|
+.I blacklist
|
|
+section.
|
|
+.LP
|
|
+The following keywords are recognized:
|
|
+.TP 17
|
|
+.B wwid
|
|
+The \fIWorld Wide Identification\fR of a device.
|
|
+.TP
|
|
+.B devnode
|
|
+Regular expression of the device nodes to be excluded.
|
|
+.TP
|
|
+.B device
|
|
+Subsection for the device description. This subsection recognizes the
|
|
+.I vendor
|
|
+and
|
|
+.I product
|
|
+keywords. For a full description of these keywords please see the
|
|
+.I devices
|
|
+section description.
|
|
+.SH "multipaths section"
|
|
+The only recognized attribute for the
|
|
+.B multipaths
|
|
+section is the
|
|
+.I multipath
|
|
+subsection.
|
|
+.LP
|
|
+The
|
|
+.B multipath
|
|
+subsection recognizes the following attributes:
|
|
+.TP 17
|
|
+.B wwid
|
|
+Index of the container. Mandatory for this subsection.
|
|
+.TP
|
|
+.B alias
|
|
+(Optional) symbolic name for the multipath map.
|
|
+.LP
|
|
+The following attributes are optional; if not set the default values
|
|
+are taken from the
|
|
+.I defaults
|
|
+section:
|
|
+.sp 1
|
|
+.PD .1v
|
|
+.RS
|
|
+.TP 18
|
|
+.B path_grouping_policy
|
|
+.TP
|
|
+.B path_checker
|
|
+.TP
|
|
+.B path_selector
|
|
+.TP
|
|
+.B failback
|
|
+.TP
|
|
+.B no_path_retry
|
|
+.TP
|
|
+.B rr_min_io
|
|
+.RE
|
|
+.PD
|
|
+.LP
|
|
+.SH "devices section"
|
|
+The only recognized attribute for the
|
|
+.B devices
|
|
+section is the
|
|
+.I device
|
|
+subsection.
|
|
+.LP
|
|
+The
|
|
+.I device
|
|
+subsection recognizes the following attributes:
|
|
+.TP 17
|
|
+.B vendor
|
|
+(Mandatory) Vendor identifier
|
|
+.TP
|
|
+.B product
|
|
+(Mandatory) Product identifier
|
|
+.TP
|
|
+.B product_blacklist
|
|
+Product strings to blacklist for this vendor
|
|
+.TP
|
|
+.B hardware_handler
|
|
+(Optional) The hardware handler to use for this device type.
|
|
+The following hardware handler are implemented:
|
|
+.RS
|
|
+.TP 12
|
|
+.B 1 emc
|
|
+Hardware handler for EMC storage arrays.
|
|
+.RE
|
|
+.LP
|
|
+The following attributes are optional; if not set the default values
|
|
+are taken from the
|
|
+.I defaults
|
|
+section:
|
|
+.sp 1
|
|
+.PD .1v
|
|
+.RS
|
|
+.TP 18
|
|
+.B path_grouping_policy
|
|
+.TP
|
|
+.B getuid_callout
|
|
+.TP
|
|
+.B path_selector
|
|
+.TP
|
|
+.B path_checker
|
|
+.TP
|
|
+.B features
|
|
+.TP
|
|
+.B prio_callout
|
|
+.TP
|
|
+.B failback
|
|
+.TP
|
|
+.B rr_weight
|
|
+.TP
|
|
+.B no_path_retry
|
|
+.TP
|
|
+.B rr_min_io
|
|
+.RE
|
|
+.PD
|
|
+.LP
|
|
+.SH "SEE ALSO"
|
|
+.BR udev (8),
|
|
+.BR dmsetup (8)
|
|
+.BR multipath (8)
|
|
+.BR multipathd (8)
|
|
+.SH AUTHORS
|
|
+.B multipath
|
|
+was developed by Christophe Varoqui, <christophe.varoqui@free.fr> and others.
|
|
diff --git a/multipathd/Makefile b/multipathd/Makefile
|
|
index 8ad25ee..da351dc 100644
|
|
--- a/multipathd/Makefile
|
|
+++ b/multipathd/Makefile
|
|
@@ -35,7 +35,6 @@ klibc:
|
|
|
|
$(EXEC): clean $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
- $(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
|
|
|
$(CHECKERSLIB)-glibc.a:
|
|
$(MAKE) -C $(checkersdir) BUILD=glibc glibc
|
|
@@ -48,12 +47,12 @@ install:
|
|
install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
install -d $(DESTDIR)$(rcdir)
|
|
install -d $(DESTDIR)$(mandir)
|
|
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
|
+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
|
|
uninstall:
|
|
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
|
rm -f $(DESTDIR)$(rcdir)/$(EXEC)
|
|
- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
+ rm -f $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
$(MAKE) -C $(multipathdir) prepare DAEMON=1
|
|
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
|
index d786eef..587514f 100644
|
|
--- a/multipathd/cli.c
|
|
+++ b/multipathd/cli.c
|
|
@@ -498,7 +498,7 @@ key_generator (const char * str, int sta
|
|
/*
|
|
* Loop through keywords for completion candidates
|
|
*/
|
|
- vector_foreach_slot_after (keys, kw, index) {
|
|
+ vector_foreach_slot (keys, kw, index) {
|
|
if (!strncmp(kw->str, str, len)) {
|
|
/*
|
|
* Discard keywords already in the command line
|
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
|
index f2f9a96..94b0b95 100644
|
|
--- a/multipathd/main.c
|
|
+++ b/multipathd/main.c
|
|
@@ -225,6 +225,8 @@ ev_add_map (char * devname, struct vecto
|
|
int map_present;
|
|
int r = 1;
|
|
|
|
+ /* libsysfs seems to forget to terminate the string... */
|
|
+ memset(dev_t, 0, BLK_DEV_SIZE);
|
|
if (sscanf(devname, "dm-%d", &minor) == 1 &&
|
|
!sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
|
|
sscanf(dev_t, "%d:%d", &major, &minor) == 2)
|
|
@@ -646,10 +648,12 @@ uev_trigger (struct uevent * uev, void *
|
|
lock(vecs->lock);
|
|
|
|
/*
|
|
- * device map add/remove event
|
|
+ * device map event
|
|
+ * Add events are ignored here as the tables
|
|
+ * are not fully initialised then.
|
|
*/
|
|
if (!strncmp(devname, "dm-", 3)) {
|
|
- if (!strncmp(uev->action, "add", 3)) {
|
|
+ if (!strncmp(uev->action, "change", 6)) {
|
|
r = uev_add_map(devname, vecs);
|
|
goto out;
|
|
}
|
|
@@ -1397,6 +1401,7 @@ main (int argc, char *argv[])
|
|
int err;
|
|
|
|
logsink = 1;
|
|
+ dm_init();
|
|
|
|
if (getuid() != 0) {
|
|
fprintf(stderr, "need to be root\n");
|
|
diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile
|
|
index 983ffe3..6c58529 100644
|
|
--- a/path_priority/pp_alua/Makefile
|
|
+++ b/path_priority/pp_alua/Makefile
|
|
@@ -35,20 +35,17 @@ glibc: $(OBJS)
|
|
klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
-install: $(BUILD) $(EXEC).8.gz
|
|
+install: $(EXEC) $(EXEC).8
|
|
$(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
- $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
+ $(INSTALL) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
+ rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
rm -f *.o *.gz $(EXEC)
|
|
|
|
-$(EXEC).8.gz: $(EXEC).8
|
|
- $(GZIP) $< >$@
|
|
-
|
|
main.o: main.c rtpg.h spc3.h
|
|
|
|
rtpg.o: rtpg.c rtpg.h spc3.h
|
|
diff --git a/path_priority/pp_emc/pp_emc.c b/path_priority/pp_emc/pp_emc.c
|
|
index dd58424..4031720 100644
|
|
--- a/path_priority/pp_emc/pp_emc.c
|
|
+++ b/path_priority/pp_emc/pp_emc.c
|
|
@@ -60,8 +60,12 @@ int emc_clariion_prio(const char *dev)
|
|
|
|
if ( /* Effective initiator type */
|
|
sense_buffer[27] != 0x03
|
|
- /* Failover mode should be set to 1 */
|
|
- || (sense_buffer[28] & 0x07) != 0x04
|
|
+ /*
|
|
+ * Failover mode should be set to 1 (PNR failover mode)
|
|
+ * or 4 (ALUA failover mode).
|
|
+ */
|
|
+ || (((sense_buffer[28] & 0x07) != 0x04) &&
|
|
+ ((sense_buffer[28] & 0x07) != 0x06))
|
|
/* Arraycommpath should be set to 1 */
|
|
|| (sense_buffer[30] & 0x04) != 0x04) {
|
|
fprintf(stderr, "Path not correctly configured for failover");
|
|
diff --git a/path_priority/pp_hp_sw/Makefile b/path_priority/pp_hp_sw/Makefile
|
|
new file mode 100644
|
|
index 0000000..e7debf5
|
|
--- /dev/null
|
|
+++ b/path_priority/pp_hp_sw/Makefile
|
|
@@ -0,0 +1,25 @@
|
|
+EXEC = mpath_prio_hp_sw
|
|
+BUILD = glibc
|
|
+OBJS = pp_hp_sw.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 -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+
|
|
+uninstall:
|
|
+ rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
+clean:
|
|
+ rm -f *.o $(EXEC)
|
|
+
|
|
+%.o: %.c
|
|
+ $(CC) $(CFLAGS) -c -o $@ $<
|
|
diff --git a/path_priority/pp_hp_sw/pp_hp_sw.c b/path_priority/pp_hp_sw/pp_hp_sw.c
|
|
new file mode 100644
|
|
index 0000000..e4a18b1
|
|
--- /dev/null
|
|
+++ b/path_priority/pp_hp_sw/pp_hp_sw.c
|
|
@@ -0,0 +1,119 @@
|
|
+/*
|
|
+ * Path priority checker for HP active/standby controller
|
|
+ *
|
|
+ * Check the path state and sort them into groups.
|
|
+ * There is actually a preferred path in the controller;
|
|
+ * we should ask HP on how to retrieve that information.
|
|
+ */
|
|
+#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>
|
|
+
|
|
+#define TUR_CMD_LEN 6
|
|
+#define SCSI_CHECK_CONDITION 0x2
|
|
+#define SCSI_COMMAND_TERMINATED 0x22
|
|
+#define SG_ERR_DRIVER_SENSE 0x08
|
|
+#define RECOVERED_ERROR 0x01
|
|
+#define NOT_READY 0x02
|
|
+#define UNIT_ATTENTION 0x06
|
|
+
|
|
+#define HP_PATH_ACTIVE 0x04
|
|
+#define HP_PATH_STANDBY 0x02
|
|
+#define HP_PATH_FAILED 0x00
|
|
+
|
|
+#include "../../libmultipath/sg_include.h"
|
|
+
|
|
+int hp_sw_prio(const char *dev)
|
|
+{
|
|
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
|
+ unsigned char sb[128];
|
|
+ struct sg_io_hdr io_hdr;
|
|
+ int ret = HP_PATH_FAILED;
|
|
+ int fd;
|
|
+
|
|
+ fd = open(dev, O_RDWR|O_NONBLOCK);
|
|
+
|
|
+ if (fd <= 0) {
|
|
+ fprintf(stderr, "Opening the device failed.\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
|
|
+ io_hdr.interface_id = 'S';
|
|
+ io_hdr.cmd_len = sizeof (turCmdBlk);
|
|
+ io_hdr.mx_sb_len = sizeof (sb);
|
|
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
|
|
+ io_hdr.cmdp = turCmdBlk;
|
|
+ io_hdr.sbp = sb;
|
|
+ io_hdr.timeout = 60000;
|
|
+ io_hdr.pack_id = 0;
|
|
+ retry:
|
|
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
|
+ fprintf(stderr, "sending tur command failed\n");
|
|
+ goto out;
|
|
+ }
|
|
+ io_hdr.status &= 0x7e;
|
|
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
|
|
+ (0 == io_hdr.driver_status)) {
|
|
+ /* Command completed normally, path is active */
|
|
+ ret = HP_PATH_ACTIVE;
|
|
+ }
|
|
+
|
|
+ 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, asc, asq;
|
|
+ unsigned char * sense_buffer = io_hdr.sbp;
|
|
+ if (sense_buffer[0] & 0x2) {
|
|
+ sense_key = sense_buffer[1] & 0xf;
|
|
+ asc = sense_buffer[2];
|
|
+ asq = sense_buffer[3];
|
|
+ } else {
|
|
+ sense_key = sense_buffer[2] & 0xf;
|
|
+ asc = sense_buffer[12];
|
|
+ asq = sense_buffer[13];
|
|
+ }
|
|
+ if(RECOVERED_ERROR == sense_key)
|
|
+ ret = HP_PATH_ACTIVE;
|
|
+ if(NOT_READY == sense_key) {
|
|
+ if (asc == 0x04 && asq == 0x02) {
|
|
+ /* This is a standby path */
|
|
+ ret = HP_PATH_STANDBY;
|
|
+ }
|
|
+ }
|
|
+ if(UNIT_ATTENTION == sense_key) {
|
|
+ if (asc == 0x29) {
|
|
+ /* Retry for device reset */
|
|
+ goto retry;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+out:
|
|
+ return(ret);
|
|
+}
|
|
+
|
|
+int
|
|
+main (int argc, char **argv)
|
|
+{
|
|
+ int prio;
|
|
+ if (argc != 2) {
|
|
+ fprintf(stderr, "Arguments wrong!\n");
|
|
+ prio = 0;
|
|
+ } else
|
|
+ prio = hp_sw_prio(argv[1]);
|
|
+
|
|
+ printf("%d\n", prio);
|
|
+ exit(0);
|
|
+}
|
|
+
|