forked from pool/multipath-tools
14276 lines
383 KiB
Plaintext
14276 lines
383 KiB
Plaintext
diff --git a/.gitignore b/.gitignore
|
||
new file mode 100644
|
||
index 0000000..5ef5aec
|
||
--- /dev/null
|
||
+++ b/.gitignore
|
||
@@ -0,0 +1,9 @@
|
||
+*.o
|
||
+.dotest
|
||
+*~
|
||
+*.so
|
||
+*.a
|
||
+*.gz
|
||
+kpartx
|
||
+multipath
|
||
+multipathd
|
||
diff --git a/Makefile b/Makefile
|
||
index ee554e7..54be0a5 100644
|
||
--- a/Makefile
|
||
+++ b/Makefile
|
||
@@ -1,8 +1,7 @@
|
||
# Makefile
|
||
#
|
||
# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
-
|
||
-BUILD = glibc
|
||
+#
|
||
|
||
#
|
||
# Try to supply the linux kernel headers.
|
||
@@ -20,7 +19,13 @@ endif
|
||
export KRNLSRC
|
||
export KRNLOBJ
|
||
|
||
-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -vE '^lib|/\.')
|
||
+BUILDDIRS = \
|
||
+ libmultipath \
|
||
+ libmultipath/prioritizers \
|
||
+ libmultipath/checkers \
|
||
+ multipath \
|
||
+ multipathd \
|
||
+ kpartx
|
||
|
||
ifeq ($(MULTIPATH_VERSION),)
|
||
VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
|
||
diff --git a/Makefile.inc b/Makefile.inc
|
||
index 7e2d4e6..3e5bca0 100644
|
||
--- a/Makefile.inc
|
||
+++ b/Makefile.inc
|
||
@@ -13,31 +13,22 @@ ifeq ($(TOPDIR),)
|
||
TOPDIR = ..
|
||
endif
|
||
|
||
-ifeq ($(strip $(BUILD)),klibc)
|
||
- CC = klcc
|
||
- klibcdir = /usr/lib/klibc
|
||
- libdm = $(klibcdir)/lib/libdevmapper.a
|
||
-endif
|
||
-
|
||
prefix =
|
||
exec_prefix = $(prefix)
|
||
bindir = $(exec_prefix)/sbin
|
||
libudevdir = ${prefix}/lib/udev
|
||
-checkersdir = $(TOPDIR)/libcheckers
|
||
multipathdir = $(TOPDIR)/libmultipath
|
||
mandir = $(prefix)/usr/share/man/man8
|
||
man5dir = $(prefix)/usr/share/man/man5
|
||
rcdir = $(prefix)/etc/init.d
|
||
+libdir = $(prefix)/lib/multipath
|
||
|
||
GZIP = /bin/gzip -9 -c
|
||
-
|
||
-CHECKERSLIB = $(checkersdir)/libcheckers
|
||
-MULTIPATHLIB = $(multipathdir)/libmultipath
|
||
-
|
||
-INSTALL_PROGRAM = install -s
|
||
+INSTALL_PROGRAM = install
|
||
|
||
OPTFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
|
||
-CFLAGS = $(OPTFLAGS)
|
||
+CFLAGS = $(OPTFLAGS) -fPIC
|
||
+SHARED_FLAGS = -shared
|
||
|
||
%.o: %.c
|
||
$(CC) $(CFLAGS) -c -o $@ $<
|
||
diff --git a/devmap_name/Makefile b/devmap_name/Makefile
|
||
deleted file mode 100644
|
||
index d8d8b09..0000000
|
||
--- a/devmap_name/Makefile
|
||
+++ /dev/null
|
||
@@ -1,42 +0,0 @@
|
||
-# Makefile
|
||
-#
|
||
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
-BUILD = glibc
|
||
-
|
||
-include ../Makefile.inc
|
||
-
|
||
-OBJS = devmap_name.o
|
||
-
|
||
-ifeq ($(strip $(BUILD)),klibc)
|
||
- OBJS += $(libdm)
|
||
-else
|
||
- LDFLAGS = -ldevmapper
|
||
-endif
|
||
-
|
||
-EXEC = devmap_name
|
||
-
|
||
-all: $(BUILD)
|
||
-
|
||
-prepare:
|
||
- rm -f core *.o *.gz
|
||
-
|
||
-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: $(EXEC) $(EXEC).8
|
||
- install -d $(DESTDIR)$(bindir)
|
||
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||
- install -d $(DESTDIR)$(mandir)
|
||
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
||
-
|
||
-clean:
|
||
- rm -f core *.o $(EXEC) *.gz
|
||
diff --git a/devmap_name/devmap_name.8 b/devmap_name/devmap_name.8
|
||
deleted file mode 100644
|
||
index 86d0931..0000000
|
||
--- a/devmap_name/devmap_name.8
|
||
+++ /dev/null
|
||
@@ -1,30 +0,0 @@
|
||
-.TH DEVMAP_NAME 8 "July 2006" "" "Linux Administrator's Manual"
|
||
-.SH NAME
|
||
-devmap_name \- Query device-mapper name
|
||
-.SH SYNOPSIS
|
||
-.BI devmap_name " major minor"
|
||
-.SH DESCRIPTION
|
||
-.B devmap_name
|
||
-queries the device-mapper for the name for the device
|
||
-specified by
|
||
-.I major
|
||
-and
|
||
-.I minor
|
||
-number.
|
||
-.br
|
||
-.B devmap_name
|
||
-can be called from
|
||
-.B udev
|
||
-by the following rule in
|
||
-.IR /etc/udev/udev.rules :
|
||
-.sp
|
||
-.nf
|
||
-KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \\
|
||
- NAME="%k", SYMLINK="%c"
|
||
-.fi
|
||
-.SH "SEE ALSO"
|
||
-.BR udev (8),
|
||
-.BR dmsetup (8)
|
||
-.SH AUTHORS
|
||
-.B devmap_name
|
||
-was developed by Christophe Varoqui, <christophe.varoqui@free.fr> and others.
|
||
diff --git a/devmap_name/devmap_name.c b/devmap_name/devmap_name.c
|
||
deleted file mode 100644
|
||
index 525c348..0000000
|
||
--- a/devmap_name/devmap_name.c
|
||
+++ /dev/null
|
||
@@ -1,88 +0,0 @@
|
||
-/*
|
||
- * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
- */
|
||
-#include <stdio.h>
|
||
-#include <stdlib.h>
|
||
-#include <string.h>
|
||
-#include <ctype.h>
|
||
-#include <unistd.h>
|
||
-#include <linux/kdev_t.h>
|
||
-#include <libdevmapper.h>
|
||
-
|
||
-static void usage(char * progname) {
|
||
- fprintf(stderr, "usage : %s [-t target type] dev_t\n", progname);
|
||
- fprintf(stderr, "where dev_t is either 'major minor' or 'major:minor'\n");
|
||
- exit(1);
|
||
-}
|
||
-
|
||
-int dm_target_type(int major, int minor, char *type)
|
||
-{
|
||
- struct dm_task *dmt;
|
||
- void *next = NULL;
|
||
- uint64_t start, length;
|
||
- char *target_type = NULL;
|
||
- char *params;
|
||
- int r = 1;
|
||
-
|
||
- if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
|
||
- return 1;
|
||
-
|
||
- if (!dm_task_set_major(dmt, major) ||
|
||
- !dm_task_set_minor(dmt, minor))
|
||
- goto bad;
|
||
-
|
||
- dm_task_no_open_count(dmt);
|
||
-
|
||
- if (!dm_task_run(dmt))
|
||
- goto bad;
|
||
-
|
||
- if (!type)
|
||
- goto good;
|
||
-
|
||
- do {
|
||
- next = dm_get_next_target(dmt, next, &start, &length,
|
||
- &target_type, ¶ms);
|
||
- if (target_type && strcmp(target_type, type))
|
||
- goto bad;
|
||
- } while (next);
|
||
-
|
||
-good:
|
||
- printf("%s\n", dm_task_get_name(dmt));
|
||
- r = 0;
|
||
-bad:
|
||
- dm_task_destroy(dmt);
|
||
- return r;
|
||
-}
|
||
-
|
||
-int main(int argc, char **argv)
|
||
-{
|
||
- int c;
|
||
- int major, minor;
|
||
- char *target_type = NULL;
|
||
-
|
||
- while ((c = getopt(argc, argv, "t:")) != -1) {
|
||
- switch (c) {
|
||
- case 't':
|
||
- target_type = optarg;
|
||
- break;
|
||
- default:
|
||
- usage(argv[0]);
|
||
- return 1;
|
||
- break;
|
||
- }
|
||
- }
|
||
-
|
||
- /* sanity check */
|
||
- if (optind == argc - 2) {
|
||
- major = atoi(argv[argc - 2]);
|
||
- minor = atoi(argv[argc - 1]);
|
||
- } else if (optind != argc - 1 ||
|
||
- 2 != sscanf(argv[argc - 1], "%i:%i", &major, &minor))
|
||
- usage(argv[0]);
|
||
-
|
||
- if (dm_target_type(major, minor, target_type))
|
||
- return 1;
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
diff --git a/kpartx/Makefile b/kpartx/Makefile
|
||
index b4cca6c..21e4ad4 100644
|
||
--- a/kpartx/Makefile
|
||
+++ b/kpartx/Makefile
|
||
@@ -2,49 +2,30 @@
|
||
#
|
||
# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
#
|
||
-BUILD=glibc
|
||
-
|
||
include ../Makefile.inc
|
||
|
||
CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||
|
||
-ifeq ($(strip $(BUILD)),klibc)
|
||
- OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \
|
||
- lopart.o xstrncpy.o devmapper.o dasd.o mac.o sun.o \
|
||
- $(MULTIPATHLIB)-$(BUILD).a $(libdm)
|
||
-else
|
||
- LDFLAGS = -ldevmapper
|
||
- OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
|
||
- gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
|
||
-endif
|
||
-
|
||
+LDFLAGS = -ldevmapper
|
||
+OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
|
||
+ gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
|
||
EXEC = kpartx
|
||
|
||
-all: $(BUILD)
|
||
-
|
||
-prepare:
|
||
- rm -f core *.o *.gz
|
||
+all: $(EXEC)
|
||
|
||
-glibc: prepare $(OBJS)
|
||
+$(EXEC): $(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: $(EXEC) $(EXEC).8
|
||
- install -d $(DESTDIR)$(bindir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
||
- install -d $(DESTDIR)$(libudevdir)
|
||
- install -m 755 kpartx_id $(DESTDIR)$(libudevdir)
|
||
- install -d $(DESTDIR)/etc/udev/rules.d
|
||
- install -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/
|
||
- install -d $(DESTDIR)$(mandir)
|
||
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)
|
||
+ $(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d
|
||
+ $(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
|
||
uninstall:
|
||
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
||
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
|
||
index 6e3e198..893d6dd 100644
|
||
--- a/kpartx/devmapper.c
|
||
+++ b/kpartx/devmapper.c
|
||
@@ -4,10 +4,12 @@
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
+#include <stdint.h>
|
||
#include <libdevmapper.h>
|
||
#include <ctype.h>
|
||
#include <linux/kdev_t.h>
|
||
#include <errno.h>
|
||
+#include "devmapper.h"
|
||
|
||
#define UUID_PREFIX "part%d-"
|
||
#define MAX_PREFIX_LEN 8
|
||
@@ -72,10 +74,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 *uuid, int part) {
|
||
+ const char *params, uint64_t size, const char *uuid, int part) {
|
||
int r = 0;
|
||
struct dm_task *dmt;
|
||
- char *prefixed_uuid;
|
||
+ char *prefixed_uuid = NULL;
|
||
|
||
if (!(dmt = dm_task_create (task)))
|
||
return 0;
|
||
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
|
||
index ccdbead..2bd27d2 100644
|
||
--- a/kpartx/devmapper.h
|
||
+++ b/kpartx/devmapper.h
|
||
@@ -1,7 +1,7 @@
|
||
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,
|
||
- char *, int);
|
||
+int dm_addmap (int, const char *, const char *, const char *, uint64_t,
|
||
+ const char *, int);
|
||
int dm_map_present (char *);
|
||
char * dm_mapname(int major, int minor);
|
||
dev_t dm_get_first_dep(char *devname);
|
||
diff --git a/kpartx/gpt.c b/kpartx/gpt.c
|
||
index dc846ca..047a829 100644
|
||
--- a/kpartx/gpt.c
|
||
+++ b/kpartx/gpt.c
|
||
@@ -36,6 +36,7 @@
|
||
#include <errno.h>
|
||
#include <endian.h>
|
||
#include <byteswap.h>
|
||
+#include <linux/fs.h>
|
||
#include "crc32.h"
|
||
|
||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||
@@ -50,10 +51,18 @@
|
||
# define __cpu_to_le32(x) bswap_32(x)
|
||
#endif
|
||
|
||
+#ifndef BLKGETLASTSECT
|
||
#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */
|
||
+#endif
|
||
+#ifndef BLKGETSIZE
|
||
#define BLKGETSIZE _IO(0x12,96) /* return device size */
|
||
+#endif
|
||
+#ifndef BLKSSZGET
|
||
#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
|
||
+#endif
|
||
+#ifndef BLKGETSIZE64
|
||
#define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
|
||
+#endif
|
||
|
||
struct blkdev_ioctl_param {
|
||
unsigned int block;
|
||
@@ -143,20 +152,14 @@ get_sector_size(int filedes)
|
||
static uint64_t
|
||
_get_num_sectors(int filedes)
|
||
{
|
||
- unsigned long sectors=0;
|
||
int rc;
|
||
-#if 0
|
||
- uint64_t bytes=0;
|
||
+ uint64_t bytes=0;
|
||
|
||
- rc = ioctl(filedes, BLKGETSIZE64, &bytes);
|
||
+ rc = ioctl(filedes, BLKGETSIZE64, &bytes);
|
||
if (!rc)
|
||
return bytes / get_sector_size(filedes);
|
||
-#endif
|
||
- rc = ioctl(filedes, BLKGETSIZE, §ors);
|
||
- if (rc)
|
||
- return 0;
|
||
-
|
||
- return sectors;
|
||
+
|
||
+ return 0;
|
||
}
|
||
|
||
/************************************************************
|
||
@@ -193,7 +196,7 @@ last_lba(int filedes)
|
||
sectors = 1;
|
||
}
|
||
|
||
- return sectors - 1;
|
||
+ return sectors ? sectors - 1 : 0;
|
||
}
|
||
|
||
|
||
@@ -220,17 +223,22 @@ read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
|
||
{
|
||
int sector_size = get_sector_size(fd);
|
||
off_t offset = lba * sector_size;
|
||
+ uint64_t lastlba;
|
||
ssize_t bytesread;
|
||
|
||
lseek(fd, offset, SEEK_SET);
|
||
bytesread = read(fd, buffer, bytes);
|
||
|
||
+ lastlba = last_lba(fd);
|
||
+ if (!lastlba)
|
||
+ return bytesread;
|
||
+
|
||
/* Kludge. This is necessary to read/write the last
|
||
block of an odd-sized disk, until Linux 2.5.x kernel fixes.
|
||
This is only used by gpt.c, and only to read
|
||
one sector, so we don't have to be fancy.
|
||
*/
|
||
- if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
|
||
+ if (!bytesread && !(lastlba & 1) && lba == lastlba) {
|
||
bytesread = read_lastoddsector(fd, lba, buffer, bytes);
|
||
}
|
||
return bytesread;
|
||
@@ -505,7 +513,8 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
|
||
if (!gpt || !ptes)
|
||
return 0;
|
||
|
||
- lastlba = last_lba(fd);
|
||
+ if (!(lastlba = last_lba(fd)))
|
||
+ return 0;
|
||
good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
|
||
&pgpt, &pptes);
|
||
if (good_pgpt) {
|
||
diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8
|
||
index 87b07ce..c61f312 100644
|
||
--- a/kpartx/kpartx.8
|
||
+++ b/kpartx/kpartx.8
|
||
@@ -26,6 +26,9 @@ List partition mappings that would be added -a
|
||
.B \-p
|
||
set device name-partition number delimiter
|
||
.TP
|
||
+.B \-g
|
||
+force GUID partition table (GPT)
|
||
+.TP
|
||
.B \-v
|
||
Operate verbosely
|
||
.SH "SEE ALSO"
|
||
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
||
index dbe2ee2..8658731 100644
|
||
--- a/kpartx/kpartx.c
|
||
+++ b/kpartx/kpartx.c
|
||
@@ -25,6 +25,7 @@
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
+#include <stdint.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/types.h>
|
||
#include <ctype.h>
|
||
@@ -82,7 +83,7 @@ initpts(void)
|
||
addpts("sun", read_sun_pt);
|
||
}
|
||
|
||
-static char short_opts[] = "ladgvnp:t:";
|
||
+static char short_opts[] = "ladgvp:t:";
|
||
|
||
/* Used in gpt.c */
|
||
int force_gpt=0;
|
||
@@ -94,6 +95,7 @@ usage(void) {
|
||
printf("\t-d del partition devmappings\n");
|
||
printf("\t-l list partitions devmappings that would be added by -a\n");
|
||
printf("\t-p set device name-partition number delimiter\n");
|
||
+ printf("\t-g force GUID partition table (GPT)\n");
|
||
printf("\t-v verbose\n");
|
||
return 1;
|
||
}
|
||
@@ -187,8 +189,7 @@ main(int argc, char **argv){
|
||
struct slice all;
|
||
struct pt *ptp;
|
||
enum action what = LIST;
|
||
- char *p, *type, *diskdevice, *device, *progname;
|
||
- int lower, upper;
|
||
+ char *type, *diskdevice, *device, *progname;
|
||
int verbose = 0;
|
||
char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
|
||
char * loopdev = NULL;
|
||
@@ -202,7 +203,6 @@ main(int argc, char **argv){
|
||
initpts();
|
||
init_crc32();
|
||
|
||
- lower = upper = 0;
|
||
type = device = diskdevice = NULL;
|
||
memset(&all, 0, sizeof(all));
|
||
memset(&partname, 0, sizeof(partname));
|
||
@@ -239,14 +239,6 @@ main(int argc, char **argv){
|
||
case 'v':
|
||
verbose = 1;
|
||
break;
|
||
- case 'n':
|
||
- p = optarg;
|
||
- lower = atoi(p);
|
||
- if ((p[1] == '-') && p[2])
|
||
- upper = atoi(p+2);
|
||
- else
|
||
- upper = lower;
|
||
- break;
|
||
case 'p':
|
||
delim = optarg;
|
||
break;
|
||
@@ -331,10 +323,9 @@ main(int argc, char **argv){
|
||
perror(device);
|
||
exit(1);
|
||
}
|
||
- if (!lower)
|
||
- lower = 1;
|
||
|
||
/* add/remove partitions to the kernel devmapper tables */
|
||
+ int r = 0;
|
||
for (i = 0; i < ptct; i++) {
|
||
ptp = &pts[i];
|
||
|
||
@@ -366,16 +357,16 @@ main(int argc, char **argv){
|
||
|
||
slices[j].minor = m++;
|
||
|
||
- printf("%s%s%d : 0 %lu %s %lu\n",
|
||
+ printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
|
||
mapname, delim, j+1,
|
||
- (unsigned long) slices[j].size, device,
|
||
- (unsigned long) slices[j].start);
|
||
+ slices[j].size, device,
|
||
+ slices[j].start);
|
||
}
|
||
/* Loop to resolve contained slices */
|
||
d = c;
|
||
while (c) {
|
||
for (j = 0; j < n; j++) {
|
||
- unsigned long start;
|
||
+ uint64_t start;
|
||
int k = slices[j].container - 1;
|
||
|
||
if (slices[j].size == 0)
|
||
@@ -387,9 +378,9 @@ main(int argc, char **argv){
|
||
slices[j].minor = m++;
|
||
|
||
start = slices[j].start - slices[k].start;
|
||
- printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n",
|
||
+ printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
|
||
mapname, delim, j+1,
|
||
- (unsigned long) slices[j].size,
|
||
+ slices[j].size,
|
||
slices[k].minor, start);
|
||
c--;
|
||
}
|
||
@@ -401,7 +392,7 @@ main(int argc, char **argv){
|
||
break;
|
||
|
||
case DELETE:
|
||
- for (j = 0; j < n; j++) {
|
||
+ for (j = n-1; j >= 0; j--) {
|
||
if (safe_sprintf(partname, "%s%s%d",
|
||
mapname, delim, j+1)) {
|
||
fprintf(stderr, "partname too small\n");
|
||
@@ -412,9 +403,10 @@ main(int argc, char **argv){
|
||
if (!slices[j].size || !dm_map_present(partname))
|
||
continue;
|
||
|
||
- if (!dm_simplecmd(DM_DEVICE_REMOVE, partname))
|
||
+ if (!dm_simplecmd(DM_DEVICE_REMOVE, partname)) {
|
||
+ r++;
|
||
continue;
|
||
-
|
||
+ }
|
||
if (verbose)
|
||
printf("del devmap : %s\n", partname);
|
||
}
|
||
@@ -448,8 +440,8 @@ main(int argc, char **argv){
|
||
}
|
||
strip_slash(partname);
|
||
|
||
- if (safe_sprintf(params, "%s %lu", device,
|
||
- (unsigned long)slices[j].start)) {
|
||
+ if (safe_sprintf(params, "%s %" PRIu64 ,
|
||
+ device, slices[j].start)) {
|
||
fprintf(stderr, "params too small\n");
|
||
exit(1);
|
||
}
|
||
@@ -457,18 +449,23 @@ main(int argc, char **argv){
|
||
op = (dm_map_present(partname) ?
|
||
DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
|
||
|
||
- dm_addmap(op, partname, DM_TARGET, params,
|
||
- slices[j].size, uuid, j+1);
|
||
-
|
||
- if (op == DM_DEVICE_RELOAD)
|
||
- dm_simplecmd(DM_DEVICE_RESUME,
|
||
- partname);
|
||
-
|
||
+ if (!dm_addmap(op, partname, DM_TARGET, params,
|
||
+ slices[j].size, uuid, j+1)) {
|
||
+ fprintf(stderr, "create/reload failed on %s\n",
|
||
+ partname);
|
||
+ r++;
|
||
+ }
|
||
+ if (op == DM_DEVICE_RELOAD &&
|
||
+ !dm_simplecmd(DM_DEVICE_RESUME, partname)) {
|
||
+ fprintf(stderr, "resume failed on %s\n",
|
||
+ partname);
|
||
+ r++;
|
||
+ }
|
||
dm_devn(partname, &slices[j].major,
|
||
&slices[j].minor);
|
||
|
||
if (verbose)
|
||
- printf("add map %s (%d:%d): 0 %lu %s %s\n",
|
||
+ printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
|
||
partname, slices[j].major,
|
||
slices[j].minor, slices[j].size,
|
||
DM_TARGET, params);
|
||
@@ -502,10 +499,10 @@ main(int argc, char **argv){
|
||
}
|
||
strip_slash(partname);
|
||
|
||
- if (safe_sprintf(params, "%d:%d %lu",
|
||
+ if (safe_sprintf(params, "%d:%d %" PRIu64,
|
||
slices[k].major,
|
||
slices[k].minor,
|
||
- (unsigned long)slices[j].start)) {
|
||
+ slices[j].start)) {
|
||
fprintf(stderr, "params too small\n");
|
||
exit(1);
|
||
}
|
||
@@ -524,7 +521,7 @@ main(int argc, char **argv){
|
||
&slices[j].minor);
|
||
|
||
if (verbose)
|
||
- printf("add map %s : 0 %lu %s %s\n",
|
||
+ printf("add map %s : 0 %" PRIu64 " %s %s\n",
|
||
partname, slices[j].size,
|
||
DM_TARGET, params);
|
||
c--;
|
||
@@ -545,7 +542,7 @@ main(int argc, char **argv){
|
||
dm_lib_release();
|
||
dm_lib_exit();
|
||
|
||
- return 0;
|
||
+ return r;
|
||
}
|
||
|
||
void *
|
||
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
|
||
index 9b3aeca..43ae3f8 100644
|
||
--- a/kpartx/kpartx.h
|
||
+++ b/kpartx/kpartx.h
|
||
@@ -1,6 +1,8 @@
|
||
#ifndef _KPARTX_H
|
||
#define _KPARTX_H
|
||
|
||
+#include <stdint.h>
|
||
+
|
||
/*
|
||
* For each partition type there is a routine that takes
|
||
* a block device and a range, and returns the list of
|
||
@@ -20,8 +22,8 @@
|
||
* units: 512 byte sectors
|
||
*/
|
||
struct slice {
|
||
- unsigned long start;
|
||
- unsigned long size;
|
||
+ uint64_t start;
|
||
+ uint64_t size;
|
||
int container;
|
||
int major;
|
||
int minor;
|
||
diff --git a/libcheckers/Makefile b/libcheckers/Makefile
|
||
deleted file mode 100644
|
||
index 6340a68..0000000
|
||
--- a/libcheckers/Makefile
|
||
+++ /dev/null
|
||
@@ -1,27 +0,0 @@
|
||
-# Makefile
|
||
-#
|
||
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
-#
|
||
-BUILD = glibc
|
||
-
|
||
-include ../Makefile.inc
|
||
-
|
||
-OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o
|
||
-
|
||
-all: $(BUILD)
|
||
-
|
||
-prepare:
|
||
- @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
|
||
-
|
||
-klibc: prepare $(OBJS)
|
||
- ar rs libcheckers-klibc.a *.o
|
||
-
|
||
-glibc: prepare $(OBJS)
|
||
- ar rs libcheckers-glibc.a *.o
|
||
-
|
||
-install:
|
||
-
|
||
-uninstall:
|
||
-
|
||
-clean:
|
||
- rm -f core *.a *.o *.gz
|
||
diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c
|
||
deleted file mode 100644
|
||
index d7728a5..0000000
|
||
--- a/libcheckers/checkers.c
|
||
+++ /dev/null
|
||
@@ -1,159 +0,0 @@
|
||
-#include <stdio.h>
|
||
-#include <string.h>
|
||
-
|
||
-#include "checkers.h"
|
||
-
|
||
-#include "directio.h"
|
||
-#include "tur.h"
|
||
-#include "hp_sw.h"
|
||
-#include "emc_clariion.h"
|
||
-#include "rdac.h"
|
||
-#include "readsector0.h"
|
||
-
|
||
-static struct checker checkers[] = {
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = DIRECTIO,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = directio,
|
||
- .init = directio_init,
|
||
- .free = directio_free
|
||
- },
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = TUR,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = tur,
|
||
- .init = tur_init,
|
||
- .free = tur_free
|
||
- },
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = HP_SW,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = hp_sw,
|
||
- .init = hp_sw_init,
|
||
- .free = hp_sw_free
|
||
- },
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = EMC_CLARIION,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = emc_clariion,
|
||
- .init = emc_clariion_init,
|
||
- .free = emc_clariion_free
|
||
- },
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = RDAC,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = rdac,
|
||
- .init = rdac_init,
|
||
- .free = rdac_free
|
||
- },
|
||
- {
|
||
- .fd = 0,
|
||
- .sync = 1,
|
||
- .name = READSECTOR0,
|
||
- .message = "",
|
||
- .context = NULL,
|
||
- .check = readsector0,
|
||
- .init = readsector0_init,
|
||
- .free = readsector0_free
|
||
- },
|
||
- {0, 1, "", "", NULL, NULL, NULL, NULL},
|
||
-};
|
||
-
|
||
-void checker_set_fd (struct checker * c, int fd)
|
||
-{
|
||
- c->fd = fd;
|
||
-}
|
||
-
|
||
-void checker_set_sync (struct checker * c)
|
||
-{
|
||
- c->sync = 1;
|
||
-}
|
||
-
|
||
-void checker_set_async (struct checker * c)
|
||
-{
|
||
- c->sync = 0;
|
||
-}
|
||
-
|
||
-struct checker * checker_lookup (char * name)
|
||
-{
|
||
- struct checker * c = &checkers[0];
|
||
-
|
||
- while (c->check) {
|
||
- if (!strncmp(name, c->name, CHECKER_NAME_LEN))
|
||
- return c;
|
||
- c++;
|
||
- }
|
||
- return NULL;
|
||
-}
|
||
-
|
||
-int checker_init (struct checker * c, void ** mpctxt_addr)
|
||
-{
|
||
- c->mpcontext = mpctxt_addr;
|
||
- return c->init(c);
|
||
-}
|
||
-
|
||
-void checker_put (struct checker * c)
|
||
-{
|
||
- if (c->free)
|
||
- c->free(c);
|
||
- memset(c, 0x0, sizeof(struct checker));
|
||
-}
|
||
-
|
||
-int checker_check (struct checker * c)
|
||
-{
|
||
- int r;
|
||
-
|
||
- if (c->fd <= 0) {
|
||
- MSG(c, "no usable fd");
|
||
- return PATH_WILD;
|
||
- }
|
||
- r = c->check(c);
|
||
-
|
||
- return r;
|
||
-}
|
||
-
|
||
-int checker_selected (struct checker * c)
|
||
-{
|
||
- return (c->check) ? 1 : 0;
|
||
-}
|
||
-
|
||
-char * checker_name (struct checker * c)
|
||
-{
|
||
- return c->name;
|
||
-}
|
||
-
|
||
-char * checker_message (struct checker * c)
|
||
-{
|
||
- return c->message;
|
||
-}
|
||
-
|
||
-struct checker * checker_default (void)
|
||
-{
|
||
- return checker_lookup(DEFAULT_CHECKER);
|
||
-}
|
||
-
|
||
-void checker_get (struct checker * dst, struct checker * src)
|
||
-{
|
||
- dst->fd = src->fd;
|
||
- dst->sync = src->sync;
|
||
- strncpy(dst->name, src->name, CHECKER_NAME_LEN);
|
||
- strncpy(dst->message, src->message, CHECKER_MSG_LEN);
|
||
- dst->check = src->check;
|
||
- dst->init = src->init;
|
||
- dst->free = src->free;
|
||
-}
|
||
diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h
|
||
deleted file mode 100644
|
||
index 9b270eb..0000000
|
||
--- a/libcheckers/checkers.h
|
||
+++ /dev/null
|
||
@@ -1,116 +0,0 @@
|
||
-#ifndef _CHECKERS_H
|
||
-#define _CHECKERS_H
|
||
-
|
||
-/*
|
||
- *
|
||
- * 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.
|
||
- *
|
||
- * PATH_PENDING:
|
||
- * - Use: All async checkers
|
||
- * - Description: Indicates a check IO is in flight.
|
||
- */
|
||
-#define PATH_WILD -1
|
||
-#define PATH_UNCHECKED 0
|
||
-#define PATH_DOWN 1
|
||
-#define PATH_UP 2
|
||
-#define PATH_SHAKY 3
|
||
-#define PATH_GHOST 4
|
||
-#define PATH_PENDING 5
|
||
-
|
||
-#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 DIRECTIO
|
||
-
|
||
-/*
|
||
- * 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
|
||
-#define ASYNC_TIMEOUT_SEC 30
|
||
-
|
||
-/*
|
||
- * strings lengths
|
||
- */
|
||
-#define CHECKER_NAME_LEN 16
|
||
-#define CHECKER_MSG_LEN 256
|
||
-#define CHECKER_DEV_LEN 256
|
||
-
|
||
-struct checker {
|
||
- int fd;
|
||
- int sync;
|
||
- 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, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
|
||
-
|
||
-int checker_init (struct checker *, void **);
|
||
-void checker_put (struct checker *);
|
||
-void checker_reset (struct checker * c);
|
||
-void checker_set_sync (struct checker * c);
|
||
-void checker_set_async (struct checker * c);
|
||
-void checker_set_fd (struct checker *, int);
|
||
-struct checker * checker_lookup (char *);
|
||
-int checker_check (struct checker *);
|
||
-int checker_selected (struct checker *);
|
||
-char * checker_name (struct checker *);
|
||
-char * checker_message (struct checker *);
|
||
-struct checker * checker_default (void);
|
||
-void checker_get (struct checker *, struct checker *);
|
||
-
|
||
-#endif /* _CHECKERS_H */
|
||
diff --git a/libcheckers/directio.c b/libcheckers/directio.c
|
||
deleted file mode 100644
|
||
index ee09af7..0000000
|
||
--- a/libcheckers/directio.c
|
||
+++ /dev/null
|
||
@@ -1,197 +0,0 @@
|
||
-/*
|
||
- * Copyright (c) 2005 Hannes Reinecke, Suse
|
||
- */
|
||
-#define _GNU_SOURCE
|
||
-#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 <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"
|
||
-#define MSG_DIRECTIO_PENDING "directio checker is waiting on aio"
|
||
-
|
||
-#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
|
||
-
|
||
-struct directio_context {
|
||
- 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;
|
||
- memset(ct, 0, sizeof(struct directio_context));
|
||
-
|
||
- if (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");
|
||
- ct->blksize = 512;
|
||
- }
|
||
- if (ct->blksize > 4096) {
|
||
- /*
|
||
- * Sanity check for DASD; BSZGET is broken
|
||
- */
|
||
- ct->blksize = 4096;
|
||
- }
|
||
- if (!ct->blksize)
|
||
- goto out;
|
||
- ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
|
||
- if (!ct->buf)
|
||
- goto out;
|
||
-
|
||
- 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);
|
||
- io_destroy(ct->ioctx);
|
||
- free(ct);
|
||
- return 1;
|
||
-}
|
||
-
|
||
-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);
|
||
- io_destroy(ct->ioctx);
|
||
- free(ct);
|
||
-}
|
||
-
|
||
-static int
|
||
-check_state(int fd, struct directio_context *ct, int sync)
|
||
-{
|
||
- struct timespec timeout = { .tv_nsec = 5 };
|
||
- struct io_event event;
|
||
- struct stat sb;
|
||
- int rc = PATH_UNCHECKED;
|
||
- long r;
|
||
-
|
||
- if (fstat(fd, &sb) == 0) {
|
||
- LOG(4, "called for %x", (unsigned) sb.st_rdev);
|
||
- }
|
||
- if (sync) {
|
||
- LOG(4, "called in synchronous mode");
|
||
- timeout.tv_sec = ASYNC_TIMEOUT_SEC;
|
||
- timeout.tv_nsec = 0;
|
||
- }
|
||
-
|
||
- if (!ct->running) {
|
||
- struct iocb *ios[1] = { &ct->io };
|
||
-
|
||
- LOG(3, "starting new request");
|
||
- memset(&ct->io, 0, sizeof(struct iocb));
|
||
- io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
|
||
- if (io_submit(ct->ioctx, 1, ios) != 1) {
|
||
- LOG(3, "io_submit error %i", errno);
|
||
- return PATH_UNCHECKED;
|
||
- }
|
||
- }
|
||
- ct->running++;
|
||
-
|
||
- r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
|
||
- LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
|
||
-
|
||
- if (r < 1L) {
|
||
- if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
|
||
- LOG(3, "abort check on timeout");
|
||
- rc = PATH_DOWN;
|
||
- } else
|
||
- rc = PATH_PENDING;
|
||
- } else {
|
||
- LOG(3, "io finished %lu/%lu", event.res, event.res2);
|
||
- ct->running = 0;
|
||
- rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
|
||
- }
|
||
-
|
||
- return rc;
|
||
-}
|
||
-
|
||
-int directio (struct checker * c)
|
||
-{
|
||
- int ret;
|
||
- struct directio_context * ct = (struct directio_context *)c->context;
|
||
-
|
||
- if (!ct)
|
||
- return PATH_UNCHECKED;
|
||
-
|
||
- ret = check_state(c->fd, ct, c->sync);
|
||
-
|
||
- switch (ret)
|
||
- {
|
||
- case PATH_UNCHECKED:
|
||
- MSG(c, MSG_DIRECTIO_UNKNOWN);
|
||
- break;
|
||
- case PATH_DOWN:
|
||
- MSG(c, MSG_DIRECTIO_DOWN);
|
||
- break;
|
||
- case PATH_UP:
|
||
- MSG(c, MSG_DIRECTIO_UP);
|
||
- break;
|
||
- case PATH_PENDING:
|
||
- MSG(c, MSG_DIRECTIO_PENDING);
|
||
- break;
|
||
- default:
|
||
- break;
|
||
- }
|
||
- return ret;
|
||
-}
|
||
diff --git a/libcheckers/directio.h b/libcheckers/directio.h
|
||
deleted file mode 100644
|
||
index 1865b1f..0000000
|
||
--- a/libcheckers/directio.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#ifndef _DIRECTIO_H
|
||
-#define _DIRECTIO_H
|
||
-
|
||
-int directio (struct checker *);
|
||
-int directio_init (struct checker *);
|
||
-void directio_free (struct checker *);
|
||
-
|
||
-#endif /* _DIRECTIO_H */
|
||
diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c
|
||
deleted file mode 100644
|
||
index 6c7167e..0000000
|
||
--- a/libcheckers/emc_clariion.c
|
||
+++ /dev/null
|
||
@@ -1,230 +0,0 @@
|
||
-/*
|
||
- * Copyright (c) 2004, 2005 Lars Marowsky-Bree
|
||
- */
|
||
-#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 "../libmultipath/sg_include.h"
|
||
-#include "libsg.h"
|
||
-#include "checkers.h"
|
||
-
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define INQUIRY_CMDLEN 6
|
||
-#define HEAVY_CHECK_COUNT 10
|
||
-
|
||
-/*
|
||
- * 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)
|
||
-{
|
||
- /*
|
||
- * 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_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;
|
||
-}
|
||
-
|
||
-void emc_clariion_free (struct checker * c)
|
||
-{
|
||
- free(c->context);
|
||
-}
|
||
-
|
||
-int emc_clariion(struct checker * c)
|
||
-{
|
||
- 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(sense_buffer), 0};
|
||
- struct sg_io_hdr io_hdr;
|
||
- 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';
|
||
- io_hdr.cmd_len = sizeof (inqCmdBlk);
|
||
- io_hdr.mx_sb_len = sizeof (sb);
|
||
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
- io_hdr.dxferp = sense_buffer;
|
||
- io_hdr.cmdp = inqCmdBlk;
|
||
- io_hdr.sbp = sb;
|
||
- 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");
|
||
- return PATH_DOWN;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- MSG(c, "emc_clariion_checker: query command indicates error");
|
||
- return PATH_DOWN;
|
||
- }
|
||
- 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");
|
||
- return PATH_DOWN;
|
||
- }
|
||
-
|
||
- if ( /* Effective initiator type */
|
||
- sense_buffer[27] != 0x03
|
||
- /*
|
||
- * 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 "
|
||
- "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");
|
||
- return PATH_SHAKY;
|
||
- }
|
||
-
|
||
- if ( /* LUN should at least be bound somewhere and not be LUNZ */
|
||
- sense_buffer[4] == 0x00) {
|
||
- MSG(c, "emc_clariion_checker: Logical Unit is unbound "
|
||
- "or LUNZ");
|
||
- return PATH_DOWN;
|
||
- }
|
||
-
|
||
- /*
|
||
- * store the LUN WWN there and compare that it indeed did not
|
||
- * change in between, to protect against the path suddenly
|
||
- * pointing somewhere else.
|
||
- */
|
||
- if (ct->wwn_set) {
|
||
- if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
|
||
- MSG(c, "emc_clariion_checker: Logical Unit WWN "
|
||
- "has changed!");
|
||
- return PATH_DOWN;
|
||
- }
|
||
- } else {
|
||
- memcpy(ct->wwn, &sense_buffer[10], 16);
|
||
- ct->wwn_set = 1;
|
||
- }
|
||
-
|
||
- /*
|
||
- * Issue read on active path to determine if inactive snapshot.
|
||
- */
|
||
- if (sense_buffer[4] == 2) {/* if active path */
|
||
- unsigned char buf[4096];
|
||
-
|
||
- 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/emc_clariion.h b/libcheckers/emc_clariion.h
|
||
deleted file mode 100644
|
||
index a1018a6..0000000
|
||
--- a/libcheckers/emc_clariion.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#ifndef _EMC_CLARIION_H
|
||
-#define _EMC_CLARIION_H
|
||
-
|
||
-int emc_clariion (struct checker *);
|
||
-int emc_clariion_init (struct checker *);
|
||
-void emc_clariion_free (struct checker *);
|
||
-
|
||
-#endif /* _EMC_CLARIION_H */
|
||
diff --git a/libcheckers/hp_sw.c b/libcheckers/hp_sw.c
|
||
deleted file mode 100644
|
||
index b9731ff..0000000
|
||
--- a/libcheckers/hp_sw.c
|
||
+++ /dev/null
|
||
@@ -1,141 +0,0 @@
|
||
-/*
|
||
- * 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 TUR_CMD_LEN 6
|
||
-#define INQUIRY_CMDLEN 6
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define SENSE_BUFF_LEN 32
|
||
-#define SCSI_CHECK_CONDITION 0x2
|
||
-#define SCSI_COMMAND_TERMINATED 0x22
|
||
-#define SG_ERR_DRIVER_SENSE 0x08
|
||
-#define RECOVERED_ERROR 0x01
|
||
-#define MX_ALLOC_LEN 255
|
||
-#define HEAVY_CHECK_COUNT 10
|
||
-
|
||
-#define MSG_HP_SW_UP "hp_sw checker reports path is up"
|
||
-#define MSG_HP_SW_DOWN "hp_sw checker reports path is down"
|
||
-#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
|
||
-
|
||
-struct sw_checker_context {
|
||
- void * dummy;
|
||
-};
|
||
-
|
||
-int hp_sw_init (struct checker * c)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-void hp_sw_free (struct checker * c)
|
||
-{
|
||
- return;
|
||
-}
|
||
-
|
||
-static int
|
||
-do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
|
||
- void *resp, int mx_resp_len, int noisy)
|
||
-{
|
||
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
|
||
- { 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)
|
||
- inqCmdBlk[1] |= 1;
|
||
- inqCmdBlk[2] = (unsigned char) pg_op;
|
||
- inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
|
||
- 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 = 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;
|
||
-}
|
||
-
|
||
-static int
|
||
-do_tur (int fd)
|
||
-{
|
||
- unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
||
- struct sg_io_hdr io_hdr;
|
||
- unsigned char sense_buffer[32];
|
||
-
|
||
- 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 (sense_buffer);
|
||
- io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
- io_hdr.cmdp = turCmdBlk;
|
||
- io_hdr.sbp = sense_buffer;
|
||
- io_hdr.timeout = DEF_TIMEOUT;
|
||
- io_hdr.pack_id = 0;
|
||
-
|
||
- if (ioctl(fd, SG_IO, &io_hdr) < 0)
|
||
- return 1;
|
||
-
|
||
- if (io_hdr.info & SG_INFO_OK_MASK)
|
||
- return 1;
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
-extern int
|
||
-hp_sw (struct checker * c)
|
||
-{
|
||
- char buff[MX_ALLOC_LEN];
|
||
-
|
||
- if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
|
||
- MSG(c, MSG_HP_SW_DOWN);
|
||
- return PATH_DOWN;
|
||
- }
|
||
-
|
||
- if (do_tur(c->fd)) {
|
||
- MSG(c, MSG_HP_SW_GHOST);
|
||
- return PATH_GHOST;
|
||
- }
|
||
- MSG(c, MSG_HP_SW_UP);
|
||
- return PATH_UP;
|
||
-}
|
||
diff --git a/libcheckers/hp_sw.h b/libcheckers/hp_sw.h
|
||
deleted file mode 100644
|
||
index 3be0d8e..0000000
|
||
--- a/libcheckers/hp_sw.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#ifndef _HP_SW_H
|
||
-#define _HP_SW_H
|
||
-
|
||
-int hp_sw (struct checker *);
|
||
-int hp_sw_init (struct checker *);
|
||
-void hp_sw_free (struct checker *);
|
||
-
|
||
-#endif /* _HP_SW_H */
|
||
diff --git a/libcheckers/libsg.c b/libcheckers/libsg.c
|
||
deleted file mode 100644
|
||
index 9171b10..0000000
|
||
--- a/libcheckers/libsg.c
|
||
+++ /dev/null
|
||
@@ -1,84 +0,0 @@
|
||
-/*
|
||
- * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
- */
|
||
-#include <string.h>
|
||
-#include <sys/ioctl.h>
|
||
-#include <errno.h>
|
||
-#include <sys/stat.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;
|
||
- struct stat filestatus;
|
||
- int retry_count = 3;
|
||
-
|
||
- if (fstat(sg_fd, &filestatus) != 0)
|
||
- return PATH_DOWN;
|
||
- bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
|
||
- 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
|
||
deleted file mode 100644
|
||
index 97c4491..0000000
|
||
--- a/libcheckers/libsg.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#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
|
||
deleted file mode 100644
|
||
index f430488..0000000
|
||
--- a/libcheckers/rdac.c
|
||
+++ /dev/null
|
||
@@ -1,109 +0,0 @@
|
||
-/*
|
||
- * 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
|
||
deleted file mode 100644
|
||
index d7bf812..0000000
|
||
--- a/libcheckers/rdac.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#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
|
||
deleted file mode 100644
|
||
index bef0eb6..0000000
|
||
--- a/libcheckers/readsector0.c
|
||
+++ /dev/null
|
||
@@ -1,47 +0,0 @@
|
||
-/*
|
||
- * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
- */
|
||
-#include <stdio.h>
|
||
-
|
||
-#include "checkers.h"
|
||
-#include "libsg.h"
|
||
-
|
||
-#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
|
||
-#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
|
||
-
|
||
-struct readsector0_checker_context {
|
||
- void * dummy;
|
||
-};
|
||
-
|
||
-int readsector0_init (struct checker * c)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-void readsector0_free (struct checker * c)
|
||
-{
|
||
- return;
|
||
-}
|
||
-
|
||
-extern int
|
||
-readsector0 (struct checker * c)
|
||
-{
|
||
- unsigned char buf[4096];
|
||
- unsigned char sbuf[SENSE_BUFF_LEN];
|
||
- int ret;
|
||
-
|
||
- ret = sg_read(c->fd, &buf[0], &sbuf[0]);
|
||
-
|
||
- switch (ret)
|
||
- {
|
||
- case PATH_DOWN:
|
||
- MSG(c, MSG_READSECTOR0_DOWN);
|
||
- break;
|
||
- case PATH_UP:
|
||
- MSG(c, MSG_READSECTOR0_UP);
|
||
- break;
|
||
- default:
|
||
- break;
|
||
- }
|
||
- return ret;
|
||
-}
|
||
diff --git a/libcheckers/readsector0.h b/libcheckers/readsector0.h
|
||
deleted file mode 100644
|
||
index 0f5d654..0000000
|
||
--- a/libcheckers/readsector0.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#ifndef _READSECTOR0_H
|
||
-#define _READSECTOR0_H
|
||
-
|
||
-int readsector0 (struct checker *);
|
||
-int readsector0_init (struct checker *);
|
||
-void readsector0_free (struct checker *);
|
||
-
|
||
-#endif /* _READSECTOR0_H */
|
||
diff --git a/libcheckers/tur.c b/libcheckers/tur.c
|
||
deleted file mode 100644
|
||
index e79bc0a..0000000
|
||
--- a/libcheckers/tur.c
|
||
+++ /dev/null
|
||
@@ -1,66 +0,0 @@
|
||
-/*
|
||
- * Some code borrowed from sg-utils.
|
||
- *
|
||
- * Copyright (c) 2004 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 TUR_CMD_LEN 6
|
||
-#define HEAVY_CHECK_COUNT 10
|
||
-
|
||
-#define MSG_TUR_UP "tur checker reports path is up"
|
||
-#define MSG_TUR_DOWN "tur checker reports path is down"
|
||
-
|
||
-struct tur_checker_context {
|
||
- void * dummy;
|
||
-};
|
||
-
|
||
-int tur_init (struct checker * c)
|
||
-{
|
||
- return 0;
|
||
-}
|
||
-
|
||
-void tur_free (struct checker * c)
|
||
-{
|
||
- return;
|
||
-}
|
||
-
|
||
-extern int
|
||
-tur (struct checker * c)
|
||
-{
|
||
- struct sg_io_hdr io_hdr;
|
||
- unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
||
- unsigned char sense_buffer[32];
|
||
-
|
||
- 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 (sense_buffer);
|
||
- io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
- io_hdr.cmdp = turCmdBlk;
|
||
- io_hdr.sbp = sense_buffer;
|
||
- io_hdr.timeout = DEF_TIMEOUT;
|
||
- io_hdr.pack_id = 0;
|
||
- if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
|
||
- MSG(c, MSG_TUR_DOWN);
|
||
- return PATH_DOWN;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- MSG(c, MSG_TUR_DOWN);
|
||
- return PATH_DOWN;
|
||
- }
|
||
- MSG(c, MSG_TUR_UP);
|
||
- return PATH_UP;
|
||
-}
|
||
diff --git a/libcheckers/tur.h b/libcheckers/tur.h
|
||
deleted file mode 100644
|
||
index a2e8c88..0000000
|
||
--- a/libcheckers/tur.h
|
||
+++ /dev/null
|
||
@@ -1,8 +0,0 @@
|
||
-#ifndef _TUR_H
|
||
-#define _TUR_H
|
||
-
|
||
-int tur (struct checker *);
|
||
-int tur_init (struct checker *);
|
||
-void tur_free (struct checker *);
|
||
-
|
||
-#endif /* _TUR_H */
|
||
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
|
||
index 511f5ad..21fcd74 100644
|
||
--- a/libmultipath/Makefile
|
||
+++ b/libmultipath/Makefile
|
||
@@ -2,50 +2,35 @@
|
||
#
|
||
# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
#
|
||
-BUILD = glibc
|
||
-
|
||
include ../Makefile.inc
|
||
|
||
-CFLAGS += -I$(checkersdir)
|
||
+LIBS = libmultipath.so
|
||
|
||
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
|
||
hwtable.o blacklist.o util.o dmparser.o config.o \
|
||
structs.o discovery.o propsel.o dict.o \
|
||
pgpolicies.o debug.o regex.o defaults.o uevent.o \
|
||
switchgroup.o uxsock.o print.o alias.o log_pthread.o \
|
||
- log.o configure.o structs_vec.o sysfs.o
|
||
-
|
||
-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
|
||
+ log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
|
||
+ lock.o waiter.o
|
||
|
||
-LIBDM_API_FLUSH = $(shell objdump -T /lib/libdevmapper.so.* | grep -c dm_task_no_flush)
|
||
+LIBDM_API_FLUSH = $(shell if test -d /lib64 ; then objdump -T /lib64/libdevmapper.so* ; else objdump -T /lib/libdevmapper.so.* ; fi | grep -c dm_task_no_flush)
|
||
|
||
ifeq ($(strip $(LIBDM_API_FLUSH)),1)
|
||
CFLAGS += -DLIBDM_API_FLUSH
|
||
endif
|
||
|
||
-all: $(BUILD)
|
||
-
|
||
-prepare: $(CLEAN)
|
||
- @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
|
||
- @rm -f *-$(BUILD).a
|
||
-
|
||
-klibc: $(OBJS)
|
||
- ar rs libmultipath-klibc.a *.o
|
||
+all: $(LIBS)
|
||
|
||
-glibc: $(OBJS)
|
||
- ar rs libmultipath-glibc.a *.o
|
||
+$(LIBS): $(OBJS)
|
||
+ $(CC) $(SHARED_FLAGS) $(CFLAGS) -o $@ $(OBJS)
|
||
|
||
install:
|
||
+ $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir)
|
||
+ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)/$(LIBS)
|
||
|
||
uninstall:
|
||
+ rm -f $(DESTDIR)$(libdir)/$(LIBS)
|
||
|
||
clean:
|
||
- rm -f core *.a *.o *.gz
|
||
+ rm -f core *.a *.o *.gz *.so
|
||
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
|
||
index ca434fe..517b055 100644
|
||
--- a/libmultipath/alias.c
|
||
+++ b/libmultipath/alias.c
|
||
@@ -179,6 +179,46 @@ fail:
|
||
return -1;
|
||
}
|
||
|
||
+static int
|
||
+format_devname(char *name, int id, int len)
|
||
+{
|
||
+ int pos;
|
||
+
|
||
+ memset(name,0, len);
|
||
+ strcpy(name,"mpath");
|
||
+ for (pos = len - 1; pos >= 5; pos--) {
|
||
+ name[pos] = 'a' + id % 26;
|
||
+ if (id < 26)
|
||
+ break;
|
||
+ id /= 26;
|
||
+ id--;
|
||
+ }
|
||
+ memmove(name + 5, name + pos, len - pos);
|
||
+ name[5 + len - pos] = '\0';
|
||
+ return (5 + len - pos);
|
||
+}
|
||
+
|
||
+static int
|
||
+scan_devname(char *alias)
|
||
+{
|
||
+ char *c;
|
||
+ int i, n = 0;
|
||
+
|
||
+ if (strncmp(alias, "mpath", 5))
|
||
+ return -1;
|
||
+
|
||
+ c = alias + 5;
|
||
+ while (*c != '\0' && *c != ' ' && *c != '\t') {
|
||
+ i = *c - 'a';
|
||
+ n = ( n * 26 ) + i;
|
||
+ c++;
|
||
+ if (*c < 'a' || *c > 'z')
|
||
+ break;
|
||
+ n++;
|
||
+ }
|
||
+
|
||
+ return n;
|
||
+}
|
||
|
||
static int
|
||
lookup_binding(FILE *f, char *map_wwid, char **map_alias)
|
||
@@ -200,7 +240,8 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias)
|
||
alias = strtok(buf, " \t");
|
||
if (!alias) /* blank line */
|
||
continue;
|
||
- if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
|
||
+ curr_id = scan_devname(alias);
|
||
+ if (curr_id >= id)
|
||
id = curr_id + 1;
|
||
wwid = strtok(NULL, " \t");
|
||
if (!wwid){
|
||
@@ -221,7 +262,7 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias)
|
||
}
|
||
condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
|
||
return id;
|
||
-}
|
||
+}
|
||
|
||
static int
|
||
rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
|
||
@@ -243,7 +284,8 @@ rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
|
||
alias = strtok(buf, " \t");
|
||
if (!alias) /* blank line */
|
||
continue;
|
||
- if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
|
||
+ curr_id = scan_devname(alias);
|
||
+ if (curr_id >= id)
|
||
id = curr_id + 1;
|
||
wwid = strtok(NULL, " \t");
|
||
if (!wwid){
|
||
@@ -264,7 +306,7 @@ rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
|
||
}
|
||
condlog(3, "No matching alias [%s] in bindings file.", map_alias);
|
||
return id;
|
||
-}
|
||
+}
|
||
|
||
static char *
|
||
allocate_binding(int fd, char *wwid, int id)
|
||
@@ -272,13 +314,16 @@ allocate_binding(int fd, char *wwid, int id)
|
||
char buf[LINE_MAX];
|
||
off_t offset;
|
||
char *alias, *c;
|
||
-
|
||
+ int i;
|
||
+
|
||
if (id < 0) {
|
||
condlog(0, "Bindings file full. Cannot allocate new binding");
|
||
return NULL;
|
||
}
|
||
-
|
||
- snprintf(buf, LINE_MAX, "mpath%d %s\n", id, wwid);
|
||
+
|
||
+ i = format_devname(buf, id, LINE_MAX);
|
||
+ c = buf + i;
|
||
+ snprintf(c,LINE_MAX - i, " %s\n", wwid);
|
||
buf[LINE_MAX - 1] = '\0';
|
||
|
||
offset = lseek(fd, 0, SEEK_END);
|
||
@@ -304,7 +349,7 @@ allocate_binding(int fd, char *wwid, int id)
|
||
condlog(3, "Created new binding [%s] for WWID [%s]", alias,
|
||
wwid);
|
||
return alias;
|
||
-}
|
||
+}
|
||
|
||
char *
|
||
get_user_friendly_alias(char *wwid, char *file)
|
||
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
|
||
index 0c277cb..d85b385 100644
|
||
--- a/libmultipath/blacklist.c
|
||
+++ b/libmultipath/blacklist.c
|
||
@@ -2,8 +2,8 @@
|
||
* Copyright (c) 2004, 2005 Christophe Varoqui
|
||
*/
|
||
#include <stdio.h>
|
||
-#include <checkers.h>
|
||
|
||
+#include "checkers.h"
|
||
#include "memory.h"
|
||
#include "vector.h"
|
||
#include "util.h"
|
||
@@ -297,16 +297,14 @@ _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_wwid, conf->elist_devnode, pp->wwid);
|
||
- if (r)
|
||
+ if (r > 0)
|
||
return r;
|
||
r = _filter_device(conf->blist_device, conf->elist_device,
|
||
pp->vendor_id, pp->product_id);
|
||
- if (r)
|
||
+ if (r > 0)
|
||
return r;
|
||
- return 0;
|
||
+ r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
|
||
+ return r;
|
||
}
|
||
|
||
int
|
||
diff --git a/libmultipath/callout.c b/libmultipath/callout.c
|
||
index 46b89e6..4dd33c5 100644
|
||
--- a/libmultipath/callout.c
|
||
+++ b/libmultipath/callout.c
|
||
@@ -10,11 +10,11 @@
|
||
#include <unistd.h>
|
||
#include <sys/types.h>
|
||
#include <stdlib.h>
|
||
+#include <fcntl.h>
|
||
#include <sys/wait.h>
|
||
#include <errno.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "structs.h"
|
||
#include "debug.h"
|
||
@@ -33,7 +33,7 @@ int execute_program(char *path, char *value, int len)
|
||
int retval;
|
||
int count;
|
||
int status;
|
||
- int fds[2];
|
||
+ int fds[2], null_fd;
|
||
pid_t pid;
|
||
char *pos;
|
||
char arg[PROGRAM_SIZE];
|
||
@@ -76,7 +76,16 @@ int execute_program(char *path, char *value, int len)
|
||
close(STDOUT_FILENO);
|
||
|
||
/* dup write side of pipe to STDOUT */
|
||
- dup(fds[1]);
|
||
+ if (dup(fds[1]) < 0)
|
||
+ return -1;
|
||
+
|
||
+ /* Ignore writes to stderr */
|
||
+ null_fd = open("/dev/null", O_WRONLY);
|
||
+ if (null_fd > 0) {
|
||
+ close(STDERR_FILENO);
|
||
+ dup(null_fd);
|
||
+ close(null_fd);
|
||
+ }
|
||
|
||
retval = execv(argv[0], argv);
|
||
|
||
diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c
|
||
new file mode 100644
|
||
index 0000000..5889ad7
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers.c
|
||
@@ -0,0 +1,187 @@
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <stddef.h>
|
||
+#include <dlfcn.h>
|
||
+
|
||
+#include "debug.h"
|
||
+#include "checkers.h"
|
||
+#include "vector.h"
|
||
+#include "config.h"
|
||
+
|
||
+static LIST_HEAD(checkers);
|
||
+
|
||
+int init_checkers (void)
|
||
+{
|
||
+ INIT_LIST_HEAD(&checkers);
|
||
+ if (!add_checker(DEFAULT_CHECKER))
|
||
+ return 1;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+struct checker * alloc_checker (void)
|
||
+{
|
||
+ return zalloc(sizeof(struct checker));
|
||
+}
|
||
+
|
||
+void free_checker (struct checker * c)
|
||
+{
|
||
+ free(c);
|
||
+}
|
||
+
|
||
+void cleanup_checkers (void)
|
||
+{
|
||
+ struct checker * checker_loop;
|
||
+ struct checker * checker_temp;
|
||
+
|
||
+ list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
|
||
+ list_del(&checker_loop->node);
|
||
+ free(checker_loop);
|
||
+ }
|
||
+}
|
||
+
|
||
+struct checker * checker_lookup (char * name)
|
||
+{
|
||
+ struct checker * c;
|
||
+
|
||
+ list_for_each_entry(c, &checkers, node) {
|
||
+ if (!strncmp(name, c->name, CHECKER_NAME_LEN))
|
||
+ return c;
|
||
+ }
|
||
+ return add_checker(name);
|
||
+}
|
||
+
|
||
+struct checker * add_checker (char * name)
|
||
+{
|
||
+ char libname[LIB_CHECKER_NAMELEN];
|
||
+ void * handle;
|
||
+ struct checker * c;
|
||
+ char *errstr;
|
||
+
|
||
+ c = alloc_checker();
|
||
+ if (!c)
|
||
+ return NULL;
|
||
+ snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
|
||
+ conf->multipath_dir, name);
|
||
+ condlog(3, "loading %s checker", libname);
|
||
+ handle = dlopen(libname, RTLD_NOW);
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!handle)
|
||
+ goto out;
|
||
+
|
||
+ c->check = (int (*)(struct checker *)) dlsym(handle, "libcheck_check");
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!c->check)
|
||
+ goto out;
|
||
+
|
||
+ c->init = (int (*)(struct checker *)) dlsym(handle, "libcheck_init");
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!c->init)
|
||
+ goto out;
|
||
+
|
||
+ c->free = (void (*)(struct checker *)) dlsym(handle, "libcheck_free");
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!c->free)
|
||
+ goto out;
|
||
+
|
||
+ snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
|
||
+ c->fd = 0;
|
||
+ c->sync = 1;
|
||
+ list_add(&c->node, &checkers);
|
||
+ return c;
|
||
+out:
|
||
+ free_checker(c);
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+void checker_set_fd (struct checker * c, int fd)
|
||
+{
|
||
+ c->fd = fd;
|
||
+}
|
||
+
|
||
+void checker_set_sync (struct checker * c)
|
||
+{
|
||
+ c->sync = 1;
|
||
+}
|
||
+
|
||
+void checker_set_async (struct checker * c)
|
||
+{
|
||
+ c->sync = 0;
|
||
+}
|
||
+
|
||
+void checker_enable (struct checker * c)
|
||
+{
|
||
+ c->disable = 0;
|
||
+}
|
||
+
|
||
+void checker_disable (struct checker * c)
|
||
+{
|
||
+ c->disable = 1;
|
||
+}
|
||
+
|
||
+int checker_init (struct checker * c, void ** mpctxt_addr)
|
||
+{
|
||
+ c->mpcontext = mpctxt_addr;
|
||
+ return c->init(c);
|
||
+}
|
||
+
|
||
+void checker_put (struct checker * c)
|
||
+{
|
||
+ if (c->free)
|
||
+ c->free(c);
|
||
+ memset(c, 0x0, sizeof(struct checker));
|
||
+}
|
||
+
|
||
+int checker_check (struct checker * c)
|
||
+{
|
||
+ int r;
|
||
+
|
||
+ if (c->disable)
|
||
+ return PATH_UNCHECKED;
|
||
+ if (c->fd <= 0) {
|
||
+ MSG(c, "no usable fd");
|
||
+ return PATH_WILD;
|
||
+ }
|
||
+ r = c->check(c);
|
||
+
|
||
+ return r;
|
||
+}
|
||
+
|
||
+int checker_selected (struct checker * c)
|
||
+{
|
||
+ return (c->check) ? 1 : 0;
|
||
+}
|
||
+
|
||
+char * checker_name (struct checker * c)
|
||
+{
|
||
+ return c->name;
|
||
+}
|
||
+
|
||
+char * checker_message (struct checker * c)
|
||
+{
|
||
+ return c->message;
|
||
+}
|
||
+
|
||
+void checker_get (struct checker * dst, char * name)
|
||
+{
|
||
+ struct checker * src = checker_lookup(name);
|
||
+
|
||
+ if (!src) {
|
||
+ dst->check = NULL;
|
||
+ return;
|
||
+ }
|
||
+ dst->fd = src->fd;
|
||
+ dst->sync = src->sync;
|
||
+ strncpy(dst->name, src->name, CHECKER_NAME_LEN);
|
||
+ strncpy(dst->message, src->message, CHECKER_MSG_LEN);
|
||
+ dst->check = src->check;
|
||
+ dst->init = src->init;
|
||
+ dst->free = src->free;
|
||
+}
|
||
diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
|
||
new file mode 100644
|
||
index 0000000..a65aaf9
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers.h
|
||
@@ -0,0 +1,126 @@
|
||
+#ifndef _CHECKERS_H
|
||
+#define _CHECKERS_H
|
||
+
|
||
+#include "list.h"
|
||
+#include "memory.h"
|
||
+
|
||
+/*
|
||
+ *
|
||
+ * 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.
|
||
+ *
|
||
+ * PATH_PENDING:
|
||
+ * - Use: All async checkers
|
||
+ * - Description: Indicates a check IO is in flight.
|
||
+ */
|
||
+#define PATH_WILD -1
|
||
+#define PATH_UNCHECKED 0
|
||
+#define PATH_DOWN 1
|
||
+#define PATH_UP 2
|
||
+#define PATH_SHAKY 3
|
||
+#define PATH_GHOST 4
|
||
+#define PATH_PENDING 5
|
||
+
|
||
+#define DIRECTIO "directio"
|
||
+#define TUR "tur"
|
||
+#define HP_SW "hp_sw"
|
||
+#define RDAC "rdac"
|
||
+#define EMC_CLARIION "emc_clariion"
|
||
+#define READSECTOR0 "readsector0"
|
||
+#define CCISS_TUR "cciss_tur"
|
||
+
|
||
+#define DEFAULT_CHECKER DIRECTIO
|
||
+
|
||
+/*
|
||
+ * 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
|
||
+#define ASYNC_TIMEOUT_SEC 30
|
||
+
|
||
+/*
|
||
+ * strings lengths
|
||
+ */
|
||
+#define CHECKER_NAME_LEN 16
|
||
+#define CHECKER_MSG_LEN 256
|
||
+#define CHECKER_DEV_LEN 256
|
||
+#define LIB_CHECKER_NAMELEN 256
|
||
+
|
||
+struct checker {
|
||
+ struct list_head node;
|
||
+ int fd;
|
||
+ int sync;
|
||
+ int disable;
|
||
+ 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, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
|
||
+
|
||
+int init_checkers (void);
|
||
+struct checker * add_checker (char *);
|
||
+struct checker * checker_lookup (char *);
|
||
+int checker_init (struct checker *, void **);
|
||
+void checker_put (struct checker *);
|
||
+void checker_reset (struct checker *);
|
||
+void checker_set_sync (struct checker *);
|
||
+void checker_set_async (struct checker *);
|
||
+void checker_set_fd (struct checker *, int);
|
||
+void checker_enable (struct checker *);
|
||
+void checker_disable (struct checker *);
|
||
+int checker_check (struct checker *);
|
||
+int checker_selected (struct checker *);
|
||
+char * checker_name (struct checker *);
|
||
+char * checker_message (struct checker *);
|
||
+void checker_get (struct checker *, char *);
|
||
+
|
||
+#endif /* _CHECKERS_H */
|
||
diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile
|
||
new file mode 100644
|
||
index 0000000..a20dfac
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/Makefile
|
||
@@ -0,0 +1,30 @@
|
||
+# Makefile
|
||
+#
|
||
+# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
+#
|
||
+include ../../Makefile.inc
|
||
+
|
||
+LIBS= \
|
||
+ libcheckcciss_tur.so \
|
||
+ libcheckreadsector0.so \
|
||
+ libchecktur.so \
|
||
+ libcheckdirectio.so \
|
||
+ libcheckemc_clariion.so \
|
||
+ libcheckhp_sw.so \
|
||
+ libcheckrdac.so
|
||
+
|
||
+CFLAGS += -I..
|
||
+
|
||
+all: $(LIBS)
|
||
+
|
||
+libcheck%.so: libsg.o %.o
|
||
+ $(CC) $(SHARED_FLAGS) -o $@ $^
|
||
+
|
||
+install:
|
||
+ $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)
|
||
+
|
||
+uninstall:
|
||
+ rm -f $(DESTDIR)$(libdir)/$(LIBS)
|
||
+
|
||
+clean:
|
||
+ rm -f core *.a *.o *.gz *.so
|
||
diff --git a/libmultipath/checkers/cciss.h b/libmultipath/checkers/cciss.h
|
||
new file mode 100644
|
||
index 0000000..ebdff06
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/cciss.h
|
||
@@ -0,0 +1,142 @@
|
||
+#ifndef CCISS_H
|
||
+#define CCISS_H
|
||
+
|
||
+#include <linux/types.h>
|
||
+#include <linux/ioctl.h>
|
||
+
|
||
+#define CCISS_IOC_MAGIC 'B'
|
||
+
|
||
+/*
|
||
+ * transfer direction
|
||
+ */
|
||
+#define XFER_NONE 0x00
|
||
+#define XFER_WRITE 0x01
|
||
+#define XFER_READ 0x02
|
||
+#define XFER_RSVD 0x03
|
||
+
|
||
+/*
|
||
+ * task attribute
|
||
+ */
|
||
+#define ATTR_UNTAGGED 0x00
|
||
+#define ATTR_SIMPLE 0x04
|
||
+#define ATTR_HEADOFQUEUE 0x05
|
||
+#define ATTR_ORDERED 0x06
|
||
+#define ATTR_ACA 0x07
|
||
+
|
||
+/*
|
||
+ * cdb type
|
||
+ */
|
||
+#define TYPE_CMD 0x00
|
||
+#define TYPE_MSG 0x01
|
||
+
|
||
+#define SENSEINFOBYTES 32
|
||
+
|
||
+/*
|
||
+ * Type defs used in the following structs
|
||
+ */
|
||
+#define BYTE __u8
|
||
+#define WORD __u16
|
||
+#define HWORD __u16
|
||
+#define DWORD __u32
|
||
+
|
||
+#pragma pack(1)
|
||
+
|
||
+//Command List Structure
|
||
+typedef union _SCSI3Addr_struct {
|
||
+ struct {
|
||
+ BYTE Dev;
|
||
+ BYTE Bus:6;
|
||
+ BYTE Mode:2; // b00
|
||
+ } PeripDev;
|
||
+ struct {
|
||
+ BYTE DevLSB;
|
||
+ BYTE DevMSB:6;
|
||
+ BYTE Mode:2; // b01
|
||
+ } LogDev;
|
||
+ struct {
|
||
+ BYTE Dev:5;
|
||
+ BYTE Bus:3;
|
||
+ BYTE Targ:6;
|
||
+ BYTE Mode:2; // b10
|
||
+ } LogUnit;
|
||
+} SCSI3Addr_struct;
|
||
+
|
||
+typedef struct _PhysDevAddr_struct {
|
||
+ DWORD TargetId:24;
|
||
+ DWORD Bus:6;
|
||
+ DWORD Mode:2;
|
||
+ SCSI3Addr_struct Target[2]; //2 level target device addr
|
||
+} PhysDevAddr_struct;
|
||
+
|
||
+typedef struct _LogDevAddr_struct {
|
||
+ DWORD VolId:30;
|
||
+ DWORD Mode:2;
|
||
+ BYTE reserved[4];
|
||
+} LogDevAddr_struct;
|
||
+
|
||
+typedef union _LUNAddr_struct {
|
||
+ BYTE LunAddrBytes[8];
|
||
+ SCSI3Addr_struct SCSI3Lun[4];
|
||
+ PhysDevAddr_struct PhysDev;
|
||
+ LogDevAddr_struct LogDev;
|
||
+} LUNAddr_struct;
|
||
+
|
||
+typedef struct _RequestBlock_struct {
|
||
+ BYTE CDBLen;
|
||
+ struct {
|
||
+ BYTE Type:3;
|
||
+ BYTE Attribute:3;
|
||
+ BYTE Direction:2;
|
||
+ } Type;
|
||
+ HWORD Timeout;
|
||
+ BYTE CDB[16];
|
||
+} RequestBlock_struct;
|
||
+
|
||
+typedef union _MoreErrInfo_struct{
|
||
+ struct {
|
||
+ BYTE Reserved[3];
|
||
+ BYTE Type;
|
||
+ DWORD ErrorInfo;
|
||
+ }Common_Info;
|
||
+ struct{
|
||
+ BYTE Reserved[2];
|
||
+ BYTE offense_size;//size of offending entry
|
||
+ BYTE offense_num; //byte # of offense 0-base
|
||
+ DWORD offense_value;
|
||
+ }Invalid_Cmd;
|
||
+}MoreErrInfo_struct;
|
||
+
|
||
+typedef struct _ErrorInfo_struct {
|
||
+ BYTE ScsiStatus;
|
||
+ BYTE SenseLen;
|
||
+ HWORD CommandStatus;
|
||
+ DWORD ResidualCnt;
|
||
+ MoreErrInfo_struct MoreErrInfo;
|
||
+ BYTE SenseInfo[SENSEINFOBYTES];
|
||
+} ErrorInfo_struct;
|
||
+
|
||
+#pragma pack()
|
||
+
|
||
+typedef struct _IOCTL_Command_struct {
|
||
+ LUNAddr_struct LUN_info;
|
||
+ RequestBlock_struct Request;
|
||
+ ErrorInfo_struct error_info;
|
||
+ WORD buf_size; /* size in bytes of the buf */
|
||
+ BYTE *buf;
|
||
+} IOCTL_Command_struct;
|
||
+
|
||
+typedef struct _LogvolInfo_struct{
|
||
+ __u32 LunID;
|
||
+ int num_opens; /* number of opens on the logical volume */
|
||
+ int num_parts; /* number of partitions configured on logvol */
|
||
+} LogvolInfo_struct;
|
||
+
|
||
+#define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
|
||
+#define CCISS_GETLUNINFO _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
|
||
+
|
||
+int cciss_init( struct checker *);
|
||
+void cciss_free (struct checker * c);
|
||
+int cciss_tur( struct checker *);
|
||
+
|
||
+#endif
|
||
+
|
||
diff --git a/libmultipath/checkers/cciss_tur.c b/libmultipath/checkers/cciss_tur.c
|
||
new file mode 100644
|
||
index 0000000..4c26901
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/cciss_tur.c
|
||
@@ -0,0 +1,137 @@
|
||
+/*
|
||
+ *****************************************************************************
|
||
+ * *
|
||
+ * (C) Copyright 2007 Hewlett-Packard Development Company, L.P *
|
||
+ * *
|
||
+ * 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. *
|
||
+ * *
|
||
+ * 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. *
|
||
+ * *
|
||
+ * You should have received a copy of the GNU General Public License along *
|
||
+ * with this program; if not, write to the Free Software Foundation, Inc., *
|
||
+ * 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||
+ * *
|
||
+ * The copy of the GNU General Public License is available at *
|
||
+ * /opt/hp/HPDMmultipath-tool directoy *
|
||
+ * *
|
||
+ *****************************************************************************
|
||
+*/
|
||
+
|
||
+/*
|
||
+ * This program originally derived from and inspired by
|
||
+ * Christophe Varoqui's tur.c, part of libchecker.
|
||
+ */
|
||
+
|
||
+
|
||
+#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 "cciss.h"
|
||
+
|
||
+#define TUR_CMD_LEN 6
|
||
+#define HEAVY_CHECK_COUNT 10
|
||
+
|
||
+#define MSG_CCISS_TUR_UP "cciss_tur checker reports path is up"
|
||
+#define MSG_CCISS_TUR_DOWN "cciss_tur checker reports path is down"
|
||
+
|
||
+struct cciss_tur_checker_context {
|
||
+ void * dummy;
|
||
+};
|
||
+
|
||
+int libcheck_init (struct checker * c)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void libcheck_free (struct checker * c)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
+extern int
|
||
+libcheck_check (struct checker * c)
|
||
+{
|
||
+ int rc;
|
||
+ int ret;
|
||
+ unsigned int lun = 0;
|
||
+ struct cciss_tur_checker_context * ctxt = NULL;
|
||
+ LogvolInfo_struct lvi; // logical "volume" info
|
||
+ IOCTL_Command_struct cic; // cciss ioctl command
|
||
+
|
||
+ if ((c->fd) <= 0) {
|
||
+ MSG(c,"no usable fd");
|
||
+ ret = -1;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ rc = ioctl(c->fd, CCISS_GETLUNINFO, &lvi);
|
||
+ if ( rc != 0) {
|
||
+ perror("Error: ");
|
||
+ fprintf(stderr, "cciss TUR failed in CCISS_GETLUNINFO: %s\n",
|
||
+ strerror(errno));
|
||
+ MSG(c,MSG_CCISS_TUR_DOWN);
|
||
+ ret = PATH_DOWN;
|
||
+ goto out;
|
||
+ } else {
|
||
+ lun = lvi.LunID;
|
||
+ }
|
||
+
|
||
+ memset(&cic, 0, sizeof(cic));
|
||
+ cic.LUN_info.LogDev.VolId = lun & 0x3FFFFFFF;
|
||
+ cic.LUN_info.LogDev.Mode = 0x01; /* logical volume addressing */
|
||
+ cic.Request.CDBLen = 6; /* need to try just 2 bytes here */
|
||
+ cic.Request.Type.Type = TYPE_CMD; // It is a command.
|
||
+ cic.Request.Type.Attribute = ATTR_SIMPLE;
|
||
+ cic.Request.Type.Direction = XFER_NONE;
|
||
+ cic.Request.Timeout = 0;
|
||
+
|
||
+ cic.Request.CDB[0] = 0;
|
||
+ cic.Request.CDB[1] = 0;
|
||
+ cic.Request.CDB[2] = 0;
|
||
+ cic.Request.CDB[3] = 0;
|
||
+ cic.Request.CDB[4] = 0;
|
||
+ cic.Request.CDB[5] = 0;
|
||
+
|
||
+ rc = ioctl(c->fd, CCISS_PASSTHRU, &cic);
|
||
+ if (rc < 0) {
|
||
+ fprintf(stderr, "cciss TUR failed: %s\n",
|
||
+ strerror(errno));
|
||
+ MSG(c,MSG_CCISS_TUR_DOWN);
|
||
+ ret = PATH_DOWN;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if ((cic.error_info.CommandStatus | cic.error_info.ScsiStatus )) {
|
||
+ MSG(c,MSG_CCISS_TUR_DOWN);
|
||
+ ret = PATH_DOWN;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ MSG(c,MSG_CCISS_TUR_UP);
|
||
+
|
||
+ ret = PATH_UP;
|
||
+out:
|
||
+ /*
|
||
+ * caller told us he doesn't want to keep the context :
|
||
+ * free it
|
||
+ */
|
||
+ if (!c->context)
|
||
+ free(ctxt);
|
||
+
|
||
+ return(ret);
|
||
+}
|
||
diff --git a/libmultipath/checkers/directio.c b/libmultipath/checkers/directio.c
|
||
new file mode 100644
|
||
index 0000000..5c92dac
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/directio.c
|
||
@@ -0,0 +1,197 @@
|
||
+/*
|
||
+ * Copyright (c) 2005 Hannes Reinecke, Suse
|
||
+ */
|
||
+#define _GNU_SOURCE
|
||
+#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 <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"
|
||
+#define MSG_DIRECTIO_PENDING "directio checker is waiting on aio"
|
||
+
|
||
+#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
|
||
+
|
||
+struct directio_context {
|
||
+ int running;
|
||
+ int reset_flags;
|
||
+ int blksize;
|
||
+ unsigned char * buf;
|
||
+ unsigned char * ptr;
|
||
+ io_context_t ioctx;
|
||
+ struct iocb io;
|
||
+};
|
||
+
|
||
+
|
||
+int libcheck_init (struct checker * c)
|
||
+{
|
||
+ unsigned long pgsize = getpagesize();
|
||
+ struct directio_context * ct;
|
||
+ long flags;
|
||
+
|
||
+ ct = malloc(sizeof(struct directio_context));
|
||
+ if (!ct)
|
||
+ return 1;
|
||
+ memset(ct, 0, sizeof(struct directio_context));
|
||
+
|
||
+ if (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");
|
||
+ ct->blksize = 512;
|
||
+ }
|
||
+ if (ct->blksize > 4096) {
|
||
+ /*
|
||
+ * Sanity check for DASD; BSZGET is broken
|
||
+ */
|
||
+ ct->blksize = 4096;
|
||
+ }
|
||
+ if (!ct->blksize)
|
||
+ goto out;
|
||
+ ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
|
||
+ if (!ct->buf)
|
||
+ goto out;
|
||
+
|
||
+ 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);
|
||
+ io_destroy(ct->ioctx);
|
||
+ free(ct);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+void libcheck_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);
|
||
+ io_destroy(ct->ioctx);
|
||
+ free(ct);
|
||
+}
|
||
+
|
||
+static int
|
||
+check_state(int fd, struct directio_context *ct, int sync)
|
||
+{
|
||
+ struct timespec timeout = { .tv_nsec = 5 };
|
||
+ struct io_event event;
|
||
+ struct stat sb;
|
||
+ int rc = PATH_UNCHECKED;
|
||
+ long r;
|
||
+
|
||
+ if (fstat(fd, &sb) == 0) {
|
||
+ LOG(4, "called for %x", (unsigned) sb.st_rdev);
|
||
+ }
|
||
+ if (sync) {
|
||
+ LOG(4, "called in synchronous mode");
|
||
+ timeout.tv_sec = ASYNC_TIMEOUT_SEC;
|
||
+ timeout.tv_nsec = 0;
|
||
+ }
|
||
+
|
||
+ if (!ct->running) {
|
||
+ struct iocb *ios[1] = { &ct->io };
|
||
+
|
||
+ LOG(3, "starting new request");
|
||
+ memset(&ct->io, 0, sizeof(struct iocb));
|
||
+ io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
|
||
+ if (io_submit(ct->ioctx, 1, ios) != 1) {
|
||
+ LOG(3, "io_submit error %i", errno);
|
||
+ return PATH_UNCHECKED;
|
||
+ }
|
||
+ }
|
||
+ ct->running++;
|
||
+
|
||
+ r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
|
||
+ LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
|
||
+
|
||
+ if (r < 1L) {
|
||
+ if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
|
||
+ LOG(3, "abort check on timeout");
|
||
+ rc = PATH_DOWN;
|
||
+ } else
|
||
+ rc = PATH_PENDING;
|
||
+ } else {
|
||
+ LOG(3, "io finished %lu/%lu", event.res, event.res2);
|
||
+ ct->running = 0;
|
||
+ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
|
||
+ }
|
||
+
|
||
+ return rc;
|
||
+}
|
||
+
|
||
+int libcheck_check (struct checker * c)
|
||
+{
|
||
+ int ret;
|
||
+ struct directio_context * ct = (struct directio_context *)c->context;
|
||
+
|
||
+ if (!ct)
|
||
+ return PATH_UNCHECKED;
|
||
+
|
||
+ ret = check_state(c->fd, ct, c->sync);
|
||
+
|
||
+ switch (ret)
|
||
+ {
|
||
+ case PATH_UNCHECKED:
|
||
+ MSG(c, MSG_DIRECTIO_UNKNOWN);
|
||
+ break;
|
||
+ case PATH_DOWN:
|
||
+ MSG(c, MSG_DIRECTIO_DOWN);
|
||
+ break;
|
||
+ case PATH_UP:
|
||
+ MSG(c, MSG_DIRECTIO_UP);
|
||
+ break;
|
||
+ case PATH_PENDING:
|
||
+ MSG(c, MSG_DIRECTIO_PENDING);
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+ return ret;
|
||
+}
|
||
diff --git a/libmultipath/checkers/directio.h b/libmultipath/checkers/directio.h
|
||
new file mode 100644
|
||
index 0000000..1865b1f
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/directio.h
|
||
@@ -0,0 +1,8 @@
|
||
+#ifndef _DIRECTIO_H
|
||
+#define _DIRECTIO_H
|
||
+
|
||
+int directio (struct checker *);
|
||
+int directio_init (struct checker *);
|
||
+void directio_free (struct checker *);
|
||
+
|
||
+#endif /* _DIRECTIO_H */
|
||
diff --git a/libmultipath/checkers/emc_clariion.c b/libmultipath/checkers/emc_clariion.c
|
||
new file mode 100644
|
||
index 0000000..9eac31d
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/emc_clariion.c
|
||
@@ -0,0 +1,230 @@
|
||
+/*
|
||
+ * Copyright (c) 2004, 2005 Lars Marowsky-Bree
|
||
+ */
|
||
+#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 "../libmultipath/sg_include.h"
|
||
+#include "libsg.h"
|
||
+#include "checkers.h"
|
||
+
|
||
+#define INQUIRY_CMD 0x12
|
||
+#define INQUIRY_CMDLEN 6
|
||
+#define HEAVY_CHECK_COUNT 10
|
||
+
|
||
+/*
|
||
+ * 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 libcheck_init (struct checker * c)
|
||
+{
|
||
+ /*
|
||
+ * 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_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;
|
||
+}
|
||
+
|
||
+void libcheck_free (struct checker * c)
|
||
+{
|
||
+ free(c->context);
|
||
+}
|
||
+
|
||
+int libcheck_check (struct checker * c)
|
||
+{
|
||
+ 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(sense_buffer), 0};
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ 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';
|
||
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
|
||
+ io_hdr.mx_sb_len = sizeof (sb);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
+ io_hdr.dxferp = sense_buffer;
|
||
+ io_hdr.cmdp = inqCmdBlk;
|
||
+ io_hdr.sbp = sb;
|
||
+ 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");
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ MSG(c, "emc_clariion_checker: query command indicates error");
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+ 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");
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+
|
||
+ if ( /* Effective initiator type */
|
||
+ sense_buffer[27] != 0x03
|
||
+ /*
|
||
+ * 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 "
|
||
+ "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");
|
||
+ return PATH_SHAKY;
|
||
+ }
|
||
+
|
||
+ if ( /* LUN should at least be bound somewhere and not be LUNZ */
|
||
+ sense_buffer[4] == 0x00) {
|
||
+ MSG(c, "emc_clariion_checker: Logical Unit is unbound "
|
||
+ "or LUNZ");
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * store the LUN WWN there and compare that it indeed did not
|
||
+ * change in between, to protect against the path suddenly
|
||
+ * pointing somewhere else.
|
||
+ */
|
||
+ if (ct->wwn_set) {
|
||
+ if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
|
||
+ MSG(c, "emc_clariion_checker: Logical Unit WWN "
|
||
+ "has changed!");
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+ } else {
|
||
+ memcpy(ct->wwn, &sense_buffer[10], 16);
|
||
+ ct->wwn_set = 1;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Issue read on active path to determine if inactive snapshot.
|
||
+ */
|
||
+ if (sense_buffer[4] == 2) {/* if active path */
|
||
+ unsigned char buf[4096];
|
||
+
|
||
+ 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/libmultipath/checkers/emc_clariion.h b/libmultipath/checkers/emc_clariion.h
|
||
new file mode 100644
|
||
index 0000000..a1018a6
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/emc_clariion.h
|
||
@@ -0,0 +1,8 @@
|
||
+#ifndef _EMC_CLARIION_H
|
||
+#define _EMC_CLARIION_H
|
||
+
|
||
+int emc_clariion (struct checker *);
|
||
+int emc_clariion_init (struct checker *);
|
||
+void emc_clariion_free (struct checker *);
|
||
+
|
||
+#endif /* _EMC_CLARIION_H */
|
||
diff --git a/libmultipath/checkers/hp_sw.c b/libmultipath/checkers/hp_sw.c
|
||
new file mode 100644
|
||
index 0000000..7509307
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/hp_sw.c
|
||
@@ -0,0 +1,141 @@
|
||
+/*
|
||
+ * 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 TUR_CMD_LEN 6
|
||
+#define INQUIRY_CMDLEN 6
|
||
+#define INQUIRY_CMD 0x12
|
||
+#define SENSE_BUFF_LEN 32
|
||
+#define SCSI_CHECK_CONDITION 0x2
|
||
+#define SCSI_COMMAND_TERMINATED 0x22
|
||
+#define SG_ERR_DRIVER_SENSE 0x08
|
||
+#define RECOVERED_ERROR 0x01
|
||
+#define MX_ALLOC_LEN 255
|
||
+#define HEAVY_CHECK_COUNT 10
|
||
+
|
||
+#define MSG_HP_SW_UP "hp_sw checker reports path is up"
|
||
+#define MSG_HP_SW_DOWN "hp_sw checker reports path is down"
|
||
+#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
|
||
+
|
||
+struct sw_checker_context {
|
||
+ void * dummy;
|
||
+};
|
||
+
|
||
+int libcheck_init (struct checker * c)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void libcheck_free (struct checker * c)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
+static int
|
||
+do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
|
||
+ void *resp, int mx_resp_len, int noisy)
|
||
+{
|
||
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
|
||
+ { 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)
|
||
+ inqCmdBlk[1] |= 1;
|
||
+ inqCmdBlk[2] = (unsigned char) pg_op;
|
||
+ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
|
||
+ 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 = 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;
|
||
+}
|
||
+
|
||
+static int
|
||
+do_tur (int fd)
|
||
+{
|
||
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ unsigned char sense_buffer[32];
|
||
+
|
||
+ 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 (sense_buffer);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
+ io_hdr.cmdp = turCmdBlk;
|
||
+ io_hdr.sbp = sense_buffer;
|
||
+ io_hdr.timeout = DEF_TIMEOUT;
|
||
+ io_hdr.pack_id = 0;
|
||
+
|
||
+ if (ioctl(fd, SG_IO, &io_hdr) < 0)
|
||
+ return 1;
|
||
+
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK)
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+extern int
|
||
+libcheck_check (struct checker * c)
|
||
+{
|
||
+ char buff[MX_ALLOC_LEN];
|
||
+
|
||
+ if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
|
||
+ MSG(c, MSG_HP_SW_DOWN);
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+
|
||
+ if (do_tur(c->fd)) {
|
||
+ MSG(c, MSG_HP_SW_GHOST);
|
||
+ return PATH_GHOST;
|
||
+ }
|
||
+ MSG(c, MSG_HP_SW_UP);
|
||
+ return PATH_UP;
|
||
+}
|
||
diff --git a/libmultipath/checkers/hp_sw.h b/libmultipath/checkers/hp_sw.h
|
||
new file mode 100644
|
||
index 0000000..3be0d8e
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/hp_sw.h
|
||
@@ -0,0 +1,8 @@
|
||
+#ifndef _HP_SW_H
|
||
+#define _HP_SW_H
|
||
+
|
||
+int hp_sw (struct checker *);
|
||
+int hp_sw_init (struct checker *);
|
||
+void hp_sw_free (struct checker *);
|
||
+
|
||
+#endif /* _HP_SW_H */
|
||
diff --git a/libmultipath/checkers/libsg.c b/libmultipath/checkers/libsg.c
|
||
new file mode 100644
|
||
index 0000000..4cb7ecc
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/libsg.c
|
||
@@ -0,0 +1,95 @@
|
||
+/*
|
||
+ * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
+ */
|
||
+#include <string.h>
|
||
+#include <sys/ioctl.h>
|
||
+#include <errno.h>
|
||
+#include <sys/stat.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;
|
||
+ struct stat filestatus;
|
||
+ int retry_count = 3;
|
||
+
|
||
+ if (fstat(sg_fd, &filestatus) != 0)
|
||
+ return PATH_DOWN;
|
||
+ bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
|
||
+ 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 {
|
||
+ int key = 0;
|
||
+
|
||
+ if (io_hdr.sb_len_wr > 3) {
|
||
+ if (sbb[0] == 0x72 || sbb[0] == 0x73)
|
||
+ key = sbb[1] & 0x0f;
|
||
+ else if (io_hdr.sb_len_wr > 13 &&
|
||
+ ((sbb[0] & 0x7f) == 0x70 ||
|
||
+ (sbb[0] & 0x7f) == 0x71))
|
||
+ key = sbb[2] & 0x0f;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Retry if UNIT_ATTENTION check condition.
|
||
+ */
|
||
+ if (key == 0x6) {
|
||
+ if (--retry_count)
|
||
+ goto retry;
|
||
+ }
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+}
|
||
diff --git a/libmultipath/checkers/libsg.h b/libmultipath/checkers/libsg.h
|
||
new file mode 100644
|
||
index 0000000..97c4491
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/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/libmultipath/checkers/rdac.c b/libmultipath/checkers/rdac.c
|
||
new file mode 100644
|
||
index 0000000..0086125
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/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 libcheck_init (struct checker * c)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void libcheck_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
|
||
+libcheck_check (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/libmultipath/checkers/rdac.h b/libmultipath/checkers/rdac.h
|
||
new file mode 100644
|
||
index 0000000..d7bf812
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/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/libmultipath/checkers/readsector0.c b/libmultipath/checkers/readsector0.c
|
||
new file mode 100644
|
||
index 0000000..24182e6
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/readsector0.c
|
||
@@ -0,0 +1,46 @@
|
||
+/*
|
||
+ * Copyright (c) 2004, 2005 Christophe Varoqui
|
||
+ */
|
||
+#include <stdio.h>
|
||
+
|
||
+#include "checkers.h"
|
||
+#include "libsg.h"
|
||
+
|
||
+#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
|
||
+#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
|
||
+
|
||
+struct readsector0_checker_context {
|
||
+ void * dummy;
|
||
+};
|
||
+
|
||
+int libcheck_init (struct checker * c)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void libcheck_free (struct checker * c)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
+int libcheck_check (struct checker * c)
|
||
+{
|
||
+ unsigned char buf[4096];
|
||
+ unsigned char sbuf[SENSE_BUFF_LEN];
|
||
+ int ret;
|
||
+
|
||
+ ret = sg_read(c->fd, &buf[0], &sbuf[0]);
|
||
+
|
||
+ switch (ret)
|
||
+ {
|
||
+ case PATH_DOWN:
|
||
+ MSG(c, MSG_READSECTOR0_DOWN);
|
||
+ break;
|
||
+ case PATH_UP:
|
||
+ MSG(c, MSG_READSECTOR0_UP);
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+ return ret;
|
||
+}
|
||
diff --git a/libmultipath/checkers/readsector0.h b/libmultipath/checkers/readsector0.h
|
||
new file mode 100644
|
||
index 0000000..0f5d654
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/readsector0.h
|
||
@@ -0,0 +1,8 @@
|
||
+#ifndef _READSECTOR0_H
|
||
+#define _READSECTOR0_H
|
||
+
|
||
+int readsector0 (struct checker *);
|
||
+int readsector0_init (struct checker *);
|
||
+void readsector0_free (struct checker *);
|
||
+
|
||
+#endif /* _READSECTOR0_H */
|
||
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
|
||
new file mode 100644
|
||
index 0000000..43b846d
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/tur.c
|
||
@@ -0,0 +1,88 @@
|
||
+/*
|
||
+ * Some code borrowed from sg-utils.
|
||
+ *
|
||
+ * Copyright (c) 2004 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 TUR_CMD_LEN 6
|
||
+#define HEAVY_CHECK_COUNT 10
|
||
+
|
||
+#define MSG_TUR_UP "tur checker reports path is up"
|
||
+#define MSG_TUR_DOWN "tur checker reports path is down"
|
||
+
|
||
+struct tur_checker_context {
|
||
+ void * dummy;
|
||
+};
|
||
+
|
||
+int libcheck_init (struct checker * c)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void libcheck_free (struct checker * c)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
+extern int
|
||
+libcheck_check (struct checker * c)
|
||
+{
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
|
||
+ unsigned char sense_buffer[32];
|
||
+ int retry_tur = 5;
|
||
+
|
||
+ retry:
|
||
+ 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 (sense_buffer);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
|
||
+ io_hdr.cmdp = turCmdBlk;
|
||
+ io_hdr.sbp = sense_buffer;
|
||
+ io_hdr.timeout = DEF_TIMEOUT;
|
||
+ io_hdr.pack_id = 0;
|
||
+ if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
|
||
+ MSG(c, MSG_TUR_DOWN);
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ int key = 0, asc, ascq;
|
||
+
|
||
+ if (io_hdr.sb_len_wr > 3) {
|
||
+ if (io_hdr.sbp[0] == 0x72 || io_hdr.sbp[0] == 0x73) {
|
||
+ key = io_hdr.sbp[1] & 0x0f;
|
||
+ asc = io_hdr.sbp[2];
|
||
+ ascq = io_hdr.sbp[3];
|
||
+ } else if (io_hdr.sb_len_wr > 13 &&
|
||
+ ((io_hdr.sbp[0] & 0x7f) == 0x70 ||
|
||
+ (io_hdr.sbp[0] & 0x7f) == 0x71)) {
|
||
+ key = io_hdr.sbp[2] & 0x0f;
|
||
+ asc = io_hdr.sbp[12];
|
||
+ ascq = io_hdr.sbp[13];
|
||
+ }
|
||
+ }
|
||
+ if (key == 0x6) {
|
||
+ /* Unit Attention, retry */
|
||
+ if (--retry_tur)
|
||
+ goto retry;
|
||
+ }
|
||
+ MSG(c, MSG_TUR_DOWN);
|
||
+ return PATH_DOWN;
|
||
+ }
|
||
+ MSG(c, MSG_TUR_UP);
|
||
+ return PATH_UP;
|
||
+}
|
||
diff --git a/libmultipath/checkers/tur.h b/libmultipath/checkers/tur.h
|
||
new file mode 100644
|
||
index 0000000..a2e8c88
|
||
--- /dev/null
|
||
+++ b/libmultipath/checkers/tur.h
|
||
@@ -0,0 +1,8 @@
|
||
+#ifndef _TUR_H
|
||
+#define _TUR_H
|
||
+
|
||
+int tur (struct checker *);
|
||
+int tur_init (struct checker *);
|
||
+void tur_free (struct checker *);
|
||
+
|
||
+#endif /* _TUR_H */
|
||
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
||
index a39af8a..a109cd9 100644
|
||
--- a/libmultipath/config.c
|
||
+++ b/libmultipath/config.c
|
||
@@ -6,8 +6,7 @@
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "memory.h"
|
||
#include "util.h"
|
||
#include "debug.h"
|
||
@@ -19,24 +18,33 @@
|
||
#include "config.h"
|
||
#include "blacklist.h"
|
||
#include "defaults.h"
|
||
+#include "prio.h"
|
||
|
||
-static struct hwentry *
|
||
-find_hwe_strmatch (vector hwtable, char * vendor, char * product, char * revision)
|
||
+static int
|
||
+hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
|
||
{
|
||
- int i;
|
||
- struct hwentry *hwe, *ret = NULL;
|
||
+ if (hwe1->vendor && hwe2->vendor && strcmp(hwe1->vendor, hwe2->vendor))
|
||
+ return 1;
|
||
|
||
- vector_foreach_slot (hwtable, hwe, i) {
|
||
- if (hwe->vendor && vendor && strcmp(hwe->vendor, vendor))
|
||
- continue;
|
||
+ if (hwe1->product && hwe2->product && strcmp(hwe1->product, hwe2->product))
|
||
+ return 1;
|
||
|
||
- if (hwe->product && product && strcmp(hwe->product, product))
|
||
- continue;
|
||
+ if (hwe1->revision && hwe2->revision && strcmp(hwe1->revision, hwe2->revision))
|
||
+ return 1;
|
||
|
||
- if (hwe->revision && revision && strcmp(hwe->revision, revision))
|
||
- continue;
|
||
+ return 0;
|
||
+}
|
||
|
||
- ret = hwe;
|
||
+static struct hwentry *
|
||
+find_hwe_strmatch (vector hwtable, struct hwentry *hwe)
|
||
+{
|
||
+ int i;
|
||
+ struct hwentry *tmp, *ret = NULL;
|
||
+
|
||
+ vector_foreach_slot (hwtable, tmp, i) {
|
||
+ if (hwe_strmatch(tmp, hwe))
|
||
+ continue;
|
||
+ ret = tmp;
|
||
break;
|
||
}
|
||
return ret;
|
||
@@ -135,9 +143,6 @@ free_hwe (struct hwentry * hwe)
|
||
if (hwe->getuid)
|
||
FREE(hwe->getuid);
|
||
|
||
- if (hwe->getprio)
|
||
- FREE(hwe->getprio);
|
||
-
|
||
if (hwe->features)
|
||
FREE(hwe->features);
|
||
|
||
@@ -242,12 +247,47 @@ set_param_str(char * str)
|
||
return dst;
|
||
}
|
||
|
||
+#define merge_str(s) \
|
||
+ if (hwe2->s) { \
|
||
+ if (hwe1->s) \
|
||
+ free(hwe1->s); \
|
||
+ if (!(hwe1->s = set_param_str(hwe2->s))) \
|
||
+ return 1; \
|
||
+ }
|
||
+
|
||
+#define merge_num(s) \
|
||
+ if (hwe2->s) \
|
||
+ hwe1->s = hwe2->s
|
||
+
|
||
+
|
||
+static int
|
||
+merge_hwe (struct hwentry * hwe1, struct hwentry * hwe2)
|
||
+{
|
||
+ merge_str(vendor);
|
||
+ merge_str(product);
|
||
+ merge_str(revision);
|
||
+ merge_str(getuid);
|
||
+ merge_str(features);
|
||
+ merge_str(hwhandler);
|
||
+ merge_str(selector);
|
||
+ merge_str(checker_name);
|
||
+ merge_str(prio_name);
|
||
+ merge_str(bl_product);
|
||
+ merge_num(pgpolicy);
|
||
+ merge_num(pgfailback);
|
||
+ merge_num(rr_weight);
|
||
+ merge_num(no_path_retry);
|
||
+ merge_num(minio);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
int
|
||
store_hwe (vector hwtable, struct hwentry * dhwe)
|
||
{
|
||
struct hwentry * hwe;
|
||
|
||
- if (find_hwe_strmatch(hwtable, dhwe->vendor, dhwe->product, dhwe->revision))
|
||
+ if (find_hwe_strmatch(hwtable, dhwe))
|
||
return 0;
|
||
|
||
if (!(hwe = alloc_hwe()))
|
||
@@ -265,9 +305,6 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
|
||
if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
|
||
goto out;
|
||
|
||
- if (dhwe->getprio && !(hwe->getprio = set_param_str(dhwe->getprio)))
|
||
- goto out;
|
||
-
|
||
if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
|
||
goto out;
|
||
|
||
@@ -276,13 +313,18 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
|
||
|
||
if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
|
||
goto out;
|
||
+
|
||
+ if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
|
||
+ goto out;
|
||
+
|
||
+ if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
|
||
+ goto out;
|
||
|
||
hwe->pgpolicy = dhwe->pgpolicy;
|
||
hwe->pgfailback = dhwe->pgfailback;
|
||
hwe->rr_weight = dhwe->rr_weight;
|
||
hwe->no_path_retry = dhwe->no_path_retry;
|
||
hwe->minio = dhwe->minio;
|
||
- hwe->checker = dhwe->checker;
|
||
|
||
if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
|
||
goto out;
|
||
@@ -297,6 +339,27 @@ out:
|
||
return 1;
|
||
}
|
||
|
||
+static int
|
||
+factorize_hwtable (vector hw)
|
||
+{
|
||
+ struct hwentry *hwe1, *hwe2;
|
||
+ int i, j;
|
||
+
|
||
+ vector_foreach_slot(hw, hwe1, i) {
|
||
+ j = i+1;
|
||
+ vector_foreach_slot_after(hw, hwe2, j) {
|
||
+ if (hwe_strmatch(hwe1, hwe2))
|
||
+ continue;
|
||
+ /* dup */
|
||
+ merge_hwe(hwe1, hwe2);
|
||
+ free_hwe(hwe2);
|
||
+ vector_del_slot(hw, j);
|
||
+ j--;
|
||
+ }
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
struct config *
|
||
alloc_config (void)
|
||
{
|
||
@@ -315,15 +378,15 @@ free_config (struct config * conf)
|
||
if (conf->udev_dir)
|
||
FREE(conf->udev_dir);
|
||
|
||
+ if (conf->multipath_dir)
|
||
+ FREE(conf->multipath_dir);
|
||
+
|
||
if (conf->selector)
|
||
FREE(conf->selector);
|
||
|
||
if (conf->getuid)
|
||
FREE(conf->getuid);
|
||
|
||
- if (conf->getprio)
|
||
- FREE(conf->getprio);
|
||
-
|
||
if (conf->features)
|
||
FREE(conf->features);
|
||
|
||
@@ -361,7 +424,21 @@ load_config (char * file)
|
||
|
||
conf->dev_type = DEV_NONE;
|
||
conf->minio = 1000;
|
||
+ conf->max_fds = 0;
|
||
conf->bindings_file = DEFAULT_BINDINGS_FILE;
|
||
+ conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
|
||
+
|
||
+ /*
|
||
+ * preload default hwtable
|
||
+ */
|
||
+ if (conf->hwtable == NULL) {
|
||
+ conf->hwtable = vector_alloc();
|
||
+
|
||
+ if (!conf->hwtable)
|
||
+ goto out;
|
||
+ }
|
||
+ if (setup_default_hwtable(conf->hwtable))
|
||
+ goto out;
|
||
|
||
/*
|
||
* read the config file
|
||
@@ -373,35 +450,31 @@ load_config (char * file)
|
||
goto out;
|
||
}
|
||
}
|
||
-
|
||
+
|
||
/*
|
||
- * fill the voids left in the config file
|
||
+ * remove duplica in hwtable. config file takes precedence
|
||
+ * over build-in hwtable
|
||
*/
|
||
- if (conf->hwtable == NULL) {
|
||
- conf->hwtable = vector_alloc();
|
||
-
|
||
- if (!conf->hwtable)
|
||
- goto out;
|
||
-
|
||
- }
|
||
- if (setup_default_hwtable(conf->hwtable))
|
||
- goto out;
|
||
+ factorize_hwtable(conf->hwtable);
|
||
|
||
+ /*
|
||
+ * fill the voids left in the config file
|
||
+ */
|
||
if (conf->blist_devnode == NULL) {
|
||
conf->blist_devnode = vector_alloc();
|
||
-
|
||
+
|
||
if (!conf->blist_devnode)
|
||
goto out;
|
||
}
|
||
if (conf->blist_wwid == NULL) {
|
||
conf->blist_wwid = vector_alloc();
|
||
-
|
||
+
|
||
if (!conf->blist_wwid)
|
||
goto out;
|
||
}
|
||
if (conf->blist_device == NULL) {
|
||
conf->blist_device = vector_alloc();
|
||
-
|
||
+
|
||
if (!conf->blist_device)
|
||
goto out;
|
||
}
|
||
@@ -409,21 +482,21 @@ load_config (char * file)
|
||
goto out;
|
||
|
||
if (conf->elist_devnode == NULL) {
|
||
- conf->elist_devnode = vector_alloc();
|
||
+ conf->elist_devnode = vector_alloc();
|
||
|
||
- if (!conf->elist_devnode)
|
||
+ if (!conf->elist_devnode)
|
||
goto out;
|
||
}
|
||
if (conf->elist_wwid == NULL) {
|
||
conf->elist_wwid = vector_alloc();
|
||
|
||
- if (!conf->elist_wwid)
|
||
+ if (!conf->elist_wwid)
|
||
goto out;
|
||
}
|
||
|
||
if (conf->elist_device == NULL) {
|
||
conf->elist_device = vector_alloc();
|
||
-
|
||
+
|
||
if (!conf->elist_device)
|
||
goto out;
|
||
}
|
||
@@ -449,13 +522,16 @@ load_config (char * file)
|
||
if (conf->hwhandler == NULL)
|
||
conf->hwhandler = set_default(DEFAULT_HWHANDLER);
|
||
|
||
- if (!conf->selector || !conf->udev_dir ||
|
||
+ if (!conf->selector || !conf->udev_dir || !conf->multipath_dir ||
|
||
!conf->getuid || !conf->features ||
|
||
!conf->hwhandler)
|
||
goto out;
|
||
|
||
- if (!conf->checker)
|
||
- conf->checker = checker_lookup(DEFAULT_CHECKER);
|
||
+ if (!conf->prio_name)
|
||
+ conf->prio_name = set_default(DEFAULT_PRIO);
|
||
+
|
||
+ if (!conf->checker_name)
|
||
+ conf->checker_name = set_default(DEFAULT_CHECKER);
|
||
|
||
return 0;
|
||
out:
|
||
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
||
index a25b3ad..fb917f4 100644
|
||
--- a/libmultipath/config.h
|
||
+++ b/libmultipath/config.h
|
||
@@ -16,11 +16,11 @@ struct hwentry {
|
||
char * product;
|
||
char * revision;
|
||
char * getuid;
|
||
- char * getprio;
|
||
char * features;
|
||
char * hwhandler;
|
||
char * selector;
|
||
char * checker_name;
|
||
+ char * prio_name;
|
||
|
||
int pgpolicy;
|
||
int pgfailback;
|
||
@@ -28,7 +28,6 @@ struct hwentry {
|
||
int no_path_retry;
|
||
int minio;
|
||
int pg_timeout;
|
||
- struct checker * checker;
|
||
char * bl_product;
|
||
};
|
||
|
||
@@ -53,7 +52,6 @@ struct config {
|
||
int pgpolicy_flag;
|
||
int with_sysfs;
|
||
int pgpolicy;
|
||
- struct checker * checker;
|
||
enum devtypes dev_type;
|
||
int minio;
|
||
int checkint;
|
||
@@ -64,16 +62,20 @@ struct config {
|
||
int no_path_retry;
|
||
int user_friendly_names;
|
||
int pg_timeout;
|
||
+ int max_fds;
|
||
+ int force_reload;
|
||
|
||
char * dev;
|
||
char * sysfs_dir;
|
||
char * udev_dir;
|
||
+ char * multipath_dir;
|
||
char * selector;
|
||
char * getuid;
|
||
- char * getprio;
|
||
char * features;
|
||
char * hwhandler;
|
||
char * bindings_file;
|
||
+ char * prio_name;
|
||
+ char * checker_name;
|
||
|
||
vector keywords;
|
||
vector mptable;
|
||
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||
index 3cd6041..285a8a2 100644
|
||
--- a/libmultipath/configure.c
|
||
+++ b/libmultipath/configure.c
|
||
@@ -14,8 +14,7 @@
|
||
#include <errno.h>
|
||
#include <libdevmapper.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "memory.h"
|
||
#include "devmapper.h"
|
||
@@ -34,6 +33,7 @@
|
||
#include "pgpolicies.h"
|
||
#include "dict.h"
|
||
#include "alias.h"
|
||
+#include "prio.h"
|
||
|
||
extern int
|
||
setup_map (struct multipath * mpp)
|
||
@@ -130,7 +130,7 @@ pgcmp (struct multipath * mpp, struct multipath * cmpp)
|
||
}
|
||
|
||
static void
|
||
-select_action (struct multipath * mpp, vector curmp)
|
||
+select_action (struct multipath * mpp, vector curmp, int force_reload)
|
||
{
|
||
struct multipath * cmpp;
|
||
|
||
@@ -154,7 +154,7 @@ select_action (struct multipath * mpp, vector curmp)
|
||
|
||
if (!find_mp_by_wwid(curmp, mpp->wwid)) {
|
||
condlog(2, "%s: remove (wwid changed)", cmpp->alias);
|
||
- dm_flush_map(mpp->alias, DEFAULT_TARGET);
|
||
+ dm_flush_map(mpp->alias);
|
||
strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
|
||
drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
|
||
mpp->action = ACT_CREATE;
|
||
@@ -169,6 +169,12 @@ select_action (struct multipath * mpp, vector curmp)
|
||
mpp->alias);
|
||
return;
|
||
}
|
||
+ if (force_reload) {
|
||
+ mpp->action = ACT_RELOAD;
|
||
+ condlog(3, "%s: set ACT_RELOAD (forced by user)",
|
||
+ mpp->alias);
|
||
+ return;
|
||
+ }
|
||
if (cmpp->size != mpp->size) {
|
||
mpp->action = ACT_RELOAD;
|
||
condlog(3, "%s: set ACT_RELOAD (size change)",
|
||
@@ -183,14 +189,14 @@ select_action (struct multipath * mpp, vector curmp)
|
||
mpp->alias);
|
||
return;
|
||
}
|
||
- if (strncmp(cmpp->hwhandler, mpp->hwhandler,
|
||
+ if (!cmpp->selector || strncmp(cmpp->hwhandler, mpp->hwhandler,
|
||
strlen(mpp->hwhandler))) {
|
||
mpp->action = ACT_RELOAD;
|
||
condlog(3, "%s: set ACT_RELOAD (hwhandler change)",
|
||
mpp->alias);
|
||
return;
|
||
}
|
||
- if (strncmp(cmpp->selector, mpp->selector,
|
||
+ if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector,
|
||
strlen(mpp->selector))) {
|
||
mpp->action = ACT_RELOAD;
|
||
condlog(3, "%s: set ACT_RELOAD (selector change)",
|
||
@@ -203,7 +209,7 @@ select_action (struct multipath * mpp, vector curmp)
|
||
mpp->alias, cmpp->minio, mpp->minio);
|
||
return;
|
||
}
|
||
- if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
|
||
+ if (!cmpp->pg || VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
|
||
mpp->action = ACT_RELOAD;
|
||
condlog(3, "%s: set ACT_RELOAD (path group number change)",
|
||
mpp->alias);
|
||
@@ -330,28 +336,19 @@ domap (struct multipath * mpp)
|
||
break;
|
||
}
|
||
|
||
- r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
|
||
- mpp->params, mpp->size, mpp->wwid);
|
||
+ r = dm_addmap_create(mpp->alias, mpp->params, mpp->size,
|
||
+ mpp->wwid);
|
||
|
||
- /*
|
||
- * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
|
||
- * DM_TABLE_LOAD. Failing the second part leaves an
|
||
- * empty map. Clean it up.
|
||
- */
|
||
- if (!r && dm_map_present(mpp->alias)) {
|
||
- condlog(3, "%s: failed to load map "
|
||
- "(a path might be in use)",
|
||
- mpp->alias);
|
||
- dm_flush_map(mpp->alias, DEFAULT_TARGET);
|
||
- }
|
||
+ if (!r)
|
||
+ r = dm_addmap_create_ro(mpp->alias, mpp->params,
|
||
+ mpp->size, mpp->wwid);
|
||
|
||
lock_multipath(mpp, 0);
|
||
break;
|
||
|
||
case ACT_RELOAD:
|
||
- r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
|
||
- mpp->params, mpp->size, NULL) &&
|
||
- dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
|
||
+ r = (dm_addmap_reload(mpp->alias, mpp->params, mpp->size, NULL)
|
||
+ && dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
|
||
break;
|
||
|
||
case ACT_RENAME:
|
||
@@ -364,18 +361,24 @@ domap (struct multipath * mpp)
|
||
|
||
if (r) {
|
||
/*
|
||
- * DM_DEVICE_CREATE, DM_DEIVCE_RENAME, or DM_DEVICE_RELOAD
|
||
+ * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
|
||
* succeeded
|
||
*/
|
||
-#ifndef DAEMON
|
||
- dm_switchgroup(mpp->alias, mpp->bestpg);
|
||
- if (mpp->action != ACT_NOTHING)
|
||
- print_multipath_topology(mpp, conf->verbosity);
|
||
-#else
|
||
- mpp->stat_map_loads++;
|
||
- condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
|
||
- mpp->size, DEFAULT_TARGET, mpp->params);
|
||
-#endif
|
||
+ if (!mpp->waiter) {
|
||
+ /* multipath client mode */
|
||
+ dm_switchgroup(mpp->alias, mpp->bestpg);
|
||
+ if (mpp->action != ACT_NOTHING)
|
||
+ print_multipath_topology(mpp, conf->verbosity);
|
||
+ } else {
|
||
+ /* multipath daemon mode */
|
||
+ mpp->stat_map_loads++;
|
||
+ condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
|
||
+ mpp->size, TGT_MPATH, mpp->params);
|
||
+ /*
|
||
+ * Required action is over, reset for the stateful daemon
|
||
+ */
|
||
+ mpp->action = ACT_NOTHING;
|
||
+ }
|
||
return DOMAP_OK;
|
||
}
|
||
return DOMAP_FAIL;
|
||
@@ -404,7 +407,7 @@ deadmap (struct multipath * mpp)
|
||
}
|
||
|
||
extern int
|
||
-coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
+coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_reload)
|
||
{
|
||
int r = 1;
|
||
int k, i;
|
||
@@ -417,6 +420,11 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
|
||
memset(empty_buff, 0, WWID_SIZE);
|
||
|
||
+ if (force_reload) {
|
||
+ vector_foreach_slot (pathvec, pp1, k) {
|
||
+ pp1->mpp = NULL;
|
||
+ }
|
||
+ }
|
||
vector_foreach_slot (pathvec, pp1, k) {
|
||
/* skip this path for some reason */
|
||
|
||
@@ -440,7 +448,8 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
/*
|
||
* at this point, we know we really got a new mp
|
||
*/
|
||
- if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL)
|
||
+ mpp = add_map_with_path(vecs, pp1, 0);
|
||
+ if (!mpp)
|
||
return 1;
|
||
|
||
if (pp1->priority == PRIO_UNDEF)
|
||
@@ -448,7 +457,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
|
||
if (!mpp->paths) {
|
||
condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
|
||
- remove_map(mpp, vecs, NULL, 0);
|
||
+ remove_map(mpp, vecs, 0);
|
||
continue;
|
||
}
|
||
|
||
@@ -476,12 +485,12 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
verify_paths(mpp, vecs, NULL);
|
||
|
||
if (setup_map(mpp)) {
|
||
- remove_map(mpp, vecs, NULL, 0);
|
||
+ remove_map(mpp, vecs, 0);
|
||
continue;
|
||
}
|
||
|
||
if (mpp->action == ACT_UNDEF)
|
||
- select_action(mpp, curmp);
|
||
+ select_action(mpp, curmp, force_reload);
|
||
|
||
r = domap(mpp);
|
||
|
||
@@ -490,7 +499,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
"for create/reload map",
|
||
mpp->alias, r);
|
||
if (r == DOMAP_FAIL) {
|
||
- remove_map(mpp, vecs, NULL, 0);
|
||
+ remove_map(mpp, vecs, 0);
|
||
continue;
|
||
} else /* if (r == DOMAP_RETRY) */
|
||
return r;
|
||
@@ -518,7 +527,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
vector_set_slot(newmp, mpp);
|
||
}
|
||
else
|
||
- remove_map(mpp, vecs, NULL, 0);
|
||
+ remove_map(mpp, vecs, 0);
|
||
}
|
||
}
|
||
/*
|
||
@@ -538,9 +547,9 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
|
||
if ((j = find_slot(newmp, (void *)mpp)) != -1)
|
||
vector_del_slot(newmp, j);
|
||
|
||
- remove_map(mpp, vecs, NULL, 0);
|
||
+ remove_map(mpp, vecs, 0);
|
||
|
||
- if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
|
||
+ if (dm_flush_map(mpp->alias))
|
||
condlog(2, "%s: remove failed (dead)",
|
||
mpp->alias);
|
||
else
|
||
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
|
||
index 1cbbe82..75d5057 100644
|
||
--- a/libmultipath/configure.h
|
||
+++ b/libmultipath/configure.h
|
||
@@ -24,6 +24,6 @@ enum actions {
|
||
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);
|
||
+int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
|
||
char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec);
|
||
|
||
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
|
||
index 05dfb06..d30517d 100644
|
||
--- a/libmultipath/debug.c
|
||
+++ b/libmultipath/debug.c
|
||
@@ -5,11 +5,9 @@
|
||
#include <stdlib.h>
|
||
#include <stdarg.h>
|
||
|
||
-#if DAEMON
|
||
#include "log_pthread.h"
|
||
#include <sys/types.h>
|
||
#include <time.h>
|
||
-#endif
|
||
|
||
#include "vector.h"
|
||
#include "config.h"
|
||
@@ -23,12 +21,11 @@ void dlog (int sink, int prio, const char * fmt, ...)
|
||
thres = (conf) ? conf->verbosity : 0;
|
||
|
||
if (prio <= thres) {
|
||
-#if DAEMON
|
||
if (!sink) {
|
||
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';
|
||
|
||
@@ -37,9 +34,6 @@ void dlog (int sink, int prio, const char * fmt, ...)
|
||
}
|
||
else
|
||
log_safe(prio + 3, fmt, ap);
|
||
-#else
|
||
- vfprintf(stdout, fmt, ap);
|
||
-#endif
|
||
}
|
||
va_end(ap);
|
||
}
|
||
diff --git a/libmultipath/debug.h b/libmultipath/debug.h
|
||
index 082fff1..c6120c1 100644
|
||
--- a/libmultipath/debug.h
|
||
+++ b/libmultipath/debug.h
|
||
@@ -1,21 +1,13 @@
|
||
void dlog (int sink, int prio, const char * fmt, ...)
|
||
__attribute__((format(printf, 3, 4)));
|
||
|
||
-#if DAEMON
|
||
|
||
#include <pthread.h>
|
||
#include <stdarg.h>
|
||
|
||
#include "log_pthread.h"
|
||
|
||
-int logsink;
|
||
+extern int logsink;
|
||
|
||
#define condlog(prio, fmt, args...) \
|
||
dlog(logsink, prio, fmt "\n", ##args)
|
||
-
|
||
-#else /* DAEMON */
|
||
-
|
||
-#define condlog(prio, fmt, args...) \
|
||
- dlog(0, prio, fmt "\n", ##args)
|
||
-
|
||
-#endif /* DAEMON */
|
||
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
|
||
index df7d971..826f360 100644
|
||
--- a/libmultipath/defaults.h
|
||
+++ b/libmultipath/defaults.h
|
||
@@ -1,10 +1,10 @@
|
||
#define DEFAULT_GETUID "/lib/udev/scsi_id -g -u -s /block/%n"
|
||
#define DEFAULT_UDEVDIR "/dev"
|
||
+#define DEFAULT_MULTIPATHDIR "/lib/multipath"
|
||
#define DEFAULT_SELECTOR "round-robin 0"
|
||
#define DEFAULT_FEATURES "0"
|
||
#define DEFAULT_HWHANDLER "0"
|
||
#define DEFAULT_MINIO 1000
|
||
-#define DEFAULT_GETPRIO NULL
|
||
#define DEFAULT_PGPOLICY FAILOVER
|
||
#define DEFAULT_FAILBACK -FAILBACK_MANUAL
|
||
#define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE
|
||
@@ -15,7 +15,6 @@
|
||
#define DEFAULT_CHECKINT 5
|
||
#define MAX_CHECKINT(a) (a << 2)
|
||
|
||
-#define DEFAULT_TARGET "multipath"
|
||
#define DEFAULT_PIDFILE "/var/run/multipathd.pid"
|
||
#define DEFAULT_SOCKET "/var/run/multipathd.sock"
|
||
#define DEFAULT_CONFIGFILE "/etc/multipath.conf"
|
||
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
|
||
index d6991ba..d329781 100644
|
||
--- a/libmultipath/devmapper.c
|
||
+++ b/libmultipath/devmapper.c
|
||
@@ -14,8 +14,7 @@
|
||
#include <unistd.h>
|
||
#include <errno.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "structs.h"
|
||
#include "debug.h"
|
||
@@ -23,11 +22,9 @@
|
||
#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
|
||
@@ -48,8 +45,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...)
|
||
if (thres <= 3 || level > thres)
|
||
return;
|
||
|
||
- va_start(ap, f);
|
||
-#if DAEMON
|
||
+ va_start(ap, f);
|
||
if (!logsink) {
|
||
time_t t = time(NULL);
|
||
struct tm *tb = localtime(&t);
|
||
@@ -66,12 +62,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...)
|
||
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);
|
||
+ va_end(ap);
|
||
|
||
return;
|
||
}
|
||
@@ -151,11 +142,11 @@ out:
|
||
}
|
||
|
||
extern int
|
||
-dm_prereq (char * str)
|
||
+dm_prereq (void)
|
||
{
|
||
if (dm_libprereq())
|
||
return 1;
|
||
- return dm_drvprereq(str);
|
||
+ return dm_drvprereq(TGT_MPATH);
|
||
}
|
||
|
||
extern int
|
||
@@ -184,7 +175,8 @@ dm_simplecmd (int task, const char *name) {
|
||
|
||
extern int
|
||
dm_addmap (int task, const char *name, const char *target,
|
||
- const char *params, unsigned long long size, const char *uuid) {
|
||
+ const char *params, unsigned long long size, const char *uuid,
|
||
+ int ro) {
|
||
int r = 0;
|
||
struct dm_task *dmt;
|
||
char *prefixed_uuid = NULL;
|
||
@@ -198,6 +190,9 @@ dm_addmap (int task, const char *name, const char *target,
|
||
if (!dm_task_add_target (dmt, 0, size, target, params))
|
||
goto addout;
|
||
|
||
+ if (ro)
|
||
+ dm_task_set_ro(dmt);
|
||
+
|
||
if (uuid){
|
||
prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
|
||
if (!prefixed_uuid) {
|
||
@@ -220,11 +215,59 @@ dm_addmap (int task, const char *name, const char *target,
|
||
|
||
addout:
|
||
dm_task_destroy (dmt);
|
||
+
|
||
+ return r;
|
||
+}
|
||
+
|
||
+static int
|
||
+_dm_addmap_create (const char *name, const char *params,
|
||
+ unsigned long long size, const char *uuid, int ro) {
|
||
+ int r;
|
||
+ r = dm_addmap(DM_DEVICE_CREATE, name, TGT_MPATH, params, size, uuid,
|
||
+ ro);
|
||
+ /*
|
||
+ * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
|
||
+ * Failing the second part leaves an empty map. Clean it up.
|
||
+ */
|
||
+ if (!r && dm_map_present(name)) {
|
||
+ condlog(3, "%s: failed to load map (a path might be in use)",
|
||
+ name);
|
||
+ dm_flush_map(name);
|
||
+ }
|
||
return r;
|
||
}
|
||
|
||
+#define ADDMAP_RW 0
|
||
+#define ADDMAP_RO 1
|
||
+
|
||
+extern int
|
||
+dm_addmap_create (const char *name, const char *params,
|
||
+ unsigned long long size, const char *uuid) {
|
||
+ return _dm_addmap_create(name, params, size, uuid, ADDMAP_RW);
|
||
+}
|
||
+
|
||
+extern int
|
||
+dm_addmap_create_ro (const char *name, const char *params,
|
||
+ unsigned long long size, const char *uuid) {
|
||
+ return _dm_addmap_create(name, params, size, uuid, ADDMAP_RO);
|
||
+}
|
||
+
|
||
+extern int
|
||
+dm_addmap_reload (const char *name, const char *params,
|
||
+ unsigned long long size, const char *uuid) {
|
||
+ return dm_addmap(DM_DEVICE_RELOAD, name, TGT_MPATH, params, size, uuid,
|
||
+ ADDMAP_RW);
|
||
+}
|
||
+
|
||
+extern int
|
||
+dm_addmap_reload_ro (const char *name, const char *params,
|
||
+ unsigned long long size, const char *uuid) {
|
||
+ return dm_addmap(DM_DEVICE_RELOAD, name, TGT_MPATH, params, size, uuid,
|
||
+ ADDMAP_RO);
|
||
+}
|
||
+
|
||
extern int
|
||
-dm_map_present (char * str)
|
||
+dm_map_present (const char * str)
|
||
{
|
||
int r = 0;
|
||
struct dm_task *dmt;
|
||
@@ -361,7 +404,7 @@ out:
|
||
* -1 : empty map
|
||
*/
|
||
extern int
|
||
-dm_type(char * name, char * type)
|
||
+dm_type(const char * name, char * type)
|
||
{
|
||
int r = 0;
|
||
struct dm_task *dmt;
|
||
@@ -396,7 +439,7 @@ out:
|
||
}
|
||
|
||
static int
|
||
-dm_dev_t (char * mapname, char * dev_t, int len)
|
||
+dm_dev_t (const char * mapname, char * dev_t, int len)
|
||
{
|
||
int r = 1;
|
||
struct dm_task *dmt;
|
||
@@ -425,7 +468,7 @@ out:
|
||
}
|
||
|
||
int
|
||
-dm_get_opencount (char * mapname)
|
||
+dm_get_opencount (const char * mapname)
|
||
{
|
||
int r = -1;
|
||
struct dm_task *dmt;
|
||
@@ -475,14 +518,14 @@ out:
|
||
}
|
||
|
||
extern int
|
||
-dm_flush_map (char * mapname, char * type)
|
||
+dm_flush_map (const char * mapname)
|
||
{
|
||
int r;
|
||
|
||
if (!dm_map_present(mapname))
|
||
return 0;
|
||
|
||
- if (dm_type(mapname, type) <= 0)
|
||
+ if (dm_type(mapname, TGT_MPATH) <= 0)
|
||
return 1;
|
||
|
||
if (dm_remove_partmaps(mapname))
|
||
@@ -503,7 +546,7 @@ dm_flush_map (char * mapname, char * type)
|
||
}
|
||
|
||
extern int
|
||
-dm_flush_maps (char * type)
|
||
+dm_flush_maps (void)
|
||
{
|
||
int r = 0;
|
||
struct dm_task *dmt;
|
||
@@ -525,7 +568,7 @@ dm_flush_maps (char * type)
|
||
goto out;
|
||
|
||
do {
|
||
- r += dm_flush_map(names->name, type);
|
||
+ r += dm_flush_map(names->name);
|
||
next = names->next;
|
||
names = (void *) names + next;
|
||
} while (next);
|
||
@@ -642,7 +685,7 @@ dm_disablegroup(char * mapname, int index)
|
||
}
|
||
|
||
int
|
||
-dm_get_maps (vector mp, char * type)
|
||
+dm_get_maps (vector mp)
|
||
{
|
||
struct multipath * mpp;
|
||
int r = 1;
|
||
@@ -651,7 +694,7 @@ dm_get_maps (vector mp, char * type)
|
||
struct dm_names *names;
|
||
unsigned next = 0;
|
||
|
||
- if (!type || !mp)
|
||
+ if (!mp)
|
||
return 1;
|
||
|
||
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
|
||
@@ -671,7 +714,7 @@ dm_get_maps (vector mp, char * type)
|
||
}
|
||
|
||
do {
|
||
- info = dm_type(names->name, type);
|
||
+ info = dm_type(names->name, TGT_MPATH);
|
||
|
||
if (info <= 0)
|
||
goto next;
|
||
@@ -717,7 +760,7 @@ out:
|
||
}
|
||
|
||
extern int
|
||
-dm_get_name(char *uuid, char *type, char *name)
|
||
+dm_get_name(char *uuid, char *name)
|
||
{
|
||
vector vec;
|
||
struct multipath *mpp;
|
||
@@ -728,7 +771,7 @@ dm_get_name(char *uuid, char *type, char *name)
|
||
if (!vec)
|
||
return 0;
|
||
|
||
- if (dm_get_maps(vec, type)) {
|
||
+ if (dm_get_maps(vec)) {
|
||
vector_free(vec);
|
||
return 0;
|
||
}
|
||
@@ -827,7 +870,7 @@ bad:
|
||
}
|
||
|
||
int
|
||
-dm_remove_partmaps (char * mapname)
|
||
+dm_remove_partmaps (const char * mapname)
|
||
{
|
||
struct dm_task *dmt;
|
||
struct dm_names *names;
|
||
@@ -861,7 +904,7 @@ dm_remove_partmaps (char * mapname)
|
||
/*
|
||
* if devmap target is "linear"
|
||
*/
|
||
- (dm_type(names->name, "linear") > 0) &&
|
||
+ (dm_type(names->name, TGT_PART) > 0) &&
|
||
|
||
/*
|
||
* and the multipath mapname and the part mapname start
|
||
@@ -984,7 +1027,7 @@ dm_rename_partmaps (char * old, char * new)
|
||
/*
|
||
* if devmap target is "linear"
|
||
*/
|
||
- (dm_type(names->name, "linear") > 0) &&
|
||
+ (dm_type(names->name, TGT_PART) > 0) &&
|
||
|
||
/*
|
||
* and the multipath mapname and the part mapname start
|
||
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
|
||
index 8438034..a340c00 100644
|
||
--- a/libmultipath/devmapper.h
|
||
+++ b/libmultipath/devmapper.h
|
||
@@ -1,14 +1,23 @@
|
||
+#define TGT_MPATH "multipath"
|
||
+#define TGT_PART "linear"
|
||
+
|
||
void dm_init(void);
|
||
-int dm_prereq (char *);
|
||
+int dm_prereq (void);
|
||
int dm_simplecmd (int, const char *);
|
||
-int dm_addmap (int, const char *, const char *, const char *,
|
||
- unsigned long long, const char *uuid);
|
||
-int dm_map_present (char *);
|
||
+int dm_addmap_create (const char *, const char *,
|
||
+ unsigned long long size, const char *uuid);
|
||
+int dm_addmap_create_ro (const char *, const char *,
|
||
+ unsigned long long size, const char *uuid);
|
||
+int dm_addmap_reload (const char *, const char *,
|
||
+ unsigned long long size, const char *uuid);
|
||
+int dm_addmap_reload_ro (const char *, const char *,
|
||
+ unsigned long long size, const char *uuid);
|
||
+int dm_map_present (const char *);
|
||
int dm_get_map(char *, unsigned long long *, char *);
|
||
int dm_get_status(char *, char *);
|
||
-int dm_type(char *, char *);
|
||
-int dm_flush_map (char *, char *);
|
||
-int dm_flush_maps (char *);
|
||
+int dm_type(const char *, char *);
|
||
+int dm_flush_map (const char *);
|
||
+int dm_flush_maps (void);
|
||
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);
|
||
@@ -16,12 +25,12 @@ 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);
|
||
-int dm_get_maps (vector mp, char * type);
|
||
+int dm_get_maps (vector mp);
|
||
int dm_geteventnr (char *name);
|
||
int dm_get_minor (char *name);
|
||
char * dm_mapname(int major, int minor);
|
||
-int dm_remove_partmaps (char * mapname);
|
||
+int dm_remove_partmaps (const char * mapname);
|
||
int dm_get_uuid(char *name, char *uuid);
|
||
int dm_get_info (char * mapname, struct dm_info ** dmi);
|
||
int dm_rename (char * old, char * new);
|
||
-int dm_get_name(char * uuid, char * type, char * name);
|
||
+int dm_get_name(char * uuid, char * name);
|
||
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
||
index 4572a7d..f5bca30 100644
|
||
--- a/libmultipath/dict.c
|
||
+++ b/libmultipath/dict.c
|
||
@@ -4,8 +4,7 @@
|
||
* Copyright (c) 2005 Benjamin Marzinski, Redhat
|
||
* Copyright (c) 2005 Kiyoshi Ueda, NEC
|
||
*/
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "hwtable.h"
|
||
#include "structs.h"
|
||
@@ -16,6 +15,7 @@
|
||
#include "pgpolicies.h"
|
||
#include "blacklist.h"
|
||
#include "defaults.h"
|
||
+#include "prio.h"
|
||
|
||
/*
|
||
* default block handlers
|
||
@@ -44,6 +44,17 @@ udev_dir_handler(vector strvec)
|
||
}
|
||
|
||
static int
|
||
+multipath_dir_handler(vector strvec)
|
||
+{
|
||
+ conf->multipath_dir = set_value(strvec);
|
||
+
|
||
+ if (!conf->multipath_dir)
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
def_selector_handler(vector strvec)
|
||
{
|
||
conf->selector = set_value(strvec);
|
||
@@ -82,19 +93,13 @@ def_getuid_callout_handler(vector strvec)
|
||
}
|
||
|
||
static int
|
||
-def_prio_callout_handler(vector strvec)
|
||
+def_prio_handler(vector strvec)
|
||
{
|
||
- conf->getprio = set_value(strvec);
|
||
+ conf->prio_name = set_value(strvec);
|
||
|
||
- if (!conf->getprio)
|
||
+ if (!conf->prio_name)
|
||
return 1;
|
||
-
|
||
- if (strlen(conf->getprio) == 4 &&
|
||
- !strcmp(conf->getprio, "none")) {
|
||
- FREE(conf->getprio);
|
||
- conf->getprio = NULL;
|
||
- }
|
||
-
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
@@ -112,21 +117,32 @@ def_features_handler(vector strvec)
|
||
static int
|
||
def_path_checker_handler(vector strvec)
|
||
{
|
||
+ conf->checker_name = set_value(strvec);
|
||
+
|
||
+ if (!conf->checker_name)
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
+def_minio_handler(vector strvec)
|
||
+{
|
||
char * buff;
|
||
|
||
buff = set_value(strvec);
|
||
|
||
if (!buff)
|
||
return 1;
|
||
-
|
||
- conf->checker = checker_lookup(buff);
|
||
+
|
||
+ conf->minio = atoi(buff);
|
||
FREE(buff);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
-def_minio_handler(vector strvec)
|
||
+max_fds_handler(vector strvec)
|
||
{
|
||
char * buff;
|
||
|
||
@@ -135,7 +151,11 @@ def_minio_handler(vector strvec)
|
||
if (!buff)
|
||
return 1;
|
||
|
||
- conf->minio = atoi(buff);
|
||
+ if (strlen(buff) == 9 &&
|
||
+ !strcmp(buff, "unlimited"))
|
||
+ conf->max_fds = MAX_FDS_UNLIMITED;
|
||
+ else
|
||
+ conf->max_fds = atoi(buff);
|
||
FREE(buff);
|
||
|
||
return 0;
|
||
@@ -398,7 +418,8 @@ ble_except_product_handler(vector strvec)
|
||
static int
|
||
devices_handler(vector strvec)
|
||
{
|
||
- conf->hwtable = vector_alloc();
|
||
+ if (!conf->hwtable)
|
||
+ conf->hwtable = vector_alloc();
|
||
|
||
if (!conf->hwtable)
|
||
return 1;
|
||
@@ -521,20 +542,16 @@ hw_selector_handler(vector strvec)
|
||
static int
|
||
hw_path_checker_handler(vector strvec)
|
||
{
|
||
- char * buff;
|
||
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
|
||
|
||
if (!hwe)
|
||
return 1;
|
||
|
||
- buff = set_value(strvec);
|
||
+ hwe->checker_name = set_value(strvec);
|
||
|
||
- if (!buff)
|
||
+ if (!hwe->checker_name)
|
||
return 1;
|
||
|
||
- hwe->checker = checker_lookup(buff);
|
||
- FREE(buff);
|
||
-
|
||
return 0;
|
||
}
|
||
|
||
@@ -571,23 +588,18 @@ hw_handler_handler(vector strvec)
|
||
}
|
||
|
||
static int
|
||
-prio_callout_handler(vector strvec)
|
||
+hw_prio_handler(vector strvec)
|
||
{
|
||
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
|
||
-
|
||
+
|
||
if (!hwe)
|
||
return 1;
|
||
|
||
- hwe->getprio = set_value(strvec);
|
||
+ hwe->prio_name = set_value(strvec);
|
||
|
||
- if (!hwe->getprio)
|
||
+ if (!hwe->prio_name)
|
||
return 1;
|
||
|
||
- if (strlen(hwe->getprio) == 4 && !strcmp(hwe->getprio, "none")) {
|
||
- FREE(hwe->getprio);
|
||
- hwe->getprio = NULL;
|
||
- }
|
||
-
|
||
return 0;
|
||
}
|
||
|
||
@@ -1075,7 +1087,7 @@ snprint_hw_vendor (char * buff, int len, void * data)
|
||
if (!hwe->vendor)
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->vendor);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->vendor);
|
||
}
|
||
|
||
static int
|
||
@@ -1086,7 +1098,7 @@ snprint_hw_product (char * buff, int len, void * data)
|
||
if (!hwe->product)
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->product);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->product);
|
||
}
|
||
|
||
static int
|
||
@@ -1097,7 +1109,7 @@ snprint_hw_bl_product (char * buff, int len, void * data)
|
||
if (!hwe->bl_product)
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->bl_product);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->bl_product);
|
||
}
|
||
|
||
static int
|
||
@@ -1111,27 +1123,20 @@ snprint_hw_getuid_callout (char * buff, int len, void * data)
|
||
!strcmp(hwe->getuid, conf->getuid))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->getuid);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->getuid);
|
||
}
|
||
|
||
static int
|
||
-snprint_hw_prio_callout (char * buff, int len, void * data)
|
||
+snprint_hw_prio (char * buff, int len, void * data)
|
||
{
|
||
struct hwentry * hwe = (struct hwentry *)data;
|
||
|
||
- if (!conf->getprio && !hwe->getprio)
|
||
+ if (!hwe->prio_name)
|
||
return 0;
|
||
- if (!conf->getprio && hwe->getprio)
|
||
- return snprintf(buff, len, "%s", hwe->getprio);
|
||
- if (conf->getprio && !hwe->getprio)
|
||
- return snprintf(buff, len, "none");
|
||
-
|
||
- /* conf->getprio && hwe->getprio */
|
||
- if (strlen(hwe->getprio) == strlen(conf->getprio) &&
|
||
- !strcmp(hwe->getprio, conf->getprio))
|
||
+ if (!strcmp(hwe->prio_name, conf->prio_name))
|
||
return 0;
|
||
-
|
||
- return snprintf(buff, len, "%s", hwe->getprio);
|
||
+
|
||
+ return snprintf(buff, len, "%s", hwe->prio_name);
|
||
}
|
||
|
||
static int
|
||
@@ -1145,7 +1150,7 @@ snprint_hw_features (char * buff, int len, void * data)
|
||
!strcmp(hwe->features, conf->features))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->features);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->features);
|
||
}
|
||
|
||
static int
|
||
@@ -1159,7 +1164,7 @@ snprint_hw_hardware_handler (char * buff, int len, void * data)
|
||
!strcmp(hwe->hwhandler, conf->hwhandler))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", hwe->hwhandler);
|
||
+ return snprintf(buff, len, "\"%s\"", hwe->hwhandler);
|
||
}
|
||
|
||
static int
|
||
@@ -1294,14 +1299,12 @@ snprint_hw_path_checker (char * buff, int len, void * data)
|
||
{
|
||
struct hwentry * hwe = (struct hwentry *)data;
|
||
|
||
- if (!hwe->checker)
|
||
+ if (!hwe->checker_name)
|
||
return 0;
|
||
- if (!checker_selected(hwe->checker))
|
||
- return 0;
|
||
- if (hwe->checker == conf->checker)
|
||
+ if (!strcmp(hwe->checker_name, conf->checker_name))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", checker_name(hwe->checker));
|
||
+ return snprintf(buff, len, "%s", hwe->checker_name);
|
||
}
|
||
|
||
static int
|
||
@@ -1321,7 +1324,19 @@ snprint_def_udev_dir (char * buff, int len, void * data)
|
||
!strcmp(conf->udev_dir, DEFAULT_UDEVDIR))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", conf->udev_dir);
|
||
+ return snprintf(buff, len, "\"%s\"", conf->udev_dir);
|
||
+}
|
||
+
|
||
+static int
|
||
+snprint_def_multipath_dir (char * buff, int len, void * data)
|
||
+{
|
||
+ if (!conf->udev_dir)
|
||
+ return 0;
|
||
+ if (strlen(DEFAULT_MULTIPATHDIR) == strlen(conf->multipath_dir) &&
|
||
+ !strcmp(conf->multipath_dir, DEFAULT_MULTIPATHDIR))
|
||
+ return 0;
|
||
+
|
||
+ return snprintf(buff, len, "\"%s\"", conf->multipath_dir);
|
||
}
|
||
|
||
static int
|
||
@@ -1360,16 +1375,20 @@ snprint_def_getuid_callout (char * buff, int len, void * data)
|
||
!strcmp(conf->getuid, DEFAULT_GETUID))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", conf->getuid);
|
||
+ return snprintf(buff, len, "\"%s\"", conf->getuid);
|
||
}
|
||
|
||
static int
|
||
-snprint_def_getprio_callout (char * buff, int len, void * data)
|
||
+snprint_def_prio (char * buff, int len, void * data)
|
||
{
|
||
- if (!conf->getprio)
|
||
+ if (!conf->prio_name)
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", conf->getprio);
|
||
+ if (strlen(conf->prio_name) == strlen(DEFAULT_PRIO) &&
|
||
+ !strcmp(conf->prio_name, DEFAULT_PRIO))
|
||
+ return 0;
|
||
+
|
||
+ return snprintf(buff, len, "%s", conf->prio_name);
|
||
}
|
||
|
||
static int
|
||
@@ -1381,18 +1400,19 @@ snprint_def_features (char * buff, int len, void * data)
|
||
!strcmp(conf->features, DEFAULT_FEATURES))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", conf->features);
|
||
+ return snprintf(buff, len, "\"%s\"", conf->features);
|
||
}
|
||
|
||
static int
|
||
snprint_def_path_checker (char * buff, int len, void * data)
|
||
{
|
||
- if (!conf->checker)
|
||
+ if (!conf->checker_name)
|
||
return 0;
|
||
- if (conf->checker == checker_default())
|
||
+ if (strlen(conf->checker_name) == strlen(DEFAULT_CHECKER) &&
|
||
+ !strcmp(conf->checker_name, DEFAULT_CHECKER))
|
||
return 0;
|
||
|
||
- return snprintf(buff, len, "%s", checker_name(conf->checker));
|
||
+ return snprintf(buff, len, "%s", conf->checker_name);
|
||
}
|
||
|
||
static int
|
||
@@ -1428,6 +1448,17 @@ snprint_def_rr_min_io (char * buff, int len, void * data)
|
||
}
|
||
|
||
static int
|
||
+snprint_max_fds (char * buff, int len, void * data)
|
||
+{
|
||
+ if (!conf->max_fds)
|
||
+ return 0;
|
||
+
|
||
+ if (conf->max_fds < 0)
|
||
+ return snprintf(buff, len, "unlimited");
|
||
+ return snprintf(buff, len, "%d", conf->max_fds);
|
||
+}
|
||
+
|
||
+static int
|
||
snprint_def_rr_weight (char * buff, int len, void * data)
|
||
{
|
||
if (!conf->rr_weight)
|
||
@@ -1493,7 +1524,7 @@ snprint_ble_simple (char * buff, int len, void * data)
|
||
{
|
||
struct blentry * ble = (struct blentry *)data;
|
||
|
||
- return snprintf(buff, len, "%s", ble->str);
|
||
+ return snprintf(buff, len, "\"%s\"", ble->str);
|
||
}
|
||
|
||
static int
|
||
@@ -1501,7 +1532,7 @@ snprint_bled_vendor (char * buff, int len, void * data)
|
||
{
|
||
struct blentry_device * bled = (struct blentry_device *)data;
|
||
|
||
- return snprintf(buff, len, "%s", bled->vendor);
|
||
+ return snprintf(buff, len, "\"%s\"", bled->vendor);
|
||
}
|
||
|
||
static int
|
||
@@ -1509,7 +1540,7 @@ snprint_bled_product (char * buff, int len, void * data)
|
||
{
|
||
struct blentry_device * bled = (struct blentry_device *)data;
|
||
|
||
- return snprintf(buff, len, "%s", bled->product);
|
||
+ return snprintf(buff, len, "\"%s\"", bled->product);
|
||
}
|
||
|
||
#define __deprecated
|
||
@@ -1520,14 +1551,17 @@ init_keywords(void)
|
||
install_keyword_root("defaults", NULL);
|
||
install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
|
||
install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir);
|
||
+ install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir);
|
||
install_keyword("selector", &def_selector_handler, &snprint_def_selector);
|
||
install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
|
||
install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
|
||
- install_keyword("prio_callout", &def_prio_callout_handler, &snprint_def_getprio_callout);
|
||
+ install_keyword("prio", &def_prio_handler, &snprint_def_prio);
|
||
install_keyword("features", &def_features_handler, &snprint_def_features);
|
||
install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
|
||
+ install_keyword("checker", &def_path_checker_handler, &snprint_def_path_checker);
|
||
install_keyword("failback", &default_failback_handler, &snprint_def_failback);
|
||
install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
|
||
+ install_keyword("max_fds", &max_fds_handler, &snprint_max_fds);
|
||
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);
|
||
@@ -1535,7 +1569,6 @@ init_keywords(void)
|
||
__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
|
||
__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
|
||
__deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
|
||
- __deprecated install_keyword("default_prio_callout", &def_prio_callout_handler, NULL);
|
||
__deprecated install_keyword("default_features", &def_features_handler, NULL);
|
||
__deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
|
||
|
||
@@ -1577,9 +1610,10 @@ init_keywords(void)
|
||
install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
|
||
install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
|
||
install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
|
||
+ install_keyword("checker", &hw_path_checker_handler, &snprint_hw_path_checker);
|
||
install_keyword("features", &hw_features_handler, &snprint_hw_features);
|
||
install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
|
||
- install_keyword("prio_callout", &prio_callout_handler, &snprint_hw_prio_callout);
|
||
+ install_keyword("prio", &hw_prio_handler, &snprint_hw_prio);
|
||
install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
|
||
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);
|
||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||
index c842eb0..7baa9e7 100644
|
||
--- a/libmultipath/discovery.c
|
||
+++ b/libmultipath/discovery.c
|
||
@@ -11,8 +11,7 @@
|
||
#include <dirent.h>
|
||
#include <errno.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "memory.h"
|
||
#include "util.h"
|
||
@@ -25,6 +24,7 @@
|
||
#include "sg_include.h"
|
||
#include "sysfs.h"
|
||
#include "discovery.h"
|
||
+#include "prio.h"
|
||
|
||
struct path *
|
||
store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
|
||
@@ -133,9 +133,9 @@ sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
|
||
attr = sysfs_attr_get_value(dev->devpath, #fname); \
|
||
if (!attr) \
|
||
return 1; \
|
||
-\
|
||
if (strlcpy(buff, attr, len) != strlen(attr)) \
|
||
return 2; \
|
||
+ strchop(buff); \
|
||
return 0; \
|
||
}
|
||
|
||
@@ -361,10 +361,13 @@ get_inq (char * vendor, char * product, char * rev, int fd)
|
||
if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) {
|
||
memcpy(vendor, buff + 8, 8);
|
||
vendor[8] = '\0';
|
||
+ strchop(vendor);
|
||
memcpy(product, buff + 16, 16);
|
||
product[16] = '\0';
|
||
+ strchop(product);
|
||
memcpy(rev, buff + 32, 4);
|
||
rev[4] = '\0';
|
||
+ strchop(rev);
|
||
return 0;
|
||
}
|
||
return 1;
|
||
@@ -546,6 +549,9 @@ sysfs_pathinfo(struct path * pp)
|
||
if (!parent)
|
||
parent = pp->sysdev;
|
||
|
||
+ if (!strncmp(parent->kernel, "block",5))
|
||
+ parent = sysfs_device_get_parent(parent);
|
||
+
|
||
condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
|
||
|
||
if (!strncmp(parent->subsystem, "scsi",4))
|
||
@@ -617,8 +623,8 @@ get_state (struct path * pp)
|
||
}
|
||
pp->state = checker_check(c);
|
||
condlog(3, "%s: state = %i", pp->dev, pp->state);
|
||
- if (pp->state == PATH_DOWN)
|
||
- condlog(2, "%s: checker msg is \"%s\"",
|
||
+ if (pp->state == PATH_DOWN && strlen(checker_message(c)))
|
||
+ condlog(3, "%s: checker msg is \"%s\"",
|
||
pp->dev, checker_message(c));
|
||
return 0;
|
||
}
|
||
@@ -626,27 +632,22 @@ get_state (struct path * pp)
|
||
static int
|
||
get_prio (struct path * pp)
|
||
{
|
||
- char buff[CALLOUT_MAX_SIZE];
|
||
- char prio[16];
|
||
+ if (!pp)
|
||
+ return 0;
|
||
|
||
- if (!pp->getprio_selected) {
|
||
- select_getprio(pp);
|
||
- pp->getprio_selected = 1;
|
||
+ if (!pp->prio) {
|
||
+ select_prio(pp);
|
||
+ if (!pp->prio)
|
||
+ return 1;
|
||
}
|
||
- if (!pp->getprio) {
|
||
- pp->priority = PRIO_DEFAULT;
|
||
- } else if (apply_format(pp->getprio, &buff[0], pp)) {
|
||
- condlog(0, "error formatting prio callout command");
|
||
- pp->priority = PRIO_UNDEF;
|
||
- return 1;
|
||
- } else if (execute_program(buff, prio, 16)) {
|
||
- condlog(0, "error calling out %s", buff);
|
||
+ pp->priority = prio_getprio(pp->prio, pp);
|
||
+ if (pp->priority < 0) {
|
||
+ condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
|
||
pp->priority = PRIO_UNDEF;
|
||
return 1;
|
||
- } else
|
||
- pp->priority = atoi(prio);
|
||
-
|
||
- condlog(3, "%s: prio = %u", pp->dev, pp->priority);
|
||
+ }
|
||
+ condlog(3, "%s: %s prio = %u",
|
||
+ pp->dev, prio_name(pp->prio), pp->priority);
|
||
return 0;
|
||
}
|
||
|
||
@@ -662,7 +663,7 @@ get_uid (struct path * pp)
|
||
condlog(0, "error formatting uid callout command");
|
||
memset(pp->wwid, 0, WWID_SIZE);
|
||
} else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
|
||
- condlog(0, "error calling out %s", buff);
|
||
+ condlog(3, "error calling out %s", buff);
|
||
memset(pp->wwid, 0, WWID_SIZE);
|
||
return 1;
|
||
}
|
||
@@ -723,5 +724,6 @@ blank:
|
||
*/
|
||
memset(pp->wwid, 0, WWID_SIZE);
|
||
pp->state = PATH_DOWN;
|
||
+
|
||
return 0;
|
||
}
|
||
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
|
||
index 631933d..bc3f231 100644
|
||
--- a/libmultipath/dmparser.c
|
||
+++ b/libmultipath/dmparser.c
|
||
@@ -7,8 +7,7 @@
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "memory.h"
|
||
#include "structs.h"
|
||
@@ -146,6 +145,8 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
|
||
FREE(word);
|
||
return 1;
|
||
}
|
||
+ setup_feature(mpp, word);
|
||
+
|
||
FREE(word);
|
||
}
|
||
|
||
@@ -183,11 +184,12 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
|
||
num_pg = atoi(word);
|
||
FREE(word);
|
||
|
||
- if (num_pg > 0 && !mpp->pg)
|
||
+ if (num_pg > 0 && !mpp->pg) {
|
||
mpp->pg = vector_alloc();
|
||
-
|
||
- if (!mpp->pg)
|
||
- return 1;
|
||
+ if (!mpp->pg)
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
/*
|
||
* first pg to try
|
||
*/
|
||
@@ -278,10 +280,9 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
|
||
|
||
strncpy(pp->dev_t, word, BLK_DEV_SIZE);
|
||
|
||
-#ifndef DAEMON
|
||
- if (store_path(pathvec, pp))
|
||
+ /* Only call this in multipath client mode */
|
||
+ if (!mpp->waiter && store_path(pathvec, pp))
|
||
goto out;
|
||
-#endif
|
||
}
|
||
FREE(word);
|
||
|
||
@@ -329,6 +330,7 @@ out1:
|
||
FREE(word);
|
||
out:
|
||
free_pgvec(mpp->pg, KEEP_PATHS);
|
||
+ mpp->pg = NULL;
|
||
return 1;
|
||
}
|
||
|
||
@@ -398,6 +400,9 @@ disassemble_status (char * params, struct multipath * mpp)
|
||
num_pg = atoi(word);
|
||
FREE(word);
|
||
|
||
+ if (num_pg == 0)
|
||
+ return 0;
|
||
+
|
||
/*
|
||
* next pg to try
|
||
*/
|
||
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
|
||
index ef761d7..0a94f10 100644
|
||
--- a/libmultipath/hwtable.c
|
||
+++ b/libmultipath/hwtable.c
|
||
@@ -1,12 +1,12 @@
|
||
#include <stdio.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "defaults.h"
|
||
#include "structs.h"
|
||
#include "config.h"
|
||
#include "pgpolicies.h"
|
||
+#include "prio.h"
|
||
|
||
/*
|
||
* Tuning suggestions on these parameters should go to
|
||
@@ -27,7 +27,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "APPLE*",
|
||
.product = "Xserve RAID ",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -37,6 +36,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = DEFAULT_CHECKER,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
/*
|
||
* StorageWorks controller family
|
||
@@ -48,7 +48,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "3PARdata",
|
||
.product = "VV",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -58,14 +57,14 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = DEFAULT_CHECKER,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
.vendor = "DEC",
|
||
.product = "HSG80",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_hp_sw /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
- .hwhandler = "1 hp_sw",
|
||
+ .hwhandler = "1 hp-sw",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.pgpolicy = GROUP_BY_PRIO,
|
||
.pgfailback = FAILBACK_UNDEF,
|
||
@@ -73,101 +72,117 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = HP_SW,
|
||
+ .prio_name = PRIO_HP_SW,
|
||
},
|
||
{
|
||
.vendor = "HP",
|
||
.product = "A6189A",
|
||
.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,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
- .checker_name = READSECTOR0,
|
||
+ .checker_name = DIRECTIO,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
/* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */
|
||
.vendor = "(COMPAQ|HP)",
|
||
.product = "(MSA|HSV)1.0.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_hp_sw /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
- .hwhandler = "1 hp_sw",
|
||
+ .hwhandler = "1 hp-sw",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.pgpolicy = GROUP_BY_PRIO,
|
||
.pgfailback = FAILBACK_UNDEF,
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
- .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = HP_SW,
|
||
+ .prio_name = PRIO_HP_SW,
|
||
},
|
||
{
|
||
/* MSA 1000/1500 with new firmware */
|
||
.vendor = "HP",
|
||
.product = "MSA VOLUME",
|
||
.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_IMMEDIATE,
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
- .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_ALUA,
|
||
},
|
||
{
|
||
- /* EVA 3000/5000 with new firmware */
|
||
+ .vendor = "HP",
|
||
+ .product = "MSA2000s*",
|
||
+ .getuid = "/sbin/cciss_id %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 = 12,
|
||
+ .minio = DEFAULT_MINIO,
|
||
+ .checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
+ },
|
||
+ {
|
||
+ /* EVA 3000/5000 with new firmware, EVA 4000/6000/8000 */
|
||
.vendor = "(COMPAQ|HP)",
|
||
- .product = "(MSA|HSV)1.1.*",
|
||
+ .product = "HSV1[01]1|HSV2[01]0|HSV300",
|
||
.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_IMMEDIATE,
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
- .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_ALUA,
|
||
},
|
||
{
|
||
- /* EVA 4000/6000/8000 */
|
||
+ /* HP MSA2000 product family */
|
||
.vendor = "HP",
|
||
- .product = "HSV2.*",
|
||
+ .product = "MSA2[02]12*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
- .pgpolicy = GROUP_BY_PRIO,
|
||
+ .pgpolicy = MULTIBUS,
|
||
.pgfailback = -FAILBACK_IMMEDIATE,
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
- .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
/* HP Smart Array */
|
||
.vendor = "HP",
|
||
.product = "LOGICAL VOLUME.*",
|
||
.getuid = "/lib/udev/scsi_id -n -g -u -s /block/%n",
|
||
- .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,
|
||
+ .no_path_retry = 12,
|
||
.minio = DEFAULT_MINIO,
|
||
- .checker_name = TUR,
|
||
+ .checker_name = CCISS_TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
/*
|
||
* DDN controller family
|
||
@@ -179,7 +194,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "DDN",
|
||
.product = "SAN DataDirector",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -189,6 +203,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = DIRECTIO,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
/*
|
||
* EMC / Clariion controller family
|
||
@@ -200,7 +215,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "EMC",
|
||
.product = "SYMMETRIX",
|
||
.getuid = "/lib/udev/scsi_id -g -u -ppre-spc3-83 -s /block/%n",
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -209,14 +223,14 @@ 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,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
.vendor = "DGC",
|
||
.product = ".*",
|
||
.bl_product = "LUNZ",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_emc /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = "1 emc",
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -226,6 +240,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = (300 / DEFAULT_CHECKINT),
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = EMC_CLARIION,
|
||
+ .prio_name = PRIO_EMC,
|
||
},
|
||
/*
|
||
* Fujitsu controller family
|
||
@@ -237,7 +252,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "FSC",
|
||
.product = "CentricStor",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -246,7 +260,8 @@ 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,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
/*
|
||
* Hitachi controller family
|
||
@@ -258,7 +273,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "(HITACHI|HP)",
|
||
.product = "OPEN-.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -268,12 +282,12 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
.vendor = "HITACHI",
|
||
.product = "DF.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_hds_modular /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -283,6 +297,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_HDS,
|
||
},
|
||
/*
|
||
* IBM controller family
|
||
@@ -294,7 +309,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "IBM",
|
||
.product = "ProFibre 4000R",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -303,46 +317,94 @@ 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,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
- /* IBM DS4100 / FAStT100 */
|
||
+ /* IBM FAStT 1722-600 */
|
||
+ .vendor = "IBM",
|
||
+ .product = "1722-600",
|
||
+ .getuid = DEFAULT_GETUID,
|
||
+ .features = "1 queue_if_no_path",
|
||
+ .hwhandler = "1 rdac",
|
||
+ .selector = DEFAULT_SELECTOR,
|
||
+ .pgpolicy = GROUP_BY_PRIO,
|
||
+ .pgfailback = -FAILBACK_IMMEDIATE,
|
||
+ .rr_weight = RR_WEIGHT_NONE,
|
||
+ .no_path_retry = 300,
|
||
+ .minio = DEFAULT_MINIO,
|
||
+ .checker_name = RDAC,
|
||
+ .prio_name = PRIO_RDAC,
|
||
+ },
|
||
+ {
|
||
+ /* IBM DS4400 / FAStT700 */
|
||
.vendor = "IBM",
|
||
.product = "1742",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_rdac /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
- .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .hwhandler = "1 rdac",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
+ },
|
||
+ {
|
||
+ /* IBM DS4700 */
|
||
+ .vendor = "IBM",
|
||
+ .product = "1814",
|
||
+ .getuid = DEFAULT_GETUID,
|
||
+ .features = DEFAULT_FEATURES,
|
||
+ .hwhandler = "1 rdac",
|
||
+ .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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
+ },
|
||
+ {
|
||
+ /* IBM DS4800 */
|
||
+ .vendor = "IBM",
|
||
+ .product = "1815",
|
||
+ .getuid = DEFAULT_GETUID,
|
||
+ .features = DEFAULT_FEATURES,
|
||
+ .hwhandler = "1 rdac",
|
||
+ .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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
{
|
||
/* IBM Netfinity Fibre Channel RAID Controller Unit */
|
||
.vendor = "IBM",
|
||
.product = "3526",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_rdac /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
- .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .hwhandler = "1 rdac",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
{
|
||
/* IBM DS4200 / FAStT200 */
|
||
.vendor = "IBM",
|
||
.product = "3542",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -352,13 +414,13 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
/* IBM ESS F20 aka Shark */
|
||
.vendor = "IBM",
|
||
.product = "2105(800|F20)",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -368,13 +430,13 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
/* IBM DS6000 */
|
||
.vendor = "IBM",
|
||
.product = "1750500",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_alua /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -384,13 +446,13 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_ALUA,
|
||
},
|
||
{
|
||
/* IBM DS8000 */
|
||
.vendor = "IBM",
|
||
.product = "2107900",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -400,13 +462,13 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
/* 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,
|
||
@@ -416,6 +478,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_ALUA,
|
||
},
|
||
{
|
||
/* IBM S/390 ECKD DASD */
|
||
@@ -423,7 +486,6 @@ static struct hwentry default_hw[] = {
|
||
.product = "S/390 DASD ECKD",
|
||
.bl_product = "S/390.*",
|
||
.getuid = "/sbin/dasdinfo -u -b %n",
|
||
- .getprio = NULL,
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -433,8 +495,26 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = DIRECTIO,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
- /*
|
||
+ {
|
||
+ /* IBM S/390 FBA DASD */
|
||
+ .vendor = "IBM",
|
||
+ .product = "S/390 DASD FBA",
|
||
+ .bl_product = "S/390.*",
|
||
+ .getuid = "/sbin/dasdinfo -u -b %n",
|
||
+ .features = "1 queue_if_no_path",
|
||
+ .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 = DIRECTIO,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
+ },
|
||
+ /*
|
||
* NETAPP controller family
|
||
*
|
||
* Maintainer : Dave Wysochanski
|
||
@@ -444,7 +524,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "NETAPP",
|
||
.product = "LUN.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_netapp /dev/%n",
|
||
.features = "1 queue_if_no_path",
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -453,9 +532,10 @@ static struct hwentry default_hw[] = {
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = 128,
|
||
- .checker_name = READSECTOR0,
|
||
+ .checker_name = DIRECTIO,
|
||
+ .prio_name = PRIO_NETAPP,
|
||
},
|
||
- /*
|
||
+ /*
|
||
* IBM NSeries (NETAPP) controller family
|
||
*
|
||
* Maintainer : Dave Wysochanski
|
||
@@ -465,7 +545,6 @@ static struct hwentry default_hw[] = {
|
||
.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,
|
||
@@ -474,7 +553,8 @@ static struct hwentry default_hw[] = {
|
||
.rr_weight = RR_WEIGHT_NONE,
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = 128,
|
||
- .checker_name = READSECTOR0,
|
||
+ .checker_name = DIRECTIO,
|
||
+ .prio_name = PRIO_NETAPP,
|
||
},
|
||
/*
|
||
* Pillar Data controller family
|
||
@@ -486,7 +566,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "Pillar",
|
||
.product = "Axiom.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_alua %n",
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -496,6 +575,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_ALUA,
|
||
},
|
||
/*
|
||
* SGI arrays
|
||
@@ -507,7 +587,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "SGI",
|
||
.product = "TP9[13]00",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -516,15 +595,15 @@ 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,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
},
|
||
{
|
||
.vendor = "SGI",
|
||
.product = "TP9[45]00",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_rdac /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
- .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .hwhandler = "1 rdac",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.pgpolicy = GROUP_BY_PRIO,
|
||
.pgfailback = -FAILBACK_IMMEDIATE,
|
||
@@ -532,14 +611,14 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_QUEUE,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = RDAC,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
{
|
||
.vendor = "SGI",
|
||
.product = "IS.*",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_rdac /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
- .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .hwhandler = "1 rdac",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.pgpolicy = GROUP_BY_PRIO,
|
||
.pgfailback = -FAILBACK_IMMEDIATE,
|
||
@@ -547,6 +626,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_QUEUE,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = RDAC,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
/*
|
||
* STK arrays
|
||
@@ -558,9 +638,8 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "STK",
|
||
.product = "OPENstorage D280",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = "/sbin/mpath_prio_rdac /dev/%n",
|
||
.features = DEFAULT_FEATURES,
|
||
- .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .hwhandler = "1 rdac",
|
||
.selector = DEFAULT_SELECTOR,
|
||
.pgpolicy = GROUP_BY_PRIO,
|
||
.pgfailback = -FAILBACK_IMMEDIATE,
|
||
@@ -568,6 +647,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
.minio = DEFAULT_MINIO,
|
||
.checker_name = TUR,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
/*
|
||
* SUN arrays
|
||
@@ -579,7 +659,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = "SUN",
|
||
.product = "(StorEdge 3510|T4)",
|
||
.getuid = DEFAULT_GETUID,
|
||
- .getprio = NULL,
|
||
.features = DEFAULT_FEATURES,
|
||
.hwhandler = DEFAULT_HWHANDLER,
|
||
.selector = DEFAULT_SELECTOR,
|
||
@@ -588,7 +667,60 @@ 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,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
+ },
|
||
+ /*
|
||
+ * Pivot3 RAIGE
|
||
+ *
|
||
+ * Maintainer : Bart Brooks, Pivot3
|
||
+ * Mail : bartb@pivot3.com
|
||
+ */
|
||
+ {
|
||
+ .vendor = "PIVOT3",
|
||
+ .product = "RAIGE VOLUME",
|
||
+ .getuid = "/sbin/scsi_id -p 0x80 -g -u -s /block/%n",
|
||
+ .features = "1 queue_if_no_path",
|
||
+ .hwhandler = DEFAULT_HWHANDLER,
|
||
+ .selector = DEFAULT_SELECTOR,
|
||
+ .pgpolicy = MULTIBUS,
|
||
+ .pgfailback = FAILBACK_UNDEF,
|
||
+ .rr_weight = RR_WEIGHT_NONE,
|
||
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
|
||
+ .minio = 100,
|
||
+ .checker_name = TUR,
|
||
+ .prio_name = DEFAULT_PRIO,
|
||
+ },
|
||
+ {
|
||
+ .vendor = "SUN",
|
||
+ .product = "CSM200_R",
|
||
+ .getuid = DEFAULT_GETUID,
|
||
+ .features = DEFAULT_FEATURES,
|
||
+ .hwhandler = "1 rdac",
|
||
+ .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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
+ },
|
||
+ /* SUN/LSI 2540 */
|
||
+ {
|
||
+ .vendor = "SUN",
|
||
+ .product = "LCSM100_F",
|
||
+ .getuid = DEFAULT_GETUID,
|
||
+ .features = DEFAULT_FEATURES,
|
||
+ .hwhandler = "1 rdac",
|
||
+ .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,
|
||
+ .prio_name = PRIO_RDAC,
|
||
},
|
||
/*
|
||
* EOL
|
||
@@ -597,7 +729,6 @@ static struct hwentry default_hw[] = {
|
||
.vendor = NULL,
|
||
.product = NULL,
|
||
.getuid = NULL,
|
||
- .getprio = NULL,
|
||
.features = NULL,
|
||
.hwhandler = NULL,
|
||
.selector = NULL,
|
||
@@ -607,6 +738,7 @@ static struct hwentry default_hw[] = {
|
||
.no_path_retry = 0,
|
||
.minio = 0,
|
||
.checker_name = NULL,
|
||
+ .prio_name = NULL,
|
||
},
|
||
};
|
||
|
||
@@ -617,7 +749,6 @@ setup_default_hwtable (vector hw)
|
||
struct hwentry * hwe = default_hw;
|
||
|
||
while (hwe->vendor) {
|
||
- hwe->checker = checker_lookup(hwe->checker_name);
|
||
r += store_hwe(hw, hwe);
|
||
hwe++;
|
||
}
|
||
diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c
|
||
index 5a82b6a..8909440 100644
|
||
--- a/libmultipath/log_pthread.c
|
||
+++ b/libmultipath/log_pthread.c
|
||
@@ -15,9 +15,7 @@
|
||
void log_safe (int prio, const char * fmt, va_list ap)
|
||
{
|
||
pthread_mutex_lock(logq_lock);
|
||
- //va_start(ap, fmt);
|
||
log_enqueue(prio, fmt, ap);
|
||
- va_end(ap);
|
||
pthread_mutex_unlock(logq_lock);
|
||
|
||
pthread_mutex_lock(logev_lock);
|
||
@@ -33,7 +31,8 @@ static void flush_logqueue (void)
|
||
pthread_mutex_lock(logq_lock);
|
||
empty = log_dequeue(la->buff);
|
||
pthread_mutex_unlock(logq_lock);
|
||
- log_syslog(la->buff);
|
||
+ if (!empty)
|
||
+ log_syslog(la->buff);
|
||
} while (empty == 0);
|
||
}
|
||
|
||
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
|
||
index f9c555e..ad2bb4f 100644
|
||
--- a/libmultipath/parser.c
|
||
+++ b/libmultipath/parser.c
|
||
@@ -203,7 +203,7 @@ alloc_strvec(char *string)
|
||
cp = string;
|
||
|
||
/* Skip white spaces */
|
||
- while (isspace((int) *cp) && *cp != '\0')
|
||
+ while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
|
||
cp++;
|
||
|
||
/* Return if there is only white spaces */
|
||
@@ -241,8 +241,10 @@ alloc_strvec(char *string)
|
||
in_string = 1;
|
||
|
||
} else {
|
||
- while ((in_string || !isspace((int) *cp)) && *cp
|
||
- != '\0' && *cp != '"')
|
||
+ while ((in_string ||
|
||
+ (!isspace((int) *cp) && isascii((int) *cp) &&
|
||
+ *cp != '!' && *cp != '#')) &&
|
||
+ *cp != '\0' && *cp != '"')
|
||
cp++;
|
||
strlen = cp - start;
|
||
token = MALLOC(strlen + 1);
|
||
@@ -255,7 +257,8 @@ alloc_strvec(char *string)
|
||
}
|
||
vector_set_slot(strvec, token);
|
||
|
||
- while (isspace((int) *cp) && *cp != '\0')
|
||
+ while ((isspace((int) *cp) || !isascii((int) *cp))
|
||
+ && *cp != '\0')
|
||
cp++;
|
||
if (*cp == '\0' || *cp == '!' || *cp == '#')
|
||
return strvec;
|
||
diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
|
||
index 0ac7448..2a9671a 100644
|
||
--- a/libmultipath/pgpolicies.c
|
||
+++ b/libmultipath/pgpolicies.c
|
||
@@ -5,8 +5,7 @@
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "util.h"
|
||
#include "memory.h"
|
||
#include "vector.h"
|
||
@@ -127,6 +126,7 @@ out1:
|
||
FREE(bitmap);
|
||
out:
|
||
free_pgvec(mp->pg, KEEP_PATHS);
|
||
+ mp->pg = NULL;
|
||
return 1;
|
||
}
|
||
|
||
@@ -198,6 +198,7 @@ out1:
|
||
FREE(bitmap);
|
||
out:
|
||
free_pgvec(mp->pg, KEEP_PATHS);
|
||
+ mp->pg = NULL;
|
||
return 1;
|
||
}
|
||
|
||
@@ -232,6 +233,7 @@ one_path_per_group (struct multipath * mp)
|
||
return 0;
|
||
out:
|
||
free_pgvec(mp->pg, KEEP_PATHS);
|
||
+ mp->pg = NULL;
|
||
return 1;
|
||
}
|
||
|
||
@@ -264,6 +266,7 @@ one_group (struct multipath * mp) /* aka multibus */
|
||
return 0;
|
||
out:
|
||
free_pgvec(mp->pg, KEEP_PATHS);
|
||
+ mp->pg = NULL;
|
||
return 1;
|
||
}
|
||
|
||
@@ -338,6 +341,7 @@ group_by_prio (struct multipath * mp)
|
||
return 0;
|
||
out:
|
||
free_pgvec(mp->pg, KEEP_PATHS);
|
||
+ mp->pg = NULL;
|
||
return 1;
|
||
|
||
}
|
||
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||
index 01a157a..3be1c9d 100644
|
||
--- a/libmultipath/print.c
|
||
+++ b/libmultipath/print.c
|
||
@@ -8,8 +8,7 @@
|
||
#include <sys/stat.h>
|
||
#include <dirent.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "structs.h"
|
||
#include "structs_vec.h"
|
||
@@ -21,6 +20,8 @@
|
||
#include "defaults.h"
|
||
#include "parser.h"
|
||
#include "blacklist.h"
|
||
+#include "switchgroup.h"
|
||
+#include "devmapper.h"
|
||
|
||
#define MAX(x,y) (x > y) ? x : y
|
||
#define TAIL (line + len - 1 - c)
|
||
@@ -89,8 +90,19 @@ snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
|
||
{
|
||
if (mpp->dmi)
|
||
return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
|
||
+ else
|
||
+ return snprintf(buff, len, "n/a");
|
||
+}
|
||
|
||
- return 0;
|
||
+static int
|
||
+snprint_ro (char * buff, size_t len, struct multipath * mpp)
|
||
+{
|
||
+ if (!mpp->dmi)
|
||
+ return snprintf(buff, len, "n/a");
|
||
+ if (mpp->dmi->read_only)
|
||
+ return snprintf(buff, len, "ro");
|
||
+ else
|
||
+ return snprintf(buff, len, "rw");
|
||
}
|
||
|
||
static int
|
||
@@ -221,6 +233,16 @@ snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
|
||
}
|
||
|
||
static int
|
||
+snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
|
||
+{
|
||
+ struct path * pp = first_path(mpp);
|
||
+ if (!pp)
|
||
+ return 0;
|
||
+ return snprintf(buff, len, "%s,%s",
|
||
+ pp->vendor_id, pp->product_id);
|
||
+}
|
||
+
|
||
+static int
|
||
snprint_action (char * buff, size_t len, struct multipath * mpp)
|
||
{
|
||
switch (mpp->action) {
|
||
@@ -340,6 +362,13 @@ snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
|
||
static int
|
||
snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
|
||
{
|
||
+ /*
|
||
+ * path group priority is not updated for every path prio change,
|
||
+ * but only on switch group code path.
|
||
+ *
|
||
+ * Printing is another reason to update.
|
||
+ */
|
||
+ path_group_prio_update(pgp);
|
||
return snprint_int(buff, len, pgp->priority);
|
||
}
|
||
|
||
@@ -371,6 +400,7 @@ struct multipath_data mpd[] = {
|
||
{'F', "failback", 0, snprint_failback},
|
||
{'Q', "queueing", 0, snprint_queueing},
|
||
{'N', "paths", 0, snprint_nb_paths},
|
||
+ {'r', "write_prot", 0, snprint_ro},
|
||
{'t', "dm-st", 0, snprint_dm_map_state},
|
||
{'S', "size", 0, snprint_multipath_size},
|
||
{'f', "features", 0, snprint_features},
|
||
@@ -381,6 +411,7 @@ struct multipath_data mpd[] = {
|
||
{'2', "map_loads", 0, snprint_map_loads},
|
||
{'3', "total_q_time", 0, snprint_total_q_time},
|
||
{'4', "q_timeouts", 0, snprint_q_timeouts},
|
||
+ {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
|
||
{0, NULL, 0 , NULL}
|
||
};
|
||
|
||
@@ -405,14 +436,17 @@ struct pathgroup_data pgd[] = {
|
||
};
|
||
|
||
void
|
||
-get_path_layout (vector pathvec)
|
||
+get_path_layout (vector pathvec, int header)
|
||
{
|
||
int i, j;
|
||
char buff[MAX_FIELD_LEN];
|
||
struct path * pp;
|
||
|
||
for (j = 0; pd[j].header; j++) {
|
||
- pd[j].width = strlen(pd[j].header);
|
||
+ if (header)
|
||
+ pd[j].width = strlen(pd[j].header);
|
||
+ else
|
||
+ pd[j].width = 0;
|
||
|
||
vector_foreach_slot (pathvec, pp, i) {
|
||
pd[j].snprint(buff, MAX_FIELD_LEN, pp);
|
||
@@ -422,14 +456,17 @@ get_path_layout (vector pathvec)
|
||
}
|
||
|
||
void
|
||
-get_multipath_layout (vector mpvec)
|
||
+get_multipath_layout (vector mpvec, int header)
|
||
{
|
||
int i, j;
|
||
char buff[MAX_FIELD_LEN];
|
||
struct multipath * mpp;
|
||
|
||
for (j = 0; mpd[j].header; j++) {
|
||
- mpd[j].width = strlen(mpd[j].header);
|
||
+ if (header)
|
||
+ mpd[j].width = strlen(mpd[j].header);
|
||
+ else
|
||
+ mpd[j].width = 0;
|
||
|
||
vector_foreach_slot (mpvec, mpp, i) {
|
||
mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
|
||
@@ -683,16 +720,15 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
|
||
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));
|
||
+ c += sprintf(c, " %%d %%s");
|
||
|
||
fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
|
||
if (fwd > len)
|
||
return len;
|
||
fwd += snprint_multipath(buff + fwd, len - fwd,
|
||
- "[size=%S][features=%f][hwhandler=%h]", mpp);
|
||
+ "[size=%S][features=%f][hwhandler=%h][%r]", mpp);
|
||
if (fwd > len)
|
||
return len;
|
||
|
||
@@ -1118,15 +1154,16 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
|
||
return len;
|
||
fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
|
||
|
||
- strcpy(devpath,"/sys/block");
|
||
- devptr = devpath + 10;
|
||
+ strcpy(devpath,"/sys/block/");
|
||
while ((blkdev = readdir(blkdir)) != NULL) {
|
||
if ((strcmp(blkdev->d_name,".") == 0) ||
|
||
(strcmp(blkdev->d_name,"..") == 0))
|
||
continue;
|
||
|
||
- strcat(devptr,blkdev->d_name);
|
||
- if (stat(devptr, &statbuf) < 0)
|
||
+ devptr = devpath + 11;
|
||
+ *devptr = '\0';
|
||
+ strncat(devptr, blkdev->d_name, PATH_MAX-12);
|
||
+ if (stat(devpath, &statbuf) < 0)
|
||
continue;
|
||
|
||
if (S_ISDIR(statbuf.st_mode) == 0)
|
||
@@ -1135,18 +1172,20 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
|
||
if ((len - fwd - threshold) <= 0)
|
||
return len;
|
||
|
||
- fwd += snprintf(buff + fwd, len - fwd, " %s", devpath);
|
||
- pp = find_path_by_dev(vecs->pathvec, devpath);
|
||
+ fwd += snprintf(buff + fwd, len - fwd, " %s", devptr);
|
||
+ pp = find_path_by_dev(vecs->pathvec, devptr);
|
||
if (!pp) {
|
||
r = filter_devnode(conf->blist_devnode,
|
||
- conf->elist_devnode, devpath);
|
||
+ conf->elist_devnode, devptr);
|
||
if (r > 0)
|
||
fwd += snprintf(buff + fwd, len - fwd,
|
||
- " (blacklisted)");
|
||
+ " devnode blacklisted, unmonitored");
|
||
else if (r < 0)
|
||
fwd += snprintf(buff + fwd, len - fwd,
|
||
- " (whitelisted)");
|
||
- }
|
||
+ " devnode whitelisted, unmonitored");
|
||
+ } else
|
||
+ fwd += snprintf(buff + fwd, len - fwd,
|
||
+ " devnode whitelisted, monitored");
|
||
fwd += snprintf(buff + fwd, len - fwd, "\n");
|
||
}
|
||
closedir(blkdir);
|
||
@@ -1197,13 +1236,19 @@ print_map (struct multipath * mpp)
|
||
{
|
||
if (mpp->size && mpp->params)
|
||
printf("0 %llu %s %s\n",
|
||
- mpp->size, DEFAULT_TARGET, mpp->params);
|
||
+ mpp->size, TGT_MPATH, mpp->params);
|
||
return;
|
||
}
|
||
|
||
extern void
|
||
print_all_paths (vector pathvec, int banner)
|
||
{
|
||
+ print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
|
||
+}
|
||
+
|
||
+extern void
|
||
+print_all_paths_custo (vector pathvec, int banner, char *fmt)
|
||
+{
|
||
int i;
|
||
struct path * pp;
|
||
char line[MAX_LINE_LEN];
|
||
@@ -1217,11 +1262,11 @@ print_all_paths (vector pathvec, int banner)
|
||
if (banner)
|
||
fprintf(stdout, "===== paths list =====\n");
|
||
|
||
- get_path_layout(pathvec);
|
||
- snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
|
||
+ get_path_layout(pathvec, 1);
|
||
+ snprint_path_header(line, MAX_LINE_LEN, fmt);
|
||
fprintf(stdout, "%s", line);
|
||
|
||
vector_foreach_slot (pathvec, pp, i)
|
||
- print_path(pp, PRINT_PATH_LONG);
|
||
+ print_path(pp, fmt);
|
||
}
|
||
|
||
diff --git a/libmultipath/print.h b/libmultipath/print.h
|
||
index 73c2f63..5c7023c 100644
|
||
--- a/libmultipath/print.h
|
||
+++ b/libmultipath/print.h
|
||
@@ -1,7 +1,7 @@
|
||
#define PRINT_PATH_LONG "%w %i %d %D %p %t%T %s"
|
||
#define PRINT_PATH_INDENT " \\_ %i %d %D %t%T"
|
||
#define PRINT_PATH_CHECKER "%i %d %D %p %t%T %C"
|
||
-#define PRINT_MAP_STATUS "%n %F %Q %N %t"
|
||
+#define PRINT_MAP_STATUS "%n %F %Q %N %t %r"
|
||
#define PRINT_MAP_STATS "%n %0 %1 %2 %3 %4"
|
||
#define PRINT_MAP_NAMES "%n %d %w"
|
||
#define PRINT_PG_INDENT "\\_ %s [prio=%p]%t"
|
||
@@ -32,8 +32,8 @@ struct pathgroup_data {
|
||
int (*snprint)(char * buff, size_t len, struct pathgroup * pgp);
|
||
};
|
||
|
||
-void get_path_layout (vector pathvec);
|
||
-void get_multipath_layout (vector mpvec);
|
||
+void get_path_layout (vector pathvec, int header);
|
||
+void get_multipath_layout (vector mpvec, int header);
|
||
int snprint_path_header (char *, int, char *);
|
||
int snprint_multipath_header (char *, int, char *);
|
||
int snprint_path (char *, int, char *, struct path *);
|
||
@@ -54,5 +54,6 @@ void print_multipath (struct multipath * mpp, char * style);
|
||
void print_pathgroup (struct pathgroup * pgp, char * style);
|
||
void print_map (struct multipath * mpp);
|
||
void print_all_paths (vector pathvec, int banner);
|
||
+void print_all_paths_custo (vector pathvec, int banner, char *fmt);
|
||
void print_hwtable (vector hwtable);
|
||
|
||
diff --git a/libmultipath/prio.c b/libmultipath/prio.c
|
||
new file mode 100644
|
||
index 0000000..c9d2873
|
||
--- /dev/null
|
||
+++ b/libmultipath/prio.c
|
||
@@ -0,0 +1,93 @@
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <stddef.h>
|
||
+#include <dlfcn.h>
|
||
+
|
||
+#include "debug.h"
|
||
+#include "prio.h"
|
||
+#include "config.h"
|
||
+
|
||
+static LIST_HEAD(prioritizers);
|
||
+
|
||
+int init_prio (void)
|
||
+{
|
||
+ INIT_LIST_HEAD(&prioritizers);
|
||
+ if (!add_prio(DEFAULT_PRIO))
|
||
+ return 1;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+struct prio * alloc_prio (void)
|
||
+{
|
||
+ return zalloc(sizeof(struct prio));
|
||
+}
|
||
+
|
||
+void free_prio (struct prio * p)
|
||
+{
|
||
+ free(p);
|
||
+}
|
||
+
|
||
+void cleanup_prio(void)
|
||
+{
|
||
+ struct prio * prio_loop;
|
||
+ struct prio * prio_temp;
|
||
+
|
||
+ list_for_each_entry_safe(prio_loop, prio_temp, &prioritizers, node) {
|
||
+ list_del(&prio_loop->node);
|
||
+ free(prio_loop);
|
||
+ }
|
||
+}
|
||
+
|
||
+struct prio * prio_lookup (char * name)
|
||
+{
|
||
+ struct prio * p;
|
||
+
|
||
+ list_for_each_entry(p, &prioritizers, node) {
|
||
+ if (!strncmp(name, p->name, PRIO_NAME_LEN))
|
||
+ return p;
|
||
+ }
|
||
+ return add_prio(name);
|
||
+}
|
||
+
|
||
+struct prio * add_prio (char * name)
|
||
+{
|
||
+ char libname[LIB_PRIO_NAMELEN];
|
||
+ void * handle;
|
||
+ struct prio * p;
|
||
+ char *errstr;
|
||
+
|
||
+ p = alloc_prio();
|
||
+ if (!p)
|
||
+ return NULL;
|
||
+ snprintf(libname, LIB_PRIO_NAMELEN, "%s/libprio%s.so",
|
||
+ conf->multipath_dir, name);
|
||
+ condlog(3, "loading %s prioritizer", libname);
|
||
+ handle = dlopen(libname, RTLD_NOW);
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!handle)
|
||
+ goto out;
|
||
+ p->getprio = (int (*)(struct path *)) dlsym(handle, "getprio");
|
||
+ errstr = dlerror();
|
||
+ if (errstr != NULL)
|
||
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
|
||
+ if (!p->getprio)
|
||
+ goto out;
|
||
+ snprintf(p->name, PRIO_NAME_LEN, "%s", name);
|
||
+ list_add(&p->node, &prioritizers);
|
||
+ return p;
|
||
+out:
|
||
+ free_prio(p);
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+int prio_getprio (struct prio * p, struct path * pp)
|
||
+{
|
||
+ return p->getprio(pp);
|
||
+}
|
||
+
|
||
+char * prio_name (struct prio * p)
|
||
+{
|
||
+ return p->name;
|
||
+}
|
||
diff --git a/libmultipath/prio.h b/libmultipath/prio.h
|
||
new file mode 100644
|
||
index 0000000..491e6fc
|
||
--- /dev/null
|
||
+++ b/libmultipath/prio.h
|
||
@@ -0,0 +1,50 @@
|
||
+#ifndef _PRIO_H
|
||
+#define _PRIO_H
|
||
+
|
||
+/*
|
||
+ * knowing about path struct gives flexibility to prioritizers
|
||
+ */
|
||
+#include "checkers.h"
|
||
+#include "vector.h"
|
||
+#include "structs.h"
|
||
+#include "list.h"
|
||
+#include "memory.h"
|
||
+
|
||
+#define DEFAULT_PRIO "const"
|
||
+
|
||
+/*
|
||
+ * Known prioritizers for use in hwtable.c
|
||
+ */
|
||
+#define PRIO_ALUA "alua"
|
||
+#define PRIO_CONST "const"
|
||
+#define PRIO_EMC "emc"
|
||
+#define PRIO_HDS "hds"
|
||
+#define PRIO_HP_SW "hp_sw"
|
||
+#define PRIO_NETAPP "netapp"
|
||
+#define PRIO_RANDOM "random"
|
||
+#define PRIO_RDAC "rdac"
|
||
+
|
||
+/*
|
||
+ * Value used to mark the fact prio was not defined
|
||
+ */
|
||
+#define PRIO_UNDEF -1
|
||
+
|
||
+/*
|
||
+ * strings lengths
|
||
+ */
|
||
+#define LIB_PRIO_NAMELEN 255
|
||
+#define PRIO_NAME_LEN 16
|
||
+
|
||
+struct prio {
|
||
+ struct list_head node;
|
||
+ char name[PRIO_NAME_LEN];
|
||
+ int (*getprio)(struct path *);
|
||
+};
|
||
+
|
||
+int init_prio (void);
|
||
+struct prio * add_prio (char *);
|
||
+struct prio * prio_lookup (char *);
|
||
+int prio_getprio (struct prio *, struct path *);
|
||
+char * prio_name (struct prio *);
|
||
+
|
||
+#endif /* _PRIO_H */
|
||
diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
|
||
new file mode 100644
|
||
index 0000000..1f70ef1
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/Makefile
|
||
@@ -0,0 +1,34 @@
|
||
+# Makefile
|
||
+#
|
||
+# Copyright (C) 2007 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
+#
|
||
+include ../../Makefile.inc
|
||
+
|
||
+LIBS = \
|
||
+ libpriorandom.so \
|
||
+ libprioconst.so \
|
||
+ libpriohp_sw.so \
|
||
+ libprioemc.so \
|
||
+ libpriordac.so \
|
||
+ libprioalua.so \
|
||
+ libprionetapp.so \
|
||
+ libpriohds.so
|
||
+
|
||
+CFLAGS += -I..
|
||
+
|
||
+all: $(LIBS)
|
||
+
|
||
+libprioalua.so: alua.o alua_rtpg.o
|
||
+ $(CC) $(SHARED_FLAGS) -o $@ $^
|
||
+
|
||
+libprio%.so: %.o
|
||
+ $(CC) $(SHARED_FLAGS) -o $@ $^
|
||
+
|
||
+install: $(LIBS)
|
||
+ $(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir)
|
||
+
|
||
+uninstall:
|
||
+ rm -f $(DESTDIR)$(libdir)/libprio*.so
|
||
+
|
||
+clean:
|
||
+ rm -f core *.a *.o *.gz *.so
|
||
diff --git a/libmultipath/prioritizers/alua.c b/libmultipath/prioritizers/alua.c
|
||
new file mode 100644
|
||
index 0000000..1b52b8e
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/alua.c
|
||
@@ -0,0 +1,95 @@
|
||
+/*
|
||
+ * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
+ *
|
||
+ * main.c
|
||
+ *
|
||
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
+ * It determines the ALUA state of a device and prints a priority value to
|
||
+ * stdout.
|
||
+ *
|
||
+ * Author(s): Jan Kunigk
|
||
+ * S. Bader <shbader@de.ibm.com>
|
||
+ *
|
||
+ * This file is released under the GPL.
|
||
+ */
|
||
+#include <stdio.h>
|
||
+
|
||
+#include <debug.h>
|
||
+#include <prio.h>
|
||
+
|
||
+#include "alua.h"
|
||
+
|
||
+#define ALUA_PRIO_NOT_SUPPORTED 1
|
||
+#define ALUA_PRIO_RTPG_FAILED 2
|
||
+#define ALUA_PRIO_GETAAS_FAILED 3
|
||
+#define ALUA_PRIO_TPGS_FAILED 4
|
||
+
|
||
+int
|
||
+get_alua_info(int fd)
|
||
+{
|
||
+ char * aas_string[] = {
|
||
+ [AAS_OPTIMIZED] = "active/optimized",
|
||
+ [AAS_NON_OPTIMIZED] = "active/non-optimized",
|
||
+ [AAS_STANDBY] = "standby",
|
||
+ [AAS_UNAVAILABLE] = "unavailable",
|
||
+ [AAS_TRANSITIONING] = "transitioning between states",
|
||
+ };
|
||
+ int rc;
|
||
+ int tpg;
|
||
+
|
||
+ rc = get_target_port_group_support(fd);
|
||
+ if (rc < 0)
|
||
+ return -ALUA_PRIO_TPGS_FAILED;
|
||
+
|
||
+ if (rc == TPGS_NONE)
|
||
+ return -ALUA_PRIO_NOT_SUPPORTED;
|
||
+
|
||
+ tpg = get_target_port_group(fd);
|
||
+ if (tpg < 0)
|
||
+ return -ALUA_PRIO_RTPG_FAILED;
|
||
+
|
||
+ condlog(3, "reported target port group is %i", tpg);
|
||
+ rc = get_asymmetric_access_state(fd, tpg);
|
||
+ if (rc < 0)
|
||
+ return -ALUA_PRIO_GETAAS_FAILED;
|
||
+
|
||
+ condlog(3, "aas = [%s]",
|
||
+ (aas_string[rc]) ? aas_string[rc] : "invalid/reserved");
|
||
+ return rc;
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ int rc = get_alua_info(pp->fd);
|
||
+ if (rc >= 0) {
|
||
+ switch(rc) {
|
||
+ case AAS_OPTIMIZED:
|
||
+ rc = 50;
|
||
+ break;
|
||
+ case AAS_NON_OPTIMIZED:
|
||
+ rc = 10;
|
||
+ break;
|
||
+ case AAS_STANDBY:
|
||
+ rc = 1;
|
||
+ break;
|
||
+ default:
|
||
+ rc = 0;
|
||
+ }
|
||
+ } else {
|
||
+ switch(-rc) {
|
||
+ case ALUA_PRIO_NOT_SUPPORTED:
|
||
+ condlog(0, "%s: alua not supported", pp->dev);
|
||
+ break;
|
||
+ case ALUA_PRIO_RTPG_FAILED:
|
||
+ condlog(0, "%s: couldn't get target port group", pp->dev);
|
||
+ break;
|
||
+ case ALUA_PRIO_GETAAS_FAILED:
|
||
+ condlog(0, "%s: couln't get asymmetric access state", pp->dev);
|
||
+ break;
|
||
+ case ALUA_PRIO_TPGS_FAILED:
|
||
+ condlog(3, "%s: couln't get supported alua states", pp->dev);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ return rc;
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/alua.h b/libmultipath/prioritizers/alua.h
|
||
new file mode 100644
|
||
index 0000000..78a3d15
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/alua.h
|
||
@@ -0,0 +1,9 @@
|
||
+#ifndef _ALUA_H
|
||
+#define _ALUA_H
|
||
+
|
||
+#include "alua_rtpg.h"
|
||
+
|
||
+#define PRIO_ALUA "alua"
|
||
+int prio_alua(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/alua_rtpg.c b/libmultipath/prioritizers/alua_rtpg.c
|
||
new file mode 100644
|
||
index 0000000..c5528c5
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/alua_rtpg.c
|
||
@@ -0,0 +1,301 @@
|
||
+/*
|
||
+ * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
+ *
|
||
+ * rtpg.c
|
||
+ *
|
||
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
+ * It determines the ALUA state of a device and prints a priority value to
|
||
+ * stdout.
|
||
+ *
|
||
+ * Author(s): Jan Kunigk
|
||
+ * S. Bader <shbader@de.ibm.com>
|
||
+ *
|
||
+ * This file is released under the GPL.
|
||
+ */
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <sys/ioctl.h>
|
||
+#include <inttypes.h>
|
||
+
|
||
+#define __user
|
||
+#include <scsi/sg.h>
|
||
+
|
||
+#include "alua_rtpg.h"
|
||
+
|
||
+#define SENSE_BUFF_LEN 32
|
||
+#define DEF_TIMEOUT 300000
|
||
+
|
||
+/*
|
||
+ * Macro used to print debug messaged.
|
||
+ */
|
||
+#if DEBUG > 0
|
||
+#define PRINT_DEBUG(f, a...) \
|
||
+ fprintf(stderr, "DEBUG: " f, ##a)
|
||
+#else
|
||
+#define PRINT_DEBUG(f, a...)
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Optionally print the commands sent and the data received a hex dump.
|
||
+ */
|
||
+#if DEBUG > 0
|
||
+#if DEBUG_DUMPHEX > 0
|
||
+#define PRINT_HEX(p, l) print_hex(p, l)
|
||
+void
|
||
+print_hex(unsigned char *p, unsigned long len)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for(i = 0; i < len; i++) {
|
||
+ if (i % 16 == 0)
|
||
+ printf("%04x: ", i);
|
||
+ printf("%02x%s", p[i], (((i + 1) % 16) == 0) ? "\n" : " ");
|
||
+ }
|
||
+ printf("\n");
|
||
+}
|
||
+#else
|
||
+#define PRINT_HEX(p, l)
|
||
+#endif
|
||
+#else
|
||
+#define PRINT_HEX(p, l)
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Returns 0 if the SCSI command either was successful or if the an error was
|
||
+ * recovered, otherwise 1. (definitions taken from sg_err.h)
|
||
+ */
|
||
+#define SCSI_CHECK_CONDITION 0x2
|
||
+#define SCSI_COMMAND_TERMINATED 0x22
|
||
+#define SG_ERR_DRIVER_SENSE 0x08
|
||
+#define RECOVERED_ERROR 0x01
|
||
+
|
||
+static int
|
||
+scsi_error(struct sg_io_hdr *hdr)
|
||
+{
|
||
+ /* Treat SG_ERR here to get rid of sg_err.[ch] */
|
||
+ hdr->status &= 0x7e;
|
||
+
|
||
+ if (
|
||
+ (hdr->status == 0) &&
|
||
+ (hdr->host_status == 0) &&
|
||
+ (hdr->driver_status == 0)
|
||
+ ) {
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (
|
||
+ (hdr->status == SCSI_CHECK_CONDITION) ||
|
||
+ (hdr->status == SCSI_COMMAND_TERMINATED) ||
|
||
+ ((hdr->driver_status & 0xf) == SG_ERR_DRIVER_SENSE)
|
||
+ ) {
|
||
+ if (hdr->sbp && (hdr->sb_len_wr > 2)) {
|
||
+ int sense_key;
|
||
+ unsigned char * sense_buffer = hdr->sbp;
|
||
+
|
||
+ if (sense_buffer[0] & 0x2)
|
||
+ sense_key = sense_buffer[1] & 0xf;
|
||
+ else
|
||
+ sense_key = sense_buffer[2] & 0xf;
|
||
+
|
||
+ if (sense_key == RECOVERED_ERROR)
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Helper function to setup and run a SCSI inquiry command.
|
||
+ */
|
||
+int
|
||
+do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
|
||
+{
|
||
+ struct inquiry_command cmd;
|
||
+ struct sg_io_hdr hdr;
|
||
+ unsigned char sense[SENSE_BUFF_LEN];
|
||
+
|
||
+ memset(&cmd, 0, sizeof(cmd));
|
||
+ cmd.op = OPERATION_CODE_INQUIRY;
|
||
+ if (evpd) {
|
||
+ inquiry_command_set_evpd(&cmd);
|
||
+ cmd.page = codepage;
|
||
+ }
|
||
+ set_uint16(cmd.length, resplen);
|
||
+ PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
|
||
+
|
||
+ memset(&hdr, 0, sizeof(hdr));
|
||
+ hdr.interface_id = 'S';
|
||
+ hdr.cmdp = (unsigned char *) &cmd;
|
||
+ hdr.cmd_len = sizeof(cmd);
|
||
+ hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ hdr.dxferp = resp;
|
||
+ hdr.dxfer_len = resplen;
|
||
+ hdr.sbp = sense;
|
||
+ hdr.mx_sb_len = sizeof(sense);
|
||
+ hdr.timeout = DEF_TIMEOUT;
|
||
+
|
||
+ if (ioctl(fd, SG_IO, &hdr) < 0) {
|
||
+ PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
|
||
+ return -RTPG_INQUIRY_FAILED;
|
||
+ }
|
||
+
|
||
+ if (scsi_error(&hdr)) {
|
||
+ PRINT_DEBUG("do_inquiry: SCSI error!\n");
|
||
+ return -RTPG_INQUIRY_FAILED;
|
||
+ }
|
||
+ PRINT_HEX((unsigned char *) resp, resplen);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function returns the support for target port groups by evaluating the
|
||
+ * data returned by the standard inquiry command.
|
||
+ */
|
||
+int
|
||
+get_target_port_group_support(int fd)
|
||
+{
|
||
+ struct inquiry_data inq;
|
||
+ int rc;
|
||
+
|
||
+ rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
|
||
+ if (!rc) {
|
||
+ rc = inquiry_data_get_tpgs(&inq);
|
||
+ }
|
||
+
|
||
+ return rc;
|
||
+}
|
||
+
|
||
+int
|
||
+get_target_port_group(int fd)
|
||
+{
|
||
+ unsigned char buf[128];
|
||
+ struct vpd83_data * vpd83;
|
||
+ struct vpd83_dscr * dscr;
|
||
+ int rc;
|
||
+
|
||
+ rc = do_inquiry(fd, 1, 0x83, buf, sizeof(buf));
|
||
+ if (!rc) {
|
||
+ vpd83 = (struct vpd83_data *) buf;
|
||
+
|
||
+ rc = -RTPG_NO_TPG_IDENTIFIER;
|
||
+ FOR_EACH_VPD83_DSCR(vpd83, dscr) {
|
||
+ if ((((char *) dscr) - ((char *) vpd83)) > sizeof(buf))
|
||
+ break;
|
||
+
|
||
+ if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
|
||
+ struct vpd83_tpg_dscr * p;
|
||
+
|
||
+ if (rc != -RTPG_NO_TPG_IDENTIFIER) {
|
||
+ PRINT_DEBUG("get_target_port_group: "
|
||
+ "more than one TPG identifier "
|
||
+ "found!\n");
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ p = (struct vpd83_tpg_dscr *) dscr->data;
|
||
+ rc = get_uint16(p->tpg);
|
||
+ }
|
||
+ }
|
||
+ if (rc == -RTPG_NO_TPG_IDENTIFIER) {
|
||
+ PRINT_DEBUG("get_target_port_group: "
|
||
+ "no TPG identifier found!\n");
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return rc;
|
||
+}
|
||
+
|
||
+int
|
||
+do_rtpg(int fd, void* resp, long resplen)
|
||
+{
|
||
+ struct rtpg_command cmd;
|
||
+ struct sg_io_hdr hdr;
|
||
+ unsigned char sense[SENSE_BUFF_LEN];
|
||
+
|
||
+ memset(&cmd, 0, sizeof(cmd));
|
||
+ cmd.op = OPERATION_CODE_RTPG;
|
||
+ rtpg_command_set_service_action(&cmd);
|
||
+ set_uint32(cmd.length, resplen);
|
||
+ PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
|
||
+
|
||
+ memset(&hdr, 0, sizeof(hdr));
|
||
+ hdr.interface_id = 'S';
|
||
+ hdr.cmdp = (unsigned char *) &cmd;
|
||
+ hdr.cmd_len = sizeof(cmd);
|
||
+ hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ hdr.dxferp = resp;
|
||
+ hdr.dxfer_len = resplen;
|
||
+ hdr.mx_sb_len = sizeof(sense);
|
||
+ hdr.sbp = sense;
|
||
+ hdr.timeout = DEF_TIMEOUT;
|
||
+
|
||
+ if (ioctl(fd, SG_IO, &hdr) < 0)
|
||
+ return -RTPG_RTPG_FAILED;
|
||
+
|
||
+ if (scsi_error(&hdr)) {
|
||
+ PRINT_DEBUG("do_rtpg: SCSI error!\n");
|
||
+ return -RTPG_RTPG_FAILED;
|
||
+ }
|
||
+ PRINT_HEX(resp, resplen);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+int
|
||
+get_asymmetric_access_state(int fd, unsigned int tpg)
|
||
+{
|
||
+ unsigned char *buf;
|
||
+ struct rtpg_data * tpgd;
|
||
+ struct rtpg_tpg_dscr * dscr;
|
||
+ int rc;
|
||
+ 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;
|
||
+ RTPG_FOR_EACH_PORT_GROUP(tpgd, dscr) {
|
||
+ if (get_uint16(dscr->tpg) == tpg) {
|
||
+ if (rc != -RTPG_TPG_NOT_FOUND) {
|
||
+ PRINT_DEBUG("get_asymmetric_access_state: "
|
||
+ "more than one entry with same port "
|
||
+ "group.\n");
|
||
+ } else {
|
||
+ PRINT_DEBUG("pref=%i\n", dscr->pref);
|
||
+ rc = rtpg_tpg_dscr_get_aas(dscr);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+out:
|
||
+ free(buf);
|
||
+ return rc;
|
||
+}
|
||
+
|
||
diff --git a/libmultipath/prioritizers/alua_rtpg.h b/libmultipath/prioritizers/alua_rtpg.h
|
||
new file mode 100644
|
||
index 0000000..c43e0a9
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/alua_rtpg.h
|
||
@@ -0,0 +1,30 @@
|
||
+/*
|
||
+ * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
+ *
|
||
+ * rtpg.h
|
||
+ *
|
||
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
+ * It determines the ALUA state of a device and prints a priority value to
|
||
+ * stdout.
|
||
+ *
|
||
+ * Author(s): Jan Kunigk
|
||
+ * S. Bader <shbader@de.ibm.com>
|
||
+ *
|
||
+ * This file is released under the GPL.
|
||
+ */
|
||
+#ifndef __RTPG_H__
|
||
+#define __RTPG_H__
|
||
+#include "alua_spc3.h"
|
||
+
|
||
+#define RTPG_SUCCESS 0
|
||
+#define RTPG_INQUIRY_FAILED 1
|
||
+#define RTPG_NO_TPG_IDENTIFIER 2
|
||
+#define RTPG_RTPG_FAILED 3
|
||
+#define RTPG_TPG_NOT_FOUND 4
|
||
+
|
||
+int get_target_port_group_support(int fd);
|
||
+int get_target_port_group(int fd);
|
||
+int get_asymmetric_access_state(int fd, unsigned int tpg);
|
||
+
|
||
+#endif /* __RTPG_H__ */
|
||
+
|
||
diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h
|
||
new file mode 100644
|
||
index 0000000..bddbbdd
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/alua_spc3.h
|
||
@@ -0,0 +1,322 @@
|
||
+/*
|
||
+ * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
+ *
|
||
+ * spc3.h
|
||
+ *
|
||
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
+ * It determines the ALUA state of a device and prints a priority value to
|
||
+ * stdout.
|
||
+ *
|
||
+ * Author(s): Jan Kunigk
|
||
+ * S. Bader <shbader@de.ibm.com>
|
||
+ *
|
||
+ * This file is released under the GPL.
|
||
+ */
|
||
+#ifndef __SPC3_H__
|
||
+#define __SPC3_H__
|
||
+/*=============================================================================
|
||
+ * Some helper functions for getting and setting 16 and 32 bit values.
|
||
+ *=============================================================================
|
||
+ */
|
||
+static inline unsigned short
|
||
+get_uint16(unsigned char *p)
|
||
+{
|
||
+ return (p[0] << 8) + p[1];
|
||
+}
|
||
+
|
||
+static inline void
|
||
+set_uint16(unsigned char *p, unsigned short v)
|
||
+{
|
||
+ p[0] = (v >> 8) & 0xff;
|
||
+ p[1] = v & 0xff;
|
||
+}
|
||
+
|
||
+static inline unsigned int
|
||
+get_uint32(unsigned char *p)
|
||
+{
|
||
+ return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||
+}
|
||
+
|
||
+static inline void
|
||
+set_uint32(unsigned char *p, unsigned int v)
|
||
+{
|
||
+ p[0] = (v >> 24) & 0xff;
|
||
+ p[1] = (v >> 16) & 0xff;
|
||
+ p[2] = (v >> 8) & 0xff;
|
||
+ p[3] = v & 0xff;
|
||
+}
|
||
+
|
||
+/*=============================================================================
|
||
+ * Definitions to support the standard inquiry command as defined in SPC-3.
|
||
+ * If the evpd (enable vital product data) bit is set the data that will be
|
||
+ * returned is selected by the page field. This field must be 0 if the evpd
|
||
+ * bit is not set.
|
||
+ *=============================================================================
|
||
+ */
|
||
+#define OPERATION_CODE_INQUIRY 0x12
|
||
+
|
||
+struct inquiry_command {
|
||
+ unsigned char op;
|
||
+ unsigned char b1; /* xxxxxx.. = reserved */
|
||
+ /* ......x. = obsolete */
|
||
+ /* .......x = evpd */
|
||
+ unsigned char page;
|
||
+ unsigned char length[2];
|
||
+ unsigned char control;
|
||
+} __attribute__((packed));
|
||
+
|
||
+static inline void
|
||
+inquiry_command_set_evpd(struct inquiry_command *ic)
|
||
+{
|
||
+ ic->b1 |= 1;
|
||
+}
|
||
+
|
||
+/*-----------------------------------------------------------------------------
|
||
+ * Data returned by the standard inquiry command.
|
||
+ *-----------------------------------------------------------------------------
|
||
+ *
|
||
+ * Peripheral qualifier codes.
|
||
+ */
|
||
+#define PQ_CONNECTED 0x0
|
||
+#define PQ_DISCONNECTED 0x1
|
||
+#define PQ_UNSUPPORTED 0x3
|
||
+
|
||
+/* Defined peripheral device types. */
|
||
+#define PDT_DIRECT_ACCESS 0x00
|
||
+#define PDT_SEQUENTIAL_ACCESS 0x01
|
||
+#define PDT_PRINTER 0x02
|
||
+#define PDT_PROCESSOR 0x03
|
||
+#define PDT_WRITE_ONCE 0x04
|
||
+#define PDT_CD_DVD 0x05
|
||
+#define PDT_SCANNER 0x06
|
||
+#define PDT_OPTICAL_MEMORY 0x07
|
||
+#define PDT_MEDIUM_CHANGER 0x08
|
||
+#define PDT_COMMUNICATIONS 0x09
|
||
+#define PDT_STORAGE_ARRAY_CONTROLLER 0x0c
|
||
+#define PDT_ENCLOSURE_SERVICES 0x0d
|
||
+#define PDT_SIMPLIFIED_DIRECT_ACCESS 0x0e
|
||
+#define PDT_OPTICAL_CARD_READER_WRITER 0x0f
|
||
+#define PDT_BRIDGE_CONTROLLER 0x10
|
||
+#define PDT_OBJECT_BASED 0x11
|
||
+#define PDT_AUTOMATION_INTERFACE 0x12
|
||
+#define PDT_LUN 0x1e
|
||
+#define PDT_UNKNOWN 0x1f
|
||
+
|
||
+/* Defined version codes. */
|
||
+#define VERSION_NONE 0x00
|
||
+#define VERSION_SPC 0x03
|
||
+#define VERSION_SPC2 0x04
|
||
+#define VERSION_SPC3 0x05
|
||
+
|
||
+/* Defined TPGS field values. */
|
||
+#define TPGS_NONE 0x0
|
||
+#define TPGS_IMPLICIT 0x1
|
||
+#define TPGS_EXPLICIT 0x2
|
||
+#define TPGS_BOTH 0x3
|
||
+
|
||
+struct inquiry_data {
|
||
+ unsigned char b0; /* xxx..... = peripheral_qualifier */
|
||
+ /* ...xxxxx = peripheral_device_type */
|
||
+ unsigned char b1; /* x....... = removable medium */
|
||
+ /* .xxxxxxx = reserverd */
|
||
+ unsigned char version;
|
||
+ unsigned char b3; /* xx...... = obsolete */
|
||
+ /* ..x..... = normal aca supported */
|
||
+ /* ...x.... = hirarchichal lun supp. */
|
||
+ /* ....xxxx = response format */
|
||
+ /* 2 is spc-3 format */
|
||
+ unsigned char length;
|
||
+ unsigned char b5; /* x....... = storage controller */
|
||
+ /* component supported */
|
||
+ /* .x...... = access controls coord. */
|
||
+ /* ..xx.... = target port group supp.*/
|
||
+ /* ....x... = third party copy supp. */
|
||
+ /* .....xx. = reserved */
|
||
+ /* .......x = protection info supp. */
|
||
+ unsigned char b6; /* x....... = bque */
|
||
+ /* .x...... = enclosure services sup.*/
|
||
+ /* ..x..... = vs1 */
|
||
+ /* ...x.... = multiport support */
|
||
+ /* ....x... = medium changer */
|
||
+ /* .....xx. = obsolete */
|
||
+ /* .......x = add16 */
|
||
+ unsigned char b7; /* xx...... = obsolete */
|
||
+ /* ..x..... = wbus16 */
|
||
+ /* ...x.... = sync */
|
||
+ /* ....x... = linked commands supp. */
|
||
+ /* .....x.. = obsolete */
|
||
+ /* ......x. = command queue support */
|
||
+ /* .......x = vs2 */
|
||
+ unsigned char vendor_identification[8];
|
||
+ unsigned char product_identification[16];
|
||
+ unsigned char product_revision[4];
|
||
+ unsigned char vendor_specific[20];
|
||
+ unsigned char b56; /* xxxx.... = reserved */
|
||
+ /* ....xx.. = clocking */
|
||
+ /* ......x. = qas */
|
||
+ /* .......x = ius */
|
||
+ unsigned char reserved4;
|
||
+ unsigned char version_descriptor[8][2];
|
||
+ unsigned char reserved5[22];
|
||
+ unsigned char vendor_parameters[0];
|
||
+} __attribute__((packed));
|
||
+
|
||
+static inline int
|
||
+inquiry_data_get_tpgs(struct inquiry_data *id)
|
||
+{
|
||
+ return (id->b5 >> 4) & 3;
|
||
+}
|
||
+
|
||
+/*-----------------------------------------------------------------------------
|
||
+ * Inquiry data returned when requesting vital product data page 0x83.
|
||
+ *-----------------------------------------------------------------------------
|
||
+ */
|
||
+#define CODESET_BINARY 0x1
|
||
+#define CODESET_ACSII 0x2
|
||
+#define CODESET_UTF8 0x3
|
||
+
|
||
+#define ASSOCIATION_UNIT 0x0
|
||
+#define ASSOCIATION_PORT 0x1
|
||
+#define ASSOCIATION_DEVICE 0x2
|
||
+
|
||
+#define IDTYPE_VENDOR_SPECIFIC 0x0
|
||
+#define IDTYPE_T10_VENDOR_ID 0x1
|
||
+#define IDTYPE_EUI64 0x2
|
||
+#define IDTYPE_NAA 0x3
|
||
+#define IDTYPE_RELATIVE_TPG_ID 0x4
|
||
+#define IDTYPE_TARGET_PORT_GROUP 0x5
|
||
+#define IDTYPE_LUN_GROUP 0x6
|
||
+#define IDTYPE_MD5_LUN_ID 0x7
|
||
+#define IDTYPE_SCSI_NAME_STRING 0x8
|
||
+
|
||
+struct vpd83_tpg_dscr {
|
||
+ unsigned char reserved1[2];
|
||
+ unsigned char tpg[2];
|
||
+} __attribute__((packed));
|
||
+
|
||
+struct vpd83_dscr {
|
||
+ unsigned char b0; /* xxxx.... = protocol id */
|
||
+ /* ....xxxx = codeset */
|
||
+ unsigned char b1; /* x....... = protocol id valid */
|
||
+ /* .x...... = reserved */
|
||
+ /* ..xx.... = association */
|
||
+ /* ....xxxx = id type */
|
||
+ unsigned char reserved2;
|
||
+ unsigned char length; /* size-4 */
|
||
+ unsigned char data[0];
|
||
+} __attribute__((packed));
|
||
+
|
||
+static inline int
|
||
+vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
|
||
+{
|
||
+ return ((d->b1 & 7) == type);
|
||
+}
|
||
+
|
||
+struct vpd83_data {
|
||
+ unsigned char b0; /* xxx..... = peripheral_qualifier */
|
||
+ /* ...xxxxx = peripheral_device_type */
|
||
+ unsigned char page_code; /* 0x83 */
|
||
+ unsigned char length[2]; /* size-4 */
|
||
+ struct vpd83_dscr data[0];
|
||
+} __attribute__((packed));
|
||
+
|
||
+/*-----------------------------------------------------------------------------
|
||
+ * This macro should be used to walk through all identification descriptors
|
||
+ * defined in the code page 0x83.
|
||
+ * The argument p is a pointer to the code page 0x83 data and d is used to
|
||
+ * point to the current descriptor.
|
||
+ *-----------------------------------------------------------------------------
|
||
+ */
|
||
+#define FOR_EACH_VPD83_DSCR(p, d) \
|
||
+ for( \
|
||
+ d = p->data; \
|
||
+ (((char *) d) - ((char *) p)) < \
|
||
+ get_uint16(p->length); \
|
||
+ d = (struct vpd83_dscr *) \
|
||
+ ((char *) d + d->length + 4) \
|
||
+ )
|
||
+
|
||
+/*=============================================================================
|
||
+ * The following stuctures and macros are used to call the report target port
|
||
+ * groups command defined in SPC-3.
|
||
+ * This command is used to get information about the target port groups (which
|
||
+ * states are supported, which ports belong to this group, and so on) and the
|
||
+ * current state of each target port group.
|
||
+ *=============================================================================
|
||
+ */
|
||
+#define OPERATION_CODE_RTPG 0xa3
|
||
+#define SERVICE_ACTION_RTPG 0x0a
|
||
+
|
||
+struct rtpg_command {
|
||
+ unsigned char op; /* 0xa3 */
|
||
+ unsigned char b1; /* xxx..... = reserved */
|
||
+ /* ...xxxxx = service action (0x0a) */
|
||
+ unsigned char reserved2[4];
|
||
+ unsigned char length[4];
|
||
+ unsigned char reserved3;
|
||
+ unsigned char control;
|
||
+} __attribute__((packed));
|
||
+
|
||
+static inline void
|
||
+rtpg_command_set_service_action(struct rtpg_command *cmd)
|
||
+{
|
||
+ cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
|
||
+}
|
||
+
|
||
+struct rtpg_tp_dscr {
|
||
+ unsigned char obsolete1[2];
|
||
+ /* The Relative Target Port Identifier of a target port. */
|
||
+ unsigned char rtpi[2];
|
||
+} __attribute__((packed));
|
||
+
|
||
+#define AAS_OPTIMIZED 0x0
|
||
+#define AAS_NON_OPTIMIZED 0x1
|
||
+#define AAS_STANDBY 0x2
|
||
+#define AAS_UNAVAILABLE 0x3
|
||
+#define AAS_TRANSITIONING 0xf
|
||
+
|
||
+#define TPG_STATUS_NONE 0x0
|
||
+#define TPG_STATUS_SET 0x1
|
||
+#define TPG_STATUS_IMPLICIT_CHANGE 0x2
|
||
+
|
||
+struct rtpg_tpg_dscr {
|
||
+ unsigned char b0; /* x....... = pref(ered) port */
|
||
+ /* .xxx.... = reserved */
|
||
+ /* ....xxxx = asymetric access state */
|
||
+ unsigned char b1; /* xxxx.... = reserved */
|
||
+ /* ....x... = unavailable support */
|
||
+ /* .....x.. = standby support */
|
||
+ /* ......x. = non-optimized support */
|
||
+ /* .......x = optimized support */
|
||
+ unsigned char tpg[2];
|
||
+ unsigned char reserved3;
|
||
+ unsigned char status;
|
||
+ unsigned char vendor_unique;
|
||
+ unsigned char port_count;
|
||
+ struct rtpg_tp_dscr data[0];
|
||
+} __attribute__((packed));
|
||
+
|
||
+static inline int
|
||
+rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
|
||
+{
|
||
+ return (d->b0 & 0x0f);
|
||
+}
|
||
+
|
||
+struct rtpg_data {
|
||
+ unsigned char length[4]; /* size-4 */
|
||
+ struct rtpg_tpg_dscr data[0];
|
||
+} __attribute__((packed));
|
||
+
|
||
+#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
|
||
+ for( \
|
||
+ g = &(p->data[0]); \
|
||
+ (((char *) g) - ((char *) p)) < get_uint32(p->length); \
|
||
+ g = (struct rtpg_tpg_dscr *) ( \
|
||
+ ((char *) g) + \
|
||
+ sizeof(struct rtpg_tpg_dscr) + \
|
||
+ g->port_count * sizeof(struct rtpg_tp_dscr) \
|
||
+ ) \
|
||
+ )
|
||
+
|
||
+#endif /* __SPC3_H__ */
|
||
+
|
||
diff --git a/libmultipath/prioritizers/const.c b/libmultipath/prioritizers/const.c
|
||
new file mode 100644
|
||
index 0000000..529cf82
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/const.c
|
||
@@ -0,0 +1,8 @@
|
||
+#include <stdio.h>
|
||
+
|
||
+#include <prio.h>
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return 1;
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/const.h b/libmultipath/prioritizers/const.h
|
||
new file mode 100644
|
||
index 0000000..220db54
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/const.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _CONST_H
|
||
+#define _CONST_H
|
||
+
|
||
+#define PRIO_CONST "const"
|
||
+int prio_const(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/emc.c b/libmultipath/prioritizers/emc.c
|
||
new file mode 100644
|
||
index 0000000..61d7a77
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/emc.c
|
||
@@ -0,0 +1,79 @@
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <sys/ioctl.h>
|
||
+
|
||
+#include <sg_include.h>
|
||
+#include <debug.h>
|
||
+#include <prio.h>
|
||
+
|
||
+#define INQUIRY_CMD 0x12
|
||
+#define INQUIRY_CMDLEN 6
|
||
+
|
||
+#define pp_emc_log(prio, msg) condlog(prio, "%s: emc prio: " msg, dev)
|
||
+
|
||
+int emc_clariion_prio(const char *dev, int fd)
|
||
+{
|
||
+ unsigned char sense_buffer[256];
|
||
+ unsigned char sb[128];
|
||
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
|
||
+ sizeof(sb), 0};
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ int ret = 0;
|
||
+
|
||
+ 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 (sb);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
+ io_hdr.dxferp = sense_buffer;
|
||
+ io_hdr.cmdp = inqCmdBlk;
|
||
+ io_hdr.sbp = sb;
|
||
+ io_hdr.timeout = 60000;
|
||
+ io_hdr.pack_id = 0;
|
||
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
+ pp_emc_log(0, "sending query command failed");
|
||
+ goto out;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ pp_emc_log(0, "query command indicates error");
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if (/* Verify the code page - right page & revision */
|
||
+ sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
|
||
+ pp_emc_log(0, "path unit report page in unknown format");
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if ( /* Effective initiator type */
|
||
+ sense_buffer[27] != 0x03
|
||
+ /*
|
||
+ * 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) {
|
||
+ pp_emc_log(0, "path not correctly configured for failover");
|
||
+ }
|
||
+
|
||
+ if ( /* LUN operations should indicate normal operations */
|
||
+ sense_buffer[48] != 0x00) {
|
||
+ pp_emc_log(0, "path not available for normal operations");
|
||
+ }
|
||
+
|
||
+ /* Is the default owner equal to this path? */
|
||
+ /* Note this will switch to the default priority group, even if
|
||
+ * it is not the currently active one. */
|
||
+ ret = (sense_buffer[5] == sense_buffer[8]) ? 1 : 0;
|
||
+
|
||
+out:
|
||
+ return(ret);
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return emc_clariion_prio(pp->dev, pp->fd);
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/emc.h b/libmultipath/prioritizers/emc.h
|
||
new file mode 100644
|
||
index 0000000..0ab0bc5
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/emc.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _EMC_H
|
||
+#define _EMC_H
|
||
+
|
||
+#define PRIO_EMC "emc"
|
||
+int prio_emc(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/hds.c b/libmultipath/prioritizers/hds.c
|
||
new file mode 100644
|
||
index 0000000..6ebe4d8
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/hds.c
|
||
@@ -0,0 +1,170 @@
|
||
+/*
|
||
+ * (C) Copyright HDS GmbH 2006. All Rights Reserved.
|
||
+ *
|
||
+ * pp_hds_modular.c
|
||
+ * Version 2.00
|
||
+ *
|
||
+ * Prioritizer for Device Mapper Multipath 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 command 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
|
||
+ *
|
||
+ * To compile this source please execute # cc pp_hds_modular.c -o /sbin/mpath_prio_hds_modular
|
||
+ *
|
||
+ * Changes 2006-07-16:
|
||
+ * - Changed to forward declaration of functions
|
||
+ * - The switch-statement was changed to a logical expression
|
||
+ * - unlinking of the devpath now also occurs at the end of
|
||
+ * hds_modular_prio to avoid old /tmp/.pp_balance.%u.%u.devnode
|
||
+ * entries in /tmp-Directory
|
||
+ * - The for-statements for passing variables where changed to
|
||
+ * snprintf-commands in verbose mode
|
||
+ * Changes 2006-08-10:
|
||
+ * - Back to the old switch statements because the regular expression does
|
||
+ * not work under RHEL4 U3 i386
|
||
+ * Changes 2007-06-27:
|
||
+ * - switched from major:minor argument to device node argument
|
||
+ *
|
||
+ * This file is released under the GPL.
|
||
+ *
|
||
+ */
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <unistd.h>
|
||
+#include <string.h>
|
||
+#include <errno.h>
|
||
+#include <sys/ioctl.h>
|
||
+#include <stdlib.h>
|
||
+
|
||
+#include <sg_include.h>
|
||
+#include <debug.h>
|
||
+#include <prio.h>
|
||
+
|
||
+#define INQ_REPLY_LEN 255
|
||
+#define INQ_CMD_CODE 0x12
|
||
+#define INQ_CMD_LEN 6
|
||
+
|
||
+#define pp_hds_log(prio, fmt, args...) \
|
||
+ condlog(prio, "%s: hds prio: " fmt, dev, ##args)
|
||
+
|
||
+int hds_modular_prio (const char *dev, int fd)
|
||
+{
|
||
+ int k;
|
||
+ char vendor[8];
|
||
+ char product[32];
|
||
+ char serial[32];
|
||
+ char ldev[32];
|
||
+ char ctrl[32];
|
||
+ char port[32];
|
||
+ unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
|
||
+ unsigned char inqBuff[INQ_REPLY_LEN];
|
||
+ unsigned char *inqBuffp = inqBuff;
|
||
+ unsigned char sense_buffer[32];
|
||
+ sg_io_hdr_t io_hdr;
|
||
+
|
||
+ if ((ioctl (fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
|
||
+ pp_hds_log(0, "can't use SG ioctl interface");
|
||
+ return -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 (fd, SG_IO, &io_hdr) < 0) {
|
||
+ pp_hds_log(0, "SG_IO error");
|
||
+ return -1;
|
||
+ }
|
||
+ if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
|
||
+ pp_hds_log(0, "SCSI error");
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ snprintf (vendor, 9, "%.8s", inqBuffp + 8);
|
||
+ snprintf (product, 17, "%.16s", inqBuffp + 16);
|
||
+ snprintf (serial, 5, "%.4s", inqBuffp + 40);
|
||
+ snprintf (ldev, 5, "%.4s", inqBuffp + 44);
|
||
+ snprintf (ctrl, 2, "%.1s", inqBuffp + 49);
|
||
+ snprintf (port, 2, "%.1s", inqBuffp + 50);
|
||
+
|
||
+ pp_hds_log(4, "VENDOR: %s", vendor);
|
||
+ pp_hds_log(4, "PRODUCT: %s", product);
|
||
+ pp_hds_log(4, "SERIAL: 0x%s", serial);
|
||
+ pp_hds_log(4, "LDEV: 0x%s", ldev);
|
||
+ pp_hds_log(4, "CTRL: %s", ctrl);
|
||
+ pp_hds_log(4, "PORT: %s", 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':
|
||
+ pp_hds_log(4, "CTRL EVEN, LDEV EVEN, PRIO 1");
|
||
+ return 1;
|
||
+ break;
|
||
+ case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
|
||
+ pp_hds_log(4, "CTRL EVEN, LDEV ODD, PRIO 0");
|
||
+ 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':
|
||
+ pp_hds_log(4, "CTRL ODD, LDEV EVEN, PRIO 0");
|
||
+ return 0;
|
||
+ break;
|
||
+ case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
|
||
+ pp_hds_log(4, "CTRL ODD, LDEV ODD, PRIO 1");
|
||
+ return 1;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return hds_modular_prio(pp->dev, pp->fd);
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/hds.h b/libmultipath/prioritizers/hds.h
|
||
new file mode 100644
|
||
index 0000000..084d77c
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/hds.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _HDS_H
|
||
+#define _HDS_H
|
||
+
|
||
+#define PRIO_HDS "hds"
|
||
+int prio_hds(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/hp_sw.c b/libmultipath/prioritizers/hp_sw.c
|
||
new file mode 100644
|
||
index 0000000..ae0975f
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/hp_sw.c
|
||
@@ -0,0 +1,100 @@
|
||
+/*
|
||
+ * 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 <unistd.h>
|
||
+#include <sys/ioctl.h>
|
||
+#include <errno.h>
|
||
+
|
||
+#include <sg_include.h>
|
||
+#include <debug.h>
|
||
+#include <prio.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
|
||
+
|
||
+#define pp_hp_sw_log(prio, fmt, args...) \
|
||
+ condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
|
||
+
|
||
+int hp_sw_prio(const char *dev, int fd)
|
||
+{
|
||
+ 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;
|
||
+
|
||
+ 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) {
|
||
+ pp_hp_sw_log(0, "sending tur command failed");
|
||
+ 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;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+out:
|
||
+ return(ret);
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return hp_sw_prio(pp->dev, pp->fd);
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/hp_sw.h b/libmultipath/prioritizers/hp_sw.h
|
||
new file mode 100644
|
||
index 0000000..2fea486
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/hp_sw.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _HP_SW_H
|
||
+#define _HP_SW_H
|
||
+
|
||
+#define PRIO_HP_SW "hp_sw"
|
||
+int prio_hp_sw(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/netapp.c b/libmultipath/prioritizers/netapp.c
|
||
new file mode 100644
|
||
index 0000000..812ecf6
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/netapp.c
|
||
@@ -0,0 +1,243 @@
|
||
+/*
|
||
+ * Copyright 2005 Network Appliance, Inc., All Rights Reserved
|
||
+ * Author: David Wysochanski available at davidw@netapp.com
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License version 2 as
|
||
+ * published by the Free Software Foundation.
|
||
+ *
|
||
+ * 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 v2 for more details.
|
||
+ */
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <sys/ioctl.h>
|
||
+#include <errno.h>
|
||
+#include <assert.h>
|
||
+
|
||
+#include <sg_include.h>
|
||
+#include <debug.h>
|
||
+#include <prio.h>
|
||
+
|
||
+#define INQUIRY_CMD 0x12
|
||
+#define INQUIRY_CMDLEN 6
|
||
+#define DEFAULT_PRIOVAL 10
|
||
+#define RESULTS_MAX 256
|
||
+#define SG_TIMEOUT 30000
|
||
+
|
||
+#define pp_netapp_log(prio, fmt, args...) \
|
||
+ condlog(prio, "%s: netapp prio: " fmt, dev, ##args)
|
||
+
|
||
+static void dump_cdb(unsigned char *cdb, int size)
|
||
+{
|
||
+ int i;
|
||
+ char buf[10*5+1];
|
||
+ char * p = &buf[0];
|
||
+
|
||
+ condlog(0, "- SCSI CDB: ");
|
||
+ for (i=0; i<size; i++) {
|
||
+ p += snprintf(p, 10*(size-i), "0x%02x ", cdb[i]);
|
||
+ }
|
||
+ condlog(0, "%s", buf);
|
||
+}
|
||
+
|
||
+static void process_sg_error(struct sg_io_hdr *io_hdr)
|
||
+{
|
||
+ int i;
|
||
+ char buf[128*5+1];
|
||
+ char * p = &buf[0];
|
||
+
|
||
+ condlog(0, "- masked_status=0x%02x, host_status=0x%02x, "
|
||
+ "driver_status=0x%02x", io_hdr->masked_status,
|
||
+ io_hdr->host_status, io_hdr->driver_status);
|
||
+ if (io_hdr->sb_len_wr > 0) {
|
||
+ condlog(0, "- SCSI sense data: ");
|
||
+ for (i=0; i<io_hdr->sb_len_wr; i++) {
|
||
+ p += snprintf(p, 128*(io_hdr->sb_len_wr-i), "0x%02x ",
|
||
+ io_hdr->sbp[i]);
|
||
+ }
|
||
+ condlog(0, "%s", buf);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Returns:
|
||
+ * -1: error, errno set
|
||
+ * 0: success
|
||
+ */
|
||
+static int send_gva(const char *dev, int fd, unsigned char pg,
|
||
+ unsigned char *results, int *results_size)
|
||
+{
|
||
+ unsigned char sb[128];
|
||
+ unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
|
||
+ pg, sizeof(sb), 0, 0};
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ int ret = -1;
|
||
+
|
||
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
|
||
+ io_hdr.interface_id = 'S';
|
||
+ io_hdr.cmd_len = sizeof (cdb);
|
||
+ io_hdr.mx_sb_len = sizeof (sb);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ io_hdr.dxfer_len = *results_size;
|
||
+ io_hdr.dxferp = results;
|
||
+ io_hdr.cmdp = cdb;
|
||
+ io_hdr.sbp = sb;
|
||
+ io_hdr.timeout = SG_TIMEOUT;
|
||
+ io_hdr.pack_id = 0;
|
||
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
+ pp_netapp_log(0, "SG_IO ioctl failed, errno=%d", errno);
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ goto out;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ pp_netapp_log(0, "SCSI error");
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ process_sg_error(&io_hdr);
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if (results[4] != 0x0a || results[5] != 0x98 ||
|
||
+ results[6] != 0x0a ||results[7] != 0x01) {
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ pp_netapp_log(0, "GVA return wrong format ");
|
||
+ pp_netapp_log(0, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x",
|
||
+ results[4], results[5], results[6], results[7]);
|
||
+ goto out;
|
||
+ }
|
||
+ ret = 0;
|
||
+ out:
|
||
+ return(ret);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Retuns:
|
||
+ * -1: Unable to obtain proxy info
|
||
+ * 0: Device _not_ proxy path
|
||
+ * 1: Device _is_ proxy path
|
||
+ */
|
||
+static int get_proxy(const char *dev, int fd)
|
||
+{
|
||
+ unsigned char results[256];
|
||
+ unsigned char sb[128];
|
||
+ unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
|
||
+ sizeof(sb), 0};
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ int ret = -1;
|
||
+
|
||
+ memset(&results, 0, sizeof (results));
|
||
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
|
||
+ io_hdr.interface_id = 'S';
|
||
+ io_hdr.cmd_len = sizeof (cdb);
|
||
+ io_hdr.mx_sb_len = sizeof (sb);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ io_hdr.dxfer_len = sizeof (results);
|
||
+ io_hdr.dxferp = results;
|
||
+ io_hdr.cmdp = cdb;
|
||
+ io_hdr.sbp = sb;
|
||
+ io_hdr.timeout = SG_TIMEOUT;
|
||
+ io_hdr.pack_id = 0;
|
||
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
+ pp_netapp_log(0, "ioctl sending inquiry command failed, "
|
||
+ "errno=%d", errno);
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ goto out;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ pp_netapp_log(0, "SCSI error");
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ process_sg_error(&io_hdr);
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if (results[1] != 0xc1 || results[8] != 0x0a ||
|
||
+ results[9] != 0x98 || results[10] != 0x0a ||
|
||
+ results[11] != 0x0 || results[12] != 0xc1 ||
|
||
+ results[13] != 0x0) {
|
||
+ pp_netapp_log(0,"proxy info page in unknown format - ");
|
||
+ pp_netapp_log(0,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
|
||
+ "0x%02x 0x%02x",
|
||
+ results[8], results[9], results[10],
|
||
+ results[11], results[12], results[13]);
|
||
+ dump_cdb(cdb, sizeof(cdb));
|
||
+ goto out;
|
||
+ }
|
||
+ ret = (results[19] & 0x02) >> 1;
|
||
+
|
||
+ out:
|
||
+ return(ret);
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Returns priority of device based on device info.
|
||
+ *
|
||
+ * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
|
||
+ * 3: iSCSI HBA
|
||
+ * 2: iSCSI software
|
||
+ * 1: FCP proxy
|
||
+ */
|
||
+static int netapp_prio(const char *dev, int fd)
|
||
+{
|
||
+ unsigned char results[RESULTS_MAX];
|
||
+ int results_size=RESULTS_MAX;
|
||
+ int rc;
|
||
+ int is_proxy;
|
||
+ int is_iscsi_software;
|
||
+ int is_iscsi_hardware;
|
||
+ int tot_len;
|
||
+
|
||
+ is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
|
||
+
|
||
+ memset(&results, 0, sizeof (results));
|
||
+ rc = send_gva(dev, fd, 0x41, results, &results_size);
|
||
+ if (rc == 0) {
|
||
+ tot_len = results[0] << 24 | results[1] << 16 |
|
||
+ results[2] << 8 | results[3];
|
||
+ if (tot_len <= 8) {
|
||
+ goto try_fcp_proxy;
|
||
+ }
|
||
+ if (results[8] != 0x41) {
|
||
+ pp_netapp_log(0, "GVA page 0x41 error - "
|
||
+ "results[8] = 0x%x", results[8]);
|
||
+ goto try_fcp_proxy;
|
||
+ }
|
||
+ if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
|
||
+ (strncmp((char *)&results[12], "iswt", 4) == 0)) {
|
||
+ is_iscsi_software = 1;
|
||
+ goto prio_select;
|
||
+ }
|
||
+ else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
|
||
+ is_iscsi_hardware = 1;
|
||
+ goto prio_select;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ try_fcp_proxy:
|
||
+ rc = get_proxy(dev, fd);
|
||
+ if (rc >= 0) {
|
||
+ is_proxy = rc;
|
||
+ }
|
||
+
|
||
+ prio_select:
|
||
+ if (is_iscsi_hardware) {
|
||
+ return 3;
|
||
+ } else if (is_iscsi_software) {
|
||
+ return 2;
|
||
+ } else {
|
||
+ if (is_proxy) {
|
||
+ return 1;
|
||
+ } else {
|
||
+ /* Either non-proxy, or couldn't get proxy info */
|
||
+ return 4;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return netapp_prio(pp->dev, pp->fd);
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/netapp.h b/libmultipath/prioritizers/netapp.h
|
||
new file mode 100644
|
||
index 0000000..ec38821
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/netapp.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _NETAPP_H
|
||
+#define _NETAPP_H
|
||
+
|
||
+#define PRIO_NETAPP "netapp"
|
||
+int prio_netapp(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/random.c b/libmultipath/prioritizers/random.c
|
||
new file mode 100644
|
||
index 0000000..e3852a7
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/random.c
|
||
@@ -0,0 +1,15 @@
|
||
+#include <stdio.h>
|
||
+#include <stdlib.h>
|
||
+#include <sys/time.h>
|
||
+#include <time.h>
|
||
+
|
||
+#include <prio.h>
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ struct timeval tv;
|
||
+
|
||
+ gettimeofday(&tv, NULL);
|
||
+ srand((unsigned int)tv.tv_usec);
|
||
+ return 1+(int) (10.0*rand()/(RAND_MAX+1.0));
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/random.h b/libmultipath/prioritizers/random.h
|
||
new file mode 100644
|
||
index 0000000..b9dae69
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/random.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _RANDOM_H
|
||
+#define _RANDOM_H
|
||
+
|
||
+#define PRIO_RANDOM "random"
|
||
+int prio_random(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/prioritizers/rdac.c b/libmultipath/prioritizers/rdac.c
|
||
new file mode 100644
|
||
index 0000000..4dd8f44
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/rdac.c
|
||
@@ -0,0 +1,90 @@
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <sys/ioctl.h>
|
||
+
|
||
+#include <sg_include.h>
|
||
+#include <debug.h>
|
||
+#include <prio.h>
|
||
+
|
||
+#define INQUIRY_CMD 0x12
|
||
+#define INQUIRY_CMDLEN 6
|
||
+
|
||
+#define pp_rdac_log(prio, msg) condlog(prio, "%s: rdac prio: " msg, dev)
|
||
+
|
||
+int rdac_prio(const char *dev, int fd)
|
||
+{
|
||
+ unsigned char sense_buffer[256];
|
||
+ unsigned char sb[128];
|
||
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
|
||
+ sizeof(sb), 0};
|
||
+ struct sg_io_hdr io_hdr;
|
||
+ int ret = 0;
|
||
+
|
||
+ 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 (sb);
|
||
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
+ io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
+ io_hdr.dxferp = sense_buffer;
|
||
+ io_hdr.cmdp = inqCmdBlk;
|
||
+ io_hdr.sbp = sb;
|
||
+ io_hdr.timeout = 60000;
|
||
+ io_hdr.pack_id = 0;
|
||
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
+ pp_rdac_log(0, "sending inquiry command failed");
|
||
+ goto out;
|
||
+ }
|
||
+ if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
+ pp_rdac_log(0, "inquiry command indicates error");
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if (/* Verify the code page - right page & page identifier */
|
||
+ sense_buffer[1] != 0xc9 ||
|
||
+ sense_buffer[3] != 0x2c ||
|
||
+ sense_buffer[4] != 'v' ||
|
||
+ sense_buffer[5] != 'a' ||
|
||
+ sense_buffer[6] != 'c' ) {
|
||
+ pp_rdac_log(0, "volume access control page in unknown format");
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if ( /* Current Volume Path Bit */
|
||
+ ( sense_buffer[8] & 0x01) == 0x01 ) {
|
||
+ /*
|
||
+ * This volume was owned by the controller receiving
|
||
+ * the inquiry command.
|
||
+ */
|
||
+ ret |= 0x01;
|
||
+ }
|
||
+
|
||
+ /* Volume Preferred Path Priority */
|
||
+ switch ( sense_buffer[9] & 0x0F ) {
|
||
+ case 0x01:
|
||
+ /*
|
||
+ * Access to this volume is most preferred through
|
||
+ * this path and other paths with this value.
|
||
+ */
|
||
+ ret |= 0x02;
|
||
+ break;
|
||
+ case 0x02:
|
||
+ /*
|
||
+ * Access to this volume through this path is to be used
|
||
+ * as a secondary path. Typically this path would be used
|
||
+ * for fail-over situations.
|
||
+ */
|
||
+ /* Fallthrough */
|
||
+ default:
|
||
+ /* Reserved values */
|
||
+ break;
|
||
+ }
|
||
+
|
||
+out:
|
||
+ return(ret);
|
||
+}
|
||
+
|
||
+int getprio (struct path * pp)
|
||
+{
|
||
+ return rdac_prio(pp->dev, pp->fd);
|
||
+}
|
||
diff --git a/libmultipath/prioritizers/rdac.h b/libmultipath/prioritizers/rdac.h
|
||
new file mode 100644
|
||
index 0000000..a5b7f8e
|
||
--- /dev/null
|
||
+++ b/libmultipath/prioritizers/rdac.h
|
||
@@ -0,0 +1,7 @@
|
||
+#ifndef _RDAC_H
|
||
+#define _RDAC_H
|
||
+
|
||
+#define PRIO_RDAC "rdac"
|
||
+int prio_rdac(struct path * pp);
|
||
+
|
||
+#endif
|
||
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
||
index 45a3728..43611ff 100644
|
||
--- a/libmultipath/propsel.c
|
||
+++ b/libmultipath/propsel.c
|
||
@@ -5,8 +5,7 @@
|
||
*/
|
||
#include <stdio.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "memory.h"
|
||
#include "vector.h"
|
||
#include "structs.h"
|
||
@@ -16,6 +15,7 @@
|
||
#include "alias.h"
|
||
#include "defaults.h"
|
||
#include "devmapper.h"
|
||
+#include "prio.h"
|
||
|
||
pgpolicyfn *pgpolicies[] = {
|
||
NULL,
|
||
@@ -168,8 +168,7 @@ select_alias (struct multipath * mp)
|
||
if (mp->alias == NULL){
|
||
char *alias;
|
||
if ((alias = MALLOC(WWID_SIZE)) != NULL){
|
||
- if (dm_get_name(mp->wwid, DEFAULT_TARGET,
|
||
- alias) == 1)
|
||
+ if (dm_get_name(mp->wwid, alias) == 1)
|
||
mp->alias = alias;
|
||
else
|
||
FREE(alias);
|
||
@@ -217,19 +216,19 @@ select_checker(struct path *pp)
|
||
{
|
||
struct checker * c = &pp->checker;
|
||
|
||
- if (pp->hwe && pp->hwe->checker) {
|
||
- checker_get(c, pp->hwe->checker);
|
||
+ if (pp->hwe && pp->hwe->checker_name) {
|
||
+ checker_get(c, pp->hwe->checker_name);
|
||
condlog(3, "%s: path checker = %s (controller setting)",
|
||
pp->dev, checker_name(c));
|
||
return 0;
|
||
}
|
||
- if (conf->checker) {
|
||
- checker_get(c, conf->checker);
|
||
+ if (conf->checker_name) {
|
||
+ checker_get(c, conf->checker_name);
|
||
condlog(3, "%s: path checker = %s (config file default)",
|
||
pp->dev, checker_name(c));
|
||
return 0;
|
||
}
|
||
- checker_get(c, checker_default());
|
||
+ checker_get(c, DEFAULT_CHECKER);
|
||
condlog(3, "%s: path checker = %s (internal default)",
|
||
pp->dev, checker_name(c));
|
||
return 0;
|
||
@@ -257,22 +256,23 @@ select_getuid (struct path * pp)
|
||
}
|
||
|
||
extern int
|
||
-select_getprio (struct path * pp)
|
||
+select_prio (struct path * pp)
|
||
{
|
||
- if (pp->hwe && pp->hwe->getprio) {
|
||
- pp->getprio = pp->hwe->getprio;
|
||
- condlog(3, "%s: getprio = %s (controller setting)",
|
||
- pp->dev, pp->getprio);
|
||
+ if (pp->hwe && pp->hwe->prio_name) {
|
||
+ pp->prio = prio_lookup(pp->hwe->prio_name);
|
||
+ condlog(3, "%s: prio = %s (controller setting)",
|
||
+ pp->dev, pp->hwe->prio_name);
|
||
return 0;
|
||
}
|
||
- if (conf->getprio) {
|
||
- pp->getprio = conf->getprio;
|
||
- condlog(3, "%s: getprio = %s (config file default)",
|
||
- pp->dev, pp->getprio);
|
||
+ if (conf->prio_name) {
|
||
+ pp->prio = prio_lookup(conf->prio_name);
|
||
+ condlog(3, "%s: prio = %s (config file default)",
|
||
+ pp->dev, conf->prio_name);
|
||
return 0;
|
||
}
|
||
- pp->getprio = DEFAULT_GETPRIO;
|
||
- condlog(3, "%s: getprio = NULL (internal default)", pp->dev);
|
||
+ pp->prio = prio_lookup(DEFAULT_PRIO);
|
||
+ condlog(3, "%s: prio = %s (internal default)",
|
||
+ pp->dev, DEFAULT_PRIO);
|
||
return 0;
|
||
}
|
||
|
||
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
|
||
index afd1f88..62802f8 100644
|
||
--- a/libmultipath/propsel.h
|
||
+++ b/libmultipath/propsel.h
|
||
@@ -7,7 +7,7 @@ int select_features (struct multipath * mp);
|
||
int select_hwhandler (struct multipath * mp);
|
||
int select_checker(struct path *pp);
|
||
int select_getuid (struct path * pp);
|
||
-int select_getprio (struct path * pp);
|
||
+int select_prio (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 d36eaef..852e6b3 100644
|
||
--- a/libmultipath/structs.c
|
||
+++ b/libmultipath/structs.c
|
||
@@ -6,8 +6,7 @@
|
||
#include <unistd.h>
|
||
#include <libdevmapper.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "memory.h"
|
||
#include "vector.h"
|
||
#include "util.h"
|
||
@@ -17,6 +16,7 @@
|
||
#include "structs_vec.h"
|
||
#include "blacklist.h"
|
||
#include "waiter.h"
|
||
+#include "prio.h"
|
||
|
||
struct path *
|
||
alloc_path (void)
|
||
@@ -170,14 +170,12 @@ free_multipath (struct multipath * mpp, int free_paths)
|
||
|
||
if (mpp->dmi)
|
||
FREE(mpp->dmi);
|
||
-
|
||
-#if DAEMON
|
||
+
|
||
/*
|
||
* better own vecs->lock here
|
||
*/
|
||
if (mpp->waiter)
|
||
((struct event_thread *)mpp->waiter)->mpp = NULL;
|
||
-#endif
|
||
|
||
free_pathvec(mpp->paths, free_paths);
|
||
free_pgvec(mpp->pg, free_paths);
|
||
@@ -364,15 +362,27 @@ pathcount (struct multipath * mpp, int state)
|
||
int count = 0;
|
||
int i;
|
||
|
||
- vector_foreach_slot (mpp->pg, pgp, i)
|
||
- count += pathcountgr(pgp, state);
|
||
-
|
||
+ if (mpp->pg) {
|
||
+ vector_foreach_slot (mpp->pg, pgp, i)
|
||
+ count += pathcountgr(pgp, state);
|
||
+ }
|
||
return count;
|
||
}
|
||
|
||
struct path *
|
||
first_path (struct multipath * mpp)
|
||
{
|
||
- struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0);
|
||
- return VECTOR_SLOT(pgp->paths, 0);
|
||
+ struct pathgroup * pgp;
|
||
+ if (!mpp->pg)
|
||
+ return NULL;
|
||
+ pgp = VECTOR_SLOT(mpp->pg, 0);
|
||
+
|
||
+ return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
|
||
+}
|
||
+
|
||
+extern void
|
||
+setup_feature(struct multipath * mpp, char *feature)
|
||
+{
|
||
+ if (!strncmp(feature, "queue_if_no_path", 16))
|
||
+ mpp->no_path_retry = NO_PATH_RETRY_QUEUE;
|
||
}
|
||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||
index f821f87..85d5109 100644
|
||
--- a/libmultipath/structs.h
|
||
+++ b/libmultipath/structs.h
|
||
@@ -21,8 +21,7 @@
|
||
#define NO_PATH_RETRY_FAIL -1
|
||
#define NO_PATH_RETRY_QUEUE -2
|
||
|
||
-#define PRIO_UNDEF -1
|
||
-#define PRIO_DEFAULT 1
|
||
+#define MAX_FDS_UNLIMITED -1
|
||
|
||
enum free_path_switch {
|
||
KEEP_PATHS,
|
||
@@ -121,8 +120,7 @@ struct path {
|
||
int priority;
|
||
int pgindex;
|
||
char * getuid;
|
||
- char * getprio;
|
||
- int getprio_selected;
|
||
+ struct prio * prio;
|
||
struct checker checker;
|
||
struct multipath * mpp;
|
||
int fd;
|
||
@@ -213,6 +211,7 @@ struct path * first_path (struct multipath * mpp);
|
||
|
||
int pathcountgr (struct pathgroup *, int);
|
||
int pathcount (struct multipath *, int);
|
||
+void setup_feature(struct multipath *, char *);
|
||
|
||
extern char sysfs_path[PATH_SIZE];
|
||
|
||
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||
index 1cc6028..34b7669 100644
|
||
--- a/libmultipath/structs_vec.c
|
||
+++ b/libmultipath/structs_vec.c
|
||
@@ -2,20 +2,20 @@
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "defaults.h"
|
||
#include "debug.h"
|
||
#include "structs.h"
|
||
#include "structs_vec.h"
|
||
+#include "waiter.h"
|
||
#include "devmapper.h"
|
||
#include "dmparser.h"
|
||
#include "config.h"
|
||
#include "propsel.h"
|
||
#include "sysfs.h"
|
||
#include "discovery.h"
|
||
-#include "waiter.h"
|
||
+#include "prio.h"
|
||
|
||
/*
|
||
* creates or updates mpp->paths reading mpp->pg
|
||
@@ -62,7 +62,7 @@ adopt_paths (vector pathvec, struct multipath * mpp)
|
||
condlog(3, "%s: ownership set to %s",
|
||
pp->dev, mpp->alias);
|
||
pp->mpp = mpp;
|
||
-
|
||
+
|
||
if (!mpp->paths && !(mpp->paths = vector_alloc()))
|
||
return 1;
|
||
|
||
@@ -81,8 +81,7 @@ orphan_path (struct path * pp)
|
||
pp->mpp = NULL;
|
||
pp->dmstate = PSTATE_UNDEF;
|
||
pp->getuid = NULL;
|
||
- pp->getprio = NULL;
|
||
- pp->getprio_selected = 0;
|
||
+ pp->prio = NULL;
|
||
checker_put(&pp->checker);
|
||
if (pp->fd >= 0)
|
||
close(pp->fd);
|
||
@@ -112,9 +111,13 @@ set_multipath_wwid (struct multipath * mpp)
|
||
dm_get_uuid(mpp->alias, mpp->wwid);
|
||
}
|
||
|
||
-extern void
|
||
-remove_map (struct multipath * mpp, struct vectors * vecs,
|
||
- stop_waiter_thread_func *stop_waiter, int purge_vec)
|
||
+#define KEEP_WAITER 0
|
||
+#define STOP_WAITER 1
|
||
+#define PURGE_VEC 1
|
||
+
|
||
+static void
|
||
+_remove_map (struct multipath * mpp, struct vectors * vecs,
|
||
+ int stop_waiter, int purge_vec)
|
||
{
|
||
int i;
|
||
|
||
@@ -124,7 +127,7 @@ remove_map (struct multipath * mpp, struct vectors * vecs,
|
||
* stop the DM event waiter thread
|
||
*/
|
||
if (stop_waiter)
|
||
- stop_waiter(mpp, vecs);
|
||
+ stop_waiter_thread(mpp, vecs);
|
||
|
||
/*
|
||
* clear references to this map
|
||
@@ -142,14 +145,26 @@ remove_map (struct multipath * mpp, struct vectors * vecs,
|
||
}
|
||
|
||
extern void
|
||
-remove_maps (struct vectors * vecs,
|
||
- stop_waiter_thread_func *stop_waiter)
|
||
+remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
|
||
+{
|
||
+ _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
|
||
+}
|
||
+
|
||
+extern void
|
||
+remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
|
||
+ int purge_vec)
|
||
+{
|
||
+ _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
|
||
+}
|
||
+
|
||
+static void
|
||
+_remove_maps (struct vectors * vecs, int stop_waiter)
|
||
{
|
||
int i;
|
||
struct multipath * mpp;
|
||
|
||
vector_foreach_slot (vecs->mpvec, mpp, i) {
|
||
- remove_map(mpp, vecs, stop_waiter, 1);
|
||
+ _remove_map(mpp, vecs, stop_waiter, 1);
|
||
i--;
|
||
}
|
||
|
||
@@ -157,16 +172,31 @@ remove_maps (struct vectors * vecs,
|
||
vecs->mpvec = NULL;
|
||
}
|
||
|
||
+extern void
|
||
+remove_maps (struct vectors * vecs)
|
||
+{
|
||
+ _remove_maps(vecs, KEEP_WAITER);
|
||
+}
|
||
+
|
||
+extern void
|
||
+remove_maps_and_stop_waiters (struct vectors * vecs)
|
||
+{
|
||
+ _remove_maps(vecs, STOP_WAITER);
|
||
+}
|
||
+
|
||
static struct hwentry *
|
||
extract_hwe_from_path(struct multipath * mpp)
|
||
{
|
||
- struct path * pp;
|
||
- struct pathgroup * pgp;
|
||
+ struct path * pp = NULL;
|
||
+ struct pathgroup * pgp = NULL;
|
||
|
||
- pgp = VECTOR_SLOT(mpp->pg, 0);
|
||
- pp = VECTOR_SLOT(pgp->paths, 0);
|
||
+ if (mpp && mpp->pg)
|
||
+ pgp = VECTOR_SLOT(mpp->pg, 0);
|
||
|
||
- return pp->hwe;
|
||
+ if (pgp && pgp->paths)
|
||
+ pp = VECTOR_SLOT(pgp->paths, 0);
|
||
+
|
||
+ return pp?pp->hwe:NULL;
|
||
}
|
||
|
||
static int
|
||
@@ -220,7 +250,8 @@ set_no_path_retry(struct multipath *mpp)
|
||
{
|
||
mpp->retry_tick = 0;
|
||
mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
|
||
- select_no_path_retry(mpp);
|
||
+ if (mpp->nr_active > 0)
|
||
+ select_no_path_retry(mpp);
|
||
|
||
switch (mpp->no_path_retry) {
|
||
case NO_PATH_RETRY_UNDEF:
|
||
@@ -267,18 +298,17 @@ retry:
|
||
char new_alias[WWID_SIZE];
|
||
|
||
/*
|
||
- * detect an external rename of the multipath device
|
||
+ * detect an external rename of the multipath device
|
||
*/
|
||
- if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
|
||
+ if (dm_get_name(mpp->wwid, new_alias)) {
|
||
condlog(3, "%s multipath mapped device name has "
|
||
"changed from %s to %s", mpp->wwid,
|
||
mpp->alias, new_alias);
|
||
strcpy(mpp->alias, new_alias);
|
||
-#if DAEMON
|
||
- if (mpp->waiter)
|
||
+
|
||
+ if (mpp->waiter)
|
||
strncpy(((struct event_thread *)mpp->waiter)->mapname,
|
||
new_alias, WWID_SIZE);
|
||
-#endif
|
||
goto retry;
|
||
}
|
||
condlog(0, "%s: failed to setup multipath", mpp->alias);
|
||
@@ -294,14 +324,13 @@ retry:
|
||
|
||
return 0;
|
||
out:
|
||
- remove_map(mpp, vecs, NULL, 1);
|
||
+ remove_map(mpp, vecs, PURGE_VEC);
|
||
return 1;
|
||
}
|
||
|
||
extern struct multipath *
|
||
add_map_without_path (struct vectors * vecs,
|
||
- int minor, char * alias,
|
||
- start_waiter_thread_func *start_waiter)
|
||
+ int minor, char * alias)
|
||
{
|
||
struct multipath * mpp = alloc_multipath();
|
||
|
||
@@ -315,18 +344,18 @@ add_map_without_path (struct vectors * vecs,
|
||
|
||
if (adopt_paths(vecs->pathvec, mpp))
|
||
goto out;
|
||
-
|
||
+
|
||
if (!vector_alloc_slot(vecs->mpvec))
|
||
goto out;
|
||
|
||
vector_set_slot(vecs->mpvec, mpp);
|
||
|
||
- if (start_waiter(mpp, vecs))
|
||
+ if (start_waiter_thread(mpp, vecs))
|
||
goto out;
|
||
|
||
return mpp;
|
||
out:
|
||
- remove_map(mpp, vecs, NULL, 1);
|
||
+ remove_map(mpp, vecs, PURGE_VEC);
|
||
return NULL;
|
||
}
|
||
|
||
@@ -359,7 +388,7 @@ add_map_with_path (struct vectors * vecs,
|
||
return mpp;
|
||
|
||
out:
|
||
- remove_map(mpp, vecs, NULL, add_vec);
|
||
+ remove_map(mpp, vecs, PURGE_VEC);
|
||
return NULL;
|
||
}
|
||
|
||
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
|
||
index 81d9eaa..19a2387 100644
|
||
--- a/libmultipath/structs_vec.h
|
||
+++ b/libmultipath/structs_vec.h
|
||
@@ -2,16 +2,11 @@
|
||
#define _STRUCTS_VEC_H
|
||
|
||
struct vectors {
|
||
-#if DAEMON
|
||
pthread_mutex_t *lock;
|
||
-#endif
|
||
vector pathvec;
|
||
vector mpvec;
|
||
};
|
||
|
||
-typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
|
||
-typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
|
||
-
|
||
void set_no_path_retry(struct multipath *mpp);
|
||
|
||
int adopt_paths (vector pathvec, struct multipath * mpp);
|
||
@@ -23,14 +18,13 @@ int update_mpp_paths(struct multipath * mpp, vector pathvec);
|
||
int setup_multipath (struct vectors * vecs, struct multipath * mpp);
|
||
int update_multipath_strings (struct multipath *mpp, vector pathvec);
|
||
|
||
-void remove_map (struct multipath * mpp, struct vectors * vecs,
|
||
- stop_waiter_thread_func *stop_waiter, int purge_vec);
|
||
-void remove_maps (struct vectors * vecs,
|
||
- stop_waiter_thread_func *stop_waiter);
|
||
+void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
|
||
+void remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs, int purge_vec);
|
||
+void remove_maps (struct vectors * vecs);
|
||
+void remove_maps_and_stop_waiters (struct vectors * vecs);
|
||
|
||
struct multipath * add_map_without_path (struct vectors * vecs,
|
||
- int minor, char * alias,
|
||
- start_waiter_thread_func *start_waiter);
|
||
+ int minor, char * alias);
|
||
struct multipath * add_map_with_path (struct vectors * vecs,
|
||
struct path * pp, int add_vec);
|
||
int update_multipath (struct vectors *vecs, char *mapname);
|
||
diff --git a/libmultipath/switchgroup.c b/libmultipath/switchgroup.c
|
||
index 757543f..58b08f6 100644
|
||
--- a/libmultipath/switchgroup.c
|
||
+++ b/libmultipath/switchgroup.c
|
||
@@ -2,21 +2,36 @@
|
||
* Copyright (c) 2005 Christophe Varoqui
|
||
* Copyright (c) 2005 Edward Goggin, EMC
|
||
*/
|
||
-#include <checkers.h>
|
||
-
|
||
+#include "checkers.h"
|
||
#include "vector.h"
|
||
#include "structs.h"
|
||
#include "switchgroup.h"
|
||
|
||
+extern void
|
||
+path_group_prio_update (struct pathgroup * pgp)
|
||
+{
|
||
+ int i;
|
||
+ int priority = 0;
|
||
+ struct path * pp;
|
||
+
|
||
+ if (!pgp->paths) {
|
||
+ pgp->priority = 0;
|
||
+ return;
|
||
+ }
|
||
+ vector_foreach_slot (pgp->paths, pp, i) {
|
||
+ if (pp->state != PATH_DOWN)
|
||
+ priority += pp->priority;
|
||
+ }
|
||
+ pgp->priority = priority;
|
||
+}
|
||
+
|
||
extern int
|
||
select_path_group (struct multipath * mpp)
|
||
{
|
||
- int i, j;
|
||
+ int i;
|
||
int highest = 0;
|
||
int bestpg = 1;
|
||
struct pathgroup * pgp;
|
||
- struct path * pp;
|
||
- int priority;
|
||
|
||
if (!mpp->pg)
|
||
return 1;
|
||
@@ -25,14 +40,7 @@ select_path_group (struct multipath * mpp)
|
||
if (!pgp->paths)
|
||
continue;
|
||
|
||
- priority = 0;
|
||
-
|
||
- vector_foreach_slot (pgp->paths, pp, j) {
|
||
- if (pp->state != PATH_DOWN)
|
||
- priority += pp->priority;
|
||
- }
|
||
- pgp->priority = priority;
|
||
-
|
||
+ path_group_prio_update(pgp);
|
||
if (pgp->priority > highest) {
|
||
highest = pgp->priority;
|
||
bestpg = i + 1;
|
||
diff --git a/libmultipath/switchgroup.h b/libmultipath/switchgroup.h
|
||
index edf6f24..9365e2e 100644
|
||
--- a/libmultipath/switchgroup.h
|
||
+++ b/libmultipath/switchgroup.h
|
||
@@ -1 +1,2 @@
|
||
+void path_group_prio_update (struct pathgroup * pgp);
|
||
int select_path_group (struct multipath * mpp);
|
||
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
|
||
index b9621ac..9f11b95 100644
|
||
--- a/libmultipath/sysfs.c
|
||
+++ b/libmultipath/sysfs.c
|
||
@@ -4,12 +4,12 @@
|
||
* 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 version 2 of the License.
|
||
- *
|
||
+ *
|
||
* 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.
|
||
- *
|
||
+ *
|
||
* You should have received a copy of the GNU General Public License along
|
||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
@@ -58,7 +58,7 @@ int sysfs_init(char *path, size_t len)
|
||
strlcpy(sysfs_path, path, len);
|
||
remove_trailing_chars(sysfs_path, '/');
|
||
} else
|
||
- strlcpy(sysfs_path, "/sys", len);
|
||
+ strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
|
||
dbg("sysfs_path='%s'", sysfs_path);
|
||
|
||
INIT_LIST_HEAD(&attr_list);
|
||
@@ -80,6 +80,7 @@ void sysfs_cleanup(void)
|
||
}
|
||
|
||
list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) {
|
||
+ list_del(&sysdev_loop->node);
|
||
free(sysdev_loop);
|
||
}
|
||
}
|
||
@@ -162,9 +163,23 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
||
int len;
|
||
char *pos;
|
||
|
||
+ /* we handle only these devpathes */
|
||
+ if (devpath != NULL &&
|
||
+ strncmp(devpath, "/devices/", 9) != 0 &&
|
||
+ strncmp(devpath, "/subsystem/", 11) != 0 &&
|
||
+ strncmp(devpath, "/module/", 8) != 0 &&
|
||
+ strncmp(devpath, "/bus/", 5) != 0 &&
|
||
+ strncmp(devpath, "/class/", 7) != 0 &&
|
||
+ strncmp(devpath, "/block/", 7) != 0) {
|
||
+ dbg("invalid devpath '%s'", devpath);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
dbg("open '%s'", devpath);
|
||
strlcpy(devpath_real, devpath, sizeof(devpath_real));
|
||
remove_trailing_chars(devpath_real, '/');
|
||
+ if (devpath[0] == '\0' )
|
||
+ return NULL;
|
||
|
||
/* if we got a link, resolve it to the real device */
|
||
strlcpy(path, sysfs_path, sizeof(path));
|
||
@@ -174,24 +189,26 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
||
dbg("stat '%s' failed: %s", path, strerror(errno));
|
||
list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
|
||
if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
|
||
- dbg("found vanished dev in cache '%s'", sysdev_loop->dev.devpath);
|
||
+ dbg("found vanished dev in cache '%s'",
|
||
+ sysdev_loop->dev.devpath);
|
||
return &sysdev_loop->dev;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
+
|
||
if (S_ISLNK(statbuf.st_mode)) {
|
||
if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
|
||
return NULL;
|
||
-
|
||
}
|
||
|
||
list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
|
||
if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
|
||
dbg("found dev in cache '%s'", sysdev_loop->dev.devpath);
|
||
- dev = &sysdev_loop->dev;
|
||
+ dev = &sysdev_loop->dev;
|
||
}
|
||
}
|
||
+
|
||
if(!dev) {
|
||
/* it is a new device */
|
||
dbg("new device '%s'", devpath_real);
|
||
@@ -217,33 +234,25 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
||
pos = strrchr(link_target, '/');
|
||
if (pos != NULL)
|
||
strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
|
||
- } else if (strncmp(dev->devpath, "/class/", 7) == 0) {
|
||
- /* get subsystem from class dir */
|
||
- strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem));
|
||
- pos = strchr(dev->subsystem, '/');
|
||
- if (pos != NULL)
|
||
- pos[0] = '\0';
|
||
- else
|
||
- dev->subsystem[0] = '\0';
|
||
- } else if (strncmp(dev->devpath, "/block/", 7) == 0) {
|
||
- strlcpy(dev->subsystem, "block", sizeof(dev->subsystem));
|
||
- } else if (strncmp(dev->devpath, "/devices/", 9) == 0) {
|
||
- /* get subsystem from "bus" link */
|
||
- strlcpy(link_path, sysfs_path, sizeof(link_path));
|
||
- strlcat(link_path, dev->devpath, sizeof(link_path));
|
||
- strlcat(link_path, "/bus", sizeof(link_path));
|
||
- len = readlink(link_path, link_target, sizeof(link_target));
|
||
- if (len > 0) {
|
||
- link_target[len] = '\0';
|
||
- dbg("bus link '%s' points to '%s'", link_path, link_target);
|
||
- pos = strrchr(link_target, '/');
|
||
- if (pos != NULL)
|
||
- strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
|
||
- }
|
||
} else if (strstr(dev->devpath, "/drivers/") != NULL) {
|
||
strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
|
||
} else if (strncmp(dev->devpath, "/module/", 8) == 0) {
|
||
strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
|
||
+ } else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) {
|
||
+ pos = strrchr(dev->devpath, '/');
|
||
+ if (pos == &dev->devpath[10])
|
||
+ strlcpy(dev->subsystem, "subsystem",
|
||
+ sizeof(dev->subsystem));
|
||
+ } else if (strncmp(dev->devpath, "/class/", 7) == 0) {
|
||
+ pos = strrchr(dev->devpath, '/');
|
||
+ if (pos == &dev->devpath[6])
|
||
+ strlcpy(dev->subsystem, "subsystem",
|
||
+ sizeof(dev->subsystem));
|
||
+ } else if (strncmp(dev->devpath, "/bus/", 5) == 0) {
|
||
+ pos = strrchr(dev->devpath, '/');
|
||
+ if (pos == &dev->devpath[4])
|
||
+ strlcpy(dev->subsystem, "subsystem",
|
||
+ sizeof(dev->subsystem));
|
||
}
|
||
|
||
/* get driver name */
|
||
@@ -258,6 +267,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
||
if (pos != NULL)
|
||
strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
|
||
}
|
||
+
|
||
return dev;
|
||
}
|
||
|
||
@@ -272,13 +282,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
||
if (dev->parent != NULL)
|
||
return dev->parent;
|
||
|
||
- /* requesting a parent is only valid for devices */
|
||
- if ((strncmp(dev->devpath, "/devices/", 9) != 0) &&
|
||
- (strncmp(dev->devpath, "/subsystem/", 11) != 0) &&
|
||
- (strncmp(dev->devpath, "/class/", 7) != 0) &&
|
||
- (strncmp(dev->devpath, "/block/", 7) != 0))
|
||
- return NULL;
|
||
-
|
||
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
|
||
dbg("'%s'", parent_devpath);
|
||
|
||
@@ -288,20 +291,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
||
return NULL;
|
||
pos[0] = '\0';
|
||
|
||
- /* are we at the top level of /devices */
|
||
- if (strcmp(parent_devpath, "/devices") == 0) {
|
||
- dbg("/devices top level");
|
||
- return NULL;
|
||
- }
|
||
-
|
||
- /* at the subsystems top level we want to follow the old-style "device" link */
|
||
- if (strncmp(parent_devpath, "/subsystem", 10) == 0) {
|
||
- pos = strrchr(parent_devpath, '/');
|
||
- if (pos == &parent_devpath[10] || pos == parent_devpath || strcmp(pos, "/devices") == 0) {
|
||
- dbg("/subsystem top level, look for device link");
|
||
- goto device_link;
|
||
- }
|
||
- }
|
||
if (strncmp(parent_devpath, "/class", 6) == 0) {
|
||
pos = strrchr(parent_devpath, '/');
|
||
if (pos == &parent_devpath[6] || pos == parent_devpath) {
|
||
@@ -314,6 +303,11 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
||
goto device_link;
|
||
}
|
||
|
||
+ /* are we at the top level? */
|
||
+ pos = strrchr(parent_devpath, '/');
|
||
+ if (pos == NULL || pos == parent_devpath)
|
||
+ return NULL;
|
||
+
|
||
/* get parent and remember it */
|
||
dev->parent = sysfs_device_get(parent_devpath);
|
||
return dev->parent;
|
||
@@ -375,6 +369,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
||
|
||
dbg("open '%s'/'%s'", devpath, attr_name);
|
||
sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
|
||
+ if(sysfs_len >= sizeof(path_full))
|
||
+ sysfs_len = sizeof(path_full) - 1;
|
||
path = &path_full[sysfs_len];
|
||
strlcat(path_full, devpath, sizeof(path_full));
|
||
strlcat(path_full, "/", sizeof(path_full));
|
||
@@ -419,8 +415,10 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
||
link_target[len] = '\0';
|
||
pos = strrchr(link_target, '/');
|
||
if (pos != NULL) {
|
||
- dbg("cache '%s' with link value '%s'", path_full, value);
|
||
- strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
|
||
+ dbg("cache '%s' with link value '%s'",
|
||
+ path_full, value);
|
||
+ strlcpy(attr->value_local, &pos[1],
|
||
+ sizeof(attr->value_local));
|
||
attr->value = attr->value_local;
|
||
}
|
||
}
|
||
@@ -438,7 +436,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
||
/* read attribute value */
|
||
fd = open(path_full, O_RDONLY);
|
||
if (fd < 0) {
|
||
- dbg("attribute '%s' does not exist", path_full);
|
||
+ dbg("attribute '%s' can not be opened: %s",
|
||
+ path_full, strerror(errno));
|
||
goto out;
|
||
}
|
||
size = read(fd, value, sizeof(value));
|
||
@@ -458,3 +457,95 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
||
out:
|
||
return attr->value;
|
||
}
|
||
+
|
||
+int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len,
|
||
+ const char *subsystem, const char *id)
|
||
+{
|
||
+ size_t sysfs_len;
|
||
+ char path_full[PATH_SIZE];
|
||
+ char *path;
|
||
+ struct stat statbuf;
|
||
+
|
||
+ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
|
||
+ path = &path_full[sysfs_len];
|
||
+
|
||
+ if (strcmp(subsystem, "subsystem") == 0) {
|
||
+ strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+
|
||
+ strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+ goto out;
|
||
+
|
||
+ strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+ }
|
||
+
|
||
+ if (strcmp(subsystem, "module") == 0) {
|
||
+ strlcpy(path, "/module/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ if (strcmp(subsystem, "drivers") == 0) {
|
||
+ char subsys[NAME_SIZE];
|
||
+ char *driver;
|
||
+
|
||
+ strlcpy(subsys, id, sizeof(subsys));
|
||
+ driver = strchr(subsys, ':');
|
||
+ if (driver != NULL) {
|
||
+ driver[0] = '\0';
|
||
+ driver = &driver[1];
|
||
+ strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, subsys, sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, driver, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+
|
||
+ strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, subsys, sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, driver, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+ }
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+
|
||
+ strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+
|
||
+ strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, "/", sizeof(path_full) - sysfs_len);
|
||
+ strlcat(path, id, sizeof(path_full) - sysfs_len);
|
||
+ if (stat(path_full, &statbuf) == 0)
|
||
+ goto found;
|
||
+out:
|
||
+ return 0;
|
||
+found:
|
||
+ if (S_ISLNK(statbuf.st_mode))
|
||
+ sysfs_resolve_link(path, sizeof(path_full) - sysfs_len);
|
||
+ strlcpy(devpath_full, path, len);
|
||
+ return 1;
|
||
+}
|
||
diff --git a/libmultipath/uxsock.c b/libmultipath/uxsock.c
|
||
index abb9f85..a070943 100644
|
||
--- a/libmultipath/uxsock.c
|
||
+++ b/libmultipath/uxsock.c
|
||
@@ -14,6 +14,7 @@
|
||
#include <sys/socket.h>
|
||
#include <sys/un.h>
|
||
#include <sys/poll.h>
|
||
+#include <signal.h>
|
||
#include <errno.h>
|
||
|
||
#include "memory.h"
|
||
@@ -127,9 +128,23 @@ size_t read_all(int fd, void *buf, size_t len)
|
||
*/
|
||
int send_packet(int fd, const char *buf, size_t len)
|
||
{
|
||
- if (write_all(fd, &len, sizeof(len)) != sizeof(len)) return -1;
|
||
- if (write_all(fd, buf, len) != len) return -1;
|
||
- return 0;
|
||
+ int ret = 0;
|
||
+ sigset_t set, old;
|
||
+
|
||
+ /* Block SIGPIPE */
|
||
+ sigemptyset(&set);
|
||
+ sigaddset(&set, SIGPIPE);
|
||
+ pthread_sigmask(SIG_BLOCK, &set, &old);
|
||
+
|
||
+ if (write_all(fd, &len, sizeof(len)) != sizeof(len))
|
||
+ ret = -1;
|
||
+ if (!ret && write_all(fd, buf, len) != len)
|
||
+ ret = -1;
|
||
+
|
||
+ /* And unblock it again */
|
||
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
|
||
+
|
||
+ return ret;
|
||
}
|
||
|
||
/*
|
||
diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
|
||
index 0223924..468ce5f 100644
|
||
--- a/libmultipath/waiter.h
|
||
+++ b/libmultipath/waiter.h
|
||
@@ -1,8 +1,6 @@
|
||
#ifndef _WAITER_H
|
||
#define _WAITER_H
|
||
|
||
-#if DAEMON
|
||
-
|
||
struct event_thread {
|
||
struct dm_task *dmt;
|
||
pthread_t thread;
|
||
@@ -19,5 +17,4 @@ 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 3caede6..b224779 100644
|
||
--- a/multipath-tools.spec.in
|
||
+++ b/multipath-tools.spec.in
|
||
@@ -22,7 +22,6 @@ are :
|
||
* multipath : scan the system for multipathed devices, assembles them
|
||
and update the device-mapper's maps
|
||
* multipathd : wait for maps events, then execs multipath
|
||
-* devmap-name : provides a meaningful device name to udev for devmaps
|
||
* kpartx : maps linear devmaps upon device partitions, which makes
|
||
multipath maps partionable
|
||
|
||
@@ -41,20 +40,10 @@ rm -rf $RPM_BUILD_ROOT
|
||
|
||
%files
|
||
%defattr(-,root,root,-)
|
||
-%{prefix}/sbin/devmap_name
|
||
%{prefix}/sbin/multipath
|
||
%{prefix}/sbin/kpartx
|
||
-%{prefix}/sbin/mpath_prio_alua
|
||
-%{prefix}/sbin/mpath_prio_emc
|
||
-%{prefix}/sbin/mpath_prio_random
|
||
-%{prefix}/sbin/mpath_prio_balance_units
|
||
-%{prefix}/sbin/mpath_prio_netapp
|
||
-%{prefix}/sbin/mpath_prio_rdac
|
||
-%{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
|
||
-%{prefix}/usr/share/man/man8/mpath_prio_alua.8.gz
|
||
%{prefix}/usr/share/man/man8/multipathd.8.gz
|
||
%{prefix}/sbin/multipathd
|
||
%{prefix}/etc/udev/rules.d/multipath.rules
|
||
diff --git a/multipath.conf.annotated b/multipath.conf.annotated
|
||
index e6cfe9a..49c9c5c 100644
|
||
--- a/multipath.conf.annotated
|
||
+++ b/multipath.conf.annotated
|
||
@@ -38,7 +38,7 @@
|
||
# # scope : multipath
|
||
# # desc : the default path grouping policy to apply to unspecified
|
||
# # multipaths
|
||
-# # default : multibus
|
||
+# # default : failover
|
||
# #
|
||
# path_grouping_policy multibus
|
||
#
|
||
@@ -52,14 +52,14 @@
|
||
# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n"
|
||
#
|
||
# #
|
||
-# # name : prio_callout
|
||
+# # name : prio
|
||
# # scope : multipath
|
||
-# # desc : the default program and args to callout to obtain a path
|
||
+# # desc : the default function to call to obtain a path
|
||
# # priority value. The ALUA bits in SPC-3 provide an
|
||
-# # exploitable prio value for example. "none" is a valid value
|
||
+# # exploitable prio value for example.
|
||
# # default : (null)
|
||
# #
|
||
-# #prio_callout "/bin/true"
|
||
+# #prio "alua"
|
||
#
|
||
# #
|
||
# # name : path_checker
|
||
@@ -80,6 +80,16 @@
|
||
# rr_min_io 100
|
||
#
|
||
# #
|
||
+# # name : max_fds
|
||
+# # scope : multipathd
|
||
+# # desc : Sets the maximum number of open file descriptors for the
|
||
+# # multipathd process.
|
||
+# # values : unlimited|n > 0
|
||
+# # default : None
|
||
+# #
|
||
+# max_fds 8192
|
||
+#
|
||
+# #
|
||
# # name : rr_weight
|
||
# # scope : multipath
|
||
# # desc : if set to priorities the multipath configurator will assign
|
||
@@ -96,9 +106,9 @@
|
||
# # 0 means immediate failback, values >0 means deffered failback
|
||
# # expressed in seconds.
|
||
# # values : manual|immediate|n > 0
|
||
-# # default : immediate
|
||
+# # default : manual
|
||
# #
|
||
-# failback manual
|
||
+# failback immediate
|
||
#
|
||
# #
|
||
# # name : no_path_retry
|
||
@@ -219,9 +229,9 @@
|
||
# # 0 means immediate failback, values >0 means deffered failback
|
||
# # expressed in seconds.
|
||
# # values : manual|immediate|n > 0
|
||
-# # default : immediate
|
||
+# # default : manual
|
||
# #
|
||
-# failback manual
|
||
+# failback immediate
|
||
#
|
||
# #
|
||
# # name : no_path_retry
|
||
@@ -296,15 +306,14 @@
|
||
# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n"
|
||
#
|
||
# #
|
||
-# # name : prio_callout
|
||
+# # name : prio
|
||
# # scope : multipath
|
||
-# # desc : the program and args to callout to obtain a path
|
||
+# # desc : the function to call to obtain a path
|
||
# # weight. Weights are summed for each path group to
|
||
# # determine the next PG to use case of failure.
|
||
-# # "none" is a valid value.
|
||
# # default : no callout, all paths equals
|
||
# #
|
||
-# prio_callout "/sbin/mpath_prio_balance_units %d"
|
||
+# prio "hp_sw"
|
||
#
|
||
# #
|
||
# # name : path_checker
|
||
@@ -331,7 +340,7 @@
|
||
# # 0 means immediate failback, values >0 means deffered failback
|
||
# # expressed in seconds.
|
||
# # values : manual|immediate|n > 0
|
||
-# # default : immediate
|
||
+# # default : manual
|
||
# #
|
||
# failback 30
|
||
#
|
||
diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
|
||
index 633d625..33f820b 100644
|
||
--- a/multipath.conf.synthetic
|
||
+++ b/multipath.conf.synthetic
|
||
@@ -8,9 +8,10 @@
|
||
# selector "round-robin 0"
|
||
# path_grouping_policy multibus
|
||
# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n"
|
||
-# prio_callout /bin/true
|
||
+# prio const
|
||
# path_checker directio
|
||
# rr_min_io 100
|
||
+# max_fds 8192
|
||
# rr_weight priorities
|
||
# failback immediate
|
||
# no_path_retry fail
|
||
diff --git a/multipath/02_multipath b/multipath/02_multipath
|
||
index 067c582..467a7cb 100755
|
||
--- a/multipath/02_multipath
|
||
+++ b/multipath/02_multipath
|
||
@@ -5,7 +5,6 @@
|
||
# this tool is statically linked against klibc : no additional libs
|
||
#
|
||
cp /sbin/multipath $INITRDDIR/sbin
|
||
-cp /sbin/devmap_name $INITRDDIR/sbin
|
||
cp /sbin/kpartx $INITRDDIR/sbin
|
||
|
||
#
|
||
diff --git a/multipath/Makefile b/multipath/Makefile
|
||
index 4923b2f..2d74ffe 100644
|
||
--- a/multipath/Makefile
|
||
+++ b/multipath/Makefile
|
||
@@ -1,52 +1,33 @@
|
||
# Makefile
|
||
#
|
||
# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
-BUILD = glibc
|
||
-
|
||
+#
|
||
include ../Makefile.inc
|
||
|
||
-OBJS = main.o $(MULTIPATHLIB)-$(BUILD).a $(CHECKERSLIB)-$(BUILD).a
|
||
+OBJS = main.o
|
||
|
||
-CFLAGS += -I$(multipathdir) -I$(checkersdir)
|
||
-LDFLAGS += -laio
|
||
-
|
||
-ifeq ($(strip $(BUILD)),klibc)
|
||
- OBJS += $(libdm)
|
||
-else
|
||
- LDFLAGS += -ldevmapper
|
||
-endif
|
||
+CFLAGS += -I$(multipathdir) -Wl,-rpath,$(libdir)
|
||
+LDFLAGS += -lpthread -ldevmapper -laio -ldl \
|
||
+ -lmultipath -L$(multipathdir)
|
||
|
||
EXEC = multipath
|
||
|
||
-all: $(BUILD)
|
||
+all: $(EXEC)
|
||
|
||
-prepare:
|
||
- make -C $(multipathdir) prepare
|
||
- rm -f core *.o *.gz
|
||
+$(EXEC): $(OBJS)
|
||
+ $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
||
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
||
$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
|
||
|
||
-glibc: prepare $(OBJS)
|
||
- $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
||
-
|
||
-klibc: prepare $(OBJS)
|
||
- $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
|
||
-
|
||
-$(CHECKERSLIB)-$(BUILD).a:
|
||
- make -C $(checkersdir) BUILD=$(BUILD) $(BUILD)
|
||
-
|
||
-$(MULTIPATHLIB)-$(BUILD).a:
|
||
- make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
|
||
-
|
||
install:
|
||
- install -d $(DESTDIR)$(bindir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||
- 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 -d $(DESTDIR)$(man5dir)
|
||
- install -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d
|
||
+ $(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
|
||
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
|
||
|
||
uninstall:
|
||
rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
|
||
diff --git a/multipath/main.c b/multipath/main.c
|
||
index 815c307..4c65808 100644
|
||
--- a/multipath/main.c
|
||
+++ b/multipath/main.c
|
||
@@ -27,6 +27,7 @@
|
||
#include <ctype.h>
|
||
|
||
#include <checkers.h>
|
||
+#include <prio.h>
|
||
#include <vector.h>
|
||
#include <memory.h>
|
||
#include <libdevmapper.h>
|
||
@@ -48,6 +49,8 @@
|
||
#include <pgpolicies.h>
|
||
#include <version.h>
|
||
|
||
+int logsink;
|
||
+
|
||
static int
|
||
filter_pathvec (vector pathvec, char * refwwid)
|
||
{
|
||
@@ -72,34 +75,39 @@ static void
|
||
usage (char * progname)
|
||
{
|
||
fprintf (stderr, VERSION_STRING);
|
||
- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n",
|
||
- progname);
|
||
+ fprintf (stderr, "Usage:\n");
|
||
+ fprintf (stderr, " %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname);
|
||
+ fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
|
||
+ fprintf (stderr, " %s -F [-v lvl]\n", progname);
|
||
+ fprintf (stderr, " %s -h\n", progname);
|
||
fprintf (stderr,
|
||
- "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
|
||
- "\t\t\t[device]\n" \
|
||
- "\n" \
|
||
- "\t-v level\tverbosity level\n" \
|
||
- "\t 0\t\t\tno output\n" \
|
||
- "\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" \
|
||
- "\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-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" \
|
||
- "\t group_by_serial\t1 priority group per serial\n" \
|
||
- "\t group_by_prio\t1 priority group per priority lvl\n" \
|
||
- "\t group_by_node_name\t1 priority group per target node\n" \
|
||
- "\n" \
|
||
- "\tdevice\t\tlimit scope to the device's multipath\n" \
|
||
- "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
|
||
- "\t\t\tor major:minor or a device map name)\n" \
|
||
+ "\n"
|
||
+ "Where:\n"
|
||
+ " -h print this usage text\n" \
|
||
+ " -l show multipath topology (sysfs and DM info)\n" \
|
||
+ " -ll show multipath topology (maximum info)\n" \
|
||
+ " -f flush a multipath device map\n" \
|
||
+ " -F flush all multipath device maps\n" \
|
||
+ " -d dry run, do not create or update devmaps\n" \
|
||
+ " -r force devmap reload\n" \
|
||
+ " -p policy failover|multibus|group_by_serial|group_by_prio\n" \
|
||
+ " -b fil bindings file location\n" \
|
||
+ " -p pol force all maps to specified path grouping policy :\n" \
|
||
+ " . failover one path per priority group\n" \
|
||
+ " . multibus all paths in one priority group\n" \
|
||
+ " . group_by_serial one priority group per serial\n" \
|
||
+ " . group_by_prio one priority group per priority lvl\n" \
|
||
+ " . group_by_node_name one priority group per target node\n" \
|
||
+ " -v lvl verbosity level\n" \
|
||
+ " . 0 no output\n" \
|
||
+ " . 1 print created devmap names only\n" \
|
||
+ " . 2 default verbosity\n" \
|
||
+ " . 3 print debug information\n" \
|
||
+ " dev action limited to:\n" \
|
||
+ " . multipath named 'dev' (ex: mpath0) or\n" \
|
||
+ " . multipath whose wwid is 'dev' (ex: 60051..)\n" \
|
||
+ " . multipath including the path named 'dev' (ex: /dev/sda)\n" \
|
||
+ " . multipath including the path with maj:min 'dev' (ex: 8:0)\n" \
|
||
);
|
||
|
||
exit(1);
|
||
@@ -149,7 +157,7 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
|
||
int i;
|
||
struct multipath * mpp;
|
||
|
||
- if (dm_get_maps(curmp, DEFAULT_TARGET))
|
||
+ if (dm_get_maps(curmp))
|
||
return 1;
|
||
|
||
vector_foreach_slot (curmp, mpp, i) {
|
||
@@ -280,7 +288,7 @@ configure (void)
|
||
if (conf->verbosity > 2)
|
||
print_all_paths(pathvec, 1);
|
||
|
||
- get_path_layout(pathvec);
|
||
+ get_path_layout(pathvec, 1);
|
||
|
||
if (get_dm_mpvec(curmp, pathvec, refwwid))
|
||
goto out;
|
||
@@ -295,7 +303,7 @@ configure (void)
|
||
/*
|
||
* core logic entry point
|
||
*/
|
||
- r = coalesce_paths(&vecs, NULL, NULL);
|
||
+ r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload);
|
||
|
||
out:
|
||
if (refwwid)
|
||
@@ -320,17 +328,25 @@ main (int argc, char *argv[])
|
||
exit(1);
|
||
}
|
||
|
||
- if (dm_prereq(DEFAULT_TARGET))
|
||
+ if (dm_prereq())
|
||
exit(1);
|
||
|
||
if (load_config(DEFAULT_CONFIGFILE))
|
||
exit(1);
|
||
|
||
+ if (init_checkers()) {
|
||
+ condlog(0, "failed to initialize checkers");
|
||
+ exit(1);
|
||
+ }
|
||
+ if (init_prio()) {
|
||
+ condlog(0, "failed to initialize prioritizers");
|
||
+ exit(1);
|
||
+ }
|
||
if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
|
||
condlog(0, "multipath tools need sysfs mounted");
|
||
exit(1);
|
||
}
|
||
- while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) {
|
||
+ while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:r")) != EOF ) {
|
||
switch(arg) {
|
||
case 1: printf("optarg : %s\n",optarg);
|
||
break;
|
||
@@ -373,6 +389,9 @@ main (int argc, char *argv[])
|
||
usage(argv[0]);
|
||
}
|
||
break;
|
||
+ case 'r':
|
||
+ conf->force_reload = 1;
|
||
+ break;
|
||
case 'h':
|
||
usage(argv[0]);
|
||
case ':':
|
||
@@ -405,14 +424,14 @@ main (int argc, char *argv[])
|
||
|
||
if (conf->remove == FLUSH_ONE) {
|
||
if (conf->dev_type == DEV_DEVMAP)
|
||
- dm_flush_map(conf->dev, DEFAULT_TARGET);
|
||
+ dm_flush_map(conf->dev);
|
||
else
|
||
condlog(0, "must provide a map name to remove");
|
||
|
||
goto out;
|
||
}
|
||
else if (conf->remove == FLUSH_ALL) {
|
||
- dm_flush_maps(DEFAULT_TARGET);
|
||
+ dm_flush_maps();
|
||
goto out;
|
||
}
|
||
while ((r = configure()) < 0)
|
||
@@ -420,9 +439,17 @@ main (int argc, char *argv[])
|
||
|
||
out:
|
||
sysfs_cleanup();
|
||
- free_config(conf);
|
||
dm_lib_release();
|
||
dm_lib_exit();
|
||
+
|
||
+ /*
|
||
+ * Freeing config must be done after dm_lib_exit(), because
|
||
+ * the logging function (dm_write_log()), which is called there,
|
||
+ * references the config.
|
||
+ */
|
||
+ free_config(conf);
|
||
+ conf = NULL;
|
||
+
|
||
#ifdef _DEBUG_
|
||
dbg_free_final(NULL);
|
||
#endif
|
||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||
index c8ab6b0..c66d7fc 100644
|
||
--- a/multipath/multipath.conf.5
|
||
+++ b/multipath/multipath.conf.5
|
||
@@ -374,6 +374,15 @@ section:
|
||
.RE
|
||
.PD
|
||
.LP
|
||
+.SH "KNOWN ISSUES"
|
||
+The usage of
|
||
+.B queue_if_no_path
|
||
+option can lead to
|
||
+.B D state
|
||
+processes being hung and not killable in situations where all the paths to the LUN go offline.
|
||
+It is advisable to use the
|
||
+.B no_path_retry
|
||
+option instead.
|
||
.SH "SEE ALSO"
|
||
.BR udev (8),
|
||
.BR dmsetup (8)
|
||
diff --git a/multipathd/Makefile b/multipathd/Makefile
|
||
index b430b94..b1af76c 100644
|
||
--- a/multipathd/Makefile
|
||
+++ b/multipathd/Makefile
|
||
@@ -1,4 +1,3 @@
|
||
-BUILD = glibc
|
||
EXEC = multipathd
|
||
|
||
include ../Makefile.inc
|
||
@@ -6,8 +5,9 @@ include ../Makefile.inc
|
||
#
|
||
# basic flags setting
|
||
#
|
||
-CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
|
||
-LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses -laio
|
||
+CFLAGS += -I$(multipathdir) -Wl,-rpath,$(libdir)
|
||
+LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -laio -ldl \
|
||
+ -lmultipath -L$(multipathdir)
|
||
|
||
#
|
||
# debuging stuff
|
||
@@ -19,36 +19,24 @@ LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses -laio
|
||
#
|
||
# object files
|
||
#
|
||
-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
|
||
- $(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
|
||
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
|
||
|
||
|
||
#
|
||
# directives
|
||
#
|
||
-all : $(BUILD)
|
||
+all : $(EXEC)
|
||
|
||
-glibc: $(EXEC)
|
||
-
|
||
-klibc:
|
||
- $(MAKE) BUILD=glibc glibc
|
||
-
|
||
-$(EXEC): clean $(OBJS)
|
||
- $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
||
+$(EXEC): $(OBJS)
|
||
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(EXEC) $(OBJS)
|
||
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
|
||
|
||
-$(CHECKERSLIB)-glibc.a:
|
||
- $(MAKE) -C $(checkersdir) BUILD=glibc glibc
|
||
-
|
||
-$(MULTIPATHLIB)-glibc.a:
|
||
- $(MAKE) -C $(multipathdir) DAEMON=1 BUILD=glibc glibc
|
||
-
|
||
install:
|
||
- install -d $(DESTDIR)$(bindir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
|
||
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
||
- install -d $(DESTDIR)$(rcdir)
|
||
- install -d $(DESTDIR)$(mandir)
|
||
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(rcdir)
|
||
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
|
||
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
|
||
|
||
uninstall:
|
||
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
||
@@ -56,6 +44,5 @@ uninstall:
|
||
rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
||
|
||
clean:
|
||
- $(MAKE) -C $(multipathdir) prepare DAEMON=1
|
||
rm -f core *.o $(EXEC) *.gz
|
||
|
||
diff --git a/multipathd/cli.c b/multipathd/cli.c
|
||
index d786eef..7eaac73 100644
|
||
--- a/multipathd/cli.c
|
||
+++ b/multipathd/cli.c
|
||
@@ -3,6 +3,7 @@
|
||
*/
|
||
#include <memory.h>
|
||
#include <vector.h>
|
||
+#include <parser.h>
|
||
#include <util.h>
|
||
#include <version.h>
|
||
#include <readline/readline.h>
|
||
@@ -168,6 +169,7 @@ load_keys (void)
|
||
r += add_key(keys, "config", CONFIG, 0);
|
||
r += add_key(keys, "blacklist", BLACKLIST, 0);
|
||
r += add_key(keys, "devices", DEVICES, 0);
|
||
+ r += add_key(keys, "format", FMT, 1);
|
||
|
||
if (r) {
|
||
free_keys(keys);
|
||
@@ -210,13 +212,17 @@ find_key (const char * str)
|
||
static int
|
||
get_cmdvec (char * cmd, vector *v)
|
||
{
|
||
- int fwd = 1;
|
||
+ int i;
|
||
int r = 0;
|
||
- char * p = cmd;
|
||
+ int get_param = 0;
|
||
char * buff;
|
||
struct key * kw = NULL;
|
||
struct key * cmdkw = NULL;
|
||
- vector cmdvec;
|
||
+ vector cmdvec, strvec;
|
||
+
|
||
+ strvec = alloc_strvec(cmd);
|
||
+ if (!strvec)
|
||
+ return 0;
|
||
|
||
cmdvec = vector_alloc();
|
||
*v = cmdvec;
|
||
@@ -224,21 +230,20 @@ get_cmdvec (char * cmd, vector *v)
|
||
if (!cmdvec)
|
||
return E_NOMEM;
|
||
|
||
- while (fwd) {
|
||
- fwd = get_word(p, &buff);
|
||
-
|
||
- if (!buff)
|
||
- break;
|
||
-
|
||
- p += fwd;
|
||
+ vector_foreach_slot(strvec, buff, i) {
|
||
+ if (*buff == '"')
|
||
+ continue;
|
||
+ if (get_param) {
|
||
+ get_param = 0;
|
||
+ cmdkw->param = strdup(buff);
|
||
+ continue;
|
||
+ }
|
||
kw = find_key(buff);
|
||
- FREE(buff);
|
||
-
|
||
- if (!kw)
|
||
- return E_SYNTAX;
|
||
-
|
||
+ if (!kw) {
|
||
+ r = E_SYNTAX;
|
||
+ goto out;
|
||
+ }
|
||
cmdkw = alloc_key();
|
||
-
|
||
if (!cmdkw) {
|
||
r = E_NOMEM;
|
||
goto out;
|
||
@@ -251,23 +256,17 @@ get_cmdvec (char * cmd, vector *v)
|
||
vector_set_slot(cmdvec, cmdkw);
|
||
cmdkw->code = kw->code;
|
||
cmdkw->has_param = kw->has_param;
|
||
-
|
||
- if (kw->has_param) {
|
||
- if (*p == '\0')
|
||
- goto out;
|
||
-
|
||
- fwd = get_word(p, &buff);
|
||
-
|
||
- if (!buff)
|
||
- return E_NOPARM;
|
||
-
|
||
- p += fwd;
|
||
- cmdkw->param = buff;
|
||
- }
|
||
+ if (kw->has_param)
|
||
+ get_param = 1;
|
||
+ }
|
||
+ if (get_param) {
|
||
+ r = E_NOPARM;
|
||
+ goto out;
|
||
}
|
||
return 0;
|
||
|
||
out:
|
||
+ free_strvec(strvec);
|
||
free_keys(cmdvec);
|
||
*v = NULL;
|
||
return r;
|
||
@@ -406,6 +405,7 @@ cli_init (void) {
|
||
return 1;
|
||
|
||
add_handler(LIST+PATHS, NULL);
|
||
+ add_handler(LIST+PATHS+FMT, NULL);
|
||
add_handler(LIST+MAPS, NULL);
|
||
add_handler(LIST+MAPS+STATUS, NULL);
|
||
add_handler(LIST+MAPS+STATS, NULL);
|
||
diff --git a/multipathd/cli.h b/multipathd/cli.h
|
||
index a2397df..8c83eab 100644
|
||
--- a/multipathd/cli.h
|
||
+++ b/multipathd/cli.h
|
||
@@ -19,6 +19,7 @@ enum {
|
||
__CONFIG,
|
||
__BLACKLIST,
|
||
__DEVICES,
|
||
+ __FMT,
|
||
};
|
||
|
||
#define LIST (1 << __LIST)
|
||
@@ -41,6 +42,7 @@ enum {
|
||
#define CONFIG (1 << __CONFIG)
|
||
#define BLACKLIST (1 << __BLACKLIST)
|
||
#define DEVICES (1 << __DEVICES)
|
||
+#define FMT (1 << __FMT)
|
||
|
||
#define INITIAL_REPLY_LEN 1000
|
||
|
||
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
||
index 7bae02a..c84805a 100644
|
||
--- a/multipathd/cli_handlers.c
|
||
+++ b/multipathd/cli_handlers.c
|
||
@@ -28,7 +28,7 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style)
|
||
unsigned int maxlen = INITIAL_REPLY_LEN;
|
||
int again = 1;
|
||
|
||
- get_path_layout(vecs->pathvec);
|
||
+ get_path_layout(vecs->pathvec, 1);
|
||
reply = MALLOC(maxlen);
|
||
|
||
while (again) {
|
||
@@ -94,7 +94,7 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
|
||
unsigned int maxlen = INITIAL_REPLY_LEN;
|
||
int again = 1;
|
||
|
||
- get_path_layout(vecs->pathvec);
|
||
+ get_path_layout(vecs->pathvec, 0);
|
||
reply = MALLOC(maxlen);
|
||
|
||
while (again) {
|
||
@@ -185,13 +185,24 @@ cli_list_paths (void * v, char ** reply, int * len, void * data)
|
||
}
|
||
|
||
int
|
||
+cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
|
||
+{
|
||
+ struct vectors * vecs = (struct vectors *)data;
|
||
+ char * fmt = get_keyparam(v, FMT);
|
||
+
|
||
+ condlog(3, "list paths (operator)");
|
||
+
|
||
+ return show_paths(reply, len, vecs, fmt);
|
||
+}
|
||
+
|
||
+int
|
||
cli_list_map_topology (void * v, char ** reply, int * len, void * data)
|
||
{
|
||
struct multipath * mpp;
|
||
struct vectors * vecs = (struct vectors *)data;
|
||
char * param = get_keyparam(v, MAP);
|
||
|
||
- get_path_layout(vecs->pathvec);
|
||
+ get_path_layout(vecs->pathvec, 0);
|
||
mpp = find_mp_by_str(vecs->mpvec, param);
|
||
|
||
if (!mpp)
|
||
@@ -222,7 +233,7 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style)
|
||
unsigned int maxlen = INITIAL_REPLY_LEN;
|
||
int again = 1;
|
||
|
||
- get_multipath_layout(vecs->mpvec);
|
||
+ get_multipath_layout(vecs->mpvec, 1);
|
||
reply = MALLOC(maxlen);
|
||
|
||
while (again) {
|
||
@@ -431,6 +442,7 @@ cli_reinstate(void * v, char ** reply, int * len, void * data)
|
||
condlog(2, "%s: reinstate path %s (operator)",
|
||
pp->mpp->alias, pp->dev_t);
|
||
|
||
+ checker_enable(&pp->checker);
|
||
return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
|
||
}
|
||
|
||
@@ -440,6 +452,7 @@ cli_fail(void * v, char ** reply, int * len, void * data)
|
||
struct vectors * vecs = (struct vectors *)data;
|
||
char * param = get_keyparam(v, PATH);
|
||
struct path * pp;
|
||
+ int r;
|
||
|
||
pp = find_path_by_dev(vecs->pathvec, param);
|
||
|
||
@@ -452,7 +465,13 @@ cli_fail(void * v, char ** reply, int * len, void * data)
|
||
condlog(2, "%s: fail path %s (operator)",
|
||
pp->mpp->alias, pp->dev_t);
|
||
|
||
- return dm_fail_path(pp->mpp->alias, pp->dev_t);
|
||
+ r = dm_fail_path(pp->mpp->alias, pp->dev_t);
|
||
+ /*
|
||
+ * Suspend path checking to avoid auto-reinstating the path
|
||
+ */
|
||
+ if (!r)
|
||
+ checker_disable(&pp->checker);
|
||
+ return r;
|
||
}
|
||
|
||
int
|
||
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
|
||
index 863694b..a688481 100644
|
||
--- a/multipathd/cli_handlers.h
|
||
+++ b/multipathd/cli_handlers.h
|
||
@@ -1,4 +1,5 @@
|
||
int cli_list_paths (void * v, char ** reply, int * len, void * data);
|
||
+int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data);
|
||
int cli_list_maps (void * v, char ** reply, int * len, void * data);
|
||
int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
|
||
int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
|
||
diff --git a/multipathd/main.c b/multipathd/main.c
|
||
index da5fd8f..8d74cb9 100644
|
||
--- a/multipathd/main.c
|
||
+++ b/multipathd/main.c
|
||
@@ -12,6 +12,8 @@
|
||
#include <sys/types.h>
|
||
#include <fcntl.h>
|
||
#include <errno.h>
|
||
+#include <sys/time.h>
|
||
+#include <sys/resource.h>
|
||
|
||
/*
|
||
* libcheckers
|
||
@@ -43,6 +45,7 @@
|
||
#include <switchgroup.h>
|
||
#include <print.h>
|
||
#include <configure.h>
|
||
+#include <prio.h>
|
||
|
||
#include "main.h"
|
||
#include "pidfile.h"
|
||
@@ -62,6 +65,8 @@
|
||
pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
|
||
pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
||
+int logsink;
|
||
+
|
||
/*
|
||
* global copy of vecs for use in sig handlers
|
||
*/
|
||
@@ -116,7 +121,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
|
||
* remove all current maps not allowed by the
|
||
* current configuration
|
||
*/
|
||
- if (dm_flush_map(ompp->alias, DEFAULT_TARGET)) {
|
||
+ if (dm_flush_map(ompp->alias)) {
|
||
condlog(0, "%s: unable to flush devmap",
|
||
ompp->alias);
|
||
/*
|
||
@@ -135,7 +140,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
|
||
}
|
||
else {
|
||
dm_lib_release();
|
||
- condlog(3, "%s devmap removed", ompp->alias);
|
||
+ condlog(2, "%s devmap removed", ompp->alias);
|
||
}
|
||
}
|
||
}
|
||
@@ -149,6 +154,9 @@ sync_map_state(struct multipath *mpp)
|
||
struct path *pp;
|
||
unsigned int i, j;
|
||
|
||
+ if (!mpp->pg)
|
||
+ return;
|
||
+
|
||
vector_foreach_slot (mpp->pg, pgp, i){
|
||
vector_foreach_slot (pgp->paths, pp, j){
|
||
if (pp->state <= PATH_UNCHECKED)
|
||
@@ -183,7 +191,7 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
|
||
* clear references to this map before flushing so we can ignore
|
||
* the spurious uevent we may generate with the dm_flush_map call below
|
||
*/
|
||
- if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) {
|
||
+ if (dm_flush_map(mpp->alias)) {
|
||
/*
|
||
* May not really be an error -- if the map was already flushed
|
||
* from the device mapper by dmsetup(8) for instance.
|
||
@@ -193,11 +201,11 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
|
||
}
|
||
else {
|
||
dm_lib_release();
|
||
- condlog(3, "%s: devmap removed", mpp->alias);
|
||
+ condlog(2, "%s: devmap removed", mpp->alias);
|
||
}
|
||
|
||
orphan_paths(vecs->pathvec, mpp);
|
||
- remove_map(mpp, vecs, stop_waiter_thread, 1);
|
||
+ remove_map_and_stop_waiter(mpp, vecs, 1);
|
||
|
||
return 0;
|
||
}
|
||
@@ -232,7 +240,7 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
|
||
|
||
map_present = dm_map_present(alias);
|
||
|
||
- if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
|
||
+ if (map_present && dm_type(alias, TGT_MPATH) <= 0) {
|
||
condlog(4, "%s: not a multipath map", alias);
|
||
return 0;
|
||
}
|
||
@@ -253,21 +261,20 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
|
||
/*
|
||
* now we can register the map
|
||
*/
|
||
- if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
|
||
- start_waiter_thread))) {
|
||
+ if (map_present && (mpp = add_map_without_path(vecs, minor, alias))) {
|
||
sync_map_state(mpp);
|
||
- condlog(3, "%s: devmap %s added", alias, dev->kernel);
|
||
+ condlog(2, "%s: devmap %s added", alias, dev->kernel);
|
||
return 0;
|
||
}
|
||
refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec);
|
||
|
||
if (refwwid) {
|
||
- r = coalesce_paths(vecs, NULL, refwwid);
|
||
+ r = coalesce_paths(vecs, NULL, refwwid, 0);
|
||
dm_lib_release();
|
||
}
|
||
|
||
if (!r)
|
||
- condlog(3, "%s: devmap %s added", alias, dev->kernel);
|
||
+ condlog(2, "%s: devmap %s added", alias, dev->kernel);
|
||
else
|
||
condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel);
|
||
|
||
@@ -290,7 +297,7 @@ ev_remove_map (char * devname, struct vectors * vecs)
|
||
mpp = find_mp_by_str(vecs->mpvec, devname);
|
||
|
||
if (!mpp) {
|
||
- condlog(3, "%s: devmap not registered, can't remove",
|
||
+ condlog(2, "%s: devmap not registered, can't remove",
|
||
devname);
|
||
return 0;
|
||
}
|
||
@@ -368,7 +375,7 @@ ev_add_path (char * devname, struct vectors * vecs)
|
||
condlog(0, "%s: failed to get path uid", devname);
|
||
return 1; /* leave path added to pathvec */
|
||
}
|
||
- if (filter_path(conf, pp)){
|
||
+ if (filter_path(conf, pp) > 0){
|
||
int i = find_slot(vecs->pathvec, (void *)pp);
|
||
if (i != -1)
|
||
vector_del_slot(vecs->pathvec, i);
|
||
@@ -431,11 +438,11 @@ rescan:
|
||
start_waiter_thread(mpp, vecs))
|
||
goto out;
|
||
|
||
- condlog(3, "%s path added to devmap %s", devname, mpp->alias);
|
||
+ condlog(2, "%s path added to devmap %s", devname, mpp->alias);
|
||
return 0;
|
||
|
||
out:
|
||
- remove_map(mpp, vecs, NULL, 1);
|
||
+ remove_map(mpp, vecs, 1);
|
||
return 1;
|
||
}
|
||
|
||
@@ -457,8 +464,7 @@ ev_remove_path (char * devname, struct vectors * vecs)
|
||
{
|
||
struct multipath * mpp;
|
||
struct path * pp;
|
||
- int i;
|
||
- int rm_path = 1;
|
||
+ int i, retval = 0;
|
||
|
||
pp = find_path_by_dev(vecs->pathvec, devname);
|
||
|
||
@@ -468,100 +474,81 @@ ev_remove_path (char * devname, struct vectors * vecs)
|
||
}
|
||
|
||
/*
|
||
- * avoid referring to the map of an orphanned path
|
||
+ * avoid referring to the map of an orphaned path
|
||
*/
|
||
if ((mpp = pp->mpp)) {
|
||
+ /*
|
||
+ * transform the mp->pg vector of vectors of paths
|
||
+ * into a mp->params string to feed the device-mapper
|
||
+ */
|
||
+ if (update_mpp_paths(mpp, vecs->pathvec)) {
|
||
+ condlog(0, "%s: failed to update paths",
|
||
+ mpp->alias);
|
||
+ goto out;
|
||
+ }
|
||
+ if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
|
||
+ vector_del_slot(mpp->paths, i);
|
||
|
||
/*
|
||
* remove the map IFF removing the last path
|
||
*/
|
||
- if (pathcount(mpp, PATH_WILD) > 1) {
|
||
- vector rpvec = vector_alloc();
|
||
+ if (VECTOR_SIZE(mpp->paths) == 0) {
|
||
+ char alias[WWID_SIZE];
|
||
|
||
/*
|
||
- * transform the mp->pg vector of vectors of paths
|
||
- * into a mp->params string to feed the device-mapper
|
||
+ * flush_map will fail if the device is open
|
||
*/
|
||
- update_mpp_paths(mpp, vecs->pathvec);
|
||
- if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
|
||
- vector_del_slot(mpp->paths, i);
|
||
-
|
||
- if (VECTOR_SIZE(mpp->paths) == 0) {
|
||
- char alias[WWID_SIZE];
|
||
-
|
||
- /*
|
||
- * flush_map will fail if the device is open
|
||
- */
|
||
- strncpy(alias, mpp->alias, WWID_SIZE);
|
||
- if (flush_map(mpp, vecs))
|
||
- rm_path = 0;
|
||
- else
|
||
- condlog(3, "%s: removed map after removing"
|
||
- " multiple paths", alias);
|
||
- }
|
||
- else {
|
||
- if (setup_map(mpp)) {
|
||
- condlog(0, "%s: failed to setup map for"
|
||
- " removal of path %s", mpp->alias, devname);
|
||
- free_pathvec(rpvec, KEEP_PATHS);
|
||
- goto out;
|
||
- }
|
||
- /*
|
||
- * reload the map
|
||
- */
|
||
- mpp->action = ACT_RELOAD;
|
||
- if (domap(mpp) <= 0) {
|
||
- condlog(0, "%s: failed in domap for "
|
||
- "removal of path %s",
|
||
- mpp->alias, devname);
|
||
- /*
|
||
- * Delete path from pathvec so that
|
||
- * update_mpp_paths wont find it later
|
||
- * when/if another path is removed.
|
||
- */
|
||
- if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
|
||
- vector_del_slot(vecs->pathvec, i);
|
||
- free_path(pp);
|
||
- return 1;
|
||
- }
|
||
- /*
|
||
- * update our state from kernel
|
||
- */
|
||
- if (setup_multipath(vecs, mpp)) {
|
||
- free_pathvec(rpvec, KEEP_PATHS);
|
||
- goto out;
|
||
- }
|
||
- sync_map_state(mpp);
|
||
-
|
||
- condlog(3, "%s: path removed from map %s",
|
||
- devname, mpp->alias);
|
||
+ strncpy(alias, mpp->alias, WWID_SIZE);
|
||
+ if (!flush_map(mpp, vecs)) {
|
||
+ condlog(2, "%s: removed map after"
|
||
+ " removing all paths",
|
||
+ alias);
|
||
+ free_path(pp);
|
||
+ return 0;
|
||
}
|
||
- free_pathvec(rpvec, KEEP_PATHS);
|
||
+ /*
|
||
+ * Not an error, continue
|
||
+ */
|
||
}
|
||
- else {
|
||
- char alias[WWID_SIZE];
|
||
|
||
+ if (setup_map(mpp)) {
|
||
+ condlog(0, "%s: failed to setup map for"
|
||
+ " removal of path %s", mpp->alias,
|
||
+ devname);
|
||
+ goto out;
|
||
+ }
|
||
+ /*
|
||
+ * reload the map
|
||
+ */
|
||
+ mpp->action = ACT_RELOAD;
|
||
+ if (domap(mpp) <= 0) {
|
||
+ condlog(0, "%s: failed in domap for "
|
||
+ "removal of path %s",
|
||
+ mpp->alias, devname);
|
||
+ retval = 1;
|
||
+ } else {
|
||
/*
|
||
- * flush_map will fail if the device is open
|
||
+ * update our state from kernel
|
||
*/
|
||
- strncpy(alias, mpp->alias, WWID_SIZE);
|
||
- if (flush_map(mpp, vecs))
|
||
- rm_path = 0;
|
||
- else
|
||
- condlog(3, "%s: removed map", alias);
|
||
+ if (setup_multipath(vecs, mpp)) {
|
||
+ goto out;
|
||
+ }
|
||
+ sync_map_state(mpp);
|
||
+
|
||
+ condlog(2, "%s: path removed from map %s",
|
||
+ devname, mpp->alias);
|
||
}
|
||
}
|
||
|
||
- if (rm_path) {
|
||
- if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
|
||
- vector_del_slot(vecs->pathvec, i);
|
||
- free_path(pp);
|
||
- }
|
||
+ if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
|
||
+ vector_del_slot(vecs->pathvec, i);
|
||
|
||
- return 0;
|
||
+ free_path(pp);
|
||
+
|
||
+ return retval;
|
||
|
||
out:
|
||
- remove_map(mpp, vecs, stop_waiter_thread, 1);
|
||
+ remove_map_and_stop_waiter(mpp, vecs, 1);
|
||
return 1;
|
||
}
|
||
|
||
@@ -571,7 +558,7 @@ map_discovery (struct vectors * vecs)
|
||
struct multipath * mpp;
|
||
unsigned int i;
|
||
|
||
- if (dm_get_maps(vecs->mpvec, "multipath"))
|
||
+ if (dm_get_maps(vecs->mpvec))
|
||
return 1;
|
||
|
||
vector_foreach_slot (vecs->mpvec, mpp, i)
|
||
@@ -704,6 +691,7 @@ uxlsnrloop (void * ap)
|
||
return NULL;
|
||
|
||
set_handler_callback(LIST+PATHS, cli_list_paths);
|
||
+ set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
|
||
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);
|
||
@@ -809,7 +797,7 @@ mpvec_garbage_collector (struct vectors * vecs)
|
||
vector_foreach_slot (vecs->mpvec, mpp, i) {
|
||
if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
|
||
condlog(2, "%s: remove dead map", mpp->alias);
|
||
- remove_map(mpp, vecs, stop_waiter_thread, 1);
|
||
+ remove_map_and_stop_waiter(mpp, vecs, 1);
|
||
i--;
|
||
}
|
||
}
|
||
@@ -852,171 +840,182 @@ retry_count_tick(vector mpvec)
|
||
}
|
||
}
|
||
|
||
-static void *
|
||
-checkerloop (void *ap)
|
||
+void
|
||
+check_path (struct vectors * vecs, struct path * pp)
|
||
{
|
||
- struct vectors *vecs;
|
||
- struct path *pp;
|
||
- int count = 0;
|
||
int newstate;
|
||
- unsigned int i;
|
||
|
||
- mlockall(MCL_CURRENT | MCL_FUTURE);
|
||
- vecs = (struct vectors *)ap;
|
||
- condlog(2, "path checkers start up");
|
||
+ if (!pp->mpp)
|
||
+ return;
|
||
+
|
||
+ if (pp->tick && --pp->tick)
|
||
+ return; /* don't check this path yet */
|
||
|
||
/*
|
||
- * init the path check interval
|
||
+ * provision a next check soonest,
|
||
+ * in case we exit abnormaly from here
|
||
*/
|
||
- vector_foreach_slot (vecs->pathvec, pp, i) {
|
||
- pp->checkint = conf->checkint;
|
||
+ pp->tick = conf->checkint;
|
||
+
|
||
+ if (!checker_selected(&pp->checker)) {
|
||
+ pathinfo(pp, conf->hwtable, DI_SYSFS);
|
||
+ select_checker(pp);
|
||
}
|
||
+ if (!checker_selected(&pp->checker)) {
|
||
+ condlog(0, "%s: checker is not set", pp->dev);
|
||
+ return;
|
||
+ }
|
||
+ /*
|
||
+ * Set checker in async mode.
|
||
+ * Honored only by checker implementing the said mode.
|
||
+ */
|
||
+ checker_set_async(&pp->checker);
|
||
|
||
- while (1) {
|
||
- pthread_cleanup_push(cleanup_lock, vecs->lock);
|
||
- lock(vecs->lock);
|
||
- condlog(4, "tick");
|
||
+ newstate = checker_check(&pp->checker);
|
||
|
||
- vector_foreach_slot (vecs->pathvec, pp, i) {
|
||
- if (!pp->mpp)
|
||
- continue;
|
||
+ if (newstate < 0) {
|
||
+ condlog(2, "%s: unusable path", pp->dev);
|
||
+ pathinfo(pp, conf->hwtable, 0);
|
||
+ return;
|
||
+ }
|
||
+ /*
|
||
+ * Async IO in flight. Keep the previous path state
|
||
+ * and reschedule as soon as possible
|
||
+ */
|
||
+ if (newstate == PATH_PENDING) {
|
||
+ pp->tick = 1;
|
||
+ return;
|
||
+ }
|
||
+ if (newstate != pp->state) {
|
||
+ int oldstate = pp->state;
|
||
+ pp->state = newstate;
|
||
+ LOG_MSG(1, checker_message(&pp->checker));
|
||
|
||
- if (pp->tick && --pp->tick)
|
||
- continue; /* don't check this path yet */
|
||
+ /*
|
||
+ * upon state change, reset the checkint
|
||
+ * to the shortest delay
|
||
+ */
|
||
+ pp->checkint = conf->checkint;
|
||
|
||
+ if (newstate == PATH_DOWN || newstate == PATH_SHAKY ||
|
||
+ update_multipath_strings(pp->mpp, vecs->pathvec)) {
|
||
/*
|
||
- * provision a next check soonest,
|
||
- * in case we exit abnormaly from here
|
||
+ * proactively fail path in the DM
|
||
*/
|
||
- pp->tick = conf->checkint;
|
||
+ if (oldstate == PATH_UP ||
|
||
+ oldstate == PATH_GHOST)
|
||
+ fail_path(pp, 1);
|
||
+ else
|
||
+ fail_path(pp, 0);
|
||
|
||
- if (!checker_selected(&pp->checker)) {
|
||
- pathinfo(pp, conf->hwtable, DI_SYSFS);
|
||
- select_checker(pp);
|
||
- }
|
||
- if (!checker_selected(&pp->checker)) {
|
||
- condlog(0, "%s: checker is not set", pp->dev);
|
||
- continue;
|
||
- }
|
||
/*
|
||
- * Set checker in async mode.
|
||
- * Honored only by checker implementing the said mode.
|
||
+ * cancel scheduled failback
|
||
*/
|
||
- checker_set_async(&pp->checker);
|
||
+ pp->mpp->failback_tick = 0;
|
||
+
|
||
+ pp->mpp->stat_path_failures++;
|
||
+ return;
|
||
+ }
|
||
|
||
- newstate = checker_check(&pp->checker);
|
||
+ /*
|
||
+ * reinstate this path
|
||
+ */
|
||
+ if (oldstate != PATH_UP &&
|
||
+ oldstate != PATH_GHOST)
|
||
+ reinstate_path(pp, 1);
|
||
+ else
|
||
+ reinstate_path(pp, 0);
|
||
|
||
- if (newstate < 0) {
|
||
- condlog(2, "%s: unusable path", pp->dev);
|
||
- pathinfo(pp, conf->hwtable, 0);
|
||
- continue;
|
||
- }
|
||
- /*
|
||
- * Async IO in flight. Keep the previous path state
|
||
- * and reschedule as soon as possible
|
||
- */
|
||
- if (newstate == PATH_PENDING) {
|
||
- pp->tick = 1;
|
||
- continue;
|
||
- }
|
||
- if (newstate != pp->state) {
|
||
- int oldstate = pp->state;
|
||
- pp->state = newstate;
|
||
- LOG_MSG(1, checker_message(&pp->checker));
|
||
+ /*
|
||
+ * schedule [defered] failback
|
||
+ */
|
||
+ if (pp->mpp->pgfailback > 0)
|
||
+ pp->mpp->failback_tick =
|
||
+ pp->mpp->pgfailback + 1;
|
||
+ else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
|
||
+ need_switch_pathgroup(pp->mpp, 1))
|
||
+ switch_pathgroup(pp->mpp);
|
||
|
||
- /*
|
||
- * upon state change, reset the checkint
|
||
- * to the shortest delay
|
||
- */
|
||
- pp->checkint = conf->checkint;
|
||
-
|
||
- if (newstate == PATH_DOWN ||
|
||
- newstate == PATH_SHAKY ||
|
||
- update_multipath_strings(pp->mpp,
|
||
- vecs->pathvec)) {
|
||
- /*
|
||
- * proactively fail path in the DM
|
||
- */
|
||
- if (oldstate == PATH_UP ||
|
||
- oldstate == PATH_GHOST)
|
||
- fail_path(pp, 1);
|
||
- else
|
||
- fail_path(pp, 0);
|
||
-
|
||
- /*
|
||
- * cancel scheduled failback
|
||
- */
|
||
- pp->mpp->failback_tick = 0;
|
||
-
|
||
- pp->mpp->stat_path_failures++;
|
||
- continue;
|
||
- }
|
||
+ /*
|
||
+ * if at least one path is up in a group, and
|
||
+ * the group is disabled, re-enable it
|
||
+ */
|
||
+ if (newstate == PATH_UP)
|
||
+ enable_group(pp);
|
||
+ }
|
||
+ else if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||
+ LOG_MSG(4, checker_message(&pp->checker));
|
||
+ /*
|
||
+ * double the next check delay.
|
||
+ * max at conf->max_checkint
|
||
+ */
|
||
+ if (pp->checkint < (conf->max_checkint / 2))
|
||
+ pp->checkint = 2 * pp->checkint;
|
||
+ else
|
||
+ pp->checkint = conf->max_checkint;
|
||
|
||
- /*
|
||
- * reinstate this path
|
||
- */
|
||
- if (oldstate != PATH_UP &&
|
||
- oldstate != PATH_GHOST)
|
||
- reinstate_path(pp, 1);
|
||
- else
|
||
- reinstate_path(pp, 0);
|
||
+ pp->tick = pp->checkint;
|
||
+ condlog(4, "%s: delay next check %is",
|
||
+ pp->dev_t, pp->tick);
|
||
+ }
|
||
+ else if (newstate == PATH_DOWN)
|
||
+ LOG_MSG(2, checker_message(&pp->checker));
|
||
|
||
- /*
|
||
- * schedule [defered] failback
|
||
- */
|
||
- if (pp->mpp->pgfailback > 0)
|
||
- pp->mpp->failback_tick =
|
||
- pp->mpp->pgfailback + 1;
|
||
- else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
|
||
- need_switch_pathgroup(pp->mpp, 1))
|
||
- switch_pathgroup(pp->mpp);
|
||
+ pp->state = newstate;
|
||
|
||
- /*
|
||
- * if at least one path is up in a group, and
|
||
- * the group is disabled, re-enable it
|
||
- */
|
||
- if (newstate == PATH_UP)
|
||
- enable_group(pp);
|
||
- }
|
||
- else if (newstate == PATH_UP || newstate == PATH_GHOST) {
|
||
- LOG_MSG(4, checker_message(&pp->checker));
|
||
- /*
|
||
- * double the next check delay.
|
||
- * max at conf->max_checkint
|
||
- */
|
||
- if (pp->checkint < (conf->max_checkint / 2))
|
||
- pp->checkint = 2 * pp->checkint;
|
||
- else
|
||
- pp->checkint = conf->max_checkint;
|
||
-
|
||
- pp->tick = pp->checkint;
|
||
- condlog(4, "%s: delay next check %is",
|
||
- pp->dev_t, pp->tick);
|
||
- }
|
||
- else if (newstate == PATH_DOWN)
|
||
- LOG_MSG(2, checker_message(&pp->checker));
|
||
+ /*
|
||
+ * path prio refreshing
|
||
+ */
|
||
+ condlog(4, "path prio refresh");
|
||
+ pathinfo(pp, conf->hwtable, DI_PRIO);
|
||
|
||
- pp->state = newstate;
|
||
+ /*
|
||
+ * pathgroup failback policy
|
||
+ */
|
||
+ if (need_switch_pathgroup(pp->mpp, 0)) {
|
||
+ if (pp->mpp->pgfailback > 0 &&
|
||
+ pp->mpp->failback_tick <= 0)
|
||
+ pp->mpp->failback_tick =
|
||
+ pp->mpp->pgfailback + 1;
|
||
+ else if (pp->mpp->pgfailback ==
|
||
+ -FAILBACK_IMMEDIATE)
|
||
+ switch_pathgroup(pp->mpp);
|
||
+ }
|
||
+}
|
||
|
||
- /*
|
||
- * path prio refreshing
|
||
- */
|
||
- condlog(4, "path prio refresh");
|
||
- pathinfo(pp, conf->hwtable, DI_PRIO);
|
||
-
|
||
- if (need_switch_pathgroup(pp->mpp, 0)) {
|
||
- if (pp->mpp->pgfailback > 0 &&
|
||
- pp->mpp->failback_tick <= 0)
|
||
- pp->mpp->failback_tick =
|
||
- pp->mpp->pgfailback + 1;
|
||
- else if (pp->mpp->pgfailback ==
|
||
- -FAILBACK_IMMEDIATE)
|
||
- switch_pathgroup(pp->mpp);
|
||
+static void *
|
||
+checkerloop (void *ap)
|
||
+{
|
||
+ struct vectors *vecs;
|
||
+ struct path *pp;
|
||
+ int count = 0;
|
||
+ unsigned int i;
|
||
+
|
||
+ mlockall(MCL_CURRENT | MCL_FUTURE);
|
||
+ vecs = (struct vectors *)ap;
|
||
+ condlog(2, "path checkers start up");
|
||
+
|
||
+ /*
|
||
+ * init the path check interval
|
||
+ */
|
||
+ vector_foreach_slot (vecs->pathvec, pp, i) {
|
||
+ pp->checkint = conf->checkint;
|
||
+ }
|
||
+
|
||
+ while (1) {
|
||
+ pthread_cleanup_push(cleanup_lock, vecs->lock);
|
||
+ lock(vecs->lock);
|
||
+ condlog(4, "tick");
|
||
+
|
||
+ if (vecs->pathvec) {
|
||
+ vector_foreach_slot (vecs->pathvec, pp, i) {
|
||
+ check_path(vecs, pp);
|
||
}
|
||
}
|
||
- defered_failback_tick(vecs->mpvec);
|
||
- retry_count_tick(vecs->mpvec);
|
||
-
|
||
+ if (vecs->mpvec) {
|
||
+ defered_failback_tick(vecs->mpvec);
|
||
+ retry_count_tick(vecs->mpvec);
|
||
+ }
|
||
if (count)
|
||
count--;
|
||
else {
|
||
@@ -1054,7 +1053,7 @@ configure (struct vectors * vecs, int start_waiters)
|
||
path_discovery(vecs->pathvec, conf, DI_ALL);
|
||
|
||
vector_foreach_slot (vecs->pathvec, pp, i){
|
||
- if (filter_path(conf, pp)){
|
||
+ if (filter_path(conf, pp) > 0){
|
||
vector_del_slot(vecs->pathvec, i);
|
||
free_path(pp);
|
||
i--;
|
||
@@ -1068,7 +1067,7 @@ configure (struct vectors * vecs, int start_waiters)
|
||
/*
|
||
* create new set of maps & push changed ones into dm
|
||
*/
|
||
- if (coalesce_paths(vecs, mpvec, NULL))
|
||
+ if (coalesce_paths(vecs, mpvec, NULL, 0))
|
||
return 1;
|
||
|
||
/*
|
||
@@ -1085,7 +1084,7 @@ configure (struct vectors * vecs, int start_waiters)
|
||
/*
|
||
* purge dm of old maps
|
||
*/
|
||
- remove_maps(vecs, NULL);
|
||
+ remove_maps(vecs);
|
||
|
||
/*
|
||
* save new set of maps formed by considering current path state
|
||
@@ -1115,7 +1114,7 @@ reconfigure (struct vectors * vecs)
|
||
* free old map and path vectors ... they use old conf state
|
||
*/
|
||
if (VECTOR_SIZE(vecs->mpvec))
|
||
- remove_maps(vecs, stop_waiter_thread);
|
||
+ remove_maps_and_stop_waiters(vecs);
|
||
|
||
if (VECTOR_SIZE(vecs->pathvec))
|
||
free_pathvec(vecs->pathvec, FREE_PATHS);
|
||
@@ -1265,6 +1264,15 @@ child (void * param)
|
||
if (load_config(DEFAULT_CONFIGFILE))
|
||
exit(1);
|
||
|
||
+ if (init_checkers()) {
|
||
+ condlog(0, "failed to initialize checkers");
|
||
+ exit(1);
|
||
+ }
|
||
+ if (init_prio()) {
|
||
+ condlog(0, "failed to initialize prioritizers");
|
||
+ exit(1);
|
||
+ }
|
||
+
|
||
setlogmask(LOG_UPTO(conf->verbosity + 3));
|
||
|
||
/*
|
||
@@ -1275,6 +1283,21 @@ child (void * param)
|
||
conf->max_checkint = MAX_CHECKINT(conf->checkint);
|
||
}
|
||
|
||
+ if (conf->max_fds) {
|
||
+ struct rlimit fd_limit;
|
||
+ if (conf->max_fds > 0) {
|
||
+ fd_limit.rlim_cur = conf->max_fds;
|
||
+ fd_limit.rlim_max = conf->max_fds;
|
||
+ }
|
||
+ else {
|
||
+ fd_limit.rlim_cur = RLIM_INFINITY;
|
||
+ fd_limit.rlim_max = RLIM_INFINITY;
|
||
+ }
|
||
+ if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
|
||
+ condlog(0, "can't set open fds limit to %d : %s\n",
|
||
+ conf->max_fds, strerror(errno));
|
||
+ }
|
||
+
|
||
if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
|
||
if (logsink)
|
||
log_thread_stop();
|
||
@@ -1319,7 +1342,7 @@ child (void * param)
|
||
* exit path
|
||
*/
|
||
lock(vecs->lock);
|
||
- remove_maps(vecs, stop_waiter_thread);
|
||
+ remove_maps_and_stop_waiters(vecs);
|
||
free_pathvec(vecs->pathvec, FREE_PATHS);
|
||
|
||
pthread_cancel(check_thr);
|
||
@@ -1340,8 +1363,6 @@ child (void * param)
|
||
vecs->lock = NULL;
|
||
FREE(vecs);
|
||
vecs = NULL;
|
||
- free_config(conf);
|
||
- conf = NULL;
|
||
|
||
condlog(2, "--------shut down-------");
|
||
|
||
@@ -1351,6 +1372,14 @@ child (void * param)
|
||
dm_lib_release();
|
||
dm_lib_exit();
|
||
|
||
+ /*
|
||
+ * Freeing config must be done after condlog() and dm_lib_exit(),
|
||
+ * because logging functions like dlog() and dm_write_log()
|
||
+ * reference the config.
|
||
+ */
|
||
+ free_config(conf);
|
||
+ conf = NULL;
|
||
+
|
||
#ifdef _DEBUG_
|
||
dbg_free_final(NULL);
|
||
#endif
|
||
diff --git a/path_priority/pp_alua/LICENSE b/path_priority/pp_alua/LICENSE
|
||
deleted file mode 100644
|
||
index 9e31bbf..0000000
|
||
--- a/path_priority/pp_alua/LICENSE
|
||
+++ /dev/null
|
||
@@ -1,483 +0,0 @@
|
||
-
|
||
- GNU LIBRARY GENERAL PUBLIC LICENSE
|
||
- Version 2, June 1991
|
||
-
|
||
- Copyright (C) 1991 Free Software Foundation, Inc.
|
||
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||
- Everyone is permitted to copy and distribute verbatim copies
|
||
- of this license document, but changing it is not allowed.
|
||
-
|
||
-[This is the first released version of the library GPL. It is
|
||
- numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||
-
|
||
- Preamble
|
||
-
|
||
- The licenses for most software are designed to take away your
|
||
-freedom to share and change it. By contrast, the GNU General Public
|
||
-Licenses are intended to guarantee your freedom to share and change
|
||
-free software--to make sure the software is free for all its users.
|
||
-
|
||
- This license, the Library General Public License, applies to some
|
||
-specially designated Free Software Foundation software, and to any
|
||
-other libraries whose authors decide to use it. You can use it for
|
||
-your libraries, too.
|
||
-
|
||
- When we speak of free software, we are referring to freedom, not
|
||
-price. Our General Public Licenses are designed to make sure that you
|
||
-have the freedom to distribute copies of free software (and charge for
|
||
-this service if you wish), that you receive source code or can get it
|
||
-if you want it, that you can change the software or use pieces of it
|
||
-in new free programs; and that you know you can do these things.
|
||
-
|
||
- To protect your rights, we need to make restrictions that forbid
|
||
-anyone to deny you these rights or to ask you to surrender the rights.
|
||
-These restrictions translate to certain responsibilities for you if
|
||
-you distribute copies of the library, or if you modify it.
|
||
-
|
||
- For example, if you distribute copies of the library, whether gratis
|
||
-or for a fee, you must give the recipients all the rights that we gave
|
||
-you. You must make sure that they, too, receive or can get the source
|
||
-code. If you link a program with the library, you must provide
|
||
-complete object files to the recipients so that they can relink them
|
||
-with the library, after making changes to the library and recompiling
|
||
-it. And you must show them these terms so they know their rights.
|
||
-
|
||
- Our method of protecting your rights has two steps: (1) copyright
|
||
-the library, and (2) offer you this license which gives you legal
|
||
-permission to copy, distribute and/or modify the library.
|
||
-
|
||
- Also, for each distributor's protection, we want to make certain
|
||
-that everyone understands that there is no warranty for this free
|
||
-library. If the library is modified by someone else and passed on, we
|
||
-want its recipients to know that what they have is not the original
|
||
-version, so that any problems introduced by others will not reflect on
|
||
-the original authors' reputations.
|
||
-
|
||
- Finally, any free program is threatened constantly by software
|
||
-patents. We wish to avoid the danger that companies distributing free
|
||
-software will individually obtain patent licenses, thus in effect
|
||
-transforming the program into proprietary software. To prevent this,
|
||
-we have made it clear that any patent must be licensed for everyone's
|
||
-free use or not licensed at all.
|
||
-
|
||
- Most GNU software, including some libraries, is covered by the ordinary
|
||
-GNU General Public License, which was designed for utility programs. This
|
||
-license, the GNU Library General Public License, applies to certain
|
||
-designated libraries. This license is quite different from the ordinary
|
||
-one; be sure to read it in full, and don't assume that anything in it is
|
||
-the same as in the ordinary license.
|
||
-
|
||
- The reason we have a separate public license for some libraries is that
|
||
-they blur the distinction we usually make between modifying or adding to a
|
||
-program and simply using it. Linking a program with a library, without
|
||
-changing the library, is in some sense simply using the library, and is
|
||
-analogous to running a utility program or application program. However, in
|
||
-a textual and legal sense, the linked executable is a combined work, a
|
||
-derivative of the original library, and the ordinary General Public License
|
||
-treats it as such.
|
||
-
|
||
- Because of this blurred distinction, using the ordinary General
|
||
-Public License for libraries did not effectively promote software
|
||
-sharing, because most developers did not use the libraries. We
|
||
-concluded that weaker conditions might promote sharing better.
|
||
-
|
||
- However, unrestricted linking of non-free programs would deprive the
|
||
-users of those programs of all benefit from the free status of the
|
||
-libraries themselves. This Library General Public License is intended to
|
||
-permit developers of non-free programs to use free libraries, while
|
||
-preserving your freedom as a user of such programs to change the free
|
||
-libraries that are incorporated in them. (We have not seen how to achieve
|
||
-this as regards changes in header files, but we have achieved it as regards
|
||
-changes in the actual functions of the Library.) The hope is that this
|
||
-will lead to faster development of free libraries.
|
||
-
|
||
- The precise terms and conditions for copying, distribution and
|
||
-modification follow. Pay close attention to the difference between a
|
||
-"work based on the library" and a "work that uses the library". The
|
||
-former contains code derived from the library, while the latter only
|
||
-works together with the library.
|
||
-
|
||
- Note that it is possible for a library to be covered by the ordinary
|
||
-General Public License rather than by this special one.
|
||
-
|
||
- GNU LIBRARY GENERAL PUBLIC LICENSE
|
||
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||
-
|
||
- 0. This License Agreement applies to any software library which
|
||
-contains a notice placed by the copyright holder or other authorized
|
||
-party saying it may be distributed under the terms of this Library
|
||
-General Public License (also called "this License"). Each licensee is
|
||
-addressed as "you".
|
||
-
|
||
- A "library" means a collection of software functions and/or data
|
||
-prepared so as to be conveniently linked with application programs
|
||
-(which use some of those functions and data) to form executables.
|
||
-
|
||
- The "Library", below, refers to any such software library or work
|
||
-which has been distributed under these terms. A "work based on the
|
||
-Library" means either the Library or any derivative work under
|
||
-copyright law: that is to say, a work containing the Library or a
|
||
-portion of it, either verbatim or with modifications and/or translated
|
||
-straightforwardly into another language. (Hereinafter, translation is
|
||
-included without limitation in the term "modification".)
|
||
-
|
||
- "Source code" for a work means the preferred form of the work for
|
||
-making modifications to it. For a library, complete source code means
|
||
-all the source code for all modules it contains, plus any associated
|
||
-interface definition files, plus the scripts used to control compilation
|
||
-and installation of the library.
|
||
-
|
||
- Activities other than copying, distribution and modification are not
|
||
-covered by this License; they are outside its scope. The act of
|
||
-running a program using the Library is not restricted, and output from
|
||
-such a program is covered only if its contents constitute a work based
|
||
-on the Library (independent of the use of the Library in a tool for
|
||
-writing it). Whether that is true depends on what the Library does
|
||
-and what the program that uses the Library does.
|
||
-
|
||
- 1. You may copy and distribute verbatim copies of the Library's
|
||
-complete source code as you receive it, in any medium, provided that
|
||
-you conspicuously and appropriately publish on each copy an
|
||
-appropriate copyright notice and disclaimer of warranty; keep intact
|
||
-all the notices that refer to this License and to the absence of any
|
||
-warranty; and distribute a copy of this License along with the
|
||
-Library.
|
||
-
|
||
- You may charge a fee for the physical act of transferring a copy,
|
||
-and you may at your option offer warranty protection in exchange for a
|
||
-fee.
|
||
-
|
||
- 2. You may modify your copy or copies of the Library or any portion
|
||
-of it, thus forming a work based on the Library, and copy and
|
||
-distribute such modifications or work under the terms of Section 1
|
||
-above, provided that you also meet all of these conditions:
|
||
-
|
||
- a) The modified work must itself be a software library.
|
||
-
|
||
- b) You must cause the files modified to carry prominent notices
|
||
- stating that you changed the files and the date of any change.
|
||
-
|
||
- c) You must cause the whole of the work to be licensed at no
|
||
- charge to all third parties under the terms of this License.
|
||
-
|
||
- d) If a facility in the modified Library refers to a function or a
|
||
- table of data to be supplied by an application program that uses
|
||
- the facility, other than as an argument passed when the facility
|
||
- is invoked, then you must make a good faith effort to ensure that,
|
||
- in the event an application does not supply such function or
|
||
- table, the facility still operates, and performs whatever part of
|
||
- its purpose remains meaningful.
|
||
-
|
||
- (For example, a function in a library to compute square roots has
|
||
- a purpose that is entirely well-defined independent of the
|
||
- application. Therefore, Subsection 2d requires that any
|
||
- application-supplied function or table used by this function must
|
||
- be optional: if the application does not supply it, the square
|
||
- root function must still compute square roots.)
|
||
-
|
||
-These requirements apply to the modified work as a whole. If
|
||
-identifiable sections of that work are not derived from the Library,
|
||
-and can be reasonably considered independent and separate works in
|
||
-themselves, then this License, and its terms, do not apply to those
|
||
-sections when you distribute them as separate works. But when you
|
||
-distribute the same sections as part of a whole which is a work based
|
||
-on the Library, the distribution of the whole must be on the terms of
|
||
-this License, whose permissions for other licensees extend to the
|
||
-entire whole, and thus to each and every part regardless of who wrote
|
||
-it.
|
||
-
|
||
-Thus, it is not the intent of this section to claim rights or contest
|
||
-your rights to work written entirely by you; rather, the intent is to
|
||
-exercise the right to control the distribution of derivative or
|
||
-collective works based on the Library.
|
||
-
|
||
-In addition, mere aggregation of another work not based on the Library
|
||
-with the Library (or with a work based on the Library) on a volume of
|
||
-a storage or distribution medium does not bring the other work under
|
||
-the scope of this License.
|
||
-
|
||
- 3. You may opt to apply the terms of the ordinary GNU General Public
|
||
-License instead of this License to a given copy of the Library. To do
|
||
-this, you must alter all the notices that refer to this License, so
|
||
-that they refer to the ordinary GNU General Public License, version 2,
|
||
-instead of to this License. (If a newer version than version 2 of the
|
||
-ordinary GNU General Public License has appeared, then you can specify
|
||
-that version instead if you wish.) Do not make any other change in
|
||
-these notices.
|
||
-
|
||
- Once this change is made in a given copy, it is irreversible for
|
||
-that copy, so the ordinary GNU General Public License applies to all
|
||
-subsequent copies and derivative works made from that copy.
|
||
-
|
||
- This option is useful when you wish to copy part of the code of
|
||
-the Library into a program that is not a library.
|
||
-
|
||
- 4. You may copy and distribute the Library (or a portion or
|
||
-derivative of it, under Section 2) in object code or executable form
|
||
-under the terms of Sections 1 and 2 above provided that you accompany
|
||
-it with the complete corresponding machine-readable source code, which
|
||
-must be distributed under the terms of Sections 1 and 2 above on a
|
||
-medium customarily used for software interchange.
|
||
-
|
||
- If distribution of object code is made by offering access to copy
|
||
-from a designated place, then offering equivalent access to copy the
|
||
-source code from the same place satisfies the requirement to
|
||
-distribute the source code, even though third parties are not
|
||
-compelled to copy the source along with the object code.
|
||
-
|
||
- 5. A program that contains no derivative of any portion of the
|
||
-Library, but is designed to work with the Library by being compiled or
|
||
-linked with it, is called a "work that uses the Library". Such a
|
||
-work, in isolation, is not a derivative work of the Library, and
|
||
-therefore falls outside the scope of this License.
|
||
-
|
||
- However, linking a "work that uses the Library" with the Library
|
||
-creates an executable that is a derivative of the Library (because it
|
||
-contains portions of the Library), rather than a "work that uses the
|
||
-library". The executable is therefore covered by this License.
|
||
-Section 6 states terms for distribution of such executables.
|
||
-
|
||
- When a "work that uses the Library" uses material from a header file
|
||
-that is part of the Library, the object code for the work may be a
|
||
-derivative work of the Library even though the source code is not.
|
||
-Whether this is true is especially significant if the work can be
|
||
-linked without the Library, or if the work is itself a library. The
|
||
-threshold for this to be true is not precisely defined by law.
|
||
-
|
||
- If such an object file uses only numerical parameters, data
|
||
-structure layouts and accessors, and small macros and small inline
|
||
-functions (ten lines or less in length), then the use of the object
|
||
-file is unrestricted, regardless of whether it is legally a derivative
|
||
-work. (Executables containing this object code plus portions of the
|
||
-Library will still fall under Section 6.)
|
||
-
|
||
- Otherwise, if the work is a derivative of the Library, you may
|
||
-distribute the object code for the work under the terms of Section 6.
|
||
-Any executables containing that work also fall under Section 6,
|
||
-whether or not they are linked directly with the Library itself.
|
||
-
|
||
- 6. As an exception to the Sections above, you may also compile or
|
||
-link a "work that uses the Library" with the Library to produce a
|
||
-work containing portions of the Library, and distribute that work
|
||
-under terms of your choice, provided that the terms permit
|
||
-modification of the work for the customer's own use and reverse
|
||
-engineering for debugging such modifications.
|
||
-
|
||
- You must give prominent notice with each copy of the work that the
|
||
-Library is used in it and that the Library and its use are covered by
|
||
-this License. You must supply a copy of this License. If the work
|
||
-during execution displays copyright notices, you must include the
|
||
-copyright notice for the Library among them, as well as a reference
|
||
-directing the user to the copy of this License. Also, you must do one
|
||
-of these things:
|
||
-
|
||
- a) Accompany the work with the complete corresponding
|
||
- machine-readable source code for the Library including whatever
|
||
- changes were used in the work (which must be distributed under
|
||
- Sections 1 and 2 above); and, if the work is an executable linked
|
||
- with the Library, with the complete machine-readable "work that
|
||
- uses the Library", as object code and/or source code, so that the
|
||
- user can modify the Library and then relink to produce a modified
|
||
- executable containing the modified Library. (It is understood
|
||
- that the user who changes the contents of definitions files in the
|
||
- Library will not necessarily be able to recompile the application
|
||
- to use the modified definitions.)
|
||
-
|
||
- b) Accompany the work with a written offer, valid for at
|
||
- least three years, to give the same user the materials
|
||
- specified in Subsection 6a, above, for a charge no more
|
||
- than the cost of performing this distribution.
|
||
-
|
||
- c) If distribution of the work is made by offering access to copy
|
||
- from a designated place, offer equivalent access to copy the above
|
||
- specified materials from the same place.
|
||
-
|
||
- d) Verify that the user has already received a copy of these
|
||
- materials or that you have already sent this user a copy.
|
||
-
|
||
- For an executable, the required form of the "work that uses the
|
||
-Library" must include any data and utility programs needed for
|
||
-reproducing the executable from it. However, as a special exception,
|
||
-the source code distributed need not include anything that is normally
|
||
-distributed (in either source or binary form) with the major
|
||
-components (compiler, kernel, and so on) of the operating system on
|
||
-which the executable runs, unless that component itself accompanies
|
||
-the executable.
|
||
-
|
||
- It may happen that this requirement contradicts the license
|
||
-restrictions of other proprietary libraries that do not normally
|
||
-accompany the operating system. Such a contradiction means you cannot
|
||
-use both them and the Library together in an executable that you
|
||
-distribute.
|
||
-
|
||
- 7. You may place library facilities that are a work based on the
|
||
-Library side-by-side in a single library together with other library
|
||
-facilities not covered by this License, and distribute such a combined
|
||
-library, provided that the separate distribution of the work based on
|
||
-the Library and of the other library facilities is otherwise
|
||
-permitted, and provided that you do these two things:
|
||
-
|
||
- a) Accompany the combined library with a copy of the same work
|
||
- based on the Library, uncombined with any other library
|
||
- facilities. This must be distributed under the terms of the
|
||
- Sections above.
|
||
-
|
||
- b) Give prominent notice with the combined library of the fact
|
||
- that part of it is a work based on the Library, and explaining
|
||
- where to find the accompanying uncombined form of the same work.
|
||
-
|
||
- 8. You may not copy, modify, sublicense, link with, or distribute
|
||
-the Library except as expressly provided under this License. Any
|
||
-attempt otherwise to copy, modify, sublicense, link with, or
|
||
-distribute the Library is void, and will automatically terminate your
|
||
-rights under this License. However, parties who have received copies,
|
||
-or rights, from you under this License will not have their licenses
|
||
-terminated so long as such parties remain in full compliance.
|
||
-
|
||
- 9. You are not required to accept this License, since you have not
|
||
-signed it. However, nothing else grants you permission to modify or
|
||
-distribute the Library or its derivative works. These actions are
|
||
-prohibited by law if you do not accept this License. Therefore, by
|
||
-modifying or distributing the Library (or any work based on the
|
||
-Library), you indicate your acceptance of this License to do so, and
|
||
-all its terms and conditions for copying, distributing or modifying
|
||
-the Library or works based on it.
|
||
-
|
||
- 10. Each time you redistribute the Library (or any work based on the
|
||
-Library), the recipient automatically receives a license from the
|
||
-original licensor to copy, distribute, link with or modify the Library
|
||
-subject to these terms and conditions. You may not impose any further
|
||
-restrictions on the recipients' exercise of the rights granted herein.
|
||
-You are not responsible for enforcing compliance by third parties to
|
||
-this License.
|
||
-
|
||
- 11. If, as a consequence of a court judgment or allegation of patent
|
||
-infringement or for any other reason (not limited to patent issues),
|
||
-conditions are imposed on you (whether by court order, agreement or
|
||
-otherwise) that contradict the conditions of this License, they do not
|
||
-excuse you from the conditions of this License. If you cannot
|
||
-distribute so as to satisfy simultaneously your obligations under this
|
||
-License and any other pertinent obligations, then as a consequence you
|
||
-may not distribute the Library at all. For example, if a patent
|
||
-license would not permit royalty-free redistribution of the Library by
|
||
-all those who receive copies directly or indirectly through you, then
|
||
-the only way you could satisfy both it and this License would be to
|
||
-refrain entirely from distribution of the Library.
|
||
-
|
||
-If any portion of this section is held invalid or unenforceable under any
|
||
-particular circumstance, the balance of the section is intended to apply,
|
||
-and the section as a whole is intended to apply in other circumstances.
|
||
-
|
||
-It is not the purpose of this section to induce you to infringe any
|
||
-patents or other property right claims or to contest validity of any
|
||
-such claims; this section has the sole purpose of protecting the
|
||
-integrity of the free software distribution system which is
|
||
-implemented by public license practices. Many people have made
|
||
-generous contributions to the wide range of software distributed
|
||
-through that system in reliance on consistent application of that
|
||
-system; it is up to the author/donor to decide if he or she is willing
|
||
-to distribute software through any other system and a licensee cannot
|
||
-impose that choice.
|
||
-
|
||
-This section is intended to make thoroughly clear what is believed to
|
||
-be a consequence of the rest of this License.
|
||
-
|
||
- 12. If the distribution and/or use of the Library is restricted in
|
||
-certain countries either by patents or by copyrighted interfaces, the
|
||
-original copyright holder who places the Library under this License may add
|
||
-an explicit geographical distribution limitation excluding those countries,
|
||
-so that distribution is permitted only in or among countries not thus
|
||
-excluded. In such case, this License incorporates the limitation as if
|
||
-written in the body of this License.
|
||
-
|
||
- 13. The Free Software Foundation may publish revised and/or new
|
||
-versions of the Library General Public License from time to time.
|
||
-Such new versions will be similar in spirit to the present version,
|
||
-but may differ in detail to address new problems or concerns.
|
||
-
|
||
-Each version is given a distinguishing version number. If the Library
|
||
-specifies a version number of this License which applies to it and
|
||
-"any later version", you have the option of following the terms and
|
||
-conditions either of that version or of any later version published by
|
||
-the Free Software Foundation. If the Library does not specify a
|
||
-license version number, you may choose any version ever published by
|
||
-the Free Software Foundation.
|
||
-
|
||
- 14. If you wish to incorporate parts of the Library into other free
|
||
-programs whose distribution conditions are incompatible with these,
|
||
-write to the author to ask for permission. For software which is
|
||
-copyrighted by the Free Software Foundation, write to the Free
|
||
-Software Foundation; we sometimes make exceptions for this. Our
|
||
-decision will be guided by the two goals of preserving the free status
|
||
-of all derivatives of our free software and of promoting the sharing
|
||
-and reuse of software generally.
|
||
-
|
||
- NO WARRANTY
|
||
-
|
||
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||
-
|
||
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||
-DAMAGES.
|
||
-
|
||
- END OF TERMS AND CONDITIONS
|
||
-
|
||
- Appendix: How to Apply These Terms to Your New Libraries
|
||
-
|
||
- If you develop a new library, and you want it to be of the greatest
|
||
-possible use to the public, we recommend making it free software that
|
||
-everyone can redistribute and change. You can do so by permitting
|
||
-redistribution under these terms (or, alternatively, under the terms of the
|
||
-ordinary General Public License).
|
||
-
|
||
- To apply these terms, attach the following notices to the library. It is
|
||
-safest to attach them to the start of each source file to most effectively
|
||
-convey the exclusion of warranty; and each file should have at least the
|
||
-"copyright" line and a pointer to where the full notice is found.
|
||
-
|
||
- <one line to give the library's name and a brief idea of what it does.>
|
||
- Copyright (C) <year> <name of author>
|
||
-
|
||
- This library is free software; you can redistribute it and/or
|
||
- modify it under the terms of the GNU Library 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
|
||
- Library General Public License for more details.
|
||
-
|
||
- You should have received a copy of the GNU Library 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
|
||
-
|
||
-Also add information on how to contact you by electronic and paper mail.
|
||
-
|
||
-You should also get your employer (if you work as a programmer) or your
|
||
-school, if any, to sign a "copyright disclaimer" for the library, if
|
||
-necessary. Here is a sample; alter the names:
|
||
-
|
||
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||
-
|
||
- <signature of Ty Coon>, 1 April 1990
|
||
- Ty Coon, President of Vice
|
||
-
|
||
-That's all there is to it!
|
||
diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile
|
||
deleted file mode 100644
|
||
index 6f356a1..0000000
|
||
--- a/path_priority/pp_alua/Makefile
|
||
+++ /dev/null
|
||
@@ -1,54 +0,0 @@
|
||
-#==============================================================================
|
||
-# (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
-#
|
||
-# Makefile
|
||
-#
|
||
-# Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
-# It determines the ALUA state of a device and prints a priority value to
|
||
-# stdout.
|
||
-#
|
||
-# Author(s): Jan Kunigk
|
||
-# S. Bader <shbader@de.ibm.com>
|
||
-#
|
||
-# This file is released under the GPL.
|
||
-#==============================================================================
|
||
-EXEC = mpath_prio_alua
|
||
-BUILD = glibc
|
||
-DEBUG = 0
|
||
-DEBUG_DUMPHEX = 0
|
||
-OBJS = main.o rtpg.o
|
||
-INSTALL = install -D
|
||
-
|
||
-TOPDIR = ../..
|
||
-
|
||
-ifneq ($(shell ls $(TOPDIR)/Makefile.inc 2>/dev/null),)
|
||
-include $(TOPDIR)/Makefile.inc
|
||
-endif
|
||
-
|
||
-CFLAGS += -DDEBUG=$(DEBUG)
|
||
-
|
||
-all: $(BUILD)
|
||
-
|
||
-glibc: $(OBJS)
|
||
- $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
|
||
-
|
||
-klibc: $(OBJS)
|
||
- $(CC) -static -o $(EXEC) $(OBJS)
|
||
-
|
||
-install: $(EXEC) $(EXEC).8.gz
|
||
- $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
||
- $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
||
-
|
||
-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_alua/main.c b/path_priority/pp_alua/main.c
|
||
deleted file mode 100644
|
||
index ba8da99..0000000
|
||
--- a/path_priority/pp_alua/main.c
|
||
+++ /dev/null
|
||
@@ -1,279 +0,0 @@
|
||
-/*
|
||
- * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
- *
|
||
- * main.c
|
||
- *
|
||
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
- * It determines the ALUA state of a device and prints a priority value to
|
||
- * stdout.
|
||
- *
|
||
- * Author(s): Jan Kunigk
|
||
- * S. Bader <shbader@de.ibm.com>
|
||
- *
|
||
- * This file is released under the GPL.
|
||
- */
|
||
-#include <sys/types.h>
|
||
-#include <sys/stat.h>
|
||
-
|
||
-#include <errno.h>
|
||
-#include <fcntl.h>
|
||
-#include <stdio.h>
|
||
-#include <limits.h>
|
||
-#include <stdlib.h>
|
||
-#include <unistd.h>
|
||
-#include <strings.h>
|
||
-
|
||
-#include "rtpg.h"
|
||
-
|
||
-#define ALUA_PRIO_SUCCESS 0
|
||
-#define ALUA_PRIO_INVALID_COMMANDLINE 1
|
||
-#define ALUA_PRIO_OPEN_FAILED 2
|
||
-#define ALUA_PRIO_NOT_SUPPORTED 3
|
||
-#define ALUA_PRIO_RTPG_FAILED 4
|
||
-#define ALUA_PRIO_GETAAS_FAILED 5
|
||
-
|
||
-#define ALUA_PRIO_MAJOR 0
|
||
-#define ALUA_PRIO_MINOR 6
|
||
-
|
||
-#define PRINT_ERROR(f, a...) \
|
||
- if (verbose) \
|
||
- fprintf(stderr, "ERROR: " f, ##a)
|
||
-#define PRINT_VERBOSE(f, a...) \
|
||
- if (verbose) \
|
||
- printf(f, ##a)
|
||
-
|
||
-char * devicename = NULL;
|
||
-int verbose = 0;
|
||
-
|
||
-char *basename(char *p)
|
||
-{
|
||
- char *r;
|
||
-
|
||
- for(r = p; *r != '\0'; r++);
|
||
- for(; r > p && *(r - 1) != '/'; r--);
|
||
-
|
||
- return r;
|
||
-}
|
||
-
|
||
-void
|
||
-print_help(char *command)
|
||
-{
|
||
- printf("Usage: %s <options> <device> [<device> [...]]\n\n",
|
||
- basename(command));
|
||
- printf("Options are:\n");
|
||
-
|
||
- printf("\t-d <device directory>\n");
|
||
- printf("\t\tSets the directory prefix for relative path names and");
|
||
- printf(" created\n\t\tpath names. (default = \"/dev\")\n");
|
||
-
|
||
- printf("\t-h\n");
|
||
- printf("\t\tPrint this help.\n");
|
||
-
|
||
- printf("\t-v\n");
|
||
- printf("\t\tTurn on verbose output.\n");
|
||
-
|
||
- printf("\t-V\n");
|
||
- printf("\t\tPrints the version number and exits.\n");
|
||
-
|
||
- printf("\nDevice may be an absolute or relative path to a device ");
|
||
- printf("node or a major and\nminor number seperated by a colon (:).");
|
||
- printf(" In this case a temporary device node\nwill be created in ");
|
||
- printf("the device directory.\n");
|
||
-}
|
||
-
|
||
-void
|
||
-print_version(char *command)
|
||
-{
|
||
- printf("(C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.\n");
|
||
- printf("This is %s version %u.%u\n",
|
||
- basename(command),
|
||
- ALUA_PRIO_MAJOR,
|
||
- ALUA_PRIO_MINOR
|
||
- );
|
||
-}
|
||
-
|
||
-int
|
||
-open_block_device(char *name)
|
||
-{
|
||
- int fd;
|
||
- struct stat st;
|
||
-
|
||
- if (stat(name, &st) != 0) {
|
||
- PRINT_ERROR("Cannot get file status from %s (errno = %i)!\n",
|
||
- name, errno);
|
||
- return -ALUA_PRIO_OPEN_FAILED;
|
||
- }
|
||
- if (!S_ISBLK(st.st_mode)) {
|
||
- PRINT_ERROR("%s is not a block device!\n", name);
|
||
- return -ALUA_PRIO_OPEN_FAILED;
|
||
- }
|
||
- fd = open(name, O_RDONLY);
|
||
- if (fd < 0) {
|
||
- PRINT_ERROR("Couldn't open %s (errno = %i)!\n", name, errno);
|
||
- return -ALUA_PRIO_OPEN_FAILED;
|
||
- }
|
||
- return fd;
|
||
-}
|
||
-
|
||
-int
|
||
-close_block_device(int fd)
|
||
-{
|
||
- return close(fd);
|
||
-}
|
||
-
|
||
-int
|
||
-get_alua_info(int fd)
|
||
-{
|
||
- char * aas_string[] = {
|
||
- [AAS_OPTIMIZED] = "active/optimized",
|
||
- [AAS_NON_OPTIMIZED] = "active/non-optimized",
|
||
- [AAS_STANDBY] = "standby",
|
||
- [AAS_UNAVAILABLE] = "unavailable",
|
||
- [AAS_TRANSITIONING] = "transitioning between states",
|
||
- };
|
||
- int rc;
|
||
- int tpg;
|
||
-
|
||
- rc = get_target_port_group_support(fd);
|
||
- if (rc < 0)
|
||
- return rc;
|
||
-
|
||
- if (verbose) {
|
||
- printf("Target port groups are ");
|
||
- switch(rc) {
|
||
- case TPGS_NONE:
|
||
- printf("not");
|
||
- break;
|
||
- case TPGS_IMPLICIT:
|
||
- printf("implicitly");
|
||
- break;
|
||
- case TPGS_EXPLICIT:
|
||
- printf("explicitly");
|
||
- break;
|
||
- case TPGS_BOTH:
|
||
- printf("implicitly and explicitly");
|
||
- break;
|
||
- }
|
||
- printf(" supported.\n");
|
||
- }
|
||
-
|
||
- if (rc == TPGS_NONE)
|
||
- return -ALUA_PRIO_NOT_SUPPORTED;
|
||
-
|
||
- tpg = get_target_port_group(fd);
|
||
- if (tpg < 0) {
|
||
- PRINT_ERROR("Couldn't get target port group!\n");
|
||
- return -ALUA_PRIO_RTPG_FAILED;
|
||
- }
|
||
- PRINT_VERBOSE("Reported target port group is %i", tpg);
|
||
-
|
||
- rc = get_asymmetric_access_state(fd, tpg);
|
||
- if (rc < 0) {
|
||
- PRINT_VERBOSE(" [get AAS failed]\n");
|
||
- PRINT_ERROR("Couln't get asymmetric access state!\n");
|
||
- return -ALUA_PRIO_GETAAS_FAILED;
|
||
- }
|
||
- PRINT_VERBOSE(" [%s]\n",
|
||
- (aas_string[rc]) ? aas_string[rc] : "invalid/reserved"
|
||
- );
|
||
-
|
||
- return rc;
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char **argv)
|
||
-{
|
||
- char devicepath[PATH_MAX];
|
||
- char * devicedir;
|
||
- char * s_opts = "d:hvV";
|
||
- char * pos;
|
||
- int fd;
|
||
- int rc;
|
||
- int c;
|
||
-
|
||
- devicedir = "/dev";
|
||
- while ((c = getopt(argc, argv, s_opts)) >= 0) {
|
||
- switch(c) {
|
||
- case 'd':
|
||
- devicedir = optarg;
|
||
- break;
|
||
- case 'h':
|
||
- print_help(argv[0]);
|
||
- return ALUA_PRIO_SUCCESS;
|
||
- case 'V':
|
||
- print_version(argv[0]);
|
||
- return ALUA_PRIO_SUCCESS;
|
||
- case 'v':
|
||
- verbose = 1;
|
||
- break;
|
||
- case '?':
|
||
- case ':':
|
||
- default:
|
||
- return ALUA_PRIO_INVALID_COMMANDLINE;
|
||
- }
|
||
- }
|
||
-
|
||
- if (optind == argc) {
|
||
- print_help(argv[0]);
|
||
- printf("\n");
|
||
- PRINT_ERROR("No device specified!\n");
|
||
- return ALUA_PRIO_INVALID_COMMANDLINE;
|
||
- }
|
||
-
|
||
- rc = ALUA_PRIO_SUCCESS;
|
||
- for(c = optind; c < argc && !rc; c++) {
|
||
- if (argv[c][0] == '/') {
|
||
- pos = NULL;
|
||
- sprintf(devicepath, "%s", argv[c]);
|
||
- } else if ((pos = index(argv[c], ':')) == NULL) {
|
||
- sprintf(devicepath, "%s/%s", devicedir, argv[c]);
|
||
- } else {
|
||
- int major;
|
||
- int minor;
|
||
-
|
||
- major = atoi(argv[c]);
|
||
- minor = atoi(++pos);
|
||
- sprintf(devicepath, "%s/tmpdev-%u:%u-%u",
|
||
- devicedir, major, minor, getpid()
|
||
- );
|
||
- mknod(
|
||
- devicepath,
|
||
- S_IFBLK|S_IRUSR|S_IWUSR,
|
||
- makedev(major, minor)
|
||
- );
|
||
-
|
||
- }
|
||
-
|
||
- fd = open_block_device(devicepath);
|
||
- if (fd < 0) {
|
||
- if (pos != NULL)
|
||
- unlink(devicepath);
|
||
- return -fd;
|
||
- }
|
||
- rc = get_alua_info(fd);
|
||
- if (rc >= 0) {
|
||
- switch(rc) {
|
||
- case AAS_OPTIMIZED:
|
||
- rc = 50;
|
||
- break;
|
||
- case AAS_NON_OPTIMIZED:
|
||
- rc = 10;
|
||
- break;
|
||
- case AAS_STANDBY:
|
||
- rc = 1;
|
||
- break;
|
||
- default:
|
||
- rc = 0;
|
||
- }
|
||
- printf("%u\n", rc);
|
||
- rc = ALUA_PRIO_SUCCESS;
|
||
- }
|
||
- close_block_device(fd);
|
||
-
|
||
- /* The path was created before. */
|
||
- if (pos != NULL)
|
||
- unlink(devicepath);
|
||
- }
|
||
-
|
||
- return -rc;
|
||
-}
|
||
diff --git a/path_priority/pp_alua/mpath_prio_alua.8 b/path_priority/pp_alua/mpath_prio_alua.8
|
||
deleted file mode 100644
|
||
index 58568a5..0000000
|
||
--- a/path_priority/pp_alua/mpath_prio_alua.8
|
||
+++ /dev/null
|
||
@@ -1,162 +0,0 @@
|
||
-.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
|
||
-.SH SYNOPSIS
|
||
-.B mpath_prio_alua
|
||
-.RB [\| \-d\ \c
|
||
-.IR directory \|]
|
||
-.RB [\| \-h \|]
|
||
-.RB [\| \-v \|]
|
||
-.RB [\| \-V \|]
|
||
-.IR device " \|[ " device " \|[ " ... " \|]\|]"
|
||
-.SH DESCRIPTION
|
||
-.B mpath_prio_alua
|
||
-is used as a priority callout for the multipath command. It returns a number
|
||
-that is used by multipath to group devices with the same priority together.
|
||
-.SH OPTIONS
|
||
-.TP
|
||
-.BI \-d " directory"
|
||
-target directory for devices given as relative device names or devices given
|
||
-as
|
||
-.IR major : minor \c
|
||
- number.
|
||
-Default is "/dev".
|
||
-.TP
|
||
-.B \-h
|
||
-displays the command line help.
|
||
-.TP
|
||
-.B \-v
|
||
-turns on verbose output. This shows all results in human readable format.
|
||
-This includes information about the port group the device is in and its
|
||
-current state.
|
||
-.TP
|
||
-.B \-V
|
||
-shows the version number and exits.
|
||
-.TP
|
||
-.BI device
|
||
-specifies the device to query (the device must be a SCSI device that supports
|
||
-the \*[lq]Report Target Port Groups\*[rq] command).
|
||
-One of the following three formats may be used:
|
||
-.RS
|
||
-.IP \(bu 2
|
||
-The full path name that starts with '/' (e.g. /dev/sda).
|
||
-.IP \(bu
|
||
-The device name only. This will prefix the directory name given by the
|
||
-\-d option (e.g. sda).
|
||
-.IP \(bu
|
||
-The major and minor number of the device separated by ':'. This will
|
||
-create a temporary device node in the device directory (e.g. 8:0). The
|
||
-temporary name will be
|
||
-.RB \*[lq] tmpdev-<major>:<minor>-<pid> \*[rq].
|
||
-.SH "RETURN VALUE"
|
||
-The mpath_prio_alua command returns the following values:
|
||
-.IP \fB0
|
||
-on success. In this case the priority for the device is printed to
|
||
-stdout. The priority value is:
|
||
-.RS
|
||
-.IP \fB50\fP
|
||
-for devices that are in the active, optimized group
|
||
-.IP \fB10
|
||
-for devices that are in an active but non-optimized group
|
||
-.IP \fB1
|
||
-for devices that are in the standby group
|
||
-.IP \fB0
|
||
-for all other groups
|
||
-.RE
|
||
-.IP ""
|
||
-The reason for the widely spaced priority values is the way multipath handles
|
||
-them. It will multiply the number of paths in a group with the priority value
|
||
-and select the group with the highest result. Thus, if there are six paths in
|
||
-the active, non-optimized group and only one in the active, optimized one,
|
||
-the non-optimized group would be used.
|
||
-.IP \fB1
|
||
-Indicates an error parsing the command line.
|
||
-.IP \fB2
|
||
-The given devices could not be opened for reading.
|
||
-.IP \fB3
|
||
-The device does not support target port groups.
|
||
-.IP \fB4
|
||
-The inquiry command did not return a target port group for the given device.
|
||
-.IP \fB5
|
||
-The report target port group command failed or did not return a target
|
||
-port group that was obtained from the inquiry command.
|
||
-.SH "EXAMPLES"
|
||
-This example queries a device directly and returns the priority string:
|
||
-.P
|
||
-.RS
|
||
-.B #> mpath_prio_alua /dev/sda
|
||
-.br
|
||
-50
|
||
-.RE
|
||
-.P
|
||
-Now the major and minor number is used to specify the device and verbose
|
||
-output is selected:
|
||
-.P
|
||
-.RS
|
||
-.B #> mpath_prio_alua -v 8:0
|
||
-.br
|
||
-Target port groups are implicitly supported.
|
||
-.br
|
||
-Reported target port group is 0 [active/optimized]
|
||
-.br
|
||
-50
|
||
-.RE
|
||
-.P
|
||
-The following example shows the entries in the devices section of the
|
||
-.RI "multipath-tool configuration file (" /etc/multipath.conf )
|
||
-to support an IBM DS6000 storage system:
|
||
-.P
|
||
-.RS
|
||
-.PD 0
|
||
-device {
|
||
-.RS
|
||
-.TP 22
|
||
-.B vendor
|
||
-"IBM "
|
||
-.TP
|
||
-.B product
|
||
-"1750500 "
|
||
-.TP
|
||
-.B path_grouping_policy
|
||
-group_by_prio
|
||
-.TP
|
||
-.B prio_callout
|
||
-"/sbin/mpath_prio_alua -d/tmp %d"
|
||
-.TP
|
||
-.B features
|
||
-"1 queue_if_no_path"
|
||
-.TP
|
||
-.B path_checker
|
||
-tur
|
||
-.RE
|
||
-}
|
||
-.PD
|
||
-.RE
|
||
-.TP
|
||
-.B Notes:
|
||
-.IP \(bu 2
|
||
-Depending on your default configuration not all keywords are required
|
||
-.RB "(e.g. if your " path_checker " is set to tur you don't have to"
|
||
-.RB "use the " path_checker " statement in the device section)."
|
||
-.IP \(bu
|
||
-.RB "The entries for " vendor " and " product " must be strings that are 8"
|
||
-.RB "characters long (for " vendor ") and 16 characters long (for " product ")."
|
||
-The strings have to be padded with blanks if necessary.
|
||
-.IP \(bu
|
||
-If you are working with hotpluggable devices whose device nodes are created
|
||
-by udev you should use the %d flag in the
|
||
-.BR prio_callout " statement."
|
||
-This is because a short time elapses between the devices being available
|
||
-and udev creating the device nodes.
|
||
-.IP \(bu
|
||
-If under certain circumstances your storage subsystem temporarily reports
|
||
-.RB "failures on all paths, you should use the " features " statement showed"
|
||
-in the example.
|
||
-This will configure the multipath volume to requeue I/O until a path becomes
|
||
-available again, instead of reporting failures in that case.
|
||
-.SH "SEE ALSO"
|
||
-.BR multipath (8),
|
||
-.SH AUTHORS
|
||
-.B mpath_prio_alua
|
||
-was developed by Jan Kunigk and adapted by Stefan Bader <shbader@de.ibm.com>
|
||
diff --git a/path_priority/pp_alua/rtpg.c b/path_priority/pp_alua/rtpg.c
|
||
deleted file mode 100644
|
||
index 701f9d5..0000000
|
||
--- a/path_priority/pp_alua/rtpg.c
|
||
+++ /dev/null
|
||
@@ -1,306 +0,0 @@
|
||
-/*
|
||
- * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
- *
|
||
- * rtpg.c
|
||
- *
|
||
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
- * It determines the ALUA state of a device and prints a priority value to
|
||
- * stdout.
|
||
- *
|
||
- * Author(s): Jan Kunigk
|
||
- * S. Bader <shbader@de.ibm.com>
|
||
- *
|
||
- * This file is released under the GPL.
|
||
- */
|
||
-#include <stdio.h>
|
||
-#include <stdlib.h>
|
||
-#include <string.h>
|
||
-#include <fcntl.h>
|
||
-#include <sys/ioctl.h>
|
||
-#include <sys/types.h>
|
||
-#include <sys/stat.h>
|
||
-#include <unistd.h>
|
||
-#include <errno.h>
|
||
-#include <inttypes.h>
|
||
-
|
||
-#define __user
|
||
-#include <scsi/sg.h>
|
||
-
|
||
-#include "rtpg.h"
|
||
-
|
||
-#define SENSE_BUFF_LEN 32
|
||
-#define DEF_TIMEOUT 300000
|
||
-
|
||
-/*
|
||
- * Macro used to print debug messaged.
|
||
- */
|
||
-#if DEBUG > 0
|
||
-#define PRINT_DEBUG(f, a...) \
|
||
- fprintf(stderr, "DEBUG: " f, ##a)
|
||
-#else
|
||
-#define PRINT_DEBUG(f, a...)
|
||
-#endif
|
||
-
|
||
-/*
|
||
- * Optionally print the commands sent and the data received a hex dump.
|
||
- */
|
||
-#if DEBUG > 0
|
||
-#if DEBUG_DUMPHEX > 0
|
||
-#define PRINT_HEX(p, l) print_hex(p, l)
|
||
-void
|
||
-print_hex(unsigned char *p, unsigned long len)
|
||
-{
|
||
- int i;
|
||
-
|
||
- for(i = 0; i < len; i++) {
|
||
- if (i % 16 == 0)
|
||
- printf("%04x: ", i);
|
||
- printf("%02x%s", p[i], (((i + 1) % 16) == 0) ? "\n" : " ");
|
||
- }
|
||
- printf("\n");
|
||
-}
|
||
-#else
|
||
-#define PRINT_HEX(p, l)
|
||
-#endif
|
||
-#else
|
||
-#define PRINT_HEX(p, l)
|
||
-#endif
|
||
-
|
||
-/*
|
||
- * Returns 0 if the SCSI command either was successful or if the an error was
|
||
- * recovered, otherwise 1. (definitions taken from sg_err.h)
|
||
- */
|
||
-#define SCSI_CHECK_CONDITION 0x2
|
||
-#define SCSI_COMMAND_TERMINATED 0x22
|
||
-#define SG_ERR_DRIVER_SENSE 0x08
|
||
-#define RECOVERED_ERROR 0x01
|
||
-
|
||
-static int
|
||
-scsi_error(struct sg_io_hdr *hdr)
|
||
-{
|
||
- /* Treat SG_ERR here to get rid of sg_err.[ch] */
|
||
- hdr->status &= 0x7e;
|
||
-
|
||
- if (
|
||
- (hdr->status == 0) &&
|
||
- (hdr->host_status == 0) &&
|
||
- (hdr->driver_status == 0)
|
||
- ) {
|
||
- return 0;
|
||
- }
|
||
-
|
||
- if (
|
||
- (hdr->status == SCSI_CHECK_CONDITION) ||
|
||
- (hdr->status == SCSI_COMMAND_TERMINATED) ||
|
||
- ((hdr->driver_status & 0xf) == SG_ERR_DRIVER_SENSE)
|
||
- ) {
|
||
- if (hdr->sbp && (hdr->sb_len_wr > 2)) {
|
||
- int sense_key;
|
||
- unsigned char * sense_buffer = hdr->sbp;
|
||
-
|
||
- if (sense_buffer[0] & 0x2)
|
||
- sense_key = sense_buffer[1] & 0xf;
|
||
- else
|
||
- sense_key = sense_buffer[2] & 0xf;
|
||
-
|
||
- if (sense_key == RECOVERED_ERROR)
|
||
- return 0;
|
||
- }
|
||
- }
|
||
-
|
||
- return 1;
|
||
-}
|
||
-
|
||
-/*
|
||
- * Helper function to setup and run a SCSI inquiry command.
|
||
- */
|
||
-int
|
||
-do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
|
||
-{
|
||
- struct inquiry_command cmd;
|
||
- struct sg_io_hdr hdr;
|
||
- unsigned char sense[SENSE_BUFF_LEN];
|
||
-
|
||
- memset(&cmd, 0, sizeof(cmd));
|
||
- cmd.op = OPERATION_CODE_INQUIRY;
|
||
- if (evpd) {
|
||
- inquiry_command_set_evpd(&cmd);
|
||
- cmd.page = codepage;
|
||
- }
|
||
- set_uint16(cmd.length, resplen);
|
||
- PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
|
||
-
|
||
- memset(&hdr, 0, sizeof(hdr));
|
||
- hdr.interface_id = 'S';
|
||
- hdr.cmdp = (unsigned char *) &cmd;
|
||
- hdr.cmd_len = sizeof(cmd);
|
||
- hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- hdr.dxferp = resp;
|
||
- hdr.dxfer_len = resplen;
|
||
- hdr.sbp = sense;
|
||
- hdr.mx_sb_len = sizeof(sense);
|
||
- hdr.timeout = DEF_TIMEOUT;
|
||
-
|
||
- if (ioctl(fd, SG_IO, &hdr) < 0) {
|
||
- PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
|
||
- return -RTPG_INQUIRY_FAILED;
|
||
- }
|
||
-
|
||
- if (scsi_error(&hdr)) {
|
||
- PRINT_DEBUG("do_inquiry: SCSI error!\n");
|
||
- return -RTPG_INQUIRY_FAILED;
|
||
- }
|
||
- PRINT_HEX((unsigned char *) resp, resplen);
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
-/*
|
||
- * This function returns the support for target port groups by evaluating the
|
||
- * data returned by the standard inquiry command.
|
||
- */
|
||
-int
|
||
-get_target_port_group_support(int fd)
|
||
-{
|
||
- struct inquiry_data inq;
|
||
- int rc;
|
||
-
|
||
- rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
|
||
- if (!rc) {
|
||
- rc = inquiry_data_get_tpgs(&inq);
|
||
- }
|
||
-
|
||
- return rc;
|
||
-}
|
||
-
|
||
-int
|
||
-get_target_port_group(int fd)
|
||
-{
|
||
- unsigned char buf[128];
|
||
- struct vpd83_data * vpd83;
|
||
- struct vpd83_dscr * dscr;
|
||
- int rc;
|
||
-
|
||
- rc = do_inquiry(fd, 1, 0x83, buf, sizeof(buf));
|
||
- if (!rc) {
|
||
- vpd83 = (struct vpd83_data *) buf;
|
||
-
|
||
- rc = -RTPG_NO_TPG_IDENTIFIER;
|
||
- FOR_EACH_VPD83_DSCR(vpd83, dscr) {
|
||
- if ((((char *) dscr) - ((char *) vpd83)) > sizeof(buf))
|
||
- break;
|
||
-
|
||
- if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
|
||
- struct vpd83_tpg_dscr * p;
|
||
-
|
||
- if (rc != -RTPG_NO_TPG_IDENTIFIER) {
|
||
- PRINT_DEBUG("get_target_port_group: "
|
||
- "more than one TPG identifier "
|
||
- "found!\n");
|
||
- continue;
|
||
- }
|
||
-
|
||
- p = (struct vpd83_tpg_dscr *) dscr->data;
|
||
- rc = get_uint16(p->tpg);
|
||
- }
|
||
- }
|
||
- if (rc == -RTPG_NO_TPG_IDENTIFIER) {
|
||
- PRINT_DEBUG("get_target_port_group: "
|
||
- "no TPG identifier found!\n");
|
||
- }
|
||
- }
|
||
-
|
||
- return rc;
|
||
-}
|
||
-
|
||
-int
|
||
-do_rtpg(int fd, void* resp, long resplen)
|
||
-{
|
||
- struct rtpg_command cmd;
|
||
- struct sg_io_hdr hdr;
|
||
- unsigned char sense[SENSE_BUFF_LEN];
|
||
-
|
||
- memset(&cmd, 0, sizeof(cmd));
|
||
- cmd.op = OPERATION_CODE_RTPG;
|
||
- rtpg_command_set_service_action(&cmd);
|
||
- set_uint32(cmd.length, resplen);
|
||
- PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
|
||
-
|
||
- memset(&hdr, 0, sizeof(hdr));
|
||
- hdr.interface_id = 'S';
|
||
- hdr.cmdp = (unsigned char *) &cmd;
|
||
- hdr.cmd_len = sizeof(cmd);
|
||
- hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- hdr.dxferp = resp;
|
||
- hdr.dxfer_len = resplen;
|
||
- hdr.mx_sb_len = sizeof(sense);
|
||
- hdr.sbp = sense;
|
||
- hdr.timeout = DEF_TIMEOUT;
|
||
-
|
||
- if (ioctl(fd, SG_IO, &hdr) < 0)
|
||
- return -RTPG_RTPG_FAILED;
|
||
-
|
||
- if (scsi_error(&hdr)) {
|
||
- PRINT_DEBUG("do_rtpg: SCSI error!\n");
|
||
- return -RTPG_RTPG_FAILED;
|
||
- }
|
||
- PRINT_HEX(resp, resplen);
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
-int
|
||
-get_asymmetric_access_state(int fd, unsigned int tpg)
|
||
-{
|
||
- unsigned char *buf;
|
||
- struct rtpg_data * tpgd;
|
||
- struct rtpg_tpg_dscr * dscr;
|
||
- int rc;
|
||
- 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;
|
||
- RTPG_FOR_EACH_PORT_GROUP(tpgd, dscr) {
|
||
- if (get_uint16(dscr->tpg) == tpg) {
|
||
- if (rc != -RTPG_TPG_NOT_FOUND) {
|
||
- PRINT_DEBUG("get_asymmetric_access_state: "
|
||
- "more than one entry with same port "
|
||
- "group.\n");
|
||
- } else {
|
||
- PRINT_DEBUG("pref=%i\n", dscr->pref);
|
||
- rc = rtpg_tpg_dscr_get_aas(dscr);
|
||
- }
|
||
- }
|
||
- }
|
||
-out:
|
||
- free(buf);
|
||
- return rc;
|
||
-}
|
||
-
|
||
diff --git a/path_priority/pp_alua/rtpg.h b/path_priority/pp_alua/rtpg.h
|
||
deleted file mode 100644
|
||
index 3c5dcf1..0000000
|
||
--- a/path_priority/pp_alua/rtpg.h
|
||
+++ /dev/null
|
||
@@ -1,30 +0,0 @@
|
||
-/*
|
||
- * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
- *
|
||
- * rtpg.h
|
||
- *
|
||
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
- * It determines the ALUA state of a device and prints a priority value to
|
||
- * stdout.
|
||
- *
|
||
- * Author(s): Jan Kunigk
|
||
- * S. Bader <shbader@de.ibm.com>
|
||
- *
|
||
- * This file is released under the GPL.
|
||
- */
|
||
-#ifndef __RTPG_H__
|
||
-#define __RTPG_H__
|
||
-#include "spc3.h"
|
||
-
|
||
-#define RTPG_SUCCESS 0
|
||
-#define RTPG_INQUIRY_FAILED 1
|
||
-#define RTPG_NO_TPG_IDENTIFIER 2
|
||
-#define RTPG_RTPG_FAILED 3
|
||
-#define RTPG_TPG_NOT_FOUND 4
|
||
-
|
||
-int get_target_port_group_support(int fd);
|
||
-int get_target_port_group(int fd);
|
||
-int get_asymmetric_access_state(int fd, unsigned int tpg);
|
||
-
|
||
-#endif /* __RTPG_H__ */
|
||
-
|
||
diff --git a/path_priority/pp_alua/spc3.h b/path_priority/pp_alua/spc3.h
|
||
deleted file mode 100644
|
||
index bddbbdd..0000000
|
||
--- a/path_priority/pp_alua/spc3.h
|
||
+++ /dev/null
|
||
@@ -1,322 +0,0 @@
|
||
-/*
|
||
- * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
|
||
- *
|
||
- * spc3.h
|
||
- *
|
||
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
|
||
- * It determines the ALUA state of a device and prints a priority value to
|
||
- * stdout.
|
||
- *
|
||
- * Author(s): Jan Kunigk
|
||
- * S. Bader <shbader@de.ibm.com>
|
||
- *
|
||
- * This file is released under the GPL.
|
||
- */
|
||
-#ifndef __SPC3_H__
|
||
-#define __SPC3_H__
|
||
-/*=============================================================================
|
||
- * Some helper functions for getting and setting 16 and 32 bit values.
|
||
- *=============================================================================
|
||
- */
|
||
-static inline unsigned short
|
||
-get_uint16(unsigned char *p)
|
||
-{
|
||
- return (p[0] << 8) + p[1];
|
||
-}
|
||
-
|
||
-static inline void
|
||
-set_uint16(unsigned char *p, unsigned short v)
|
||
-{
|
||
- p[0] = (v >> 8) & 0xff;
|
||
- p[1] = v & 0xff;
|
||
-}
|
||
-
|
||
-static inline unsigned int
|
||
-get_uint32(unsigned char *p)
|
||
-{
|
||
- return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||
-}
|
||
-
|
||
-static inline void
|
||
-set_uint32(unsigned char *p, unsigned int v)
|
||
-{
|
||
- p[0] = (v >> 24) & 0xff;
|
||
- p[1] = (v >> 16) & 0xff;
|
||
- p[2] = (v >> 8) & 0xff;
|
||
- p[3] = v & 0xff;
|
||
-}
|
||
-
|
||
-/*=============================================================================
|
||
- * Definitions to support the standard inquiry command as defined in SPC-3.
|
||
- * If the evpd (enable vital product data) bit is set the data that will be
|
||
- * returned is selected by the page field. This field must be 0 if the evpd
|
||
- * bit is not set.
|
||
- *=============================================================================
|
||
- */
|
||
-#define OPERATION_CODE_INQUIRY 0x12
|
||
-
|
||
-struct inquiry_command {
|
||
- unsigned char op;
|
||
- unsigned char b1; /* xxxxxx.. = reserved */
|
||
- /* ......x. = obsolete */
|
||
- /* .......x = evpd */
|
||
- unsigned char page;
|
||
- unsigned char length[2];
|
||
- unsigned char control;
|
||
-} __attribute__((packed));
|
||
-
|
||
-static inline void
|
||
-inquiry_command_set_evpd(struct inquiry_command *ic)
|
||
-{
|
||
- ic->b1 |= 1;
|
||
-}
|
||
-
|
||
-/*-----------------------------------------------------------------------------
|
||
- * Data returned by the standard inquiry command.
|
||
- *-----------------------------------------------------------------------------
|
||
- *
|
||
- * Peripheral qualifier codes.
|
||
- */
|
||
-#define PQ_CONNECTED 0x0
|
||
-#define PQ_DISCONNECTED 0x1
|
||
-#define PQ_UNSUPPORTED 0x3
|
||
-
|
||
-/* Defined peripheral device types. */
|
||
-#define PDT_DIRECT_ACCESS 0x00
|
||
-#define PDT_SEQUENTIAL_ACCESS 0x01
|
||
-#define PDT_PRINTER 0x02
|
||
-#define PDT_PROCESSOR 0x03
|
||
-#define PDT_WRITE_ONCE 0x04
|
||
-#define PDT_CD_DVD 0x05
|
||
-#define PDT_SCANNER 0x06
|
||
-#define PDT_OPTICAL_MEMORY 0x07
|
||
-#define PDT_MEDIUM_CHANGER 0x08
|
||
-#define PDT_COMMUNICATIONS 0x09
|
||
-#define PDT_STORAGE_ARRAY_CONTROLLER 0x0c
|
||
-#define PDT_ENCLOSURE_SERVICES 0x0d
|
||
-#define PDT_SIMPLIFIED_DIRECT_ACCESS 0x0e
|
||
-#define PDT_OPTICAL_CARD_READER_WRITER 0x0f
|
||
-#define PDT_BRIDGE_CONTROLLER 0x10
|
||
-#define PDT_OBJECT_BASED 0x11
|
||
-#define PDT_AUTOMATION_INTERFACE 0x12
|
||
-#define PDT_LUN 0x1e
|
||
-#define PDT_UNKNOWN 0x1f
|
||
-
|
||
-/* Defined version codes. */
|
||
-#define VERSION_NONE 0x00
|
||
-#define VERSION_SPC 0x03
|
||
-#define VERSION_SPC2 0x04
|
||
-#define VERSION_SPC3 0x05
|
||
-
|
||
-/* Defined TPGS field values. */
|
||
-#define TPGS_NONE 0x0
|
||
-#define TPGS_IMPLICIT 0x1
|
||
-#define TPGS_EXPLICIT 0x2
|
||
-#define TPGS_BOTH 0x3
|
||
-
|
||
-struct inquiry_data {
|
||
- unsigned char b0; /* xxx..... = peripheral_qualifier */
|
||
- /* ...xxxxx = peripheral_device_type */
|
||
- unsigned char b1; /* x....... = removable medium */
|
||
- /* .xxxxxxx = reserverd */
|
||
- unsigned char version;
|
||
- unsigned char b3; /* xx...... = obsolete */
|
||
- /* ..x..... = normal aca supported */
|
||
- /* ...x.... = hirarchichal lun supp. */
|
||
- /* ....xxxx = response format */
|
||
- /* 2 is spc-3 format */
|
||
- unsigned char length;
|
||
- unsigned char b5; /* x....... = storage controller */
|
||
- /* component supported */
|
||
- /* .x...... = access controls coord. */
|
||
- /* ..xx.... = target port group supp.*/
|
||
- /* ....x... = third party copy supp. */
|
||
- /* .....xx. = reserved */
|
||
- /* .......x = protection info supp. */
|
||
- unsigned char b6; /* x....... = bque */
|
||
- /* .x...... = enclosure services sup.*/
|
||
- /* ..x..... = vs1 */
|
||
- /* ...x.... = multiport support */
|
||
- /* ....x... = medium changer */
|
||
- /* .....xx. = obsolete */
|
||
- /* .......x = add16 */
|
||
- unsigned char b7; /* xx...... = obsolete */
|
||
- /* ..x..... = wbus16 */
|
||
- /* ...x.... = sync */
|
||
- /* ....x... = linked commands supp. */
|
||
- /* .....x.. = obsolete */
|
||
- /* ......x. = command queue support */
|
||
- /* .......x = vs2 */
|
||
- unsigned char vendor_identification[8];
|
||
- unsigned char product_identification[16];
|
||
- unsigned char product_revision[4];
|
||
- unsigned char vendor_specific[20];
|
||
- unsigned char b56; /* xxxx.... = reserved */
|
||
- /* ....xx.. = clocking */
|
||
- /* ......x. = qas */
|
||
- /* .......x = ius */
|
||
- unsigned char reserved4;
|
||
- unsigned char version_descriptor[8][2];
|
||
- unsigned char reserved5[22];
|
||
- unsigned char vendor_parameters[0];
|
||
-} __attribute__((packed));
|
||
-
|
||
-static inline int
|
||
-inquiry_data_get_tpgs(struct inquiry_data *id)
|
||
-{
|
||
- return (id->b5 >> 4) & 3;
|
||
-}
|
||
-
|
||
-/*-----------------------------------------------------------------------------
|
||
- * Inquiry data returned when requesting vital product data page 0x83.
|
||
- *-----------------------------------------------------------------------------
|
||
- */
|
||
-#define CODESET_BINARY 0x1
|
||
-#define CODESET_ACSII 0x2
|
||
-#define CODESET_UTF8 0x3
|
||
-
|
||
-#define ASSOCIATION_UNIT 0x0
|
||
-#define ASSOCIATION_PORT 0x1
|
||
-#define ASSOCIATION_DEVICE 0x2
|
||
-
|
||
-#define IDTYPE_VENDOR_SPECIFIC 0x0
|
||
-#define IDTYPE_T10_VENDOR_ID 0x1
|
||
-#define IDTYPE_EUI64 0x2
|
||
-#define IDTYPE_NAA 0x3
|
||
-#define IDTYPE_RELATIVE_TPG_ID 0x4
|
||
-#define IDTYPE_TARGET_PORT_GROUP 0x5
|
||
-#define IDTYPE_LUN_GROUP 0x6
|
||
-#define IDTYPE_MD5_LUN_ID 0x7
|
||
-#define IDTYPE_SCSI_NAME_STRING 0x8
|
||
-
|
||
-struct vpd83_tpg_dscr {
|
||
- unsigned char reserved1[2];
|
||
- unsigned char tpg[2];
|
||
-} __attribute__((packed));
|
||
-
|
||
-struct vpd83_dscr {
|
||
- unsigned char b0; /* xxxx.... = protocol id */
|
||
- /* ....xxxx = codeset */
|
||
- unsigned char b1; /* x....... = protocol id valid */
|
||
- /* .x...... = reserved */
|
||
- /* ..xx.... = association */
|
||
- /* ....xxxx = id type */
|
||
- unsigned char reserved2;
|
||
- unsigned char length; /* size-4 */
|
||
- unsigned char data[0];
|
||
-} __attribute__((packed));
|
||
-
|
||
-static inline int
|
||
-vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
|
||
-{
|
||
- return ((d->b1 & 7) == type);
|
||
-}
|
||
-
|
||
-struct vpd83_data {
|
||
- unsigned char b0; /* xxx..... = peripheral_qualifier */
|
||
- /* ...xxxxx = peripheral_device_type */
|
||
- unsigned char page_code; /* 0x83 */
|
||
- unsigned char length[2]; /* size-4 */
|
||
- struct vpd83_dscr data[0];
|
||
-} __attribute__((packed));
|
||
-
|
||
-/*-----------------------------------------------------------------------------
|
||
- * This macro should be used to walk through all identification descriptors
|
||
- * defined in the code page 0x83.
|
||
- * The argument p is a pointer to the code page 0x83 data and d is used to
|
||
- * point to the current descriptor.
|
||
- *-----------------------------------------------------------------------------
|
||
- */
|
||
-#define FOR_EACH_VPD83_DSCR(p, d) \
|
||
- for( \
|
||
- d = p->data; \
|
||
- (((char *) d) - ((char *) p)) < \
|
||
- get_uint16(p->length); \
|
||
- d = (struct vpd83_dscr *) \
|
||
- ((char *) d + d->length + 4) \
|
||
- )
|
||
-
|
||
-/*=============================================================================
|
||
- * The following stuctures and macros are used to call the report target port
|
||
- * groups command defined in SPC-3.
|
||
- * This command is used to get information about the target port groups (which
|
||
- * states are supported, which ports belong to this group, and so on) and the
|
||
- * current state of each target port group.
|
||
- *=============================================================================
|
||
- */
|
||
-#define OPERATION_CODE_RTPG 0xa3
|
||
-#define SERVICE_ACTION_RTPG 0x0a
|
||
-
|
||
-struct rtpg_command {
|
||
- unsigned char op; /* 0xa3 */
|
||
- unsigned char b1; /* xxx..... = reserved */
|
||
- /* ...xxxxx = service action (0x0a) */
|
||
- unsigned char reserved2[4];
|
||
- unsigned char length[4];
|
||
- unsigned char reserved3;
|
||
- unsigned char control;
|
||
-} __attribute__((packed));
|
||
-
|
||
-static inline void
|
||
-rtpg_command_set_service_action(struct rtpg_command *cmd)
|
||
-{
|
||
- cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
|
||
-}
|
||
-
|
||
-struct rtpg_tp_dscr {
|
||
- unsigned char obsolete1[2];
|
||
- /* The Relative Target Port Identifier of a target port. */
|
||
- unsigned char rtpi[2];
|
||
-} __attribute__((packed));
|
||
-
|
||
-#define AAS_OPTIMIZED 0x0
|
||
-#define AAS_NON_OPTIMIZED 0x1
|
||
-#define AAS_STANDBY 0x2
|
||
-#define AAS_UNAVAILABLE 0x3
|
||
-#define AAS_TRANSITIONING 0xf
|
||
-
|
||
-#define TPG_STATUS_NONE 0x0
|
||
-#define TPG_STATUS_SET 0x1
|
||
-#define TPG_STATUS_IMPLICIT_CHANGE 0x2
|
||
-
|
||
-struct rtpg_tpg_dscr {
|
||
- unsigned char b0; /* x....... = pref(ered) port */
|
||
- /* .xxx.... = reserved */
|
||
- /* ....xxxx = asymetric access state */
|
||
- unsigned char b1; /* xxxx.... = reserved */
|
||
- /* ....x... = unavailable support */
|
||
- /* .....x.. = standby support */
|
||
- /* ......x. = non-optimized support */
|
||
- /* .......x = optimized support */
|
||
- unsigned char tpg[2];
|
||
- unsigned char reserved3;
|
||
- unsigned char status;
|
||
- unsigned char vendor_unique;
|
||
- unsigned char port_count;
|
||
- struct rtpg_tp_dscr data[0];
|
||
-} __attribute__((packed));
|
||
-
|
||
-static inline int
|
||
-rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
|
||
-{
|
||
- return (d->b0 & 0x0f);
|
||
-}
|
||
-
|
||
-struct rtpg_data {
|
||
- unsigned char length[4]; /* size-4 */
|
||
- struct rtpg_tpg_dscr data[0];
|
||
-} __attribute__((packed));
|
||
-
|
||
-#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
|
||
- for( \
|
||
- g = &(p->data[0]); \
|
||
- (((char *) g) - ((char *) p)) < get_uint32(p->length); \
|
||
- g = (struct rtpg_tpg_dscr *) ( \
|
||
- ((char *) g) + \
|
||
- sizeof(struct rtpg_tpg_dscr) + \
|
||
- g->port_count * sizeof(struct rtpg_tp_dscr) \
|
||
- ) \
|
||
- )
|
||
-
|
||
-#endif /* __SPC3_H__ */
|
||
-
|
||
diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile
|
||
deleted file mode 100644
|
||
index cb1e6c6..0000000
|
||
--- a/path_priority/pp_balance_units/Makefile
|
||
+++ /dev/null
|
||
@@ -1,44 +0,0 @@
|
||
-# Makefile
|
||
-#
|
||
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
|
||
-#
|
||
-BUILD = glibc
|
||
-DEBUG = 0
|
||
-
|
||
-TOPDIR = ../..
|
||
-include $(TOPDIR)/Makefile.inc
|
||
-
|
||
-ifeq ($(strip $(BUILD)),klibc)
|
||
- CFLAGS += -I/usr/include -DDEBUG=$(DEBUG)
|
||
- OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
|
||
-else
|
||
- CFLAGS += -I$(multipathdir) -DDEBUG=$(DEBUG)
|
||
- LDFLAGS = -ldevmapper
|
||
- OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
|
||
-endif
|
||
-
|
||
-EXEC = mpath_prio_balance_units
|
||
-
|
||
-all: $(BUILD)
|
||
-
|
||
-prepare:
|
||
- rm -f core *.o *.gz
|
||
-
|
||
-glibc: prepare $(OBJS)
|
||
- $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
|
||
-
|
||
-klibc: prepare $(OBJS)
|
||
- $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
|
||
-
|
||
-$(MULTIPATHLIB)-$(BUILD).a:
|
||
- make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
|
||
-
|
||
-install:
|
||
- install -d $(DESTDIR)$(bindir)
|
||
- $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
-
|
||
-clean:
|
||
- rm -f core *.o $(EXEC) *.gz
|
||
diff --git a/path_priority/pp_balance_units/pp_balance_units.c b/path_priority/pp_balance_units/pp_balance_units.c
|
||
deleted file mode 100644
|
||
index ea70f13..0000000
|
||
--- a/path_priority/pp_balance_units/pp_balance_units.c
|
||
+++ /dev/null
|
||
@@ -1,476 +0,0 @@
|
||
-/*
|
||
- * Christophe Varoqui (2004)
|
||
- * This code is GPLv2, see license file
|
||
- *
|
||
- * This path prioritizer aims to balance logical units over all
|
||
- * controllers available. The logic is :
|
||
- *
|
||
- * - list all paths in all primary path groups
|
||
- * - 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 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
|
||
- *
|
||
- */
|
||
-#define __user
|
||
-
|
||
-#include <stdio.h>
|
||
-#include <stdlib.h>
|
||
-#include <libdevmapper.h>
|
||
-#include <vector.h>
|
||
-#include <memory.h>
|
||
-
|
||
-#include <string.h>
|
||
-#include <fcntl.h>
|
||
-#include <sys/ioctl.h>
|
||
-#include <sys/types.h>
|
||
-#include <sys/stat.h>
|
||
-#include <unistd.h>
|
||
-#include <scsi/sg.h>
|
||
-
|
||
-#define SERIAL_SIZE 255
|
||
-#define WORD_SIZE 255
|
||
-#define PARAMS_SIZE 255
|
||
-#define FILE_NAME_SIZE 255
|
||
-#define INQUIRY_CMDLEN 6
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define SENSE_BUFF_LEN 32
|
||
-#define DEF_TIMEOUT 300000
|
||
-#define RECOVERED_ERROR 0x01
|
||
-#define MX_ALLOC_LEN 255
|
||
-#define SCSI_CHECK_CONDITION 0x2
|
||
-#define SCSI_COMMAND_TERMINATED 0x22
|
||
-#define SG_ERR_DRIVER_SENSE 0x08
|
||
-
|
||
-#if DEBUG
|
||
-#define debug(format, arg...) fprintf(stderr, format "\n", ##arg)
|
||
-#else
|
||
-#define debug(format, arg...) do {} while(0)
|
||
-#endif
|
||
-
|
||
-#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
|
||
-
|
||
-struct path {
|
||
- char dev_t[WORD_SIZE];
|
||
- char serial[SERIAL_SIZE];
|
||
-};
|
||
-
|
||
-struct controller {
|
||
- char serial[SERIAL_SIZE];
|
||
- int path_count;
|
||
-};
|
||
-
|
||
-static int
|
||
-exit_tool (int ret)
|
||
-{
|
||
- printf("1\n");
|
||
- exit(ret);
|
||
-}
|
||
-
|
||
-static int
|
||
-opennode (char * devt, int mode)
|
||
-{
|
||
- char devpath[FILE_NAME_SIZE];
|
||
- unsigned int major;
|
||
- unsigned int minor;
|
||
- int fd;
|
||
-
|
||
- sscanf(devt, "%u:%u", &major, &minor);
|
||
- memset(devpath, 0, FILE_NAME_SIZE);
|
||
-
|
||
- if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
|
||
- major, minor)) {
|
||
- fprintf(stderr, "devpath too small\n");
|
||
- return -1;
|
||
- }
|
||
- unlink (devpath);
|
||
- mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor));
|
||
- fd = open(devpath, mode);
|
||
-
|
||
- if (fd < 0)
|
||
- unlink(devpath);
|
||
-
|
||
- return fd;
|
||
-
|
||
-}
|
||
-
|
||
-static void
|
||
-closenode (char * devt, int fd)
|
||
-{
|
||
- char devpath[FILE_NAME_SIZE];
|
||
- unsigned int major;
|
||
- unsigned int minor;
|
||
-
|
||
- if (fd >= 0)
|
||
- close(fd);
|
||
-
|
||
- sscanf(devt, "%u:%u", &major, &minor);
|
||
- if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
|
||
- major, minor)) {
|
||
- fprintf(stderr, "devpath too small\n");
|
||
- return;
|
||
- }
|
||
- unlink(devpath);
|
||
-}
|
||
-
|
||
-static int
|
||
-do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
|
||
- void *resp, int mx_resp_len, int noisy)
|
||
-{
|
||
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
|
||
- { 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)
|
||
- inqCmdBlk[1] |= 1;
|
||
- inqCmdBlk[2] = (unsigned char) pg_op;
|
||
- inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
|
||
- 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 = 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;
|
||
-}
|
||
-
|
||
-static int
|
||
-get_serial (char * str, int maxlen, char * devt)
|
||
-{
|
||
- int fd;
|
||
- int len;
|
||
- char buff[MX_ALLOC_LEN + 1];
|
||
-
|
||
- fd = opennode(devt, O_RDONLY);
|
||
-
|
||
- if (fd < 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 0;
|
||
- }
|
||
-
|
||
- closenode(devt, fd);
|
||
- return 1;
|
||
-}
|
||
-
|
||
-static void *
|
||
-get_params (void)
|
||
-{
|
||
- struct dm_task *dmt, *dmt1;
|
||
- struct dm_names *names = NULL;
|
||
- unsigned next = 0;
|
||
- void *nexttgt;
|
||
- uint64_t start, length;
|
||
- char *target_type = NULL;
|
||
- char *params;
|
||
- char *pp;
|
||
- vector paramsvec = NULL;
|
||
-
|
||
- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
|
||
- return NULL;
|
||
-
|
||
- if (!dm_task_run(dmt))
|
||
- goto out;
|
||
-
|
||
- if (!(names = dm_task_get_names(dmt)))
|
||
- goto out;
|
||
-
|
||
- if (!names->dev) {
|
||
- debug("no devmap found");
|
||
- goto out;
|
||
- }
|
||
- do {
|
||
- /*
|
||
- * keep only multipath maps
|
||
- */
|
||
- names = (void *) names + next;
|
||
- nexttgt = NULL;
|
||
- debug("devmap %s :", names->name);
|
||
-
|
||
- if (!(dmt1 = dm_task_create(DM_DEVICE_TABLE)))
|
||
- goto out;
|
||
-
|
||
- if (!dm_task_set_name(dmt1, names->name))
|
||
- goto out1;
|
||
-
|
||
- if (!dm_task_run(dmt1))
|
||
- goto out1;
|
||
-
|
||
- do {
|
||
- nexttgt = dm_get_next_target(dmt1, nexttgt,
|
||
- &start,
|
||
- &length,
|
||
- &target_type,
|
||
- ¶ms);
|
||
- debug("\\_ %lu %lu %s", (unsigned long) start,
|
||
- (unsigned long) length,
|
||
- target_type);
|
||
-
|
||
- if (!target_type) {
|
||
- debug("unknown target type");
|
||
- goto out1;
|
||
- }
|
||
-
|
||
- if (!strncmp(target_type, "multipath", 9)) {
|
||
- if (!paramsvec)
|
||
- paramsvec = vector_alloc();
|
||
-
|
||
- pp = malloc(PARAMS_SIZE);
|
||
- strncpy(pp, params, PARAMS_SIZE);
|
||
- vector_alloc_slot(paramsvec);
|
||
- vector_set_slot(paramsvec, pp);
|
||
- } else
|
||
- debug("skip non multipath target");
|
||
- } while (nexttgt);
|
||
-out1:
|
||
- dm_task_destroy(dmt1);
|
||
- next = names->next;
|
||
- } while (next);
|
||
-out:
|
||
- dm_task_destroy(dmt);
|
||
- return paramsvec;
|
||
-}
|
||
-
|
||
-static int
|
||
-get_word (char *sentence, char *word)
|
||
-{
|
||
- char *p;
|
||
- int skip = 0;
|
||
-
|
||
- while (*sentence == ' ') {
|
||
- sentence++;
|
||
- skip++;
|
||
- }
|
||
- p = sentence;
|
||
-
|
||
- while (*p != ' ' && *p != '\0')
|
||
- p++;
|
||
-
|
||
- skip += (p - sentence);
|
||
-
|
||
- if (p - sentence > WORD_SIZE) {
|
||
- fprintf(stderr, "word too small\n");
|
||
- exit_tool(1);
|
||
- }
|
||
- strncpy(word, sentence, WORD_SIZE);
|
||
- word += p - sentence;
|
||
- *word = '\0';
|
||
-
|
||
- if (*p == '\0')
|
||
- return 0;
|
||
-
|
||
- return skip;
|
||
-}
|
||
-
|
||
-static int
|
||
-is_path (char * word)
|
||
-{
|
||
- char *p;
|
||
-
|
||
- if (!word)
|
||
- return 0;
|
||
-
|
||
- p = word;
|
||
-
|
||
- while (*p != '\0') {
|
||
- if (*p == ':')
|
||
- return 1;
|
||
- p++;
|
||
- }
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static int
|
||
-get_paths (vector pathvec)
|
||
-{
|
||
- vector paramsvec = NULL;
|
||
- char * str;
|
||
- struct path * pp;
|
||
- int i;
|
||
- enum where {BEFOREPG, INPG, AFTERPG};
|
||
- int pos = BEFOREPG;
|
||
-
|
||
- if (!pathvec)
|
||
- return 1;
|
||
-
|
||
- if (!(paramsvec = get_params()))
|
||
- exit_tool(0);
|
||
-
|
||
- vector_foreach_slot (paramsvec, str, i) {
|
||
- debug("params %s", str);
|
||
- while (pos != AFTERPG) {
|
||
- pp = zalloc(sizeof(struct path));
|
||
- str += get_word(str, pp->dev_t);
|
||
-
|
||
- if (!is_path(pp->dev_t)) {
|
||
- debug("skip \"%s\"", pp->dev_t);
|
||
- free(pp);
|
||
-
|
||
- if (pos == INPG)
|
||
- pos = AFTERPG;
|
||
-
|
||
- continue;
|
||
- }
|
||
- if (pos == BEFOREPG)
|
||
- pos = INPG;
|
||
-
|
||
- get_serial(pp->serial, SERIAL_SIZE, pp->dev_t);
|
||
- vector_alloc_slot(pathvec);
|
||
- vector_set_slot(pathvec, pp);
|
||
- debug("store %s [%s]",
|
||
- pp->dev_t, pp->serial);
|
||
- }
|
||
- pos = BEFOREPG;
|
||
- }
|
||
- return 0;
|
||
-}
|
||
-
|
||
-static void *
|
||
-find_controller (vector controllers, char * serial)
|
||
-{
|
||
- int i;
|
||
- struct controller * cp;
|
||
-
|
||
- if (!controllers)
|
||
- return NULL;
|
||
-
|
||
- vector_foreach_slot (controllers, cp, i)
|
||
- if (!strncmp(cp->serial, serial, SERIAL_SIZE))
|
||
- return cp;
|
||
- return NULL;
|
||
-}
|
||
-
|
||
-static void
|
||
-get_controllers (vector controllers, vector pathvec)
|
||
-{
|
||
- int i;
|
||
- struct path * pp;
|
||
- struct controller * cp;
|
||
-
|
||
- if (!controllers)
|
||
- return;
|
||
-
|
||
- vector_foreach_slot (pathvec, pp, i) {
|
||
- if (!pp || !strlen(pp->serial))
|
||
- continue;
|
||
-
|
||
- cp = find_controller(controllers, pp->serial);
|
||
-
|
||
- if (!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++;
|
||
- }
|
||
-}
|
||
-
|
||
-static int
|
||
-get_max_path_count (vector controllers)
|
||
-{
|
||
- int i;
|
||
- int max = 0;
|
||
- struct controller * cp;
|
||
-
|
||
- if (!controllers)
|
||
- return 0;
|
||
-
|
||
- 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;
|
||
- }
|
||
- debug("max_path_count = %i", max);
|
||
- return max;
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char **argv)
|
||
-{
|
||
- vector pathvec = NULL;
|
||
- vector controllers = NULL;
|
||
- struct path * ref_path = NULL;
|
||
- struct controller * cp = NULL;
|
||
- int max_path_count = 0;
|
||
-
|
||
- ref_path = zalloc(sizeof(struct path));
|
||
-
|
||
- if (!ref_path)
|
||
- exit_tool(1);
|
||
-
|
||
- if (argc != 2)
|
||
- exit_tool(1);
|
||
-
|
||
- if (optind<argc)
|
||
- strncpy(ref_path->dev_t, argv[optind], WORD_SIZE);
|
||
-
|
||
- 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();
|
||
- controllers = vector_alloc();
|
||
-
|
||
- get_paths(pathvec);
|
||
- 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",
|
||
- ref_path->serial);
|
||
- exit_tool(0);
|
||
- }
|
||
-
|
||
- printf("%i\n", max_path_count - cp->path_count + 1);
|
||
-
|
||
- return(0);
|
||
-}
|
||
diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile
|
||
deleted file mode 100644
|
||
index 93e6075..0000000
|
||
--- a/path_priority/pp_emc/Makefile
|
||
+++ /dev/null
|
||
@@ -1,25 +0,0 @@
|
||
-EXEC = mpath_prio_emc
|
||
-BUILD = glibc
|
||
-OBJS = pp_emc.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_PROGRAM) -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_emc/pp_emc.c b/path_priority/pp_emc/pp_emc.c
|
||
deleted file mode 100644
|
||
index 4031720..0000000
|
||
--- a/path_priority/pp_emc/pp_emc.c
|
||
+++ /dev/null
|
||
@@ -1,101 +0,0 @@
|
||
-#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 "../../libmultipath/sg_include.h"
|
||
-
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define INQUIRY_CMDLEN 6
|
||
-
|
||
-int emc_clariion_prio(const char *dev)
|
||
-{
|
||
- unsigned char sense_buffer[256];
|
||
- unsigned char sb[128];
|
||
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
|
||
- sizeof(sb), 0};
|
||
- struct sg_io_hdr io_hdr;
|
||
- int ret = 0;
|
||
- 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 (inqCmdBlk);
|
||
- io_hdr.mx_sb_len = sizeof (sb);
|
||
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
- io_hdr.dxferp = sense_buffer;
|
||
- io_hdr.cmdp = inqCmdBlk;
|
||
- io_hdr.sbp = sb;
|
||
- io_hdr.timeout = 60000;
|
||
- io_hdr.pack_id = 0;
|
||
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
- fprintf(stderr, "sending query command failed\n");
|
||
- goto out;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- fprintf(stderr, "query command indicates error");
|
||
- goto out;
|
||
- }
|
||
-
|
||
- close(fd);
|
||
-
|
||
- if (/* Verify the code page - right page & revision */
|
||
- sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
|
||
- fprintf(stderr, "Path unit report page in unknown format");
|
||
- goto out;
|
||
- }
|
||
-
|
||
- if ( /* Effective initiator type */
|
||
- sense_buffer[27] != 0x03
|
||
- /*
|
||
- * 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");
|
||
- }
|
||
-
|
||
- if ( /* LUN operations should indicate normal operations */
|
||
- sense_buffer[48] != 0x00) {
|
||
- fprintf(stderr, "Path not available for normal operations");
|
||
- }
|
||
-
|
||
- /* Is the default owner equal to this path? */
|
||
- /* Note this will switch to the default priority group, even if
|
||
- * it is not the currently active one. */
|
||
- ret = (sense_buffer[5] == sense_buffer[8]) ? 1 : 0;
|
||
-
|
||
-out:
|
||
- return(ret);
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char **argv)
|
||
-{
|
||
- int prio;
|
||
- if (argc != 2) {
|
||
- fprintf(stderr, "Arguments wrong!\n");
|
||
- prio = 0;
|
||
- } else
|
||
- prio = emc_clariion_prio(argv[1]);
|
||
-
|
||
- printf("%d\n", prio);
|
||
- exit(0);
|
||
-}
|
||
-
|
||
diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile
|
||
deleted file mode 100644
|
||
index ca00ca7..0000000
|
||
--- a/path_priority/pp_hds_modular/Makefile
|
||
+++ /dev/null
|
||
@@ -1,22 +0,0 @@
|
||
-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_PROGRAM) -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
|
||
deleted file mode 100644
|
||
index 7411508..0000000
|
||
--- a/path_priority/pp_hds_modular/pp_hds_modular.c
|
||
+++ /dev/null
|
||
@@ -1,211 +0,0 @@
|
||
-/*
|
||
- * (C) Copyright HDS GmbH 2006. All Rights Reserved.
|
||
- *
|
||
- * pp_hds_modular.c
|
||
- * Version 2.00
|
||
- *
|
||
- * Prioritizer for Device Mapper Multipath 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 command 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
|
||
- *
|
||
- * To compile this source please execute # cc pp_hds_modular.c -o /sbin/mpath_prio_hds_modular
|
||
- *
|
||
- * Changes 2006-07-16:
|
||
- * - Changed to forward declaration of functions
|
||
- * - The switch-statement was changed to a logical expression
|
||
- * - unlinking of the devpath now also occurs at the end of
|
||
- * hds_modular_prio to avoid old /tmp/.pp_balance.%u.%u.devnode
|
||
- * entries in /tmp-Directory
|
||
- * - The for-statements for passing variables where changed to
|
||
- * snprintf-commands in verbose mode
|
||
- * Changes 2006-08-10:
|
||
- * - Back to the old switch statements because the regular expression does
|
||
- * not work under RHEL4 U3 i386
|
||
- * Changes 2007-06-27:
|
||
- * - switched from major:minor argument to device node argument
|
||
- *
|
||
- * 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>
|
||
-
|
||
-#define INQ_REPLY_LEN 255
|
||
-#define INQ_CMD_CODE 0x12
|
||
-#define INQ_CMD_LEN 6
|
||
-#define FILE_NAME_SIZE 255
|
||
-
|
||
-int verbose=0;
|
||
-
|
||
-void print_help (void);
|
||
-int hds_modular_prio (const char *);
|
||
-
|
||
-int main (int argc, char **argv)
|
||
-{
|
||
- int prio;
|
||
- if (argc == 2)
|
||
- {
|
||
- if (strcmp (argv[1], "-h") == 0)
|
||
- {
|
||
- print_help ();
|
||
- exit (0);
|
||
- }
|
||
- else
|
||
- {
|
||
- verbose = 0;
|
||
- prio = hds_modular_prio (argv[1]);
|
||
- printf ("%d\n", prio);
|
||
- exit (0);
|
||
- }
|
||
- }
|
||
- if ((argc == 3) && (strcmp (argv[1], "-v")) == 0)
|
||
- {
|
||
- verbose = 1;
|
||
- prio = hds_modular_prio (argv[2]);
|
||
- printf ("%d\n", prio);
|
||
- exit (0);
|
||
- }
|
||
- print_help ();
|
||
- exit (1);
|
||
-}
|
||
-
|
||
-int hds_modular_prio (const char *dev)
|
||
-{
|
||
- int sg_fd, k;
|
||
- char vendor[8];
|
||
- char product[32];
|
||
- char serial[32];
|
||
- char ldev[32];
|
||
- char ctrl[32];
|
||
- char port[32];
|
||
- unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
|
||
- unsigned char inqBuff[INQ_REPLY_LEN];
|
||
- unsigned char *inqBuffp = inqBuff;
|
||
- unsigned char sense_buffer[32];
|
||
- sg_io_hdr_t io_hdr;
|
||
-
|
||
- if ((sg_fd = open (dev, 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);
|
||
-
|
||
- snprintf (vendor, 9, "%.8s\n", inqBuffp + 8);
|
||
- snprintf (product, 17, "%.16s", inqBuffp + 16);
|
||
- snprintf (serial, 5, "%.4s", inqBuffp + 40);
|
||
- snprintf (ldev, 5, "%.4s", inqBuffp + 44);
|
||
- snprintf (ctrl, 2, "%.1s", inqBuffp + 49);
|
||
- snprintf (port, 2, "%.1s", inqBuffp + 50);
|
||
-
|
||
- close (sg_fd);
|
||
-
|
||
- if (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;
|
||
- }
|
||
- }
|
||
- return 0;
|
||
-}
|
||
-
|
||
-void print_help (void)
|
||
-{
|
||
- printf ("\n");
|
||
- printf ("Usage: pp_hds_modular [-v] <device>\n");
|
||
- printf ("Option: -v verbose mode\n");
|
||
- printf ("Description: Prioritizer for Device Mapper Multipath and HDS Storage\n");
|
||
- printf ("Version: 2.00\n");
|
||
- printf ("Author: Matthias Rudolph <matthias.rudolph@hds.com>\n");
|
||
- printf ("Remarks: Prioritizer CTRL#1 corresponds to hardware CTRL#0\n");
|
||
- printf (" Prioritizer CTRL#2 corresponds to hardware CTRL#1\n");
|
||
- printf ("\n");
|
||
- return;
|
||
-}
|
||
-
|
||
diff --git a/path_priority/pp_hp_sw/Makefile b/path_priority/pp_hp_sw/Makefile
|
||
deleted file mode 100644
|
||
index e7debf5..0000000
|
||
--- a/path_priority/pp_hp_sw/Makefile
|
||
+++ /dev/null
|
||
@@ -1,25 +0,0 @@
|
||
-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
|
||
deleted file mode 100644
|
||
index e4a18b1..0000000
|
||
--- a/path_priority/pp_hp_sw/pp_hp_sw.c
|
||
+++ /dev/null
|
||
@@ -1,119 +0,0 @@
|
||
-/*
|
||
- * 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);
|
||
-}
|
||
-
|
||
diff --git a/path_priority/pp_netapp/Makefile b/path_priority/pp_netapp/Makefile
|
||
deleted file mode 100644
|
||
index b29d002..0000000
|
||
--- a/path_priority/pp_netapp/Makefile
|
||
+++ /dev/null
|
||
@@ -1,22 +0,0 @@
|
||
-EXEC = mpath_prio_netapp
|
||
-BUILD = glibc
|
||
-OBJS = pp_netapp.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_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
-clean:
|
||
- rm -f *.o $(EXEC)
|
||
diff --git a/path_priority/pp_netapp/pp_netapp.c b/path_priority/pp_netapp/pp_netapp.c
|
||
deleted file mode 100644
|
||
index 8562a95..0000000
|
||
--- a/path_priority/pp_netapp/pp_netapp.c
|
||
+++ /dev/null
|
||
@@ -1,268 +0,0 @@
|
||
-/*
|
||
- * Copyright 2005 Network Appliance, Inc., All Rights Reserved
|
||
- * Author: David Wysochanski available at davidw@netapp.com
|
||
- *
|
||
- * This program is free software; you can redistribute it and/or modify
|
||
- * it under the terms of the GNU General Public License version 2 as
|
||
- * published by the Free Software Foundation.
|
||
- *
|
||
- * 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 v2 for more details.
|
||
- */
|
||
-
|
||
-#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 <assert.h>
|
||
-
|
||
-#include "../../libmultipath/sg_include.h"
|
||
-
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define INQUIRY_CMDLEN 6
|
||
-#define DEFAULT_PRIO 10
|
||
-#define RESULTS_MAX 256
|
||
-#define SG_TIMEOUT 30000
|
||
-
|
||
-
|
||
-static void dump_cdb(unsigned char *cdb, int size)
|
||
-{
|
||
- int i;
|
||
-
|
||
- fprintf(stderr, "- SCSI CDB: ");
|
||
- for (i=0; i<size; i++) {
|
||
- fprintf(stderr, "0x%02x ", cdb[i]);
|
||
- }
|
||
- fprintf(stderr, "\n");
|
||
-}
|
||
-
|
||
-static void process_sg_error(struct sg_io_hdr *io_hdr)
|
||
-{
|
||
- int i;
|
||
-
|
||
- fprintf(stderr, "- masked_status=0x%02x, host_status=0x%02x, "
|
||
- "driver_status=0x%02x\n", io_hdr->masked_status,
|
||
- io_hdr->host_status, io_hdr->driver_status);
|
||
- if (io_hdr->sb_len_wr > 0) {
|
||
- fprintf(stderr, "- SCSI sense data: ");
|
||
- for (i=0; i<io_hdr->sb_len_wr; i++) {
|
||
- fprintf(stderr, "0x%02x ", io_hdr->sbp[i]);
|
||
- }
|
||
- fprintf(stderr, "\n");
|
||
- }
|
||
-}
|
||
-
|
||
-/*
|
||
- * Returns:
|
||
- * -1: error, errno set
|
||
- * 0: success
|
||
- */
|
||
-static int send_gva(const char *dev, unsigned char pg,
|
||
- unsigned char *results, int *results_size)
|
||
-{
|
||
- unsigned char sb[128];
|
||
- unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
|
||
- pg, sizeof(sb), 0, 0};
|
||
- struct sg_io_hdr io_hdr;
|
||
- int ret = -1;
|
||
- int fd;
|
||
-
|
||
- fd = open(dev, O_RDWR|O_NONBLOCK);
|
||
-
|
||
- if (fd <= 0) {
|
||
- fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
|
||
- goto out_no_close;
|
||
- }
|
||
-
|
||
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
|
||
- io_hdr.interface_id = 'S';
|
||
- io_hdr.cmd_len = sizeof (cdb);
|
||
- io_hdr.mx_sb_len = sizeof (sb);
|
||
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- io_hdr.dxfer_len = *results_size;
|
||
- io_hdr.dxferp = results;
|
||
- io_hdr.cmdp = cdb;
|
||
- io_hdr.sbp = sb;
|
||
- io_hdr.timeout = SG_TIMEOUT;
|
||
- io_hdr.pack_id = 0;
|
||
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
- fprintf(stderr, "SG_IO ioctl failed, errno=%d\n", errno);
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- goto out;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- fprintf(stderr, "SCSI error\n");
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- process_sg_error(&io_hdr);
|
||
- goto out;
|
||
- }
|
||
-
|
||
- if (results[4] != 0x0a || results[5] != 0x98 ||
|
||
- results[6] != 0x0a ||results[7] != 0x01) {
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- fprintf(stderr, "GVA return wrong format ");
|
||
- fprintf(stderr, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||
- results[4], results[5], results[6], results[7]);
|
||
- goto out;
|
||
- }
|
||
- ret = 0;
|
||
- out:
|
||
- close(fd);
|
||
- out_no_close:
|
||
- return(ret);
|
||
-}
|
||
-
|
||
-/*
|
||
- * Retuns:
|
||
- * -1: Unable to obtain proxy info
|
||
- * 0: Device _not_ proxy path
|
||
- * 1: Device _is_ proxy path
|
||
- */
|
||
-static int get_proxy(const char *dev)
|
||
-{
|
||
- unsigned char results[256];
|
||
- unsigned char sb[128];
|
||
- unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
|
||
- sizeof(sb), 0};
|
||
- struct sg_io_hdr io_hdr;
|
||
- int ret = -1;
|
||
- int fd;
|
||
-
|
||
- fd = open(dev, O_RDWR|O_NONBLOCK);
|
||
-
|
||
- if (fd <= 0) {
|
||
- fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
|
||
- goto out_no_close;
|
||
- }
|
||
-
|
||
- memset(&results, 0, sizeof (results));
|
||
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
|
||
- io_hdr.interface_id = 'S';
|
||
- io_hdr.cmd_len = sizeof (cdb);
|
||
- io_hdr.mx_sb_len = sizeof (sb);
|
||
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- io_hdr.dxfer_len = sizeof (results);
|
||
- io_hdr.dxferp = results;
|
||
- io_hdr.cmdp = cdb;
|
||
- io_hdr.sbp = sb;
|
||
- io_hdr.timeout = SG_TIMEOUT;
|
||
- io_hdr.pack_id = 0;
|
||
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
- fprintf(stderr, "ioctl sending inquiry command failed, "
|
||
- "errno=%d\n", errno);
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- goto out;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- fprintf(stderr, "SCSI error\n");
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- process_sg_error(&io_hdr);
|
||
- goto out;
|
||
- }
|
||
-
|
||
- if (results[1] != 0xc1 || results[8] != 0x0a ||
|
||
- results[9] != 0x98 || results[10] != 0x0a ||
|
||
- results[11] != 0x0 || results[12] != 0xc1 ||
|
||
- results[13] != 0x0) {
|
||
- fprintf(stderr,"Proxy info page in unknown format - ");
|
||
- fprintf(stderr,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
|
||
- "0x%02x 0x%02x\n",
|
||
- results[8], results[9], results[10],
|
||
- results[11], results[12], results[13]);
|
||
- dump_cdb(cdb, sizeof(cdb));
|
||
- goto out;
|
||
- }
|
||
- ret = (results[19] & 0x02) >> 1;
|
||
-
|
||
- out:
|
||
- close(fd);
|
||
- out_no_close:
|
||
- return(ret);
|
||
-}
|
||
-
|
||
-/*
|
||
- * Returns priority of device based on device info.
|
||
- *
|
||
- * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
|
||
- * 3: iSCSI HBA
|
||
- * 2: iSCSI software
|
||
- * 1: FCP proxy
|
||
- */
|
||
-static int netapp_prio(const char *dev)
|
||
-{
|
||
- unsigned char results[RESULTS_MAX];
|
||
- int results_size=RESULTS_MAX;
|
||
- int rc;
|
||
- int is_proxy;
|
||
- int is_iscsi_software;
|
||
- int is_iscsi_hardware;
|
||
- int tot_len;
|
||
-
|
||
- is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
|
||
-
|
||
- memset(&results, 0, sizeof (results));
|
||
- rc = send_gva(dev, 0x41, results, &results_size);
|
||
- if (rc == 0) {
|
||
- tot_len = results[0] << 24 | results[1] << 16 |
|
||
- results[2] << 8 | results[3];
|
||
- if (tot_len <= 8) {
|
||
- goto try_fcp_proxy;
|
||
- }
|
||
- if (results[8] != 0x41) {
|
||
- fprintf(stderr, "GVA page 0x41 error - "
|
||
- "results[8] = 0x%x\n", results[8]);
|
||
- goto try_fcp_proxy;
|
||
- }
|
||
- if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
|
||
- (strncmp((char *)&results[12], "iswt", 4) == 0)) {
|
||
- is_iscsi_software = 1;
|
||
- goto prio_select;
|
||
- }
|
||
- else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
|
||
- is_iscsi_hardware = 1;
|
||
- goto prio_select;
|
||
- }
|
||
- }
|
||
-
|
||
- try_fcp_proxy:
|
||
- rc = get_proxy(dev);
|
||
- if (rc >= 0) {
|
||
- is_proxy = rc;
|
||
- }
|
||
-
|
||
- prio_select:
|
||
- if (is_iscsi_hardware) {
|
||
- return 3;
|
||
- } else if (is_iscsi_software) {
|
||
- return 2;
|
||
- } else {
|
||
- if (is_proxy) {
|
||
- return 1;
|
||
- } else {
|
||
- /* Either non-proxy, or couldn't get proxy info */
|
||
- return 4;
|
||
- }
|
||
- }
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char **argv)
|
||
-{
|
||
- int prio;
|
||
- if (argc != 2) {
|
||
- fprintf(stderr, "Arguments wrong!\n");
|
||
- prio = 0;
|
||
- } else
|
||
- prio = netapp_prio(argv[1]);
|
||
-
|
||
- printf("%d\n", prio);
|
||
- exit(0);
|
||
-}
|
||
-
|
||
diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile
|
||
deleted file mode 100644
|
||
index 85d7c2f..0000000
|
||
--- a/path_priority/pp_random/Makefile
|
||
+++ /dev/null
|
||
@@ -1,22 +0,0 @@
|
||
-EXEC = mpath_prio_random
|
||
-BUILD = glibc
|
||
-OBJS = pp_random.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_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
-clean:
|
||
- rm -f *.o $(EXEC)
|
||
diff --git a/path_priority/pp_random/pp_random.c b/path_priority/pp_random/pp_random.c
|
||
deleted file mode 100644
|
||
index 05c4b8d..0000000
|
||
--- a/path_priority/pp_random/pp_random.c
|
||
+++ /dev/null
|
||
@@ -1,14 +0,0 @@
|
||
-#include <stdio.h>
|
||
-#include <stdlib.h>
|
||
-#include <sys/time.h>
|
||
-#include <time.h>
|
||
-
|
||
-int main(void)
|
||
-{
|
||
- struct timeval tv;
|
||
-
|
||
- gettimeofday(&tv, NULL);
|
||
- srand((unsigned int)tv.tv_usec);
|
||
- printf("%i\n", 1+(int) (10.0*rand()/(RAND_MAX+1.0)));
|
||
- return 0;
|
||
-}
|
||
diff --git a/path_priority/pp_rdac/Makefile b/path_priority/pp_rdac/Makefile
|
||
deleted file mode 100644
|
||
index 64ed4c3..0000000
|
||
--- a/path_priority/pp_rdac/Makefile
|
||
+++ /dev/null
|
||
@@ -1,22 +0,0 @@
|
||
-EXEC = mpath_prio_rdac
|
||
-BUILD = glibc
|
||
-OBJS = pp_rdac.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_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
||
-
|
||
-uninstall:
|
||
- rm $(DESTDIR)$(bindir)/$(EXEC)
|
||
-clean:
|
||
- rm -f *.o $(EXEC)
|
||
diff --git a/path_priority/pp_rdac/pp_rdac.c b/path_priority/pp_rdac/pp_rdac.c
|
||
deleted file mode 100644
|
||
index 49a13cf..0000000
|
||
--- a/path_priority/pp_rdac/pp_rdac.c
|
||
+++ /dev/null
|
||
@@ -1,112 +0,0 @@
|
||
-#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 "../../libmultipath/sg_include.h"
|
||
-
|
||
-#define INQUIRY_CMD 0x12
|
||
-#define INQUIRY_CMDLEN 6
|
||
-
|
||
-int rdac_prio(const char *dev)
|
||
-{
|
||
- unsigned char sense_buffer[256];
|
||
- unsigned char sb[128];
|
||
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
|
||
- sizeof(sb), 0};
|
||
- struct sg_io_hdr io_hdr;
|
||
- int ret = 0;
|
||
- int fd;
|
||
-
|
||
- fd = open(dev, O_RDWR|O_NONBLOCK);
|
||
-
|
||
- if (fd <= 0) {
|
||
- fprintf(stderr, "opening of 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 (inqCmdBlk);
|
||
- io_hdr.mx_sb_len = sizeof (sb);
|
||
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||
- io_hdr.dxfer_len = sizeof (sense_buffer);
|
||
- io_hdr.dxferp = sense_buffer;
|
||
- io_hdr.cmdp = inqCmdBlk;
|
||
- io_hdr.sbp = sb;
|
||
- io_hdr.timeout = 60000;
|
||
- io_hdr.pack_id = 0;
|
||
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
|
||
- fprintf(stderr, "sending inquiry command failed\n");
|
||
- goto out;
|
||
- }
|
||
- if (io_hdr.info & SG_INFO_OK_MASK) {
|
||
- fprintf(stderr, "inquiry command indicates error");
|
||
- goto out;
|
||
- }
|
||
-
|
||
- close(fd);
|
||
-
|
||
- if (/* Verify the code page - right page & page identifier */
|
||
- sense_buffer[1] != 0xc9 ||
|
||
- sense_buffer[3] != 0x2c ||
|
||
- sense_buffer[4] != 'v' ||
|
||
- sense_buffer[5] != 'a' ||
|
||
- sense_buffer[6] != 'c' ) {
|
||
- fprintf(stderr, "Volume access control page in unknown format");
|
||
- goto out;
|
||
- }
|
||
-
|
||
- if ( /* Current Volume Path Bit */
|
||
- ( sense_buffer[8] & 0x01) == 0x01 ) {
|
||
- /*
|
||
- * This volume was owned by the controller receiving
|
||
- * the inquiry command.
|
||
- */
|
||
- ret |= 0x01;
|
||
- }
|
||
-
|
||
- /* Volume Preferred Path Priority */
|
||
- switch ( sense_buffer[9] & 0x0F ) {
|
||
- case 0x01:
|
||
- /*
|
||
- * Access to this volume is most preferred through
|
||
- * this path and other paths with this value.
|
||
- */
|
||
- ret |= 0x02;
|
||
- break;
|
||
- case 0x02:
|
||
- /*
|
||
- * Access to this volume through this path is to be used
|
||
- * as a secondary path. Typically this path would be used
|
||
- * for fail-over situations.
|
||
- */
|
||
- /* Fallthrough */
|
||
- default:
|
||
- /* Reserved values */
|
||
- break;
|
||
- }
|
||
-
|
||
-out:
|
||
- return(ret);
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char **argv)
|
||
-{
|
||
- int prio;
|
||
- if (argc != 2) {
|
||
- fprintf(stderr, "Wrong number of arguments.\n");
|
||
- fprintf(stderr, "Usage: %s device\n", argv[0]);
|
||
- prio = 0;
|
||
- } else
|
||
- prio = rdac_prio(argv[1]);
|
||
-
|
||
- printf("%d\n", prio);
|
||
- exit(0);
|
||
-}
|