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, - -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, -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, 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 -#include -#include -#include -#include -#include -#include - -static void usage(char * progname) { - fprintf(stderr, "usage : %s [-t target type] dev_t\n", progname); - fprintf(stderr, "where dev_t is either 'major minor' or 'major:minor'\n"); - exit(1); -} - -int dm_target_type(int major, int minor, char *type) -{ - struct dm_task *dmt; - void *next = NULL; - uint64_t start, length; - char *target_type = NULL; - char *params; - int r = 1; - - if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) - return 1; - - if (!dm_task_set_major(dmt, major) || - !dm_task_set_minor(dmt, minor)) - goto bad; - - dm_task_no_open_count(dmt); - - if (!dm_task_run(dmt)) - goto bad; - - if (!type) - goto good; - - do { - next = dm_get_next_target(dmt, next, &start, &length, - &target_type, ¶ms); - if (target_type && strcmp(target_type, type)) - goto bad; - } while (next); - -good: - printf("%s\n", dm_task_get_name(dmt)); - r = 0; -bad: - dm_task_destroy(dmt); - return r; -} - -int main(int argc, char **argv) -{ - int c; - int major, minor; - char *target_type = NULL; - - while ((c = getopt(argc, argv, "t:")) != -1) { - switch (c) { - case 't': - target_type = optarg; - break; - default: - usage(argv[0]); - return 1; - break; - } - } - - /* sanity check */ - if (optind == argc - 2) { - major = atoi(argv[argc - 2]); - minor = atoi(argv[argc - 1]); - } else if (optind != argc - 1 || - 2 != sscanf(argv[argc - 1], "%i:%i", &major, &minor)) - usage(argv[0]); - - if (dm_target_type(major, minor, target_type)) - return 1; - - return 0; -} - diff --git a/kpartx/Makefile b/kpartx/Makefile index b4cca6c..21e4ad4 100644 --- a/kpartx/Makefile +++ b/kpartx/Makefile @@ -2,49 +2,30 @@ # # Copyright (C) 2003 Christophe Varoqui, # -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 #include #include +#include #include #include #include #include +#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 #include #include +#include #include "crc32.h" #if BYTE_ORDER == LITTLE_ENDIAN @@ -50,10 +51,18 @@ # define __cpu_to_le32(x) bswap_32(x) #endif +#ifndef BLKGETLASTSECT #define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ +#endif +#ifndef BLKGETSIZE #define BLKGETSIZE _IO(0x12,96) /* return device size */ +#endif +#ifndef BLKSSZGET #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ +#endif +#ifndef BLKGETSIZE64 #define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ +#endif struct blkdev_ioctl_param { unsigned int block; @@ -143,20 +152,14 @@ get_sector_size(int filedes) static uint64_t _get_num_sectors(int filedes) { - unsigned long sectors=0; int rc; -#if 0 - uint64_t bytes=0; + uint64_t bytes=0; - rc = ioctl(filedes, BLKGETSIZE64, &bytes); + rc = ioctl(filedes, BLKGETSIZE64, &bytes); if (!rc) return bytes / get_sector_size(filedes); -#endif - rc = ioctl(filedes, BLKGETSIZE, §ors); - if (rc) - return 0; - - return sectors; + + return 0; } /************************************************************ @@ -193,7 +196,7 @@ last_lba(int filedes) sectors = 1; } - return sectors - 1; + return sectors ? sectors - 1 : 0; } @@ -220,17 +223,22 @@ read_lba(int fd, uint64_t lba, void *buffer, size_t bytes) { int sector_size = get_sector_size(fd); off_t offset = lba * sector_size; + uint64_t lastlba; ssize_t bytesread; lseek(fd, offset, SEEK_SET); bytesread = read(fd, buffer, bytes); + lastlba = last_lba(fd); + if (!lastlba) + return bytesread; + /* Kludge. This is necessary to read/write the last block of an odd-sized disk, until Linux 2.5.x kernel fixes. This is only used by gpt.c, and only to read one sector, so we don't have to be fancy. */ - if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) { + if (!bytesread && !(lastlba & 1) && lba == lastlba) { bytesread = read_lastoddsector(fd, lba, buffer, bytes); } return bytesread; @@ -505,7 +513,8 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes) if (!gpt || !ptes) return 0; - lastlba = last_lba(fd); + if (!(lastlba = last_lba(fd))) + return 0; good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8 index 87b07ce..c61f312 100644 --- a/kpartx/kpartx.8 +++ b/kpartx/kpartx.8 @@ -26,6 +26,9 @@ List partition mappings that would be added -a .B \-p set device name-partition number delimiter .TP +.B \-g +force GUID partition table (GPT) +.TP .B \-v Operate verbosely .SH "SEE ALSO" diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c index dbe2ee2..8658731 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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 + /* * 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, -# -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 -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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, # -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 -#include +#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 #include #include +#include #include #include -#include - +#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 +#include +#include +#include + +#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, +# +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 +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include -#include - +#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 #include -#include - +#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 #include -#if DAEMON #include "log_pthread.h" #include #include -#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 #include #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 #include -#include - +#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 #include -#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 - +#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 #include -#include - +#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 #include -#include - +#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 -#include - +#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 #include -#include - +#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 #include -#include - +#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 +#include +#include +#include + +#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, +# +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 + * + * This file is released under the GPL. + */ +#include + +#include +#include + +#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 + * + * This file is released under the GPL. + */ +#include +#include +#include +#include +#include + +#define __user +#include + +#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 + * + * 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 + * + * 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 + +#include + +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 +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; imasked_status, + io_hdr->host_status, io_hdr->driver_status); + if (io_hdr->sb_len_wr > 0) { + condlog(0, "- SCSI sense data: "); + for (i=0; isb_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 +#include +#include +#include + +#include + +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 +#include +#include + +#include +#include +#include + +#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 -#include - +#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 #include -#include - +#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 #include -#include - +#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 - +#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 #include #include +#include #include #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, -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 #include +#include #include #include #include @@ -48,6 +49,8 @@ #include #include +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 #include +#include #include #include #include @@ -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 #include #include +#include +#include /* * libcheckers @@ -43,6 +45,7 @@ #include #include #include +#include #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. - - - Copyright (C) - - 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. - - , 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 -# -# 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 - * - * This file is released under the GPL. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 [ [...]]\n\n", - basename(command)); - printf("Options are:\n"); - - printf("\t-d \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-:- \*[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 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 - * - * This file is released under the GPL. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __user -#include - -#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 - * - * 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 - * - * 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, -# -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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define SERIAL_SIZE 255 -#define WORD_SIZE 255 -#define PARAMS_SIZE 255 -#define FILE_NAME_SIZE 255 -#define INQUIRY_CMDLEN 6 -#define INQUIRY_CMD 0x12 -#define SENSE_BUFF_LEN 32 -#define DEF_TIMEOUT 300000 -#define RECOVERED_ERROR 0x01 -#define MX_ALLOC_LEN 255 -#define SCSI_CHECK_CONDITION 0x2 -#define SCSI_COMMAND_TERMINATED 0x22 -#define SG_ERR_DRIVER_SENSE 0x08 - -#if DEBUG -#define debug(format, arg...) fprintf(stderr, format "\n", ##arg) -#else -#define debug(format, arg...) do {} while(0) -#endif - -#define safe_sprintf(var, format, args...) \ - snprintf(var, sizeof(var), format, ##args) >= sizeof(var) -#define safe_snprintf(var, size, format, args...) \ - snprintf(var, size, format, ##args) >= size - -struct path { - char dev_t[WORD_SIZE]; - char serial[SERIAL_SIZE]; -}; - -struct controller { - char serial[SERIAL_SIZE]; - int path_count; -}; - -static int -exit_tool (int ret) -{ - printf("1\n"); - exit(ret); -} - -static int -opennode (char * devt, int mode) -{ - char devpath[FILE_NAME_SIZE]; - unsigned int major; - unsigned int minor; - int fd; - - sscanf(devt, "%u:%u", &major, &minor); - memset(devpath, 0, FILE_NAME_SIZE); - - if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode", - major, minor)) { - fprintf(stderr, "devpath too small\n"); - return -1; - } - unlink (devpath); - mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor)); - fd = open(devpath, mode); - - if (fd < 0) - unlink(devpath); - - return fd; - -} - -static void -closenode (char * devt, int fd) -{ - char devpath[FILE_NAME_SIZE]; - unsigned int major; - unsigned int minor; - - if (fd >= 0) - close(fd); - - sscanf(devt, "%u:%u", &major, &minor); - if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode", - major, minor)) { - fprintf(stderr, "devpath too small\n"); - return; - } - unlink(devpath); -} - -static int -do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, - void *resp, int mx_resp_len, int noisy) -{ - unsigned char inqCmdBlk[INQUIRY_CMDLEN] = - { INQUIRY_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - struct sg_io_hdr io_hdr; - - if (cmddt) - inqCmdBlk[1] |= 2; - if (evpd) - inqCmdBlk[1] |= 1; - inqCmdBlk[2] = (unsigned char) pg_op; - inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); - inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff); - memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof (inqCmdBlk); - io_hdr.mx_sb_len = sizeof (sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = inqCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) - return -1; - - /* treat SG_ERR here to get rid of sg_err.[ch] */ - io_hdr.status &= 0x7e; - if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && - (0 == io_hdr.driver_status)) - return 0; - if ((SCSI_CHECK_CONDITION == io_hdr.status) || - (SCSI_COMMAND_TERMINATED == io_hdr.status) || - (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) { - if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) { - int sense_key; - unsigned char * sense_buffer = io_hdr.sbp; - if (sense_buffer[0] & 0x2) - sense_key = sense_buffer[1] & 0xf; - else - sense_key = sense_buffer[2] & 0xf; - if(RECOVERED_ERROR == sense_key) - return 0; - } - } - return -1; -} - -static int -get_serial (char * str, int maxlen, char * devt) -{ - int fd; - int len; - char buff[MX_ALLOC_LEN + 1]; - - fd = opennode(devt, O_RDONLY); - - if (fd < 0) - return 1; - - if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) { - len = buff[3]; - if (len >= maxlen) - return 1; - if (len > 0) { - memcpy(str, buff + 4, len); - buff[len] = '\0'; - } - close(fd); - return 0; - } - - closenode(devt, fd); - return 1; -} - -static void * -get_params (void) -{ - struct dm_task *dmt, *dmt1; - struct dm_names *names = NULL; - unsigned next = 0; - void *nexttgt; - uint64_t start, length; - char *target_type = NULL; - char *params; - char *pp; - vector paramsvec = NULL; - - if (!(dmt = dm_task_create(DM_DEVICE_LIST))) - return NULL; - - if (!dm_task_run(dmt)) - goto out; - - if (!(names = dm_task_get_names(dmt))) - goto out; - - if (!names->dev) { - debug("no devmap found"); - goto out; - } - do { - /* - * keep only multipath maps - */ - names = (void *) names + next; - nexttgt = NULL; - debug("devmap %s :", names->name); - - if (!(dmt1 = dm_task_create(DM_DEVICE_TABLE))) - goto out; - - if (!dm_task_set_name(dmt1, names->name)) - goto out1; - - if (!dm_task_run(dmt1)) - goto out1; - - do { - nexttgt = dm_get_next_target(dmt1, nexttgt, - &start, - &length, - &target_type, - ¶ms); - debug("\\_ %lu %lu %s", (unsigned long) start, - (unsigned long) length, - target_type); - - if (!target_type) { - debug("unknown target type"); - goto out1; - } - - if (!strncmp(target_type, "multipath", 9)) { - if (!paramsvec) - paramsvec = vector_alloc(); - - pp = malloc(PARAMS_SIZE); - strncpy(pp, params, PARAMS_SIZE); - vector_alloc_slot(paramsvec); - vector_set_slot(paramsvec, pp); - } else - debug("skip non multipath target"); - } while (nexttgt); -out1: - dm_task_destroy(dmt1); - next = names->next; - } while (next); -out: - dm_task_destroy(dmt); - return paramsvec; -} - -static int -get_word (char *sentence, char *word) -{ - char *p; - int skip = 0; - - while (*sentence == ' ') { - sentence++; - skip++; - } - p = sentence; - - while (*p != ' ' && *p != '\0') - p++; - - skip += (p - sentence); - - if (p - sentence > WORD_SIZE) { - fprintf(stderr, "word too small\n"); - exit_tool(1); - } - strncpy(word, sentence, WORD_SIZE); - word += p - sentence; - *word = '\0'; - - if (*p == '\0') - return 0; - - return skip; -} - -static int -is_path (char * word) -{ - char *p; - - if (!word) - return 0; - - p = word; - - while (*p != '\0') { - if (*p == ':') - return 1; - p++; - } - return 0; -} - -static int -get_paths (vector pathvec) -{ - vector paramsvec = NULL; - char * str; - struct path * pp; - int i; - enum where {BEFOREPG, INPG, AFTERPG}; - int pos = BEFOREPG; - - if (!pathvec) - return 1; - - if (!(paramsvec = get_params())) - exit_tool(0); - - vector_foreach_slot (paramsvec, str, i) { - debug("params %s", str); - while (pos != AFTERPG) { - pp = zalloc(sizeof(struct path)); - str += get_word(str, pp->dev_t); - - if (!is_path(pp->dev_t)) { - debug("skip \"%s\"", pp->dev_t); - free(pp); - - if (pos == INPG) - pos = AFTERPG; - - continue; - } - if (pos == BEFOREPG) - pos = INPG; - - get_serial(pp->serial, SERIAL_SIZE, pp->dev_t); - vector_alloc_slot(pathvec); - vector_set_slot(pathvec, pp); - debug("store %s [%s]", - pp->dev_t, pp->serial); - } - pos = BEFOREPG; - } - return 0; -} - -static void * -find_controller (vector controllers, char * serial) -{ - int i; - struct controller * cp; - - if (!controllers) - return NULL; - - vector_foreach_slot (controllers, cp, i) - if (!strncmp(cp->serial, serial, SERIAL_SIZE)) - return cp; - return NULL; -} - -static void -get_controllers (vector controllers, vector pathvec) -{ - int i; - struct path * pp; - struct controller * cp; - - if (!controllers) - return; - - vector_foreach_slot (pathvec, pp, i) { - if (!pp || !strlen(pp->serial)) - continue; - - cp = find_controller(controllers, pp->serial); - - if (!cp) { - cp = zalloc(sizeof(struct controller)); - vector_alloc_slot(controllers); - vector_set_slot(controllers, cp); - strncpy(cp->serial, pp->serial, SERIAL_SIZE); - } - cp->path_count++; - } -} - -static int -get_max_path_count (vector controllers) -{ - int i; - int max = 0; - struct controller * cp; - - if (!controllers) - return 0; - - vector_foreach_slot (controllers, cp, i) { - debug("controller %s : %i paths", cp->serial, cp->path_count); - if(cp->path_count > max) - max = cp->path_count; - } - debug("max_path_count = %i", max); - return max; -} - -int -main (int argc, char **argv) -{ - vector pathvec = NULL; - vector controllers = NULL; - struct path * ref_path = NULL; - struct controller * cp = NULL; - int max_path_count = 0; - - ref_path = zalloc(sizeof(struct path)); - - if (!ref_path) - exit_tool(1); - - if (argc != 2) - exit_tool(1); - - if (optinddev_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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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] \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 \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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; imasked_status, - io_hdr->host_status, io_hdr->driver_status); - if (io_hdr->sb_len_wr > 0) { - fprintf(stderr, "- SCSI sense data: "); - for (i=0; isb_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 -#include -#include -#include - -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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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); -}