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

14276 lines
383 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, &params);
- 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, &sectors);
- 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,
- &params);
- 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);
-}