From ba8402c1449f14c24e4dcdb09387574a887ed6afee6d73ec96bf549dfcecda8d Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Thu, 2 Aug 2007 20:50:38 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/multipath-tools?expand=0&rev=4 --- multipath-tools-git-update.patch | 6122 ++++++++++++++++++++++++++---- multipath-tools-local-fixes | 2036 ---------- multipath-tools-suse-update | 3522 ++--------------- multipath-tools.changes | 8 + multipath-tools.spec | 24 +- 5 files changed, 5872 insertions(+), 5840 deletions(-) delete mode 100644 multipath-tools-local-fixes diff --git a/multipath-tools-git-update.patch b/multipath-tools-git-update.patch index 27b3392..b18eefb 100644 --- a/multipath-tools-git-update.patch +++ b/multipath-tools-git-update.patch @@ -1,88 +1,13 @@ - Makefile | 4 + - devmap_name/devmap_name.8 | 2 +- - kpartx/dasd.c | 28 +- - kpartx/devmapper.c | 46 +++- - kpartx/devmapper.h | 4 +- - kpartx/kpartx.8 | 2 +- - kpartx/kpartx.c | 15 +- - libcheckers/Makefile | 2 +- - libcheckers/checkers.c | 13 +- - libcheckers/checkers.h | 61 +++- - libcheckers/emc_clariion.c | 157 ++++++-- - libcheckers/hp_sw.c | 3 +- - libcheckers/libsg.c | 79 ++++ - libcheckers/libsg.h | 8 + - libcheckers/rdac.c | 109 +++++ - libcheckers/rdac.h | 8 + - libcheckers/readsector0.c | 76 +---- - libcheckers/tur.c | 2 +- - libmultipath/Makefile | 9 +- - libmultipath/alias.c | 97 +++-- - libmultipath/blacklist.c | 179 ++++++++-- - libmultipath/blacklist.h | 21 +- - libmultipath/config.c | 100 ++++- - libmultipath/config.h | 15 +- - libmultipath/configure.c | 74 ++-- - libmultipath/configure.h | 2 +- - libmultipath/debug.c | 5 +- - libmultipath/debug.h | 4 +- - libmultipath/defaults.h | 1 + - libmultipath/devmapper.c | 111 +++++- - libmultipath/devmapper.h | 3 +- - libmultipath/dict.c | 229 +++++++++++- - libmultipath/discovery.c | 51 ++- - libmultipath/discovery.h | 6 +- - libmultipath/dmparser.c | 19 +- - libmultipath/hwtable.c | 198 ++++++++-- - libmultipath/lock.c | 8 + - libmultipath/lock.h | 22 + - libmultipath/parser.c | 15 +- - libmultipath/parser.h | 1 + - libmultipath/pgpolicies.h | 2 +- - libmultipath/print.c | 266 ++++++++++++- - libmultipath/print.h | 3 + - libmultipath/propsel.c | 71 +++- - libmultipath/propsel.h | 1 + - libmultipath/structs.c | 15 +- - libmultipath/structs.h | 21 +- - libmultipath/structs_vec.c | 95 +++++- - libmultipath/structs_vec.h | 14 +- - libmultipath/switchgroup.c | 2 +- - libmultipath/util.c | 9 + - libmultipath/util.h | 1 + - libmultipath/version.h | 37 ++ - libmultipath/waiter.c | 234 +++++++++++ - libmultipath/waiter.h | 23 ++ - multipath-tools.spec.in | 1 + - multipath.conf.annotated | 22 +- - multipath.conf.synthetic | 6 +- - multipath/main.c | 36 ++- - multipath/main.h | 39 -- - multipath/multipath.8 | 15 +- - multipathd/cli.c | 232 ++++++++++-- - multipathd/cli.h | 7 + - multipathd/cli_handlers.c | 94 +++++- - multipathd/cli_handlers.h | 2 + - multipathd/main.c | 439 +++------------------ - multipathd/multipathd.8 | 96 ++++- - multipathd/uxclnt.c | 6 + - path_priority/pp_alua/main.c | 4 +- - path_priority/pp_alua/mpath_prio_alua.8 | 2 +- - path_priority/pp_alua/rtpg.c | 36 ++- - path_priority/pp_alua/spc3.h | 4 +- - path_priority/pp_balance_units/pp_balance_units.c | 74 ++-- - path_priority/pp_hds_modular/Makefile | 22 + - path_priority/pp_hds_modular/pp_hds_modular.c | 252 ++++++++++++ - path_priority/pp_tpc/pp_tpc.c | 12 +- - 76 files changed, 3026 insertions(+), 958 deletions(-) - diff --git a/Makefile b/Makefile -index 83ae2fe..aacede3 100644 +index 83ae2fe..ee554e7 100644 --- a/Makefile +++ b/Makefile -@@ -22,7 +22,11 @@ export KRNLOBJ +@@ -20,9 +20,13 @@ endif + export KRNLSRC + export KRNLOBJ - BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib) +-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib) ++BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -vE '^lib|/\.') +ifeq ($(MULTIPATH_VERSION),) VERSION = $(shell basename ${PWD} | cut -d'-' -f3) @@ -92,6 +17,53 @@ index 83ae2fe..aacede3 100644 all: recurse +diff --git a/Makefile.inc b/Makefile.inc +index 4a705aa..7e2d4e6 100644 +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -17,15 +17,16 @@ ifeq ($(strip $(BUILD)),klibc) + CC = klcc + klibcdir = /usr/lib/klibc + libdm = $(klibcdir)/lib/libdevmapper.a +- libsysfs = $(klibcdir)/lib/libsysfs.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 + + GZIP = /bin/gzip -9 -c +@@ -33,6 +34,8 @@ GZIP = /bin/gzip -9 -c + CHECKERSLIB = $(checkersdir)/libcheckers + MULTIPATHLIB = $(multipathdir)/libmultipath + ++INSTALL_PROGRAM = install -s ++ + OPTFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes + CFLAGS = $(OPTFLAGS) + +diff --git a/devmap_name/Makefile b/devmap_name/Makefile +index 380c85b..d8d8b09 100644 +--- a/devmap_name/Makefile ++++ b/devmap_name/Makefile +@@ -28,9 +28,9 @@ klibc: prepare $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + $(GZIP) $(EXEC).8 > $(EXEC).8.gz + +-install: ++install: $(EXEC) $(EXEC).8 + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + install -d $(DESTDIR)$(mandir) + install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) + diff --git a/devmap_name/devmap_name.8 b/devmap_name/devmap_name.8 index f4f03c3..86d0931 100644 --- a/devmap_name/devmap_name.8 @@ -102,6 +74,111 @@ index f4f03c3..86d0931 100644 .SH NAME devmap_name \- Query device-mapper name .SH SYNOPSIS +diff --git a/kpartx/Makefile b/kpartx/Makefile +index bf6e6c1..b4cca6c 100644 +--- a/kpartx/Makefile ++++ b/kpartx/Makefile +@@ -6,15 +6,15 @@ BUILD=glibc + + include ../Makefile.inc + +-CFLAGS += -I. -D_LARGEFILE64_SOURCE ++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 \ ++ 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 \ ++ 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 + +@@ -36,9 +36,13 @@ klibc: prepare $(OBJS) + $(MULTIPATHLIB)-$(BUILD).a: + make -C $(multipathdir) BUILD=$(BUILD) + +-install: ++install: $(EXEC) $(EXEC).8 + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) ++ $(INSTALL_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) + +diff --git a/kpartx/bsd.c b/kpartx/bsd.c +index 3ae2dc4..f87175e 100644 +--- a/kpartx/bsd.c ++++ b/kpartx/bsd.c +@@ -10,7 +10,7 @@ struct bsd_disklabel { + short int d_type; /* drive type */ + short int d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ +- char d_packname[16]; /* pack identifier */ ++ char d_packname[16]; /* pack identifier */ + unsigned int d_secsize; /* # of bytes per sector */ + unsigned int d_nsectors; /* # of data sectors per track */ + unsigned int d_ntracks; /* # of tracks per cylinder */ +@@ -50,12 +50,12 @@ int + read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) { + struct bsd_disklabel *l; + struct bsd_partition *p; +- unsigned int offset = all.start; ++ unsigned int offset = all.start, end; + int max_partitions; + char *bp; +- int n = 0; ++ int n = 0, i, j; + +- bp = getblock(fd, offset+1); /* 1 sector suffices */ ++ bp = getblock(fd, offset+1); /* 1 sector suffices */ + if (bp == NULL) + return -1; + +@@ -79,5 +79,36 @@ read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) { + break; + } + } ++ /* ++ * Convention has it that the bsd disklabel will always have ++ * the 'c' partition spanning the entire disk. ++ * So we have to check for contained slices. ++ */ ++ for(i = 0; i < n; i++) { ++ if (sp[i].size == 0) ++ continue; ++ ++ end = sp[i].start + sp[i].size; ++ for(j = 0; j < n; j ++) { ++ if ( i == j ) ++ continue; ++ if (sp[j].size == 0) ++ continue; ++ ++ if (sp[i].start < sp[j].start) { ++ if (end > sp[j].start && ++ end < sp[j].start + sp[j].size) { ++ /* Invalid slice */ ++ fprintf(stderr, ++ "bsd_disklabel: slice %d overlaps with %d\n", i , j); ++ sp[i].size = 0; ++ } ++ } else { ++ if (end <= sp[j].start + sp[j].size) { ++ sp[i].container = j + 1; ++ } ++ } ++ } ++ } + return n; + } diff --git a/kpartx/dasd.c b/kpartx/dasd.c index 69b9807..f31111f 100644 --- a/kpartx/dasd.c @@ -128,7 +205,7 @@ index 69b9807..f31111f 100644 dasd_information_t info; struct hd_geometry geo; char type[5] = {0,}; -@@ -172,13 +178,13 @@ read_dasd_pt(int fd, struct slice all, s +@@ -172,13 +178,13 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns) /* disk is reserved minidisk */ blocksize = label[3]; offset = label[13]; @@ -147,7 +224,7 @@ index 69b9807..f31111f 100644 retval = 1; } else if ((strncmp(type, "VOL1", 4) == 0) && (!info.FBA_layout) && (!strcmp(info.type, "ECKD"))) { -@@ -214,8 +220,8 @@ read_dasd_pt(int fd, struct slice all, s +@@ -214,8 +220,8 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns) offset = cchh2blk(&f1.DS1EXT1.llimit, &geo); size = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - offset + geo.sectors; @@ -158,7 +235,7 @@ index 69b9807..f31111f 100644 counter++; blk++; } -@@ -224,10 +230,8 @@ read_dasd_pt(int fd, struct slice all, s +@@ -224,10 +230,8 @@ read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns) /* * Old style LNX1 or unlabeled disk */ @@ -172,7 +249,7 @@ index 69b9807..f31111f 100644 } diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c -index 1253941..5b27487 100644 +index 1253941..6e3e198 100644 --- a/kpartx/devmapper.c +++ b/kpartx/devmapper.c @@ -7,6 +7,10 @@ @@ -186,7 +263,7 @@ index 1253941..5b27487 100644 extern int dm_prereq (char * str, int x, int y, int z) -@@ -68,9 +72,10 @@ dm_simplecmd (int task, const char *name +@@ -68,9 +72,10 @@ dm_simplecmd (int task, const char *name) { extern int dm_addmap (int task, const char *name, const char *target, @@ -198,7 +275,7 @@ index 1253941..5b27487 100644 if (!(dmt = dm_task_create (task))) return 0; -@@ -81,10 +86,26 @@ dm_addmap (int task, const char *name, c +@@ -81,12 +86,25 @@ dm_addmap (int task, const char *name, const char *target, if (!dm_task_add_target (dmt, 0, size, target, params)) goto addout; @@ -211,21 +288,20 @@ index 1253941..5b27487 100644 + } + sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid); + if (!dm_task_set_uuid(dmt, prefixed_uuid)) -+ goto freeout; ++ goto addout; + } + dm_task_no_open_count(dmt); r = dm_task_run (dmt); -+ freeout: -+ if (prefixed_uuid) -+ free(prefixed_uuid); -+ addout: dm_task_destroy (dmt); ++ return r; -@@ -178,3 +199,26 @@ out: + } + +@@ -178,3 +196,56 @@ out: return ret; } @@ -233,7 +309,8 @@ index 1253941..5b27487 100644 +dm_mapuuid(int major, int minor) +{ + struct dm_task *dmt; -+ char *tmp, *uuid = NULL; ++ const char *tmp; ++ char *uuid = NULL; + + if (!(dmt = dm_task_create(DM_DEVICE_INFO))) + return NULL; @@ -252,11 +329,40 @@ index 1253941..5b27487 100644 + dm_task_destroy(dmt); + return uuid; +} ++ ++int ++dm_devn (char * mapname, int *major, int *minor) ++{ ++ int r = 1; ++ struct dm_task *dmt; ++ struct dm_info info; ++ ++ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) ++ return 0; ++ ++ if (!dm_task_set_name(dmt, mapname)) ++ goto out; ++ ++ if (!dm_task_run(dmt)) ++ goto out; ++ ++ if (!dm_task_get_info(dmt, &info)) ++ goto out; ++ ++ *major = info.major; ++ *minor = info.minor; ++ ++ r = 0; ++out: ++ dm_task_destroy(dmt); ++ return r; ++} ++ diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h -index 9607476..e20e456 100644 +index 9607476..ccdbead 100644 --- a/kpartx/devmapper.h +++ b/kpartx/devmapper.h -@@ -1,6 +1,8 @@ +@@ -1,6 +1,9 @@ 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); @@ -266,6 +372,39 @@ index 9607476..e20e456 100644 char * dm_mapname(int major, int minor); dev_t dm_get_first_dep(char *devname); +char * dm_mapuuid(int major, int minor); ++int dm_devn (char * mapname, int *major, int *minor); +diff --git a/kpartx/dos.c b/kpartx/dos.c +index a707423..1691105 100644 +--- a/kpartx/dos.c ++++ b/kpartx/dos.c +@@ -16,7 +16,7 @@ is_extended(int type) { + } + + static int +-read_extended_partition(int fd, struct partition *ep, ++read_extended_partition(int fd, struct partition *ep, int en, + struct slice *sp, int ns) + { + struct partition p; +@@ -53,6 +53,7 @@ read_extended_partition(int fd, struct partition *ep, + if (n < ns) { + sp[n].start = here + le32_to_cpu(p.start_sect); + sp[n].size = le32_to_cpu(p.nr_sects); ++ sp[n].container = en + 1; + n++; + } else { + fprintf(stderr, +@@ -97,9 +98,7 @@ read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) { + break; + } + if (is_extended(p.sys_type)) { +- n += read_extended_partition(fd, &p, sp+n, ns-n); +- /* hide the extended partition itself */ +- sp[i].size = 0; ++ n += read_extended_partition(fd, &p, i, sp+n, ns-n); + } + } + return n; diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8 index 259ce3f..87b07ce 100644 --- a/kpartx/kpartx.8 @@ -277,18 +416,66 @@ index 259ce3f..87b07ce 100644 kpartx \- Create device maps from partition tables .SH SYNOPSIS diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c -index 2198302..0ee0cb3 100644 +index 2198302..dbe2ee2 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c -@@ -192,6 +192,7 @@ main(int argc, char **argv){ +@@ -79,6 +79,7 @@ initpts(void) + addpts("unixware", read_unixware_pt); + addpts("dasd", read_dasd_pt); + addpts("mac", read_mac_pt); ++ addpts("sun", read_sun_pt); + } + + static char short_opts[] = "ladgvnp:t:"; +@@ -115,7 +116,7 @@ strip_slash (char * device) + char * p = device; + + while (*(p++) != 0x0) { +- ++ + if (*p == '/') + *p = '!'; + } +@@ -125,9 +126,9 @@ static int + find_devname_offset (char * device) + { + char *p, *q = NULL; +- ++ + p = device; +- ++ + while (*p++) + if (*p == '/') + q = p; +@@ -182,7 +183,7 @@ get_hotplug_device(void) + + int + main(int argc, char **argv){ +- int fd, i, j, k, n, op, off, arg; ++ int fd, i, j, m, n, op, off, arg, c, d; + struct slice all; + struct pt *ptp; + enum action what = LIST; +@@ -192,6 +193,8 @@ main(int argc, char **argv){ char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16]; char * loopdev = NULL; char * delim = NULL; + char *uuid = NULL; ++ char *mapname = NULL; int loopro = 0; int hotplug = 0; struct stat buf; -@@ -284,11 +285,6 @@ main(int argc, char **argv){ +@@ -203,7 +206,7 @@ main(int argc, char **argv){ + type = device = diskdevice = NULL; + memset(&all, 0, sizeof(all)); + memset(&partname, 0, sizeof(partname)); +- ++ + /* Check whether hotplug mode. */ + progname = strrchr(argv[0], '/'); + +@@ -284,17 +287,12 @@ main(int argc, char **argv){ } if (S_ISREG (buf.st_mode)) { @@ -300,21 +487,158 @@ index 2198302..0ee0cb3 100644 /* already looped file ? */ loopdev = find_loop_by_file(device); -@@ -313,6 +309,13 @@ main(int argc, char **argv){ + if (!loopdev && what == DELETE) + exit (0); +- ++ + if (!loopdev) { + loopdev = find_unused_loop_device(); + +@@ -311,8 +309,22 @@ main(int argc, char **argv){ + memset(delim, 0, DELIM_SIZE); + set_delimiter(device, delim); } - +- ++ off = find_devname_offset(device); + -+ if (!loopdev) ++ if (!loopdev) { + uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev), + (unsigned int)MINOR(buf.st_rdev)); ++ mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev), ++ (unsigned int)MINOR(buf.st_rdev)); ++ } ++ + if (!uuid) + uuid = device + off; -+ ++ ++ if (!mapname) ++ mapname = device + off; ++ fd = open(device, O_RDONLY); if (fd == -1) { -@@ -420,7 +423,7 @@ main(int argc, char **argv){ +@@ -328,7 +340,7 @@ main(int argc, char **argv){ + + if (type && strcmp(type, ptp->type)) + continue; +- ++ + /* here we get partitions */ + n = ptp->fn(fd, all, slices, SIZE(slices)); + +@@ -342,36 +354,56 @@ main(int argc, char **argv){ + else + continue; + +- /* +- * test for overlap, as in the case of an extended partition +- * zero their size to avoid mapping +- */ +- for (j=0; j slices[j].start && +- slices[k].start < slices[j].start + +- slices[j].size) +- slices[j].size = 0; +- } +- } +- + switch(what) { + case LIST: +- for (j = 0; j < n; j++) { ++ for (j = 0, c = 0, m = 0; j < n; j++) { + if (slices[j].size == 0) + continue; ++ if (slices[j].container > 0) { ++ c++; ++ continue; ++ } ++ ++ slices[j].minor = m++; + + printf("%s%s%d : 0 %lu %s %lu\n", +- device + off, delim, j+1, +- (unsigned long) slices[j].size, device, +- (unsigned long) slices[j].start); ++ mapname, delim, j+1, ++ (unsigned long) slices[j].size, device, ++ (unsigned long) slices[j].start); + } ++ /* Loop to resolve contained slices */ ++ d = c; ++ while (c) { ++ for (j = 0; j < n; j++) { ++ unsigned long start; ++ int k = slices[j].container - 1; ++ ++ if (slices[j].size == 0) ++ continue; ++ if (slices[j].minor > 0) ++ continue; ++ if (slices[j].container == 0) ++ continue; ++ slices[j].minor = m++; ++ ++ start = slices[j].start - slices[k].start; ++ printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n", ++ mapname, delim, j+1, ++ (unsigned long) slices[j].size, ++ slices[k].minor, start); ++ c--; ++ } ++ /* Terminate loop if nothing more to resolve */ ++ if (d == c) ++ break; ++ } ++ + break; + + case DELETE: + for (j = 0; j < n; j++) { + if (safe_sprintf(partname, "%s%s%d", +- device + off , delim, j+1)) { ++ mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); + exit(1); + } +@@ -390,7 +422,7 @@ main(int argc, char **argv){ + if (S_ISREG (buf.st_mode)) { + if (del_loop(device)) { + if (verbose) +- printf("can't del loop : %s\n", ++ printf("can't del loop : %s\n", + device); + exit(1); + } +@@ -399,17 +431,23 @@ main(int argc, char **argv){ + break; + + case ADD: +- for (j=0; j 0) { ++ c++; ++ continue; ++ } ++ + if (safe_sprintf(partname, "%s%s%d", +- device + off , delim, j+1)) { ++ mapname, delim, j+1)) { + fprintf(stderr, "partname too small\n"); + exit(1); + } + strip_slash(partname); +- ++ + if (safe_sprintf(params, "%s %lu", device, + (unsigned long)slices[j].start)) { + fprintf(stderr, "params too small\n"); +@@ -420,16 +458,80 @@ main(int argc, char **argv){ DM_DEVICE_RELOAD : DM_DEVICE_CREATE); dm_addmap(op, partname, DM_TARGET, params, @@ -323,6 +647,391 @@ index 2198302..0ee0cb3 100644 if (op == DM_DEVICE_RELOAD) dm_simplecmd(DM_DEVICE_RESUME, + partname); + ++ dm_devn(partname, &slices[j].major, ++ &slices[j].minor); ++ + if (verbose) +- printf("add map %s : 0 %lu %s %s\n", +- partname, slices[j].size, +- DM_TARGET, params); ++ printf("add map %s (%d:%d): 0 %lu %s %s\n", ++ partname, slices[j].major, ++ slices[j].minor, slices[j].size, ++ DM_TARGET, params); ++ } ++ /* Loop to resolve contained slices */ ++ d = c; ++ while (c) { ++ for (j = 0; j < n; j++) { ++ int k = slices[j].container - 1; ++ ++ if (slices[j].size == 0) ++ continue; ++ ++ /* Skip all existing slices */ ++ if (slices[j].minor > 0) ++ continue; ++ ++ /* Skip all simple slices */ ++ if (k < 0) ++ continue; ++ ++ /* Check container slice */ ++ if (slices[k].size == 0) ++ fprintf(stderr, "Invalid slice %d\n", ++ k); ++ ++ if (safe_sprintf(partname, "%s%s%d", ++ mapname, delim, j+1)) { ++ fprintf(stderr, "partname too small\n"); ++ exit(1); ++ } ++ strip_slash(partname); ++ ++ if (safe_sprintf(params, "%d:%d %lu", ++ slices[k].major, ++ slices[k].minor, ++ (unsigned long)slices[j].start)) { ++ fprintf(stderr, "params too small\n"); ++ exit(1); ++ } ++ ++ 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); ++ ++ dm_devn(partname, &slices[j].major, ++ &slices[j].minor); ++ ++ if (verbose) ++ printf("add map %s : 0 %lu %s %s\n", ++ partname, slices[j].size, ++ DM_TARGET, params); ++ c--; ++ } ++ /* Terminate loop */ ++ if (d == c) ++ break; + } + break; + +@@ -505,7 +607,7 @@ getblock (int fd, unsigned int secnr) { + bp->next = blockhead; + blockhead = bp; + bp->block = (char *) xmalloc(READ_SIZE); +- ++ + if (read(fd, bp->block, READ_SIZE) != READ_SIZE) { + fprintf(stderr, "read error, sector %d\n", secnr); + bp->block = NULL; +diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h +index 6a715de..9b3aeca 100644 +--- a/kpartx/kpartx.h ++++ b/kpartx/kpartx.h +@@ -22,6 +22,9 @@ + struct slice { + unsigned long start; + unsigned long size; ++ int container; ++ int major; ++ int minor; + }; + + typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns); +@@ -33,6 +36,7 @@ extern ptreader read_unixware_pt; + extern ptreader read_gpt_pt; + extern ptreader read_dasd_pt; + extern ptreader read_mac_pt; ++extern ptreader read_sun_pt; + + char *getblock(int fd, unsigned int secnr); + +diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules +new file mode 100644 +index 0000000..f32c718 +--- /dev/null ++++ b/kpartx/kpartx.rules +@@ -0,0 +1,36 @@ ++# ++# persistent links for device-mapper devices ++# only hardware-backed device-mapper devices (ie multipath, dmraid, ++# and kpartx) have meaningful persistent device names ++# ++ ++KERNEL!="dm-*", GOTO="kpartx_end" ++ACTION=="remove", GOTO="kpartx_end" ++ ++ENV{DM_TABLE_STATE}!="LIVE", GOTO="kpartx_end" ++ ++ENV{DM_UUID}=="?*", IMPORT{program}=="/lib/udev/kpartx_id %M %m $env{DM_UUID}" ++ ++OPTIONS="link_priority=50" ++ ++# Create persistent links for multipath tables ++ENV{DM_UUID}=="mpath-*", \ ++ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" ++ ++# Create persistent links for dmraid tables ++ENV{DM_UUID}=="mpath-*", \ ++ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" ++ ++# Create persistent links for partitions ++ENV{DM_PART}=="?*", \ ++ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}-part$env{DM_PART}" ++ ++# Create dm tables for partitions ++ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="mpath-*", \ ++ RUN+="/sbin/kpartx -a -p -part /dev/$kernel" ++ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="dmraid-*", \ ++ RUN+="/sbin/kpartx -a -p -part /dev/$kernel" ++ ++LABEL="kpartx_end" ++ ++ +diff --git a/kpartx/kpartx_id b/kpartx/kpartx_id +new file mode 100644 +index 0000000..81f32bf +--- /dev/null ++++ b/kpartx/kpartx_id +@@ -0,0 +1,93 @@ ++#!/bin/sh ++# ++# kpartx_id ++# ++# Generates ID information for device-mapper tables. ++# ++# Copyright (C) 2006 SUSE Linux Products GmbH ++# Author: ++# Hannes Reinecke ++# ++# ++# 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 script generates ID information used to generate persistent symlinks. ++# It relies on the UUID strings generated by the various programs; the name ++# of the tables are of no consequence. ++# ++# Please note that dmraid does not provide the UUIDs (yet); a patch has been ++# sent upstream but has not been accepted yet. ++# ++ ++DMSETUP=/sbin/dmsetup ++ ++MAJOR=$1 ++MINOR=$2 ++UUID=$3 ++ ++if [ -z "$MAJOR" -o -z "$MINOR" ]; then ++ echo "usage: $0 major minor" ++ exit 1; ++fi ++ ++# Device-mapper not installed; not an error ++if [ ! -x $DMSETUP ] ; then ++ exit 0 ++fi ++ ++ ++# Table UUIDs are always '-'. ++dmuuid=${UUID#*-} ++dmtbl=${UUID%%-*} ++dmpart=${dmtbl#part} ++# kpartx types are 'part' ++if [ "$dmpart" = "$dmtbl" ] ; then ++ dmpart= ++else ++ dmtbl=part ++fi ++ ++# Set the name of the table. We're only interested in dmraid, ++# multipath, and kpartx tables; everything else is ignored. ++if [ "$dmtbl" = "part" ] ; then ++ # The name of the kpartx table is the name of the parent table ++ dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid) ++ echo "DM_NAME=$dmname" ++ # We need the dependencies of the parent table to figure out ++ # the type if the parent is a multipath table ++ case "$dmuuid" in ++ mpath-*) ++ dmdeps=$($DMSETUP deps -u $dmuuid) ++ ;; ++ esac ++elif [ "$dmtbl" = "mpath" ] ; then ++ dmname=$tblname ++ # We need the dependencies of the table to figure out the type ++ dmdeps=$($DMSETUP deps -u $UUID) ++elif [ "$dmtbl" = "dmraid" ] ; then ++ dmname=$tblname ++fi ++ ++[ -n "$dmpart" ] && echo "DM_PART=$dmpart" ++ ++# Figure out the type of the map. For non-multipath maps it's ++# always 'raid'. ++if [ -n "$dmdeps" ] ; then ++ case "$dmdeps" in ++ *\(94,*) ++ echo "DM_TYPE=dasd" ++ ;; ++ *\(9*) ++ echo "DM_TYPE=raid" ++ ;; ++ *) ++ echo "DM_TYPE=scsi" ++ ;; ++ esac ++else ++ echo "DM_TYPE=raid" ++fi ++ ++exit 0 +diff --git a/kpartx/sun.c b/kpartx/sun.c +new file mode 100644 +index 0000000..3d88b21 +--- /dev/null ++++ b/kpartx/sun.c +@@ -0,0 +1,131 @@ ++/* ++ * Lifted from util-linux' partx sun.c ++ * ++ * Copyrights of the original file apply ++ * Copyright (c) 2007 Hannes Reinecke ++ */ ++#include "kpartx.h" ++#include "byteorder.h" ++#include ++#include ++#include /* time_t */ ++ ++#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */ ++#define SUN_DISK_MAXPARTITIONS 8 ++ ++struct __attribute__ ((packed)) sun_raw_part { ++ u_int32_t start_cylinder; /* where the part starts... */ ++ u_int32_t num_sectors; /* ...and it's length */ ++}; ++ ++struct __attribute__ ((packed)) sun_part_info { ++ u_int8_t spare1; ++ u_int8_t id; /* Partition type */ ++ u_int8_t spare2; ++ u_int8_t flags; /* Partition flags */ ++}; ++ ++struct __attribute__ ((packed)) sun_disk_label { ++ char info[128]; /* Informative text string */ ++ u_int8_t spare0[14]; ++ struct sun_part_info infos[SUN_DISK_MAXPARTITIONS]; ++ u_int8_t spare1[246]; /* Boot information etc. */ ++ u_int16_t rspeed; /* Disk rotational speed */ ++ u_int16_t pcylcount; /* Physical cylinder count */ ++ u_int16_t sparecyl; /* extra sects per cylinder */ ++ u_int8_t spare2[4]; /* More magic... */ ++ u_int16_t ilfact; /* Interleave factor */ ++ u_int16_t ncyl; /* Data cylinder count */ ++ u_int16_t nacyl; /* Alt. cylinder count */ ++ u_int16_t ntrks; /* Tracks per cylinder */ ++ u_int16_t nsect; /* Sectors per track */ ++ u_int8_t spare3[4]; /* Even more magic... */ ++ struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS]; ++ u_int16_t magic; /* Magic number */ ++ u_int16_t csum; /* Label xor'd checksum */ ++}; ++ ++/* Checksum Verification */ ++static int ++sun_verify_checksum (struct sun_disk_label *label) ++{ ++ u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1; ++ u_int16_t csum = 0; ++ ++ while (ush >= (u_int16_t *)label) ++ csum ^= *ush--; ++ ++ return !csum; ++} ++ ++int ++read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) { ++ struct sun_disk_label *l; ++ struct sun_raw_part *s; ++ unsigned int offset = all.start, end; ++ int i, j, n; ++ char *bp; ++ ++ bp = getblock(fd, offset); ++ if (bp == NULL) ++ return -1; ++ ++ l = (struct sun_disk_label *) bp; ++ if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC) ++ return -1; ++ ++ if (!sun_verify_checksum(l)) { ++ fprintf(stderr, "Corrupted Sun disk label\n"); ++ return -1; ++ } ++ ++ for(i=0, n=0; ipartitions[i]; ++ ++ if (s->num_sectors == 0) ++ continue; ++ if (n < ns) { ++ sp[n].start = offset + ++ be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks); ++ sp[n].size = be32_to_cpu(s->num_sectors); ++ n++; ++ } else { ++ fprintf(stderr, ++ "sun_disklabel: too many slices\n"); ++ break; ++ } ++ } ++ /* ++ * Convention has it that the SUN disklabel will always have ++ * the 'c' partition spanning the entire disk. ++ * So we have to check for contained slices. ++ */ ++ for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { ++ if (sp[i].size == 0) ++ continue; ++ ++ end = sp[i].start + sp[i].size; ++ for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) { ++ if ( i == j ) ++ continue; ++ if (sp[j].size == 0) ++ continue; ++ ++ if (sp[i].start < sp[j].start) { ++ if (end > sp[j].start && ++ end < sp[j].start + sp[j].size) { ++ /* Invalid slice */ ++ fprintf(stderr, ++ "sun_disklabel: slice %d overlaps with %d\n", i , j); ++ sp[i].size = 0; ++ } ++ } else { ++ if (end <= sp[j].start + sp[j].size) { ++ sp[i].container = j + 1; ++ } ++ } ++ } ++ } ++ return n; ++} ++ diff --git a/libcheckers/Makefile b/libcheckers/Makefile index ec8c10d..6340a68 100644 --- a/libcheckers/Makefile @@ -337,10 +1046,10 @@ index ec8c10d..6340a68 100644 all: $(BUILD) diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c -index 53770a6..a49ad59 100644 +index 53770a6..d7728a5 100644 --- a/libcheckers/checkers.c +++ b/libcheckers/checkers.c -@@ -7,6 +7,7 @@ +@@ -7,11 +7,13 @@ #include "tur.h" #include "hp_sw.h" #include "emc_clariion.h" @@ -348,10 +1057,41 @@ index 53770a6..a49ad59 100644 #include "readsector0.h" static struct checker checkers[] = { -@@ -48,6 +49,15 @@ static struct checker checkers[] = { + { + .fd = 0, ++ .sync = 1, + .name = DIRECTIO, + .message = "", + .context = NULL, +@@ -21,6 +23,7 @@ static struct checker checkers[] = { }, { .fd = 0, ++ .sync = 1, + .name = TUR, + .message = "", + .context = NULL, +@@ -30,6 +33,7 @@ static struct checker checkers[] = { + }, + { + .fd = 0, ++ .sync = 1, + .name = HP_SW, + .message = "", + .context = NULL, +@@ -39,6 +43,7 @@ static struct checker checkers[] = { + }, + { + .fd = 0, ++ .sync = 1, + .name = EMC_CLARIION, + .message = "", + .context = NULL, +@@ -48,6 +53,17 @@ static struct checker checkers[] = { + }, + { + .fd = 0, ++ .sync = 1, + .name = RDAC, + .message = "", + .context = NULL, @@ -361,10 +1101,37 @@ index 53770a6..a49ad59 100644 + }, + { + .fd = 0, ++ .sync = 1, .name = READSECTOR0, .message = "", .context = NULL, -@@ -75,8 +85,9 @@ struct checker * checker_lookup (char * +@@ -55,7 +71,7 @@ static struct checker checkers[] = { + .init = readsector0_init, + .free = readsector0_free + }, +- {0, "", "", NULL, NULL, NULL, NULL}, ++ {0, 1, "", "", NULL, NULL, NULL, NULL}, + }; + + void checker_set_fd (struct checker * c, int fd) +@@ -63,6 +79,16 @@ 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]; +@@ -75,8 +101,9 @@ struct checker * checker_lookup (char * name) return NULL; } @@ -375,11 +1142,19 @@ index 53770a6..a49ad59 100644 return c->init(c); } +@@ -123,6 +150,7 @@ struct checker * checker_default (void) + 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; diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h -index ac795ed..d4dad9c 100644 +index ac795ed..9b270eb 100644 --- a/libcheckers/checkers.h +++ b/libcheckers/checkers.h -@@ -2,7 +2,44 @@ +@@ -2,7 +2,47 @@ #define _CHECKERS_H /* @@ -422,10 +1197,18 @@ index ac795ed..d4dad9c 100644 + * 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 -@@ -14,12 +51,28 @@ +@@ -10,14 +50,32 @@ + #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" @@ -433,9 +1216,10 @@ index ac795ed..d4dad9c 100644 #define EMC_CLARIION "emc_clariion" #define READSECTOR0 "readsector0" - #define DEFAULT_CHECKER READSECTOR0 - - /* +-#define DEFAULT_CHECKER 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 @@ -448,13 +1232,16 @@ index ac795ed..d4dad9c 100644 + * Provision a long timeout. Longer than any real-world application would cope + * with. + */ -+#define DEF_TIMEOUT 300000 -+ -+/* ++#define DEF_TIMEOUT 300000 ++#define ASYNC_TIMEOUT_SEC 30 + + /* * strings lengths - */ - #define CHECKER_NAME_LEN 16 -@@ -31,14 +84,16 @@ struct checker { +@@ -28,19 +86,24 @@ + + 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 */ @@ -472,9 +1259,226 @@ index ac795ed..d4dad9c 100644 +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 *); +diff --git a/libcheckers/directio.c b/libcheckers/directio.c +index b53c1c3..ee09af7 100644 +--- a/libcheckers/directio.c ++++ b/libcheckers/directio.c +@@ -12,28 +12,47 @@ + #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 blksize; +- unsigned char *buf; +- unsigned char *ptr; ++ int running; ++ int reset_flags; ++ int blksize; ++ unsigned char * buf; ++ unsigned char * ptr; ++ io_context_t ioctx; ++ struct iocb io; + }; + ++ + int directio_init (struct checker * c) + { + unsigned long pgsize = getpagesize(); + struct directio_context * ct; ++ long flags; + + ct = malloc(sizeof(struct directio_context)); + if (!ct) + return 1; +- c->context = (void *)ct; ++ memset(ct, 0, sizeof(struct directio_context)); ++ ++ if (io_setup(1, &ct->ioctx) != 0) { ++ condlog(1, "io_setup failed"); ++ free(ct); ++ return 1; ++ } + + if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) { + MSG(c, "cannot get blocksize, set default"); +@@ -50,11 +69,28 @@ int directio_init (struct checker * c) + ct->buf = (unsigned char *)malloc(ct->blksize + pgsize); + if (!ct->buf) + goto out; +- ct->ptr = (unsigned char *)(((unsigned long)ct->buf + pgsize - 1) & +- (~(pgsize - 1))); + ++ flags = fcntl(c->fd, F_GETFL); ++ if (flags < 0) ++ goto out; ++ if (!(flags & O_DIRECT)) { ++ flags |= O_DIRECT; ++ if (fcntl(c->fd, F_SETFL, flags) < 0) ++ goto out; ++ ct->reset_flags = 1; ++ } ++ ++ ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) & ++ (~(pgsize - 1))); ++ ++ /* Sucessfully initialized, return the context. */ ++ c->context = (void *) ct; + return 0; ++ + out: ++ if (ct->buf) ++ free(ct->buf); ++ io_destroy(ct->ioctx); + free(ct); + return 1; + } +@@ -62,56 +98,72 @@ out: + void directio_free (struct checker * c) + { + struct directio_context * ct = (struct directio_context *)c->context; ++ long flags; + + if (!ct) + return; ++ ++ if (ct->reset_flags) { ++ if ((flags = fcntl(c->fd, F_GETFL)) >= 0) { ++ flags &= ~O_DIRECT; ++ /* No point in checking for errors */ ++ fcntl(c->fd, F_SETFL, flags); ++ } ++ } ++ + if (ct->buf) + free(ct->buf); ++ io_destroy(ct->ioctx); + free(ct); + } + + static int +-direct_read (int fd, unsigned char * buff, int size) ++check_state(int fd, struct directio_context *ct, int sync) + { +- long flags; +- int reset_flags = 0; +- int res, retval; +- +- flags = fcntl(fd,F_GETFL); +- +- if (flags < 0) { +- return PATH_UNCHECKED; ++ 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 (!(flags & O_DIRECT)) { +- flags |= O_DIRECT; +- if (fcntl(fd,F_SETFL,flags) < 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; + } +- reset_flags = 1; + } ++ ct->running++; + +- while ( (res = read(fd,buff,size)) < 0 && errno == EINTR ); +- if (res < 0) { +- if (errno == EINVAL) { +- /* O_DIRECT is not available */ +- retval = PATH_UNCHECKED; +- } else if (errno == ENOMEM) { +- retval = PATH_UP; +- } else { +- retval = PATH_DOWN; +- } ++ r = 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 { +- retval = PATH_UP; +- } +- +- if (reset_flags) { +- flags &= ~O_DIRECT; +- /* No point in checking for errors */ +- fcntl(fd,F_SETFL,flags); ++ LOG(3, "io finished %lu/%lu", event.res, event.res2); ++ ct->running = 0; ++ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN; + } + +- return retval; ++ return rc; + } + + int directio (struct checker * c) +@@ -119,7 +171,10 @@ int directio (struct checker * c) + int ret; + struct directio_context * ct = (struct directio_context *)c->context; + +- ret = direct_read(c->fd, ct->ptr, ct->blksize); ++ if (!ct) ++ return PATH_UNCHECKED; ++ ++ ret = check_state(c->fd, ct, c->sync); + + switch (ret) + { +@@ -132,6 +187,9 @@ int directio (struct checker * c) + case PATH_UP: + MSG(c, MSG_DIRECTIO_UP); + break; ++ case PATH_PENDING: ++ MSG(c, MSG_DIRECTIO_PENDING); ++ break; + default: + break; + } diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c -index 1d7b684..384a943 100644 +index 1d7b684..6c7167e 100644 --- a/libcheckers/emc_clariion.c +++ b/libcheckers/emc_clariion.c @@ -11,25 +11,76 @@ @@ -559,7 +1563,7 @@ index 1d7b684..384a943 100644 return 0; } -@@ -40,13 +91,15 @@ void emc_clariion_free (struct checker * +@@ -40,13 +91,15 @@ void emc_clariion_free (struct checker * c) int emc_clariion(struct checker * c) { @@ -589,7 +1593,7 @@ index 1d7b684..384a943 100644 io_hdr.pack_id = 0; if (ioctl(c->fd, SG_IO, &io_hdr) < 0) { MSG(c, "emc_clariion_checker: sending query command failed"); -@@ -69,7 +122,8 @@ int emc_clariion(struct checker * c) +@@ -69,34 +122,39 @@ int emc_clariion(struct checker * c) } if (/* Verify the code page - right page & revision */ sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) { @@ -599,8 +1603,16 @@ index 1d7b684..384a943 100644 return PATH_DOWN; } -@@ -79,24 +133,24 @@ int emc_clariion(struct checker * c) - || (sense_buffer[28] & 0x07) != 0x04 + if ( /* Effective initiator type */ + sense_buffer[27] != 0x03 +- /* Failover mode should be set to 1 */ +- || (sense_buffer[28] & 0x07) != 0x04 ++ /* ++ * Failover mode should be set to 1 (PNR failover mode) ++ * or 4 (ALUA failover mode). ++ */ ++ || (((sense_buffer[28] & 0x07) != 0x04) && ++ ((sense_buffer[28] & 0x07) != 0x06)) /* Arraycommpath should be set to 1 */ || (sense_buffer[30] & 0x04) != 0x04) { - MSG(c, "emc_clariion_checker: Path not correctly configured for failover"); @@ -633,7 +1645,7 @@ index 1d7b684..384a943 100644 /* * store the LUN WWN there and compare that it indeed did not -@@ -105,7 +159,8 @@ int emc_clariion(struct checker * c) +@@ -105,7 +163,8 @@ int emc_clariion(struct checker * c) */ if (ct->wwn_set) { if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) { @@ -643,7 +1655,7 @@ index 1d7b684..384a943 100644 return PATH_DOWN; } } else { -@@ -113,7 +168,59 @@ int emc_clariion(struct checker * c) +@@ -113,7 +172,59 @@ int emc_clariion(struct checker * c) ct->wwn_set = 1; } @@ -654,7 +1666,7 @@ index 1d7b684..384a943 100644 + * Issue read on active path to determine if inactive snapshot. + */ + if (sense_buffer[4] == 2) {/* if active path */ -+ unsigned char buf[512]; ++ unsigned char buf[4096]; + + ret = sg_read(c->fd, &buf[0], sbb = &sb[0]); + if (ret == PATH_DOWN) { @@ -729,16 +1741,17 @@ index 509e9c4..b9731ff 100644 if (ioctl(fd, SG_IO, &io_hdr) < 0) diff --git a/libcheckers/libsg.c b/libcheckers/libsg.c new file mode 100644 -index 0000000..f426aaf +index 0000000..9171b10 --- /dev/null +++ b/libcheckers/libsg.c -@@ -0,0 +1,79 @@ +@@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004, 2005 Christophe Varoqui + */ +#include +#include +#include ++#include + +#include "checkers.h" +#include "libsg.h" @@ -760,8 +1773,12 @@ index 0000000..f426aaf + 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]; @@ -956,7 +1973,7 @@ index 0000000..d7bf812 + +#endif /* _RDAC_H */ diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c -index e368fb4..3cddfa8 100644 +index e368fb4..bef0eb6 100644 --- a/libcheckers/readsector0.c +++ b/libcheckers/readsector0.c @@ -2,21 +2,9 @@ @@ -982,7 +1999,7 @@ index e368fb4..3cddfa8 100644 #define MSG_READSECTOR0_UP "readsector0 checker reports path is up" #define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down" -@@ -35,72 +23,14 @@ void readsector0_free (struct checker * +@@ -35,72 +23,14 @@ void readsector0_free (struct checker * c) return; } @@ -1048,7 +2065,8 @@ index e368fb4..3cddfa8 100644 extern int readsector0 (struct checker * c) { - unsigned char buf[512]; +- unsigned char buf[512]; ++ unsigned char buf[4096]; + unsigned char sbuf[SENSE_BUFF_LEN]; int ret; @@ -1071,10 +2089,10 @@ index d40a273..e79bc0a 100644 if (ioctl(c->fd, SG_IO, &io_hdr) < 0) { MSG(c, MSG_TUR_DOWN); diff --git a/libmultipath/Makefile b/libmultipath/Makefile -index 8a14b04..ef561a8 100644 +index 8a14b04..511f5ad 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile -@@ -6,7 +6,7 @@ BUILD = glibc +@@ -6,24 +6,31 @@ BUILD = glibc include ../Makefile.inc @@ -1083,7 +2101,12 @@ index 8a14b04..ef561a8 100644 OBJS = memory.o parser.o vector.o devmapper.o callout.o \ hwtable.o blacklist.o util.o dmparser.o config.o \ -@@ -18,12 +18,19 @@ OBJS = memory.o parser.o vector.o devmap + 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 ++ log.o configure.o structs_vec.o sysfs.o + PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe) ifeq ($(strip $(DAEMON)),1) @@ -1104,10 +2127,60 @@ index 8a14b04..ef561a8 100644 prepare: $(CLEAN) diff --git a/libmultipath/alias.c b/libmultipath/alias.c -index 6d103d7..02ca087 100644 +index 6d103d7..ca434fe 100644 --- a/libmultipath/alias.c +++ b/libmultipath/alias.c -@@ -166,28 +166,14 @@ fail: +@@ -120,21 +120,34 @@ lock_bindings_file(int fd) + + + static int +-open_bindings_file(char *file) ++open_bindings_file(char *file, int *can_write) + { + int fd; + struct stat s; + + if (ensure_directories_exist(file, 0700)) + return -1; ++ *can_write = 1; + fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) { +- condlog(0, "Cannot open bindings file [%s] : %s", file, +- strerror(errno)); +- return -1; ++ if (errno == EROFS) { ++ *can_write = 0; ++ condlog(3, "Cannot open bindings file [%s] read/write. " ++ " trying readonly", file); ++ fd = open(file, O_RDONLY); ++ if (fd < 0) { ++ condlog(0, "Cannot open bindings file [%s] " ++ "readonly : %s", file, strerror(errno)); ++ return -1; ++ } ++ } ++ else { ++ condlog(0, "Cannot open bindings file [%s] : %s", file, ++ strerror(errno)); ++ return -1; ++ } + } +- +- if (lock_bindings_file(fd) < 0) ++ if (*can_write && lock_bindings_file(fd) < 0) + goto fail; + + memset(&s, 0, sizeof(s)); +@@ -143,6 +156,8 @@ open_bindings_file(char *file) + goto fail; + } + if (s.st_size == 0) { ++ if (*can_write == 0) ++ goto fail; + /* If bindings file is empty, write the header */ + size_t len = strlen(BINDINGS_FILE_HEADER); + if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) { +@@ -166,28 +181,14 @@ fail: static int @@ -1138,7 +2211,7 @@ index 6d103d7..02ca087 100644 while (fgets(buf, LINE_MAX, f)) { char *c, *alias, *wwid; int curr_id; -@@ -210,43 +196,27 @@ lookup_binding(int fd, char *map_wwid, c +@@ -210,43 +211,27 @@ lookup_binding(int fd, char *map_wwid, char **map_alias) } if (strcmp(wwid, map_wwid) == 0){ condlog(3, "Found matching wwid [%s] in bindings file." @@ -1185,7 +2258,7 @@ index 6d103d7..02ca087 100644 while (fgets(buf, LINE_MAX, f)) { char *c, *alias, *wwid; int curr_id; -@@ -274,12 +244,10 @@ rlookup_binding(int fd, char **map_wwid, +@@ -274,12 +259,10 @@ rlookup_binding(int fd, char **map_wwid, char *map_alias) if (*map_wwid == NULL) condlog(0, "Cannot copy alias from bindings " "file : %s", strerror(errno)); @@ -1198,18 +2271,22 @@ index 6d103d7..02ca087 100644 return id; } -@@ -327,7 +295,8 @@ char * +@@ -327,24 +310,49 @@ char * get_user_friendly_alias(char *wwid, char *file) { char *alias; - int fd, id; + int fd, scan_fd, id; + FILE *f; ++ int can_write; if (!wwid || *wwid == '\0') { condlog(3, "Cannot find binding for empty WWID"); -@@ -337,14 +306,37 @@ get_user_friendly_alias(char *wwid, char - fd = open_bindings_file(file); + return NULL; + } + +- fd = open_bindings_file(file); ++ fd = open_bindings_file(file, &can_write); if (fd < 0) return NULL; - id = lookup_binding(fd, wwid, &alias); @@ -1238,8 +2315,9 @@ index 6d103d7..02ca087 100644 close(fd); return NULL; } +- if (!alias) + - if (!alias) ++ if (!alias && can_write) alias = allocate_binding(fd, wwid, id); + fclose(f); @@ -1247,18 +2325,21 @@ index 6d103d7..02ca087 100644 close(fd); return alias; } -@@ -353,7 +345,8 @@ char * +@@ -353,22 +361,45 @@ char * get_user_friendly_wwid(char *alias, char *file) { char *wwid; - int fd, id; -+ int fd, scan_fd, id; ++ int fd, scan_fd, id, unused; + FILE *f; if (!alias || *alias == '\0') { condlog(3, "Cannot find binding for empty alias"); -@@ -363,12 +356,34 @@ get_user_friendly_wwid(char *alias, char - fd = open_bindings_file(file); + return NULL; + } + +- fd = open_bindings_file(file); ++ fd = open_bindings_file(file, &unused); if (fd < 0) return NULL; - id = rlookup_binding(fd, &wwid, alias); @@ -1294,7 +2375,7 @@ index 6d103d7..02ca087 100644 return wwid; } diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c -index 6a8a681..5f7b2f5 100644 +index 6a8a681..0c277cb 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c @@ -2,7 +2,6 @@ @@ -1331,7 +2412,7 @@ index 6a8a681..5f7b2f5 100644 { struct blentry_device * ble; -@@ -91,6 +91,7 @@ set_ble_device (vector blist, char * ven +@@ -91,6 +91,7 @@ set_ble_device (vector blist, char * vendor, char * product) } ble->product = product; } @@ -1339,7 +2420,7 @@ index 6a8a681..5f7b2f5 100644 return 0; } -@@ -105,19 +106,19 @@ setup_default_blist (struct config * con +@@ -105,19 +106,19 @@ setup_default_blist (struct config * conf) str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"); if (!str) return 1; @@ -1353,8 +2434,10 @@ index 6a8a681..5f7b2f5 100644 - if (store_ble(conf->blist_devnode, str)) + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) return 1; - - str = STRDUP("^cciss!c[0-9]d[0-9]*"); +- +- str = STRDUP("^cciss!c[0-9]d[0-9]*"); ++ ++ str = STRDUP("^dcssblk[0-9]*"); if (!str) return 1; - if (store_ble(conf->blist_devnode, str)) @@ -1362,7 +2445,7 @@ index 6a8a681..5f7b2f5 100644 return 1; vector_foreach_slot (conf->hwtable, hwe, i) { -@@ -128,7 +129,8 @@ setup_default_blist (struct config * con +@@ -128,63 +129,194 @@ setup_default_blist (struct config * conf) VECTOR_SIZE(conf->blist_device) -1); if (set_ble_device(conf->blist_device, STRDUP(hwe->vendor), @@ -1372,7 +2455,10 @@ index 6a8a681..5f7b2f5 100644 FREE(ble); return 1; } -@@ -139,52 +141,183 @@ setup_default_blist (struct config * con + } + } +- + return 0; } int @@ -1399,14 +2485,12 @@ index 6a8a681..5f7b2f5 100644 - if (!regexec(&ble->regex, str, 0, NULL, 0)) { - condlog(3, "%s: blacklisted", str); + if (!regexec(&ble->regex, str, 0, NULL, 0)) - return 1; -- } - } - return 0; - } - - int --blacklist_device (vector blist, char * vendor, char * product) ++ return 1; ++ } ++ return 0; ++} ++ ++int +_blacklist_exceptions_device(vector elist, char * vendor, char * product) +{ + int i; @@ -1415,12 +2499,14 @@ index 6a8a681..5f7b2f5 100644 + vector_foreach_slot (elist, ble, i) { + if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) && + !regexec(&ble->product_reg, product, 0, NULL, 0)) -+ return 1; -+ } -+ return 0; -+} -+ -+int + return 1; +- } + } + return 0; + } + + int +-blacklist_device (vector blist, char * vendor, char * product) +_blacklist_device (vector blist, char * vendor, char * product) { int i; @@ -1522,7 +2608,7 @@ index 6a8a681..5f7b2f5 100644 + log_filter(dev, NULL, NULL, NULL, r); + return r; +} -+ + +int +_filter_wwid (vector blist, vector elist, char * wwid) +{ @@ -1534,7 +2620,7 @@ index 6a8a681..5f7b2f5 100644 + return MATCH_WWID_BLIST; + return 0; +} - ++ +int +filter_wwid (vector blist, vector elist, char * wwid) +{ @@ -1551,7 +2637,7 @@ index 6a8a681..5f7b2f5 100644 + r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev); + if (r) + return r; -+ r = _filter_wwid(conf->blist_devnode, conf->elist_devnode, pp->wwid); ++ r = _filter_wwid(conf->blist_wwid, conf->elist_devnode, pp->wwid); + if (r) + return r; + r = _filter_device(conf->blist_device, conf->elist_device, @@ -1728,7 +2814,7 @@ index 1068755..a39af8a 100644 return 0; if (!(hwe = alloc_hwe())) -@@ -232,6 +259,9 @@ store_hwe (vector hwtable, struct hwentr +@@ -232,6 +259,9 @@ store_hwe (vector hwtable, struct hwentry * dhwe) if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product))) goto out; @@ -1790,7 +2876,7 @@ index 1068755..a39af8a 100644 conf->mptable = vector_alloc(); diff --git a/libmultipath/config.h b/libmultipath/config.h -index 6e5633a..7caa11d 100644 +index 6e5633a..a25b3ad 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -1,6 +1,9 @@ @@ -1836,15 +2922,18 @@ index 6e5633a..7caa11d 100644 int minio; int checkint; int max_checkint; -@@ -57,6 +63,7 @@ struct config { +@@ -57,8 +63,10 @@ struct config { int rr_weight; int no_path_retry; int user_friendly_names; + int pg_timeout; char * dev; ++ char * sysfs_dir; char * udev_dir; -@@ -67,17 +74,21 @@ struct config { + char * selector; + char * getuid; +@@ -67,17 +75,21 @@ struct config { char * hwhandler; char * bindings_file; @@ -1868,7 +2957,7 @@ index 6e5633a..7caa11d 100644 char * get_mpe_wwid (char * alias); diff --git a/libmultipath/configure.c b/libmultipath/configure.c -index 1ba4356..9632fb4 100644 +index 1ba4356..3cd6041 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -60,6 +60,7 @@ setup_map (struct multipath * mpp) @@ -1879,7 +2968,7 @@ index 1ba4356..9632fb4 100644 /* * assign paths to path groups -- start with no groups and all paths -@@ -145,11 +146,6 @@ select_action (struct multipath * mpp, v +@@ -145,11 +146,6 @@ select_action (struct multipath * mpp, vector curmp) mpp->action = ACT_RENAME; return; } @@ -1891,7 +2980,7 @@ index 1ba4356..9632fb4 100644 mpp->action = ACT_CREATE; condlog(3, "%s: set ACT_CREATE (map does not exist)", mpp->alias); -@@ -179,8 +175,9 @@ select_action (struct multipath * mpp, v +@@ -179,8 +175,9 @@ select_action (struct multipath * mpp, vector curmp) mpp->alias); return; } @@ -1903,7 +2992,7 @@ index 1ba4356..9632fb4 100644 mpp->action = ACT_RELOAD; condlog(3, "%s: set ACT_RELOAD (features change)", mpp->alias); -@@ -286,11 +283,13 @@ lock_multipath (struct multipath * mpp, +@@ -286,11 +283,13 @@ lock_multipath (struct multipath * mpp, int lock) /* * Return value: @@ -1940,7 +3029,7 @@ index 1ba4356..9632fb4 100644 case ACT_SWITCHPG: dm_switchgroup(mpp->alias, mpp->bestpg); -@@ -317,13 +316,13 @@ domap (struct multipath * mpp) +@@ -317,18 +316,19 @@ domap (struct multipath * mpp) * retry. */ reinstate_paths(mpp); @@ -1954,8 +3043,24 @@ index 1ba4356..9632fb4 100644 - return -1; + return DOMAP_RETRY; } - dm_shut_log(); +- dm_shut_log(); +- if (dm_map_present(mpp->alias)) ++ if (dm_map_present(mpp->alias)) { ++ condlog(3, "%s: map already present", mpp->alias); + break; ++ } + + r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET, + mpp->params, mpp->size, mpp->wwid); +@@ -346,7 +346,6 @@ domap (struct multipath * mpp) + } + + lock_multipath(mpp, 0); +- dm_restore_log(); + break; + + case ACT_RELOAD: @@ -377,9 +376,9 @@ domap (struct multipath * mpp) condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias, mpp->size, DEFAULT_TARGET, mpp->params); @@ -1968,7 +3073,7 @@ index 1ba4356..9632fb4 100644 } static int -@@ -423,7 +422,7 @@ coalesce_paths (struct vectors * vecs, v +@@ -423,7 +422,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) /* 1. if path has no unique id or wwid blacklisted */ if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 || @@ -1977,7 +3082,7 @@ index 1ba4356..9632fb4 100644 continue; /* 2. if path already coalesced */ -@@ -444,7 +443,7 @@ coalesce_paths (struct vectors * vecs, v +@@ -444,7 +443,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL) return 1; @@ -1986,7 +3091,7 @@ index 1ba4356..9632fb4 100644 mpp->action = ACT_REJECT; if (!mpp->paths) { -@@ -471,7 +470,7 @@ coalesce_paths (struct vectors * vecs, v +@@ -471,7 +470,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) mpp->size); mpp->action = ACT_REJECT; } @@ -1995,22 +3100,22 @@ index 1ba4356..9632fb4 100644 mpp->action = ACT_REJECT; } verify_paths(mpp, vecs, NULL); -@@ -486,19 +485,18 @@ coalesce_paths (struct vectors * vecs, v +@@ -486,19 +485,18 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) r = domap(mpp); - if (!r) { -+ if (r == DOMAP_FAIL || r == DOMAP_RETRY) { - condlog(3, "%s: domap (%u) failure " - "for create/reload map", - mpp->alias, r); +- condlog(3, "%s: domap (%u) failure " +- "for create/reload map", +- mpp->alias, r); - remove_map(mpp, vecs, NULL, 0); - continue; - } - else if (r < 0) { -- condlog(3, "%s: domap (%u) failure " -- "for create/reload map", -- mpp->alias, r); ++ if (r == DOMAP_FAIL || r == DOMAP_RETRY) { + condlog(3, "%s: domap (%u) failure " + "for create/reload map", + mpp->alias, r); - return r; + if (r == DOMAP_FAIL) { + remove_map(mpp, vecs, NULL, 0); @@ -2023,7 +3128,7 @@ index 1ba4356..9632fb4 100644 if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) { if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) -@@ -506,6 +504,12 @@ coalesce_paths (struct vectors * vecs, v +@@ -506,6 +504,12 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) else dm_queue_if_no_path(mpp->alias, 1); } @@ -2036,7 +3141,7 @@ index 1ba4356..9632fb4 100644 if (newmp) { if (mpp->action != ACT_REJECT) { -@@ -547,11 +551,11 @@ coalesce_paths (struct vectors * vecs, v +@@ -547,11 +551,11 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid) } extern char * @@ -2050,7 +3155,7 @@ index 1ba4356..9632fb4 100644 if (dev_type == DEV_NONE) return NULL; -@@ -606,6 +610,12 @@ get_refwwid (char * dev, int dev_type, v +@@ -606,6 +610,12 @@ get_refwwid (char * dev, int dev_type, vector pathvec) goto out; } if (dev_type == DEV_DEVMAP) { @@ -2075,10 +3180,19 @@ index 42ee9b0..1cbbe82 100644 +char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec); diff --git a/libmultipath/debug.c b/libmultipath/debug.c -index 099ab52..fa06cbd 100644 +index 099ab52..05dfb06 100644 --- a/libmultipath/debug.c +++ b/libmultipath/debug.c -@@ -29,17 +29,16 @@ void dlog (int sink, int prio, char * fm +@@ -14,7 +14,7 @@ + #include "vector.h" + #include "config.h" + +-void dlog (int sink, int prio, char * fmt, ...) ++void dlog (int sink, int prio, const char * fmt, ...) + { + va_list ap; + int thres; +@@ -29,17 +29,16 @@ void dlog (int sink, int prio, char * fmt, ...) struct tm *tb = localtime(&t); char buff[16]; @@ -2099,10 +3213,16 @@ index 099ab52..fa06cbd 100644 } va_end(ap); diff --git a/libmultipath/debug.h b/libmultipath/debug.h -index e7612a9..74ed531 100644 +index e7612a9..082fff1 100644 --- a/libmultipath/debug.h +++ b/libmultipath/debug.h -@@ -11,11 +11,11 @@ void dlog (int sink, int prio, char * fm +@@ -1,4 +1,4 @@ +-void dlog (int sink, int prio, char * fmt, ...) ++void dlog (int sink, int prio, const char * fmt, ...) + __attribute__((format(printf, 3, 4))); + + #if DAEMON +@@ -11,11 +11,11 @@ void dlog (int sink, int prio, char * fmt, ...) int logsink; #define condlog(prio, fmt, args...) \ @@ -2117,9 +3237,15 @@ index e7612a9..74ed531 100644 #endif /* DAEMON */ diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h -index ab65492..8deeb0f 100644 +index ab65492..df7d971 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h +@@ -1,4 +1,4 @@ +-#define DEFAULT_GETUID "/sbin/scsi_id -g -u -s /block/%n" ++#define DEFAULT_GETUID "/lib/udev/scsi_id -g -u -s /block/%n" + #define DEFAULT_UDEVDIR "/dev" + #define DEFAULT_SELECTOR "round-robin 0" + #define DEFAULT_FEATURES "0" @@ -9,6 +9,7 @@ #define DEFAULT_FAILBACK -FAILBACK_MANUAL #define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE @@ -2129,10 +3255,16 @@ index ab65492..8deeb0f 100644 #define DEFAULT_CHECKINT 5 diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c -index 4328036..dece079 100644 +index 4328036..d6991ba 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c -@@ -11,6 +11,7 @@ +@@ -6,11 +6,13 @@ + */ + #include + #include ++#include + #include + #include #include #include #include @@ -2140,7 +3272,18 @@ index 4328036..dece079 100644 #include -@@ -23,6 +24,9 @@ +@@ -19,35 +21,96 @@ + #include "debug.h" + #include "memory.h" + #include "devmapper.h" ++#include "config.h" ++ ++#if DAEMON ++#include "log_pthread.h" ++#include ++#include ++#endif + #define MAX_WAIT 5 #define LOOPS_PER_SEC 5 @@ -2148,20 +3291,66 @@ index 4328036..dece079 100644 +#define UUID_PREFIX_LEN 6 + static void - dm_dummy_log (int level, const char *file, int line, const char *f, ...) +-dm_dummy_log (int level, const char *file, int line, const char *f, ...) ++dm_write_log (int level, const char *file, int line, const char *f, ...) { -@@ -41,13 +45,35 @@ dm_shut_log (void) - dm_log_init(&dm_dummy_log); ++ va_list ap; ++ int thres; ++ ++ if (level > 6) ++ level = 6; ++ ++ thres = (conf) ? conf->verbosity : 0; ++ if (thres <= 3 || level > thres) ++ return; ++ ++ va_start(ap, f); ++#if DAEMON ++ if (!logsink) { ++ time_t t = time(NULL); ++ struct tm *tb = localtime(&t); ++ char buff[16]; ++ ++ strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb); ++ buff[sizeof(buff)-1] = '\0'; ++ ++ fprintf(stdout, "%s | ", buff); ++ fprintf(stdout, "libdevmapper: %s(%i): ", file, line); ++ vfprintf(stdout, f, ap); ++ fprintf(stdout, "\n"); ++ } else { ++ condlog(level, "libdevmapper: %s(%i): ", file, line); ++ log_safe(level + 3, f, ap); ++ } ++#else ++ fprintf(stdout, "libdevmapper: %s(%i): ", file, line); ++ vfprintf(stdout, f, ap); ++ fprintf(stdout, "\n"); ++#endif ++ va_end(ap); ++ + return; } --extern int --dm_prereq (char * str, int x, int y, int z) +-void +-dm_restore_log (void) +-{ +- dm_log_init(NULL); ++extern void ++dm_init(void) { ++ dm_log_init(&dm_write_log); ++ dm_log_init_verbose(conf ? conf->verbosity + 3 : 0); + } + +-void +-dm_shut_log (void) +static int +dm_libprereq (void) -+{ + { +- dm_log_init(&dm_dummy_log); + char version[64]; + int v[3]; -+ int minv[3] = {1, 2, 11}; ++ int minv[3] = {1, 2, 8}; + + dm_get_library_version(version, sizeof(version)); + condlog(3, "libdevmapper version %s", version); @@ -2174,8 +3363,10 @@ index 4328036..dece079 100644 + condlog(0, "libdevmapper version must be >= %d.%.2d.%.2d", + minv[0], minv[1], minv[2]); + return 1; -+} -+ + } + +-extern int +-dm_prereq (char * str, int x, int y, int z) +static int +dm_drvprereq (char * str) { @@ -2188,7 +3379,7 @@ index 4328036..dece079 100644 if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) return 3; -@@ -58,37 +84,44 @@ dm_prereq (char * str, int x, int y, int +@@ -58,37 +121,44 @@ dm_prereq (char * str, int x, int y, int z) condlog(0, "Can not communicate with kernel DM"); goto out; } @@ -2247,7 +3438,7 @@ index 4328036..dece079 100644 dm_simplecmd (int task, const char *name) { int r = 0; struct dm_task *dmt; -@@ -100,6 +133,10 @@ dm_simplecmd (int task, const char *name +@@ -100,6 +170,10 @@ dm_simplecmd (int task, const char *name) { goto out; dm_task_no_open_count(dmt); @@ -2258,7 +3449,7 @@ index 4328036..dece079 100644 r = dm_task_run (dmt); -@@ -113,6 +150,7 @@ dm_addmap (int task, const char *name, c +@@ -113,6 +187,7 @@ dm_addmap (int task, const char *name, const char *target, const char *params, unsigned long long size, const char *uuid) { int r = 0; struct dm_task *dmt; @@ -2266,7 +3457,7 @@ index 4328036..dece079 100644 if (!(dmt = dm_task_create (task))) return 0; -@@ -123,13 +161,26 @@ dm_addmap (int task, const char *name, c +@@ -123,13 +198,26 @@ dm_addmap (int task, const char *name, const char *target, if (!dm_task_add_target (dmt, 0, size, target, params)) goto addout; @@ -2295,7 +3486,7 @@ index 4328036..dece079 100644 addout: dm_task_destroy (dmt); return r; -@@ -203,6 +254,7 @@ dm_get_uuid(char *name, char *uuid) +@@ -203,6 +291,7 @@ dm_get_uuid(char *name, char *uuid) { struct dm_task *dmt; const char *uuidtmp; @@ -2303,7 +3494,7 @@ index 4328036..dece079 100644 dmt = dm_task_create(DM_DEVICE_INFO); if (!dmt) -@@ -215,15 +267,19 @@ dm_get_uuid(char *name, char *uuid) +@@ -215,15 +304,19 @@ dm_get_uuid(char *name, char *uuid) goto uuidout; uuidtmp = dm_task_get_uuid(dmt); @@ -2327,7 +3518,7 @@ index 4328036..dece079 100644 } extern int -@@ -509,6 +565,16 @@ dm_queue_if_no_path(char *mapname, int e +@@ -509,6 +602,16 @@ dm_queue_if_no_path(char *mapname, int enable) return dm_message(mapname, message); } @@ -2344,7 +3535,7 @@ index 4328036..dece079 100644 static int dm_groupmsg (char * msg, char * mapname, int index) { -@@ -591,6 +657,7 @@ dm_get_maps (vector mp, char * type) +@@ -591,6 +694,7 @@ dm_get_maps (vector mp, char * type) goto out1; dm_get_uuid(names->name, mpp->wwid); @@ -2352,19 +3543,30 @@ index 4328036..dece079 100644 } if (!vector_alloc_slot(mp)) +@@ -697,9 +801,7 @@ dm_mapname(int major, int minor) + * daemon uev_trigger -> uev_add_map + */ + while (--loop) { +- dm_shut_log(); + r = dm_task_run(dmt); +- dm_restore_log(); + + if (r) + break; diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h -index c7879a7..59afd01 100644 +index c7879a7..8438034 100644 --- a/libmultipath/devmapper.h +++ b/libmultipath/devmapper.h -@@ -1,6 +1,6 @@ - void dm_shut_log(void); - void dm_restore_log(void); +@@ -1,6 +1,5 @@ +-void dm_shut_log(void); +-void dm_restore_log(void); -int dm_prereq (char *, int, int, int); ++void dm_init(void); +int dm_prereq (char *); int dm_simplecmd (int, const char *); int dm_addmap (int, const char *, const char *, const char *, unsigned long long, const char *uuid); -@@ -13,6 +13,7 @@ int dm_flush_maps (char *); +@@ -13,6 +12,7 @@ int dm_flush_maps (char *); int dm_fail_path(char * mapname, char * path); int dm_reinstate_path(char * mapname, char * path); int dm_queue_if_no_path(char *mapname, int enable); @@ -2373,7 +3575,7 @@ index c7879a7..59afd01 100644 int dm_enablegroup(char * mapname, int index); int dm_disablegroup(char * mapname, int index); diff --git a/libmultipath/dict.c b/libmultipath/dict.c -index 9ca228a..c705cc6 100644 +index 9ca228a..4572a7d 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -201,6 +201,32 @@ def_no_path_retry_handler(vector strvec) @@ -2419,7 +3621,7 @@ index 9ca228a..c705cc6 100644 + conf->elist_wwid = vector_alloc(); + conf->elist_device = vector_alloc(); + -+ if (!conf->elist_devnode || !conf->elist_wwid || !conf->blist_device) ++ if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device) + return 1; + + return 0; @@ -2603,7 +3805,7 @@ index 9ca228a..c705cc6 100644 /* * config file keywords printing */ -@@ -896,6 +1052,22 @@ snprint_mp_rr_min_io (char * buff, int l +@@ -896,6 +1052,22 @@ snprint_mp_rr_min_io (char * buff, int len, void * data) } static int @@ -2626,7 +3828,7 @@ index 9ca228a..c705cc6 100644 snprint_hw_vendor (char * buff, int len, void * data) { struct hwentry * hwe = (struct hwentry *)data; -@@ -1097,6 +1269,27 @@ snprint_hw_rr_min_io (char * buff, int l +@@ -1097,6 +1269,27 @@ snprint_hw_rr_min_io (char * buff, int len, void * data) } static int @@ -2654,7 +3856,7 @@ index 9ca228a..c705cc6 100644 snprint_hw_path_checker (char * buff, int len, void * data) { struct hwentry * hwe = (struct hwentry *)data; -@@ -1268,6 +1461,23 @@ snprint_def_no_path_retry (char * buff, +@@ -1268,6 +1461,23 @@ snprint_def_no_path_retry (char * buff, int len, void * data) } static int @@ -2717,10 +3919,29 @@ index 9ca228a..c705cc6 100644 install_sublevel_end(); } diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index cf8289c..a196583 100644 +index cf8289c..c842eb0 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c -@@ -61,7 +61,8 @@ path_discover (vector pathvec, struct co +@@ -8,9 +8,8 @@ + #include + #include + #include ++#include + #include +-#include +-#include + + #include + +@@ -24,6 +23,7 @@ + #include "debug.h" + #include "propsel.h" + #include "sg_include.h" ++#include "sysfs.h" + #include "discovery.h" + + struct path * +@@ -61,7 +61,8 @@ path_discover (vector pathvec, struct config * conf, char * devname, int flag) if (!devname) return 0; @@ -2730,34 +3951,351 @@ index cf8289c..a196583 100644 return 0; if(safe_sprintf(path, "%s/block/%s/device", sysfs_path, -@@ -112,7 +113,7 @@ out: - * not multipath(8), ran by udev - */ - #if DAEMON --#define WAIT_MAX_SECONDS 5 -+#define WAIT_MAX_SECONDS 60 - #define WAIT_LOOP_PER_SECOND 5 +@@ -70,8 +71,10 @@ path_discover (vector pathvec, struct config * conf, char * devname, int flag) + return 1; + } + +- if (!filepresent(path)) ++ if (strncmp(devname,"cciss",5) && !filepresent(path)) { ++ condlog(4, "path %s not present", path); + return 0; ++ } - static int -@@ -165,7 +166,7 @@ sysfs_get_##fname (char * sysfs_path, ch - goto out; \ + pp = find_path_by_dev(pathvec, devname); + +@@ -86,127 +89,117 @@ path_discover (vector pathvec, struct config * conf, char * devname, int flag) + int + path_discovery (vector pathvec, struct config * conf, int flag) + { +- struct dlist * ls; +- struct sysfs_class * class; +- struct sysfs_class_device * dev; +- int r = 1; +- +- if (!(class = sysfs_open_class("block"))) ++ DIR *blkdir; ++ struct dirent *blkdev; ++ struct stat statbuf; ++ char devpath[PATH_MAX]; ++ char *devptr; ++ int r = 0; ++ ++ if (!(blkdir = opendir("/sys/block"))) + return 1; + +- if (!(ls = sysfs_get_class_devices(class))) +- goto out; +- +- r = 0; ++ strcpy(devpath,"/sys/block"); ++ while ((blkdev = readdir(blkdir)) != NULL) { ++ if ((strcmp(blkdev->d_name,".") == 0) || ++ (strcmp(blkdev->d_name,"..") == 0)) ++ continue; + +- dlist_for_each_data(ls, dev, struct sysfs_class_device) +- r += path_discover(pathvec, conf, dev->name, flag); ++ devptr = devpath + 10; ++ *devptr = '\0'; ++ strcat(devptr,"/"); ++ strcat(devptr,blkdev->d_name); ++ if (stat(devpath, &statbuf) < 0) ++ continue; + +-out: +- sysfs_close_class(class); +- return r; +-} ++ if (S_ISDIR(statbuf.st_mode) == 0) ++ continue; + +-/* +- * the daemon can race udev upon path add, +- * not multipath(8), ran by udev +- */ +-#if DAEMON +-#define WAIT_MAX_SECONDS 5 +-#define WAIT_LOOP_PER_SECOND 5 ++ condlog(4, "Discover device %s", devpath); + +-static int +-wait_for_file (char * filename) +-{ +- int loop; +- struct stat stats; +- +- loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND; +- +- while (--loop) { +- if (stat(filename, &stats) == 0) +- return 0; +- +- if (errno != ENOENT) +- return 1; +- +- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); ++ r += path_discover(pathvec, conf, blkdev->d_name, flag); + } +- return 1; +-} +-#else +-static int +-wait_for_file (char * filename) +-{ +- return 0; ++ closedir(blkdir); ++ condlog(4, "Discovery status %d", r); ++ return r; + } +-#endif + +-#define declare_sysfs_get_str(fname, fmt) \ ++#define declare_sysfs_get_str(fname) \ + extern int \ +-sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \ ++sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \ + { \ +- struct sysfs_attribute * attr; \ +- char attr_path[SYSFS_PATH_SIZE]; \ ++ char *attr; \ \ - strncpy(buff, attr->value, attr->len - 1); \ +- if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \ ++ attr = sysfs_attr_get_value(dev->devpath, #fname); \ ++ if (!attr) \ + return 1; \ + \ +- if (wait_for_file(attr_path)) \ +- return 1; \ +-\ +- if (!(attr = sysfs_open_attribute(attr_path))) \ +- return 1; \ +-\ +- if (0 > sysfs_read_attribute(attr)) \ +- goto out; \ +-\ +- if (attr->len < 2 || attr->len - 1 > len) \ +- goto out; \ +-\ +- strncpy(buff, attr->value, attr->len - 1); \ - buff[attr->len - 1] = '\0'; \ -+ strchop(buff); \ - sysfs_close_attribute(attr); \ +- sysfs_close_attribute(attr); \ ++ if (strlcpy(buff, attr, len) != strlen(attr)) \ ++ return 2; \ return 0; \ - out: \ -@@ -237,7 +238,7 @@ devt2devname (char *devname, char *devt) - struct dlist * ls; - char attr_path[FILE_NAME_SIZE]; +-out: \ +- sysfs_close_attribute(attr); \ +- return 1; \ + } + +-declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype"); +-declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype"); +-declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor"); +-declare_sysfs_get_str(model, "%s/block/%s/device/model"); +-declare_sysfs_get_str(rev, "%s/block/%s/device/rev"); +-declare_sysfs_get_str(dev, "%s/block/%s/dev"); ++declare_sysfs_get_str(devtype); ++declare_sysfs_get_str(cutype); ++declare_sysfs_get_str(vendor); ++declare_sysfs_get_str(model); ++declare_sysfs_get_str(rev); + + int +-sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size) ++sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len) + { +- struct sysfs_attribute * attr; +- char attr_path[SYSFS_PATH_SIZE]; +- int r; ++ char *attr; + +- if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev)) ++ attr = sysfs_attr_get_value(dev->devpath, "dev"); ++ if (!attr) { ++ condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel); + return 1; ++ } ++ if (strlcpy(buff, attr, len) != strlen(attr)) { ++ condlog(3, "%s: overflow in 'dev' attribute", dev->kernel); ++ return 2; ++ } ++ return 0; ++} + +- attr = sysfs_open_attribute(attr_path); ++int ++sysfs_get_size (struct sysfs_device * dev, unsigned long long * size) ++{ ++ char *attr; ++ int r; + ++ attr = sysfs_attr_get_value(dev->devpath, "size"); + if (!attr) + return 1; + +- if (0 > sysfs_read_attribute(attr)) +- goto out; +- +- r = sscanf(attr->value, "%llu\n", size); +- sysfs_close_attribute(attr); ++ r = sscanf(attr, "%llu\n", size); + + if (r != 1) + return 1; + + return 0; +-out: +- sysfs_close_attribute(attr); ++} ++ ++int ++sysfs_get_fc_nodename (struct sysfs_device * dev, char * node, ++ unsigned int host, unsigned int channel, ++ unsigned int target) ++{ ++ char attr_path[SYSFS_PATH_SIZE], *attr; ++ ++ if (safe_sprintf(attr_path, ++ "/class/fc_transport/target%i:%i:%i", ++ host, channel, target)) { ++ condlog(0, "attr_path too small"); ++ return 1; ++ } ++ ++ attr = sysfs_attr_get_value(attr_path, "node_name"); ++ if (attr) { ++ strlcpy(node, attr, strlen(attr)); ++ return 0; ++ } ++ + return 1; + } + +@@ -216,78 +209,74 @@ out: + static int + opennode (char * dev, int mode) + { +- char devpath[FILE_NAME_SIZE]; ++ char devpath[FILE_NAME_SIZE], *ptr; + + if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) { + condlog(0, "devpath too small"); + return -1; + } +- +- if (wait_for_file(devpath)) { +- condlog(3, "failed to open %s", devpath); +- return -1; ++ /* ++ * Translate '!' into '/' ++ */ ++ ptr = devpath; ++ while ((ptr = strchr(ptr, '!'))) { ++ *ptr = '/'; ++ ptr++; + } +- + return open(devpath, mode); + } + + extern int + devt2devname (char *devname, char *devt) + { +- struct dlist * ls; +- char attr_path[FILE_NAME_SIZE]; ++ FILE *fd; ++ unsigned int tmpmaj, tmpmin, major, minor; ++ char dev[FILE_NAME_SIZE]; char block_path[FILE_NAME_SIZE]; - struct sysfs_attribute * attr; -+ struct sysfs_attribute * attr = NULL; - struct sysfs_class * class; - struct sysfs_class_device * dev; +- struct sysfs_class * class; +- struct sysfs_class_device * dev; ++ struct stat statbuf; -@@ -295,7 +296,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u +- if(safe_sprintf(block_path, "%s/block", sysfs_path)) { +- condlog(0, "block_path too small"); ++ if (sscanf(devt, "%u:%u", &major, &minor) != 2) { ++ condlog(0, "Invalid device number %s", devt); + return 1; + } +- if (!(class = sysfs_open_class("block"))) +- return 1; +- +- if (!(ls = sysfs_get_class_devices(class))) +- goto err; + +- dlist_for_each_data(ls, dev, struct sysfs_class_device) { +- if(safe_sprintf(attr_path, "%s/%s/dev", +- block_path, dev->name)) { +- condlog(0, "attr_path too small"); +- goto err; ++ if ((fd = fopen("/proc/partitions", "r")) < 0) { ++ condlog(0, "Cannot open /proc/partitions"); ++ return 1; ++ } ++ ++ while (!feof(fd)) { ++ int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev); ++ if (!r) { ++ fscanf(fd,"%*s\n"); ++ continue; + } +- if (!(attr = sysfs_open_attribute(attr_path))) +- goto err; +- +- if (sysfs_read_attribute(attr)) +- goto err1; +- +- /* discard newline */ +- if (attr->len > 1) attr->len--; +- +- if (strlen(devt) == attr->len && +- strncmp(attr->value, devt, attr->len) == 0) { +- if(safe_sprintf(attr_path, "%s/%s", +- block_path, dev->name)) { +- condlog(0, "attr_path too small"); +- goto err1; +- } +- sysfs_get_name_from_path(attr_path, devname, +- FILE_NAME_SIZE); +- sysfs_close_attribute(attr); +- sysfs_close_class(class); +- return 0; ++ if (r != 3) ++ continue; ++ ++ if ((major == tmpmaj) && (minor == tmpmin)) { ++ sprintf(block_path, "/sys/block/%s", dev); ++ break; + } + } +-err1: +- sysfs_close_attribute(attr); +-err: +- sysfs_close_class(class); +- return 1; ++ fclose(fd); ++ ++ if (strncmp(block_path,"/sys/block", 10)) ++ return 1; ++ ++ if (stat(block_path, &statbuf) < 0) { ++ condlog(0, "No sysfs entry for %s\n", block_path); ++ return 1; ++ } ++ ++ if (S_ISDIR(statbuf.st_mode) == 0) { ++ condlog(0, "sysfs entry %s is not a directory\n", block_path); ++ return 1; ++ } ++ return 0; + } + +-static int ++int + do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, + void *resp, int mx_resp_len, int noisy) + { +@@ -295,7 +284,7 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, { INQUIRY_CMD, 0, 0, 0, 0, 0 }; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; @@ -2766,7 +4304,7 @@ index cf8289c..a196583 100644 if (cmddt) inqCmdBlk[1] |= 2; if (evpd) -@@ -313,10 +314,10 @@ do_inq(int sg_fd, int cmddt, int evpd, u +@@ -313,10 +302,10 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_b; io_hdr.timeout = DEF_TIMEOUT; @@ -2779,7 +4317,7 @@ index cf8289c..a196583 100644 /* treat SG_ERR here to get rid of sg_err.[ch] */ io_hdr.status &= 0x7e; if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && -@@ -339,24 +340,26 @@ do_inq(int sg_fd, int cmddt, int evpd, u +@@ -339,100 +328,64 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, return -1; } @@ -2811,7 +4349,99 @@ index cf8289c..a196583 100644 } static int -@@ -440,7 +443,7 @@ scsi_sysfs_pathinfo (struct path * pp) +-sysfs_get_bus (char * sysfs_path, struct path * pp) ++get_inq (char * vendor, char * product, char * rev, int fd) + { +- struct sysfs_device *sdev; +- char attr_path[FILE_NAME_SIZE]; +- char attr_buff[FILE_NAME_SIZE]; +- +- pp->bus = SYSFS_BUS_UNDEF; ++ char buff[MX_ALLOC_LEN + 1] = {0}; + +- /* +- * This is ugly : we should be able to do a simple +- * get_link("%s/block/%s/device/bus", ...) but it just +- * won't work +- */ +- if(safe_sprintf(attr_path, "%s/block/%s/device", +- sysfs_path, pp->dev)) { +- condlog(0, "attr_path too small"); +- return 1; +- } +- +- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) ++ if (fd < 0) + return 1; + +-#if DAEMON +- int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND; +- +- while (loop--) { +- sdev = sysfs_open_device_path(attr_buff); +- +- if (strlen(sdev->bus)) +- break; +- +- sysfs_close_device(sdev); +- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); ++ if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) { ++ memcpy(vendor, buff + 8, 8); ++ vendor[8] = '\0'; ++ memcpy(product, buff + 16, 16); ++ product[16] = '\0'; ++ memcpy(rev, buff + 32, 4); ++ rev[4] = '\0'; ++ return 0; + } +-#else +- sdev = sysfs_open_device_path(attr_buff); +-#endif +- +- if (!strncmp(sdev->bus, "scsi", 4)) +- pp->bus = SYSFS_BUS_SCSI; +- else if (!strncmp(sdev->bus, "ide", 3)) +- pp->bus = SYSFS_BUS_IDE; +- else if (!strncmp(sdev->bus, "ccw", 3)) +- pp->bus = SYSFS_BUS_CCW; +- else +- return 1; +- +- sysfs_close_device(sdev); +- +- return 0; ++ return 1; + } + + static int +-scsi_sysfs_pathinfo (struct path * pp) ++scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) + { + char attr_path[FILE_NAME_SIZE]; +- char attr_buff[FILE_NAME_SIZE]; +- struct sysfs_attribute * attr; + +- if (sysfs_get_vendor(sysfs_path, pp->dev, +- pp->vendor_id, SCSI_VENDOR_SIZE)) ++ if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE)) + return 1; + + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); + +- if (sysfs_get_model(sysfs_path, pp->dev, +- pp->product_id, SCSI_PRODUCT_SIZE)) ++ if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE)) + return 1; + + condlog(3, "%s: product = %s", pp->dev, pp->product_id); + +- if (sysfs_get_rev(sysfs_path, pp->dev, +- pp->rev, SCSI_REV_SIZE)) ++ if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE)) + return 1; + + condlog(3, "%s: rev = %s", pp->dev, pp->rev); +@@ -440,20 +393,12 @@ scsi_sysfs_pathinfo (struct path * pp) /* * set the hwe configlet pointer */ @@ -2820,7 +4450,74 @@ index cf8289c..a196583 100644 /* * host / bus / target / lun -@@ -524,7 +527,7 @@ ccw_sysfs_pathinfo (struct path * pp) + */ +- if(safe_sprintf(attr_path, "%s/block/%s/device", +- sysfs_path, pp->dev)) { +- condlog(0, "attr_path too small"); +- return 1; +- } +- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) +- return 1; +- +- basename(attr_buff, attr_path); ++ basename(parent->devpath, attr_path); + + sscanf(attr_path, "%i:%i:%i:%i", + &pp->sg_id.host_no, +@@ -470,35 +415,19 @@ scsi_sysfs_pathinfo (struct path * pp) + /* + * target node name + */ +- if(safe_sprintf(attr_path, +- "%s/class/fc_transport/target%i:%i:%i/node_name", +- sysfs_path, +- pp->sg_id.host_no, +- pp->sg_id.channel, +- pp->sg_id.scsi_id)) { +- condlog(0, "attr_path too small"); +- return 1; ++ if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name, ++ pp->sg_id.host_no, ++ pp->sg_id.channel, ++ pp->sg_id.scsi_id)) { ++ condlog(3, "%s: tgt_node_name = %s", ++ pp->dev, pp->tgt_node_name); + } +- if (!(attr = sysfs_open_attribute(attr_path))) +- return 0; +- +- if (sysfs_read_attribute(attr)) +- goto err; +- +- if (attr->len > 0) +- strncpy(pp->tgt_node_name, attr->value, attr->len - 1); +- +- condlog(3, "%s: tgt_node_name = %s", +- pp->dev, pp->tgt_node_name); + + return 0; +-err: +- sysfs_close_attribute(attr); +- return 1; + } + + static int +-ccw_sysfs_pathinfo (struct path * pp) ++ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) + { + char attr_path[FILE_NAME_SIZE]; + char attr_buff[FILE_NAME_SIZE]; +@@ -507,8 +436,7 @@ ccw_sysfs_pathinfo (struct path * pp) + + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); + +- if (sysfs_get_devtype(sysfs_path, pp->dev, +- attr_buff, FILE_NAME_SIZE)) ++ if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE)) + return 1; + + if (!strncmp(attr_buff, "3370", 4)) { +@@ -524,20 +452,12 @@ ccw_sysfs_pathinfo (struct path * pp) /* * set the hwe configlet pointer */ @@ -2829,7 +4526,130 @@ index cf8289c..a196583 100644 /* * host / bus / target / lun -@@ -597,7 +600,7 @@ static int +- */ +- if(safe_sprintf(attr_path, "%s/block/%s/device", +- sysfs_path, pp->dev)) { +- condlog(0, "attr_path too small"); +- return 1; +- } +- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) +- return 1; +- +- basename(attr_buff, attr_path); ++ */ ++ basename(parent->devpath, attr_path); + pp->sg_id.lun = 0; + sscanf(attr_path, "%i.%i.%x", + &pp->sg_id.host_no, +@@ -554,20 +474,43 @@ ccw_sysfs_pathinfo (struct path * pp) + } + + static int +-common_sysfs_pathinfo (struct path * pp) ++cciss_sysfs_pathinfo (struct path * pp, struct sysfs_device * dev) + { +- if (sysfs_get_bus(sysfs_path, pp)) +- return 1; ++ char attr_path[FILE_NAME_SIZE]; + +- condlog(3, "%s: bus = %i", pp->dev, pp->bus); ++ /* ++ * host / bus / target / lun ++ */ ++ basename(dev->devpath, attr_path); ++ pp->sg_id.lun = 0; ++ pp->sg_id.channel = 0; ++ sscanf(attr_path, "cciss!c%id%i", ++ &pp->sg_id.host_no, ++ &pp->sg_id.scsi_id); ++ condlog(3, "%s: h:b:t:l = %i:%i:%i:%i", ++ pp->dev, ++ pp->sg_id.host_no, ++ pp->sg_id.channel, ++ pp->sg_id.scsi_id, ++ pp->sg_id.lun); ++ return 0; ++} ++ ++static int ++common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev) ++{ ++ char *attr; + +- if (sysfs_get_dev(sysfs_path, pp->dev, +- pp->dev_t, BLK_DEV_SIZE)) ++ attr = sysfs_attr_get_value(dev->devpath, "dev"); ++ if (!attr) { ++ condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); + return 1; ++ } ++ strlcpy(pp->dev_t, attr, BLK_DEV_SIZE); + + condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); + +- if (sysfs_get_size(sysfs_path, pp->dev, &pp->size)) ++ if (sysfs_get_size(dev, &pp->size)) + return 1; + + condlog(3, "%s: size = %llu", pp->dev, pp->size); +@@ -575,19 +518,53 @@ common_sysfs_pathinfo (struct path * pp) + return 0; + } + ++struct sysfs_device *sysfs_device_from_path(struct path *pp) ++{ ++ char sysdev[FILE_NAME_SIZE]; ++ ++ strlcpy(sysdev,"/block/", FILE_NAME_SIZE); ++ strlcat(sysdev,pp->dev, FILE_NAME_SIZE); ++ ++ return sysfs_device_get(sysdev); ++} ++ + extern int + sysfs_pathinfo(struct path * pp) + { +- if (common_sysfs_pathinfo(pp)) ++ struct sysfs_device *parent; ++ ++ pp->sysdev = sysfs_device_from_path(pp); ++ if (!pp->sysdev) { ++ condlog(1, "%s: failed to get sysfs information", pp->dev); ++ return 1; ++ } ++ ++ if (common_sysfs_pathinfo(pp, pp->sysdev)) + return 1; + ++ parent = sysfs_device_get_parent(pp->sysdev); ++ if (!parent) ++ parent = pp->sysdev; ++ ++ condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem); ++ ++ if (!strncmp(parent->subsystem, "scsi",4)) ++ pp->bus = SYSFS_BUS_SCSI; ++ if (!strncmp(parent->subsystem, "ccw",3)) ++ pp->bus = SYSFS_BUS_CCW; ++ if (!strncmp(pp->dev,"cciss",5)) ++ pp->bus = SYSFS_BUS_CCISS; ++ + if (pp->bus == SYSFS_BUS_UNDEF) + return 0; + else if (pp->bus == SYSFS_BUS_SCSI) { +- if (scsi_sysfs_pathinfo(pp)) ++ if (scsi_sysfs_pathinfo(pp, parent)) + return 1; + } else if (pp->bus == SYSFS_BUS_CCW) { +- if (ccw_sysfs_pathinfo(pp)) ++ if (ccw_sysfs_pathinfo(pp, parent)) ++ return 1; ++ } else if (pp->bus == SYSFS_BUS_CCISS) { ++ if (cciss_sysfs_pathinfo(pp, pp->sysdev)) + return 1; + } + return 0; +@@ -597,7 +574,7 @@ static int scsi_ioctl_pathinfo (struct path * pp, int mask) { if (mask & DI_SERIAL) { @@ -2838,7 +4658,29 @@ index cf8289c..a196583 100644 condlog(3, "%s: serial = %s", pp->dev, pp->serial); } -@@ -609,12 +612,15 @@ get_state (struct path * pp) +@@ -605,16 +582,37 @@ scsi_ioctl_pathinfo (struct path * pp, int mask) + } + + static int ++cciss_ioctl_pathinfo (struct path * pp, int mask) ++{ ++ if (mask & DI_SYSFS) { ++ get_inq(pp->vendor_id, pp->product_id, pp->rev, pp->fd); ++ condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); ++ condlog(3, "%s: product = %s", pp->dev, pp->product_id); ++ condlog(3, "%s: revision = %s", pp->dev, pp->rev); ++ /* ++ * set the hwe configlet pointer ++ */ ++ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, ++ pp->product_id, pp->rev); ++ ++ } ++ return 0; ++} ++ ++static int + get_state (struct path * pp) { struct checker * c = &pp->checker; @@ -2855,7 +4697,7 @@ index cf8289c..a196583 100644 return 1; } pp->state = checker_check(c); -@@ -636,14 +642,14 @@ get_prio (struct path * pp) +@@ -636,14 +634,14 @@ get_prio (struct path * pp) pp->getprio_selected = 1; } if (!pp->getprio) { @@ -2873,22 +4715,41 @@ index cf8289c..a196583 100644 return 1; } else pp->priority = atoi(prio); -@@ -699,7 +705,12 @@ pathinfo (struct path *pp, vector hwtabl +@@ -689,17 +687,29 @@ pathinfo (struct path *pp, vector hwtable, int mask) + if (pp->fd < 0) + pp->fd = opennode(pp->dev, O_RDONLY); + +- if (pp->fd < 0) ++ if (pp->fd < 0) { ++ condlog(4, "Couldn't open node for %s: %s", ++ pp->dev, strerror(errno)); + goto blank; ++ } + + if (pp->bus == SYSFS_BUS_SCSI && + scsi_ioctl_pathinfo(pp, mask)) + goto blank; + ++ if (pp->bus == SYSFS_BUS_CCISS && ++ cciss_ioctl_pathinfo(pp, mask)) ++ goto blank; ++ if (mask & DI_CHECKER && get_state(pp)) goto blank; - +- - if (mask & DI_PRIO && pp->state != PATH_DOWN) ++ + /* -+ * Retrieve path priority even for not PATH_UP paths if it has never ++ * Retrieve path priority, even for PATH_DOWN paths if it has never + * been successfully obtained before. + */ + if (mask & DI_PRIO && -+ (pp->state == PATH_UP || pp->priority == PRIO_UNDEF)) ++ (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF)) get_prio(pp); if (mask & DI_WWID && !strlen(pp->wwid)) diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h -index cdc9627..ab62a59 100644 +index cdc9627..c7cf7e8 100644 --- a/libmultipath/discovery.h +++ b/libmultipath/discovery.h @@ -5,7 +5,6 @@ @@ -2910,7 +4771,17 @@ index cdc9627..ab62a59 100644 /* * exerpt from sg_err.h */ -@@ -30,7 +33,6 @@ int sysfs_get_size (char * sysfs_path, c +@@ -21,16 +24,10 @@ + #define SCSI_COMMAND_TERMINATED 0x22 + #define SG_ERR_DRIVER_SENSE 0x08 + +-int sysfs_get_vendor (char * sysfs_path, char * dev, char * buff, int len); +-int sysfs_get_model (char * sysfs_path, char * dev, char * buff, int len); +-int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len); +-int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len); +- +-int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *); ++int sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len); int path_discovery (vector pathvec, struct config * conf, int flag); void basename (char *, char *); @@ -2940,7 +4811,7 @@ index 2b170c6..631933d 100644 if (shift >= freechar) { fprintf(stderr, "mp->params too small\n"); return 1; -@@ -117,6 +120,7 @@ disassemble_map (vector pathvec, char * +@@ -117,6 +120,7 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp) int num_pg_args = 0; int num_paths = 0; int num_paths_args = 0; @@ -2948,7 +4819,7 @@ index 2b170c6..631933d 100644 struct path * pp; struct pathgroup * pgp; -@@ -305,12 +309,15 @@ disassemble_map (vector pathvec, char * +@@ -305,12 +309,15 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp) if (k == 0 && !strncmp(mpp->selector, "round-robin", 11)) { p += get_word(p, &word); @@ -2968,7 +4839,7 @@ index 2b170c6..631933d 100644 else p += get_word(p, NULL); diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c -index 5c7d625..df6f5aa 100644 +index 5c7d625..ef761d7 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -12,13 +12,34 @@ @@ -3008,60 +4879,106 @@ index 5c7d625..df6f5aa 100644 * * Maintainer : Christophe Varoqui * Mail : christophe.varoqui@free.fr -@@ -54,14 +75,14 @@ static struct hwentry default_hw[] = { +@@ -42,11 +63,11 @@ static struct hwentry default_hw[] = { + .vendor = "DEC", + .product = "HSG80", + .getuid = DEFAULT_GETUID, +- .getprio = NULL, +- .features = DEFAULT_FEATURES, ++ .getprio = "/sbin/mpath_prio_hp_sw /dev/%n", ++ .features = "1 queue_if_no_path", + .hwhandler = "1 hp_sw", + .selector = DEFAULT_SELECTOR, +- .pgpolicy = GROUP_BY_SERIAL, ++ .pgpolicy = GROUP_BY_PRIO, + .pgfailback = FAILBACK_UNDEF, + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, +@@ -54,14 +75,30 @@ static struct hwentry default_hw[] = { .checker_name = HP_SW, }, { - .vendor = "{COMPAQ,HP}", - .product = "{MSA,HSV}1*", -+ .vendor = "(COMPAQ|HP)", -+ .product = "(MSA|HSV)1.*", - .getuid = DEFAULT_GETUID, - .getprio = NULL, - .features = DEFAULT_FEATURES, - .hwhandler = "1 hp_sw", - .selector = DEFAULT_SELECTOR, -- .pgpolicy = GROUP_BY_SERIAL, -+ .pgpolicy = MULTIBUS, - .pgfailback = FAILBACK_UNDEF, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, -@@ -70,7 +91,7 @@ static struct hwentry default_hw[] = { - }, - { - .vendor = "HP", -- .product = "HSV2*", ++ .vendor = "HP", + .product = "A6189A", .getuid = DEFAULT_GETUID, .getprio = NULL, .features = DEFAULT_FEATURES, -@@ -85,7 +106,8 @@ static struct hwentry default_hw[] = { ++ .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 = READSECTOR0, ++ }, ++ { ++ /* 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", + .selector = DEFAULT_SELECTOR, +- .pgpolicy = GROUP_BY_SERIAL, ++ .pgpolicy = GROUP_BY_PRIO, + .pgfailback = FAILBACK_UNDEF, + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, +@@ -69,24 +106,58 @@ static struct hwentry default_hw[] = { + .checker_name = HP_SW, }, { ++ /* MSA 1000/1500 with new firmware */ .vendor = "HP", -- .product = "DF[456]00", -+ .product = "HSV20.*", -+ .revision = "[123].*", +- .product = "HSV2*", ++ .product = "MSA VOLUME", .getuid = DEFAULT_GETUID, - .getprio = NULL, +- .getprio = NULL, ++ .getprio = "/sbin/mpath_prio_alua /dev/%n", .features = DEFAULT_FEATURES, -@@ -96,10 +118,41 @@ static struct hwentry default_hw[] = { + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, +- .pgpolicy = MULTIBUS, +- .pgfailback = FAILBACK_UNDEF, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, .rr_weight = RR_WEIGHT_NONE, .no_path_retry = NO_PATH_RETRY_UNDEF, .minio = DEFAULT_MINIO, - .checker_name = READSECTOR0, -+ .checker_name = HP_SW, ++ .checker_name = TUR, + }, + { -+ .vendor = "HP", -+ .product = "HSV20.*", -+ .revision = "[^123].*", ++ /* EVA 3000/5000 with new firmware */ ++ .vendor = "(COMPAQ|HP)", ++ .product = "(MSA|HSV)1.1.*", + .getuid = DEFAULT_GETUID, + .getprio = "/sbin/mpath_prio_alua /dev/%n", + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, -+ .pgpolicy = MULTIBUS, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_UNDEF, ++ .minio = DEFAULT_MINIO, ++ .checker_name = TUR, + }, + { ++ /* EVA 4000/6000/8000 */ + .vendor = "HP", +- .product = "DF[456]00", ++ .product = "HSV2.*", + .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, @@ -3069,18 +4986,18 @@ index 5c7d625..df6f5aa 100644 + .checker_name = TUR, + }, + { ++ /* HP Smart Array */ + .vendor = "HP", -+ .product = "HSV21.*", -+ .getuid = DEFAULT_GETUID, -+ .getprio = "/sbin/mpath_prio_alua /dev/%n", -+ .features = DEFAULT_FEATURES, -+ .hwhandler = DEFAULT_HWHANDLER, -+ .selector = DEFAULT_SELECTOR, -+ .pgpolicy = GROUP_BY_PRIO, -+ .pgfailback = FAILBACK_UNDEF, -+ .rr_weight = RR_WEIGHT_NONE, -+ .no_path_retry = NO_PATH_RETRY_UNDEF, -+ .minio = DEFAULT_MINIO, ++ .product = "LOGICAL VOLUME.*", ++ .getuid = "/lib/udev/scsi_id -n -g -u -s /block/%n", + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, +@@ -96,10 +167,10 @@ static struct hwentry default_hw[] = { + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, + .minio = DEFAULT_MINIO, +- .checker_name = READSECTOR0, + .checker_name = TUR, }, /* @@ -3089,7 +5006,7 @@ index 5c7d625..df6f5aa 100644 * * Maintainer : Christophe Varoqui * Mail : christophe.varoqui@free.fr -@@ -117,10 +170,10 @@ static struct hwentry default_hw[] = { +@@ -117,10 +188,10 @@ static struct hwentry default_hw[] = { .rr_weight = RR_WEIGHT_NONE, .no_path_retry = NO_PATH_RETRY_UNDEF, .minio = DEFAULT_MINIO, @@ -3102,7 +5019,16 @@ index 5c7d625..df6f5aa 100644 * * Maintainer : Edward Goggin, EMC * Mail : egoggin@emc.com -@@ -142,7 +195,7 @@ static struct hwentry default_hw[] = { +@@ -128,7 +199,7 @@ static struct hwentry default_hw[] = { + { + .vendor = "EMC", + .product = "SYMMETRIX", +- .getuid = "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n", ++ .getuid = "/lib/udev/scsi_id -g -u -ppre-spc3-83 -s /block/%n", + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, +@@ -142,7 +213,7 @@ static struct hwentry default_hw[] = { }, { .vendor = "DGC", @@ -3111,7 +5037,7 @@ index 5c7d625..df6f5aa 100644 .bl_product = "LUNZ", .getuid = DEFAULT_GETUID, .getprio = "/sbin/mpath_prio_emc /dev/%n", -@@ -157,7 +210,7 @@ static struct hwentry default_hw[] = { +@@ -157,7 +228,7 @@ static struct hwentry default_hw[] = { .checker_name = EMC_CLARIION, }, /* @@ -3120,7 +5046,7 @@ index 5c7d625..df6f5aa 100644 * * Maintainer : Christophe Varoqui * Mail : christophe.varoqui@free.fr -@@ -178,14 +231,14 @@ static struct hwentry default_hw[] = { +@@ -178,17 +249,17 @@ static struct hwentry default_hw[] = { .checker_name = READSECTOR0, }, /* @@ -3139,17 +5065,24 @@ index 5c7d625..df6f5aa 100644 + .product = "OPEN-.*", .getuid = DEFAULT_GETUID, .getprio = NULL, - .features = DEFAULT_FEATURES, -@@ -198,10 +251,25 @@ static struct hwentry default_hw[] = { +- .features = DEFAULT_FEATURES, ++ .features = "1 queue_if_no_path", + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, + .pgpolicy = MULTIBUS, +@@ -196,12 +267,27 @@ 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 = READSECTOR0, ++ .checker_name = TUR, ++ }, + { + .vendor = "HITACHI", + .product = "DF.*", + .getuid = DEFAULT_GETUID, -+ .getprio = "/sbin/mpath_prio_hds_modular %d", -+ .features = DEFAULT_FEATURES, ++ .getprio = "/sbin/mpath_prio_hds_modular /dev/%n", ++ .features = "1 queue_if_no_path", + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, + .pgpolicy = GROUP_BY_PRIO, @@ -3157,8 +5090,8 @@ index 5c7d625..df6f5aa 100644 + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, + .minio = DEFAULT_MINIO, -+ .checker_name = READSECTOR0, -+ }, ++ .checker_name = TUR, + }, /* - * IBM controler family + * IBM controller family @@ -3168,15 +5101,12 @@ index 5c7d625..df6f5aa 100644 * Mail : hare@suse.de */ { -@@ -236,6 +304,22 @@ static struct hwentry default_hw[] = { - .checker_name = TUR, - }, - { -+ /* IBM Netfinity Fibre Channel RAID Controller Unit */ -+ .vendor = "IBM", -+ .product = "3526", -+ .getuid = DEFAULT_GETUID, -+ .getprio = "/sbin/mpath_prio_tpc /dev/%n", +@@ -224,7 +310,23 @@ static struct hwentry default_hw[] = { + .vendor = "IBM", + .product = "1742", + .getuid = DEFAULT_GETUID, +- .getprio = "/sbin/mpath_prio_tpc /dev/%n", ++ .getprio = "/sbin/mpath_prio_rdac /dev/%n", + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, @@ -3188,10 +5118,15 @@ index 5c7d625..df6f5aa 100644 + .checker_name = TUR, + }, + { - /* IBM DS4200 / FAStT200 */ - .vendor = "IBM", - .product = "3542", -@@ -254,7 +338,7 @@ static struct hwentry default_hw[] = { ++ /* 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, + .selector = DEFAULT_SELECTOR, +@@ -254,7 +356,7 @@ static struct hwentry default_hw[] = { { /* IBM ESS F20 aka Shark */ .vendor = "IBM", @@ -3200,7 +5135,7 @@ index 5c7d625..df6f5aa 100644 .getuid = DEFAULT_GETUID, .getprio = NULL, .features = "1 queue_if_no_path", -@@ -268,9 +352,9 @@ static struct hwentry default_hw[] = { +@@ -268,9 +370,9 @@ static struct hwentry default_hw[] = { .checker_name = TUR, }, { @@ -3212,7 +5147,7 @@ index 5c7d625..df6f5aa 100644 .getuid = DEFAULT_GETUID, .getprio = "/sbin/mpath_prio_alua /dev/%n", .features = "1 queue_if_no_path", -@@ -292,7 +376,7 @@ static struct hwentry default_hw[] = { +@@ -292,7 +394,7 @@ static struct hwentry default_hw[] = { .features = "1 queue_if_no_path", .hwhandler = DEFAULT_HWHANDLER, .selector = DEFAULT_SELECTOR, @@ -3221,7 +5156,7 @@ index 5c7d625..df6f5aa 100644 .pgfailback = FAILBACK_UNDEF, .rr_weight = RR_WEIGHT_NONE, .no_path_retry = NO_PATH_RETRY_UNDEF, -@@ -300,10 +384,27 @@ static struct hwentry default_hw[] = { +@@ -300,12 +402,29 @@ static struct hwentry default_hw[] = { .checker_name = TUR, }, { @@ -3246,11 +5181,14 @@ index 5c7d625..df6f5aa 100644 .product = "S/390 DASD ECKD", - .getuid = "/sbin/dasdview -j /dev/%n", + .bl_product = "S/390.*", -+ .getuid = "/sbin/dasd_id /dev/%n", ++ .getuid = "/sbin/dasdinfo -u -b %n", .getprio = NULL, - .features = DEFAULT_FEATURES, +- .features = DEFAULT_FEATURES, ++ .features = "1 queue_if_no_path", .hwhandler = DEFAULT_HWHANDLER, -@@ -315,38 +416,59 @@ static struct hwentry default_hw[] = { + .selector = DEFAULT_SELECTOR, + .pgpolicy = MULTIBUS, +@@ -315,38 +434,59 @@ static struct hwentry default_hw[] = { .minio = DEFAULT_MINIO, .checker_name = DIRECTIO, }, @@ -3322,7 +5260,51 @@ index 5c7d625..df6f5aa 100644 .features = DEFAULT_FEATURES, .hwhandler = DEFAULT_HWHANDLER, .selector = DEFAULT_SELECTOR, -@@ -422,7 +544,7 @@ static struct hwentry default_hw[] = { +@@ -382,16 +522,31 @@ static struct hwentry default_hw[] = { + .vendor = "SGI", + .product = "TP9[45]00", + .getuid = DEFAULT_GETUID, +- .getprio = "/sbin/mpath_prio_tpc /dev/%n", ++ .getprio = "/sbin/mpath_prio_rdac /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 = NO_PATH_RETRY_QUEUE, + .minio = DEFAULT_MINIO, +- .checker_name = TUR, ++ .checker_name = RDAC, ++ }, ++ { ++ .vendor = "SGI", ++ .product = "IS.*", ++ .getuid = DEFAULT_GETUID, ++ .getprio = "/sbin/mpath_prio_rdac /dev/%n", ++ .features = DEFAULT_FEATURES, ++ .hwhandler = DEFAULT_HWHANDLER, ++ .selector = DEFAULT_SELECTOR, ++ .pgpolicy = GROUP_BY_PRIO, ++ .pgfailback = -FAILBACK_IMMEDIATE, ++ .rr_weight = RR_WEIGHT_NONE, ++ .no_path_retry = NO_PATH_RETRY_QUEUE, ++ .minio = DEFAULT_MINIO, ++ .checker_name = RDAC, + }, + /* + * STK arrays +@@ -403,7 +558,7 @@ static struct hwentry default_hw[] = { + .vendor = "STK", + .product = "OPENstorage D280", + .getuid = DEFAULT_GETUID, +- .getprio = "/sbin/mpath_prio_tpc /dev/%n", ++ .getprio = "/sbin/mpath_prio_rdac /dev/%n", + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, +@@ -422,7 +577,7 @@ static struct hwentry default_hw[] = { */ { .vendor = "SUN", @@ -3331,6 +5313,301 @@ index 5c7d625..df6f5aa 100644 .getuid = DEFAULT_GETUID, .getprio = NULL, .features = DEFAULT_FEATURES, +diff --git a/libmultipath/list.h b/libmultipath/list.h +new file mode 100644 +index 0000000..8626630 +--- /dev/null ++++ b/libmultipath/list.h +@@ -0,0 +1,289 @@ ++/* ++ * Copied from the Linux kernel source tree, version 2.6.0-test1. ++ * ++ * Licensed under the GPL v2 as per the whole kernel source tree. ++ * ++ */ ++ ++#ifndef _LIST_H ++#define _LIST_H ++ ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++ ++/* ++ * These are non-NULL pointers that will result in page faults ++ * under normal circumstances, used to verify that nobody uses ++ * non-initialized list entries. ++ */ ++#define LIST_POISON1 ((void *) 0x00100100) ++#define LIST_POISON2 ((void *) 0x00200200) ++ ++/* ++ * Simple doubly linked list implementation. ++ * ++ * Some of the internal functions ("__xxx") are useful when ++ * manipulating whole lists rather than single entries, as ++ * sometimes we already know the next/prev entries and we can ++ * generate better code by using them directly rather than ++ * using the generic single-entry routines. ++ */ ++ ++struct list_head { ++ struct list_head *next, *prev; ++}; ++ ++#define LIST_HEAD_INIT(name) { &(name), &(name) } ++ ++#define LIST_HEAD(name) \ ++ struct list_head name = LIST_HEAD_INIT(name) ++ ++#define INIT_LIST_HEAD(ptr) do { \ ++ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ ++} while (0) ++ ++/* ++ * Insert a new entry between two known consecutive entries. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_add(struct list_head *new, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ next->prev = new; ++ new->next = next; ++ new->prev = prev; ++ prev->next = new; ++} ++ ++/** ++ * list_add - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it after ++ * ++ * Insert a new entry after the specified head. ++ * This is good for implementing stacks. ++ */ ++static inline void list_add(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head, head->next); ++} ++ ++/** ++ * list_add_tail - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it before ++ * ++ * Insert a new entry before the specified head. ++ * This is useful for implementing queues. ++ */ ++static inline void list_add_tail(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head->prev, head); ++} ++ ++/* ++ * Delete a list entry by making the prev/next entries ++ * point to each other. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_del(struct list_head * prev, struct list_head * next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++ ++/** ++ * list_del - deletes entry from list. ++ * @entry: the element to delete from the list. ++ * Note: list_empty on entry does not return true after this, the entry is ++ * in an undefined state. ++ */ ++static inline void list_del(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ entry->next = LIST_POISON1; ++ entry->prev = LIST_POISON2; ++} ++ ++/** ++ * list_del_init - deletes entry from list and reinitialize it. ++ * @entry: the element to delete from the list. ++ */ ++static inline void list_del_init(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ INIT_LIST_HEAD(entry); ++} ++ ++/** ++ * list_move - delete from one list and add as another's head ++ * @list: the entry to move ++ * @head: the head that will precede our entry ++ */ ++static inline void list_move(struct list_head *list, struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add(list, head); ++} ++ ++/** ++ * list_move_tail - delete from one list and add as another's tail ++ * @list: the entry to move ++ * @head: the head that will follow our entry ++ */ ++static inline void list_move_tail(struct list_head *list, ++ struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add_tail(list, head); ++} ++ ++/** ++ * list_empty - tests whether a list is empty ++ * @head: the list to test. ++ */ ++static inline int list_empty(struct list_head *head) ++{ ++ return head->next == head; ++} ++ ++static inline void __list_splice(struct list_head *list, ++ struct list_head *head) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ struct list_head *at = head->next; ++ ++ first->prev = head; ++ head->next = first; ++ ++ last->next = at; ++ at->prev = last; ++} ++ ++/** ++ * list_splice - join two lists ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ */ ++static inline void list_splice(struct list_head *list, struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice(list, head); ++} ++ ++/** ++ * list_splice_init - join two lists and reinitialise the emptied list. ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ * ++ * The list at @list is reinitialised ++ */ ++static inline void list_splice_init(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) { ++ __list_splice(list, head); ++ INIT_LIST_HEAD(list); ++ } ++} ++ ++/** ++ * list_entry - get the struct for this entry ++ * @ptr: the &struct list_head pointer. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_entry(ptr, type, member) \ ++ container_of(ptr, type, member) ++ ++/** ++ * list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop counter. ++ * @head: the head for your list. ++ */ ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); \ ++ pos = pos->next) ++ ++/** ++ * __list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop counter. ++ * @head: the head for your list. ++ * ++ * This variant differs from list_for_each() in that it's the ++ * simplest possible list iteration code. ++ * Use this for code that knows the list to be very short (empty ++ * or 1 entry) most of the time. ++ */ ++#define __list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++ ++/** ++ * list_for_each_prev - iterate over a list backwards ++ * @pos: the &struct list_head to use as a loop counter. ++ * @head: the head for your list. ++ */ ++#define list_for_each_prev(pos, head) \ ++ for (pos = (head)->prev; pos != (head); pos = pos->prev) ++ ++/** ++ * list_for_each_safe - iterate over a list safe against removal of list entry ++ * @pos: the &struct list_head to use as a loop counter. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. ++ */ ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++ ++/** ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop counter. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_reverse - iterate backwards over list of given type. ++ * @pos: the type * to use as a loop counter. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_reverse(pos, head, member) \ ++ for (pos = list_entry((head)->prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.prev, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @pos: the type * to use as a loop counter. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++#endif /* _LIST_H */ diff --git a/libmultipath/lock.c b/libmultipath/lock.c new file mode 100644 index 0000000..0ca8783 @@ -3373,6 +5650,48 @@ index 0000000..6afecda +void cleanup_lock (void * data); + +#endif /* _LOCK_H */ +diff --git a/libmultipath/log.c b/libmultipath/log.c +index 8b339d7..90e4d1f 100644 +--- a/libmultipath/log.c ++++ b/libmultipath/log.c +@@ -118,6 +118,11 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + /* not enough space on tail : rewind */ + if (la->head <= la->tail && len > (la->end - la->tail)) { + logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail); ++ if (la->head == la->start ) { ++ logdbg(stderr, "enqueue: can not rewind tail, drop msg\n"); ++ la->tail = lastmsg; ++ return 1; /* can't reuse */ ++ } + la->tail = la->start; + + if (la->empty) +diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c +index f98cfa4..5a82b6a 100644 +--- a/libmultipath/log_pthread.c ++++ b/libmultipath/log_pthread.c +@@ -12,7 +12,7 @@ + #include "log_pthread.h" + #include "log.h" + +-void log_safe (int prio, char * fmt, va_list ap) ++void log_safe (int prio, const char * fmt, va_list ap) + { + pthread_mutex_lock(logq_lock); + //va_start(ap, fmt); +diff --git a/libmultipath/log_pthread.h b/libmultipath/log_pthread.h +index 7c902c7..2b18f59 100644 +--- a/libmultipath/log_pthread.h ++++ b/libmultipath/log_pthread.h +@@ -7,7 +7,7 @@ pthread_mutex_t *logq_lock; + pthread_mutex_t *logev_lock; + pthread_cond_t *logev_cond; + +-void log_safe(int prio, char * fmt, va_list ap); ++void log_safe(int prio, const char * fmt, va_list ap); + void log_thread_start(void); + void log_thread_stop(void); + diff --git a/libmultipath/parser.c b/libmultipath/parser.c index 9b0b5c2..f9c555e 100644 --- a/libmultipath/parser.c @@ -3391,7 +5710,7 @@ index 9b0b5c2..f9c555e 100644 int keyword_alloc(vector keywords, char *string, int (*handler) (vector), -@@ -53,7 +60,10 @@ keyword_alloc(vector keywords, char *str +@@ -53,7 +60,10 @@ keyword_alloc(vector keywords, char *string, int (*handler) (vector), int install_keyword_root(char *string, int (*handler) (vector)) { @@ -3439,15 +5758,15 @@ index 66c3c29..1f010a3 100644 IOPOLICY_UNDEF, FAILOVER, diff --git a/libmultipath/print.c b/libmultipath/print.c -index 6cc63e2..e50f37d 100644 +index 6cc63e2..01a157a 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -5,6 +5,8 @@ #include #include #include -+#include -+#include ++#include ++#include #include @@ -3465,7 +5784,7 @@ index 6cc63e2..e50f37d 100644 #define MAX(x,y) (x > y) ? x : y #define TAIL (line + len - 1 - c) -@@ -52,16 +55,26 @@ snprint_uint (char * buff, size_t len, u +@@ -52,16 +55,26 @@ snprint_uint (char * buff, size_t len, unsigned int val) static int snprint_size (char * buff, size_t len, unsigned long long size) { @@ -3499,7 +5818,18 @@ index 6cc63e2..e50f37d 100644 static int snprint_name (char * buff, size_t len, struct multipath * mpp) { -@@ -222,6 +235,9 @@ snprint_action (char * buff, size_t len, +@@ -211,6 +224,10 @@ static int + snprint_action (char * buff, size_t len, struct multipath * mpp) + { + switch (mpp->action) { ++ case ACT_REJECT: ++ return snprint_str(buff, len, ACT_REJECT_STR); ++ case ACT_RENAME: ++ return snprint_str(buff, len, ACT_RENAME_STR); + case ACT_RELOAD: + return snprint_str(buff, len, ACT_RELOAD_STR); + case ACT_CREATE: +@@ -222,6 +239,9 @@ snprint_action (char * buff, size_t len, struct multipath * mpp) } } @@ -3509,7 +5839,7 @@ index 6cc63e2..e50f37d 100644 static int snprint_path_uuid (char * buff, size_t len, struct path * pp) { -@@ -292,8 +308,8 @@ snprint_dm_path_state (char * buff, size +@@ -292,8 +312,8 @@ snprint_dm_path_state (char * buff, size_t len, struct path * pp) static int snprint_vpr (char * buff, size_t len, struct path * pp) { @@ -3520,7 +5850,7 @@ index 6cc63e2..e50f37d 100644 } static int -@@ -496,7 +512,7 @@ snprint_multipath (char * line, int len, +@@ -496,7 +516,7 @@ snprint_multipath (char * line, int len, char * format, char * f = format; /* format string cursor */ int fwd; struct multipath_data * data; @@ -3529,7 +5859,7 @@ index 6cc63e2..e50f37d 100644 do { if (!TAIL) -@@ -515,6 +531,7 @@ snprint_multipath (char * line, int len, +@@ -515,6 +535,7 @@ snprint_multipath (char * line, int len, char * format, data->snprint(buff, MAX_FIELD_LEN, mpp); PRINT(c, TAIL, buff); PAD(data->width); @@ -3537,7 +5867,7 @@ index 6cc63e2..e50f37d 100644 } while (*f++); line[c - line - 1] = '\n'; -@@ -631,7 +648,7 @@ snprint_pathgroup (char * line, int len, +@@ -631,7 +652,7 @@ snprint_pathgroup (char * line, int len, char * format, extern void print_multipath_topology (struct multipath * mpp, int verbosity) { @@ -3546,7 +5876,7 @@ index 6cc63e2..e50f37d 100644 snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES, mpp, verbosity); -@@ -662,7 +679,10 @@ snprint_multipath_topology (char * buff, +@@ -662,7 +683,10 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp, c += sprintf(c, "%%n"); if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE)) @@ -3558,7 +5888,7 @@ index 6cc63e2..e50f37d 100644 fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp); if (fwd > len) -@@ -833,6 +853,110 @@ snprint_defaults (char * buff, int len) +@@ -833,6 +857,110 @@ snprint_defaults (char * buff, int len) } @@ -3669,7 +5999,7 @@ index 6cc63e2..e50f37d 100644 extern int snprint_blacklist (char * buff, int len) { -@@ -895,12 +1019,126 @@ snprint_blacklist (char * buff, int len) +@@ -895,12 +1023,137 @@ snprint_blacklist (char * buff, int len) if (fwd > len) return len; } @@ -3678,7 +6008,7 @@ index 6cc63e2..e50f37d 100644 + return len; + return fwd; +} -+ + +extern int +snprint_blacklist_except (char * buff, int len) +{ @@ -3718,7 +6048,7 @@ index 6cc63e2..e50f37d 100644 + rootkw = find_keyword(rootkw->sub, "device"); + if (!rootkw) + return 0; - ++ + vector_foreach_slot (conf->elist_device, eled, i) { + fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n"); + if (fwd > len) @@ -3751,35 +6081,46 @@ index 6cc63e2..e50f37d 100644 +extern int +snprint_devices (char * buff, int len, struct vectors *vecs) +{ -+ struct dlist * ls; -+ struct sysfs_class * class; -+ struct sysfs_class_device * dev; ++ DIR *blkdir; ++ struct dirent *blkdev; ++ struct stat statbuf; ++ char devpath[PATH_MAX]; ++ char *devptr; + int threshold = MAX_LINE_LEN; + int fwd = 0; + int r; + + struct path * pp; + -+ if (!(class = sysfs_open_class("block"))) -+ return 0; -+ -+ if (!(ls = sysfs_get_class_devices(class))) { -+ sysfs_close_class(class); -+ return 0; -+ } ++ if (!(blkdir = opendir("/sys/block"))) ++ return 1; + + if ((len - fwd - threshold) <= 0) + return len; + fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n"); + -+ dlist_for_each_data(ls, dev, struct sysfs_class_device) { ++ strcpy(devpath,"/sys/block"); ++ devptr = devpath + 10; ++ 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) ++ continue; ++ ++ if (S_ISDIR(statbuf.st_mode) == 0) ++ continue; ++ + if ((len - fwd - threshold) <= 0) + return len; -+ fwd += snprintf(buff + fwd, len - fwd, " %s", dev->name); -+ pp = find_path_by_dev(vecs->pathvec, dev->name); ++ ++ fwd += snprintf(buff + fwd, len - fwd, " %s", devpath); ++ pp = find_path_by_dev(vecs->pathvec, devpath); + if (!pp) { + r = filter_devnode(conf->blist_devnode, -+ conf->elist_devnode, dev->name); ++ conf->elist_devnode, devpath); + if (r > 0) + fwd += snprintf(buff + fwd, len - fwd, + " (blacklisted)"); @@ -3788,8 +6129,8 @@ index 6cc63e2..e50f37d 100644 + " (whitelisted)"); + } + fwd += snprintf(buff + fwd, len - fwd, "\n"); -+ } -+ sysfs_close_class(class); ++ } ++ closedir(blkdir); + + if (fwd > len) + return len; @@ -3801,7 +6142,7 @@ diff --git a/libmultipath/print.h b/libmultipath/print.h index 3dde45d..73c2f63 100644 --- a/libmultipath/print.h +++ b/libmultipath/print.h -@@ -42,6 +42,9 @@ int snprint_multipath_topology (char *, +@@ -42,6 +42,9 @@ int snprint_multipath_topology (char *, int, struct multipath * mpp, int verbosity); int snprint_defaults (char *, int); int snprint_blacklist (char *, int); @@ -3832,7 +6173,7 @@ index 79cee8b..45a3728 100644 mp->alias, mp->rr_weight); return 0; } -@@ -68,7 +69,7 @@ select_pgfailback (struct multipath * mp +@@ -68,7 +69,7 @@ select_pgfailback (struct multipath * mp) } if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) { mp->pgfailback = mp->hwe->pgfailback; @@ -3921,7 +6262,7 @@ index 79cee8b..45a3728 100644 pp->dev, pp->getprio); return 0; } -@@ -276,7 +287,7 @@ select_no_path_retry(struct multipath *m +@@ -276,7 +287,7 @@ select_no_path_retry(struct multipath *mp) } if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) { mp->no_path_retry = mp->hwe->no_path_retry; @@ -4024,7 +6365,7 @@ index 024e790..d36eaef 100644 return mpp; } -@@ -178,6 +181,7 @@ free_multipath (struct multipath * mpp, +@@ -178,6 +181,7 @@ free_multipath (struct multipath * mpp, int free_paths) free_pathvec(mpp->paths, free_paths); free_pgvec(mpp->pg, free_paths); @@ -4032,7 +6373,7 @@ index 024e790..d36eaef 100644 FREE(mpp); } -@@ -365,3 +369,10 @@ pathcount (struct multipath * mpp, int s +@@ -365,3 +369,10 @@ pathcount (struct multipath * mpp, int state) return count; } @@ -4044,10 +6385,10 @@ index 024e790..d36eaef 100644 + return VECTOR_SLOT(pgp->paths, 0); +} diff --git a/libmultipath/structs.h b/libmultipath/structs.h -index 2b96cfb..46dcdee 100644 +index 2b96cfb..f821f87 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h -@@ -1,8 +1,8 @@ +@@ -1,14 +1,17 @@ #ifndef _STRUCTS_H #define _STRUCTS_H @@ -4058,7 +6399,16 @@ index 2b96cfb..46dcdee 100644 #define NODE_NAME_SIZE 19 #define PATH_STR_SIZE 16 #define PARAMS_SIZE 1024 -@@ -18,6 +18,9 @@ + #define FILE_NAME_SIZE 256 + #define CALLOUT_MAX_SIZE 128 + #define BLK_DEV_SIZE 33 ++#define PATH_SIZE 512 ++#define NAME_SIZE 128 ++ + + #define SCSI_VENDOR_SIZE 9 + #define SCSI_PRODUCT_SIZE 17 +@@ -18,6 +21,9 @@ #define NO_PATH_RETRY_FAIL -1 #define NO_PATH_RETRY_QUEUE -2 @@ -4068,7 +6418,15 @@ index 2b96cfb..46dcdee 100644 enum free_path_switch { KEEP_PATHS, FREE_PATHS -@@ -55,6 +58,11 @@ enum pgstates { +@@ -40,6 +46,7 @@ enum sysfs_buses { + SYSFS_BUS_SCSI, + SYSFS_BUS_IDE, + SYSFS_BUS_CCW, ++ SYSFS_BUS_CCISS, + }; + + enum pathstates { +@@ -55,6 +62,11 @@ enum pgstates { PGSTATE_ACTIVE }; @@ -4080,7 +6438,27 @@ index 2b96cfb..46dcdee 100644 struct scsi_idlun { int dev_id; int host_unique_id; -@@ -127,6 +135,7 @@ struct multipath { +@@ -78,9 +90,19 @@ struct scsi_dev { + int host_no; + }; + ++struct sysfs_device { ++ struct sysfs_device *parent; /* parent device */ ++ char devpath[PATH_SIZE]; ++ char subsystem[NAME_SIZE]; /* $class, $bus, drivers, module */ ++ char kernel[NAME_SIZE]; /* device instance name */ ++ char kernel_number[NAME_SIZE]; ++ char driver[NAME_SIZE]; /* device driver name */ ++}; ++ + struct path { + char dev[FILE_NAME_SIZE]; + char dev_t[BLK_DEV_SIZE]; ++ struct sysfs_device *sysdev; + struct scsi_idlun scsi_id; + struct sg_id sg_id; + char wwid[WWID_SIZE]; +@@ -127,6 +149,7 @@ struct multipath { int no_path_retry; /* number of retries after all paths are down */ int retry_tick; /* remaining times for retries */ int minio; @@ -4088,7 +6466,7 @@ index 2b96cfb..46dcdee 100644 unsigned long long size; vector paths; vector pg; -@@ -142,7 +151,7 @@ struct multipath { +@@ -142,7 +165,7 @@ struct multipath { struct mpentry * mpe; struct hwentry * hwe; @@ -4097,7 +6475,7 @@ index 2b96cfb..46dcdee 100644 void * waiter; /* stats */ -@@ -151,6 +160,9 @@ struct multipath { +@@ -151,6 +174,9 @@ struct multipath { unsigned int stat_map_loads; unsigned int stat_total_queueing_time; unsigned int stat_queueing_timeouts; @@ -4107,7 +6485,7 @@ index 2b96cfb..46dcdee 100644 }; struct pathgroup { -@@ -183,10 +195,11 @@ struct multipath * find_mp_by_minor (vec +@@ -183,10 +209,11 @@ struct multipath * find_mp_by_minor (vector mp, int minor); struct path * find_path_by_devt (vector pathvec, char * devt); struct path * find_path_by_dev (vector pathvec, char * dev); @@ -4116,23 +6494,27 @@ index 2b96cfb..46dcdee 100644 int pathcountgr (struct pathgroup *, int); int pathcount (struct multipath *, int); - char sysfs_path[FILE_NAME_SIZE]; +-char sysfs_path[FILE_NAME_SIZE]; ++extern char sysfs_path[PATH_SIZE]; -#endif +#endif /* _STRUCTS_H */ diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c -index 86bf2a5..53b7e17 100644 +index 86bf2a5..1cc6028 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c -@@ -14,6 +14,7 @@ +@@ -13,8 +13,9 @@ + #include "dmparser.h" #include "config.h" #include "propsel.h" ++#include "sysfs.h" #include "discovery.h" +- +#include "waiter.h" - /* -@@ -58,8 +59,8 @@ adopt_paths (vector pathvec, struct mult + * creates or updates mpp->paths reading mpp->pg +@@ -58,8 +59,8 @@ adopt_paths (vector pathvec, struct multipath * mpp) vector_foreach_slot (pathvec, pp, i) { if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) { @@ -4143,7 +6525,7 @@ index 86bf2a5..53b7e17 100644 pp->mpp = mpp; if (!mpp->paths && !(mpp->paths = vector_alloc())) -@@ -96,7 +97,7 @@ orphan_paths (vector pathvec, struct mul +@@ -96,7 +97,7 @@ orphan_paths (vector pathvec, struct multipath * mpp) vector_foreach_slot (pathvec, pp, i) { if (pp->mpp == mpp) { @@ -4152,7 +6534,43 @@ index 86bf2a5..53b7e17 100644 orphan_path(pp); } } -@@ -277,6 +278,7 @@ retry: +@@ -117,6 +118,8 @@ remove_map (struct multipath * mpp, struct vectors * vecs, + { + int i; + ++ condlog(4, "%s: remove multipath map", mpp->alias); ++ + /* + * stop the DM event waiter thread + */ +@@ -244,8 +247,17 @@ extern int + setup_multipath (struct vectors * vecs, struct multipath * mpp) + { + retry: +- if (dm_get_info(mpp->alias, &mpp->dmi)) ++ if (dm_get_info(mpp->alias, &mpp->dmi)) { ++ /* Error accessing table */ ++ condlog(3, "%s: cannot access table", mpp->alias); ++ goto out; ++ } ++ ++ if (!dm_map_present(mpp->alias)) { ++ /* Table has been removed */ ++ condlog(3, "%s: table does not exist", mpp->alias); + goto out; ++ } + + set_multipath_wwid(mpp); + mpp->mpe = find_mpe(mpp->wwid); +@@ -269,6 +281,7 @@ retry: + #endif + goto retry; + } ++ condlog(0, "%s: failed to setup multipath", mpp->alias); + goto out; + } + +@@ -277,10 +290,10 @@ retry: select_rr_weight(mpp); select_pgfailback(mpp); set_no_path_retry(mpp); @@ -4160,7 +6578,25 @@ index 86bf2a5..53b7e17 100644 return 0; out: -@@ -382,3 +384,90 @@ verify_paths(struct multipath * mpp, str +- condlog(0, "%s: failed to setup multipath", mpp->alias); + remove_map(mpp, vecs, NULL, 1); + return 1; + } +@@ -361,10 +374,10 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec) + /* + * see if path is in sysfs + */ +- if (!pp->dev || sysfs_get_dev(sysfs_path, +- pp->dev, pp->dev_t, BLK_DEV_SIZE)) { ++ if (!pp->sysdev || sysfs_get_dev(pp->sysdev, ++ pp->dev_t, BLK_DEV_SIZE)) { + condlog(0, "%s: failed to access path %s", mpp->alias, +- pp->dev ? pp->dev : pp->dev_t); ++ pp->sysdev ? pp->sysdev->devpath : pp->dev_t); + count++; + vector_del_slot(mpp->paths, i); + i--; +@@ -382,3 +395,88 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec) return count; } @@ -4170,18 +6606,19 @@ index 86bf2a5..53b7e17 100644 + struct pathgroup *pgp; + struct path *pp; + int i, j; -+ int r = 1; + + mpp = find_mp_by_alias(vecs->mpvec, mapname); + -+ if (!mpp) -+ goto out; ++ if (!mpp) { ++ condlog(3, "%s: multipath map not found\n", mapname); ++ return 2; ++ } + + free_pgvec(mpp->pg, KEEP_PATHS); + mpp->pg = NULL; + + if (setup_multipath(vecs, mpp)) -+ goto out; /* mpp freed in setup_multipath */ ++ return 1; /* mpp freed in setup_multipath */ + + /* + * compare checkers states with DM states @@ -4209,11 +6646,8 @@ index 86bf2a5..53b7e17 100644 + } + } + } -+ r = 0; -+out: -+ if (r) -+ condlog(0, "failed to update multipath"); -+ return r; ++ ++ return 0; +} + +/* @@ -4273,7 +6707,7 @@ index 348e9e5..81d9eaa 100644 typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *); typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *); -@@ -44,5 +33,8 @@ struct multipath * add_map_without_path +@@ -44,5 +33,8 @@ struct multipath * add_map_without_path (struct vectors * vecs, start_waiter_thread_func *start_waiter); struct multipath * add_map_with_path (struct vectors * vecs, struct path * pp, int add_vec); @@ -4282,21 +6716,639 @@ index 348e9e5..81d9eaa 100644 +void update_queue_mode_add_path(struct multipath *mpp); #endif /* _STRUCTS_VEC_H */ -diff --git a/libmultipath/switchgroup.c b/libmultipath/switchgroup.c -index 757543f..9b84bc2 100644 ---- a/libmultipath/switchgroup.c -+++ b/libmultipath/switchgroup.c -@@ -28,7 +28,7 @@ select_path_group (struct multipath * mp - priority = 0; +diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c +new file mode 100644 +index 0000000..b9621ac +--- /dev/null ++++ b/libmultipath/sysfs.c +@@ -0,0 +1,460 @@ ++/* ++ * Copyright (C) 2005-2006 Kay Sievers ++ * ++ * 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. ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "checkers.h" ++#include "vector.h" ++#include "structs.h" ++#include "sysfs.h" ++#include "list.h" ++#include "util.h" ++ ++char sysfs_path[PATH_SIZE]; ++ ++/* attribute value cache */ ++static LIST_HEAD(attr_list); ++struct sysfs_attr { ++ struct list_head node; ++ char path[PATH_SIZE]; ++ char *value; /* points to value_local if value is cached */ ++ char value_local[NAME_SIZE]; ++}; ++ ++/* list of sysfs devices */ ++static LIST_HEAD(sysfs_dev_list); ++struct sysfs_dev { ++ struct list_head node; ++ struct sysfs_device dev; ++}; ++ ++int sysfs_init(char *path, size_t len) ++{ ++ if (path) { ++ strlcpy(sysfs_path, path, len); ++ remove_trailing_chars(sysfs_path, '/'); ++ } else ++ strlcpy(sysfs_path, "/sys", len); ++ dbg("sysfs_path='%s'", sysfs_path); ++ ++ INIT_LIST_HEAD(&attr_list); ++ INIT_LIST_HEAD(&sysfs_dev_list); ++ return 0; ++} ++ ++void sysfs_cleanup(void) ++{ ++ struct sysfs_attr *attr_loop; ++ struct sysfs_attr *attr_temp; ++ ++ struct sysfs_dev *sysdev_loop; ++ struct sysfs_dev *sysdev_temp; ++ ++ list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) { ++ list_del(&attr_loop->node); ++ free(attr_loop); ++ } ++ ++ list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) { ++ free(sysdev_loop); ++ } ++} ++ ++void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, ++ const char *subsystem, const char *driver) ++{ ++ char *pos; ++ ++ strlcpy(dev->devpath, devpath, sizeof(dev->devpath)); ++ if (subsystem != NULL) ++ strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem)); ++ if (driver != NULL) ++ strlcpy(dev->driver, driver, sizeof(dev->driver)); ++ ++ /* set kernel name */ ++ pos = strrchr(dev->devpath, '/'); ++ if (pos == NULL) ++ return; ++ strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); ++ dbg("kernel='%s'", dev->kernel); ++ ++ /* some devices have '!' in their name, change that to '/' */ ++ pos = dev->kernel; ++ while (pos[0] != '\0') { ++ if (pos[0] == '!') ++ pos[0] = '/'; ++ pos++; ++ } ++ ++ /* get kernel number */ ++ pos = &dev->kernel[strlen(dev->kernel)]; ++ while (isdigit(pos[-1])) ++ pos--; ++ strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number)); ++ dbg("kernel_number='%s'", dev->kernel_number); ++} ++ ++int sysfs_resolve_link(char *devpath, size_t size) ++{ ++ char link_path[PATH_SIZE]; ++ char link_target[PATH_SIZE]; ++ int len; ++ int i; ++ int back; ++ ++ strlcpy(link_path, sysfs_path, sizeof(link_path)); ++ strlcat(link_path, devpath, sizeof(link_path)); ++ len = readlink(link_path, link_target, sizeof(link_target)); ++ if (len <= 0) ++ return -1; ++ link_target[len] = '\0'; ++ dbg("path link '%s' points to '%s'", devpath, link_target); ++ ++ for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) ++ ; ++ dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back); ++ for (i = 0; i <= back; i++) { ++ char *pos = strrchr(devpath, '/'); ++ ++ if (pos == NULL) ++ return -1; ++ pos[0] = '\0'; ++ } ++ dbg("after moving back '%s'", devpath); ++ strlcat(devpath, "/", size); ++ strlcat(devpath, &link_target[back * 3], size); ++ return 0; ++} ++ ++struct sysfs_device *sysfs_device_get(const char *devpath) ++{ ++ char path[PATH_SIZE]; ++ char devpath_real[PATH_SIZE]; ++ struct sysfs_device *dev = NULL; ++ struct sysfs_dev *sysdev_loop, *sysdev; ++ struct stat statbuf; ++ char link_path[PATH_SIZE]; ++ char link_target[PATH_SIZE]; ++ int len; ++ char *pos; ++ ++ dbg("open '%s'", devpath); ++ strlcpy(devpath_real, devpath, sizeof(devpath_real)); ++ remove_trailing_chars(devpath_real, '/'); ++ ++ /* if we got a link, resolve it to the real device */ ++ strlcpy(path, sysfs_path, sizeof(path)); ++ strlcat(path, devpath_real, sizeof(path)); ++ if (lstat(path, &statbuf) != 0) { ++ /* if stat fails look in the cache */ ++ 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); ++ 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; ++ } ++ } ++ if(!dev) { ++ /* it is a new device */ ++ dbg("new device '%s'", devpath_real); ++ sysdev = malloc(sizeof(struct sysfs_dev)); ++ if (sysdev == NULL) ++ return NULL; ++ memset(sysdev, 0x00, sizeof(struct sysfs_dev)); ++ list_add(&sysdev->node, &sysfs_dev_list); ++ dev = &sysdev->dev; ++ } ++ ++ sysfs_device_set_values(dev, devpath_real, NULL, NULL); ++ ++ /* get subsystem name */ ++ strlcpy(link_path, sysfs_path, sizeof(link_path)); ++ strlcat(link_path, dev->devpath, sizeof(link_path)); ++ strlcat(link_path, "/subsystem", sizeof(link_path)); ++ len = readlink(link_path, link_target, sizeof(link_target)); ++ if (len > 0) { ++ /* get subsystem from "subsystem" link */ ++ link_target[len] = '\0'; ++ dbg("subsystem 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 (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)); ++ } ++ ++ /* get driver name */ ++ strlcpy(link_path, sysfs_path, sizeof(link_path)); ++ strlcat(link_path, dev->devpath, sizeof(link_path)); ++ strlcat(link_path, "/driver", sizeof(link_path)); ++ len = readlink(link_path, link_target, sizeof(link_target)); ++ if (len > 0) { ++ link_target[len] = '\0'; ++ dbg("driver link '%s' points to '%s'", link_path, link_target); ++ pos = strrchr(link_target, '/'); ++ if (pos != NULL) ++ strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); ++ } ++ return dev; ++} ++ ++struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) ++{ ++ char parent_devpath[PATH_SIZE]; ++ char *pos; ++ ++ dbg("open '%s'", dev->devpath); ++ ++ /* look if we already know the parent */ ++ 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); ++ ++ /* strip last element */ ++ pos = strrchr(parent_devpath, '/'); ++ if (pos == NULL || pos == parent_devpath) ++ 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) { ++ dbg("/class top level, look for device link"); ++ goto device_link; ++ } ++ } ++ if (strcmp(parent_devpath, "/block") == 0) { ++ dbg("/block top level, look for device link"); ++ goto device_link; ++ } ++ ++ /* get parent and remember it */ ++ dev->parent = sysfs_device_get(parent_devpath); ++ return dev->parent; ++ ++device_link: ++ strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); ++ strlcat(parent_devpath, "/device", sizeof(parent_devpath)); ++ if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0) ++ return NULL; ++ ++ /* get parent and remember it */ ++ dev->parent = sysfs_device_get(parent_devpath); ++ return dev->parent; ++} ++ ++struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem) ++{ ++ struct sysfs_device *dev_parent; ++ ++ dev_parent = sysfs_device_get_parent(dev); ++ while (dev_parent != NULL) { ++ if (strcmp(dev_parent->subsystem, subsystem) == 0) ++ return dev_parent; ++ dev_parent = sysfs_device_get_parent(dev_parent); ++ } ++ return NULL; ++} ++ ++void sysfs_device_put(struct sysfs_device *dev) ++{ ++ struct sysfs_dev *sysdev_loop; ++ ++ list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { ++ if (&sysdev_loop->dev == dev) { ++ dbg("removed dev '%s' from cache", ++ sysdev_loop->dev.devpath); ++ list_del(&sysdev_loop->node); ++ free(sysdev_loop); ++ return; ++ } ++ } ++ dbg("dev '%s' not found in cache", ++ sysdev_loop->dev.devpath); ++ ++ return; ++} ++ ++char *sysfs_attr_get_value(const char *devpath, const char *attr_name) ++{ ++ char path_full[PATH_SIZE]; ++ const char *path; ++ char value[NAME_SIZE]; ++ struct sysfs_attr *attr_loop; ++ struct sysfs_attr *attr = NULL; ++ struct stat statbuf; ++ int fd; ++ ssize_t size; ++ size_t sysfs_len; ++ ++ dbg("open '%s'/'%s'", devpath, attr_name); ++ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); ++ path = &path_full[sysfs_len]; ++ strlcat(path_full, devpath, sizeof(path_full)); ++ strlcat(path_full, "/", sizeof(path_full)); ++ strlcat(path_full, attr_name, sizeof(path_full)); ++ ++ /* look for attribute in cache */ ++ list_for_each_entry(attr_loop, &attr_list, node) { ++ if (strcmp(attr_loop->path, path) == 0) { ++ dbg("found in cache '%s'", attr_loop->path); ++ attr = attr_loop; ++ } ++ } ++ if (!attr) { ++ /* store attribute in cache */ ++ dbg("new uncached attribute '%s'", path_full); ++ attr = malloc(sizeof(struct sysfs_attr)); ++ if (attr == NULL) ++ return NULL; ++ memset(attr, 0x00, sizeof(struct sysfs_attr)); ++ strlcpy(attr->path, path, sizeof(attr->path)); ++ dbg("add to cache '%s'", path_full); ++ list_add(&attr->node, &attr_list); ++ } else { ++ /* clear old value */ ++ if(attr->value) ++ memset(attr->value, 0x00, sizeof(attr->value)); ++ } ++ ++ if (lstat(path_full, &statbuf) != 0) { ++ dbg("stat '%s' failed: %s", path_full, strerror(errno)); ++ goto out; ++ } ++ ++ if (S_ISLNK(statbuf.st_mode)) { ++ /* links return the last element of the target path */ ++ char link_target[PATH_SIZE]; ++ int len; ++ const char *pos; ++ ++ len = readlink(path_full, link_target, sizeof(link_target)); ++ if (len > 0) { ++ 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)); ++ attr->value = attr->value_local; ++ } ++ } ++ goto out; ++ } ++ ++ /* skip directories */ ++ if (S_ISDIR(statbuf.st_mode)) ++ goto out; ++ ++ /* skip non-readable files */ ++ if ((statbuf.st_mode & S_IRUSR) == 0) ++ goto out; ++ ++ /* read attribute value */ ++ fd = open(path_full, O_RDONLY); ++ if (fd < 0) { ++ dbg("attribute '%s' does not exist", path_full); ++ goto out; ++ } ++ size = read(fd, value, sizeof(value)); ++ close(fd); ++ if (size < 0) ++ goto out; ++ if (size == sizeof(value)) ++ goto out; ++ ++ /* got a valid value, store and return it */ ++ value[size] = '\0'; ++ remove_trailing_chars(value, '\n'); ++ dbg("cache '%s' with attribute value '%s'", path_full, value); ++ strlcpy(attr->value_local, value, sizeof(attr->value_local)); ++ attr->value = attr->value_local; ++ ++out: ++ return attr->value; ++} +diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h +new file mode 100644 +index 0000000..e7fa3e7 +--- /dev/null ++++ b/libmultipath/sysfs.h +@@ -0,0 +1,25 @@ ++/* ++ * sysfs.h ++ */ ++ ++#ifndef _LIBMULTIPATH_SYSFS_H ++#define _LIBMULTIPATH_SYSFS_H ++ ++#ifdef DEBUG ++# define dbg(format, args...) printf(format "\n", ##args) ++#else ++# define dbg(format, args...) do {} while (0) ++#endif ++ ++int sysfs_init(char *path, size_t len); ++void sysfs_cleanup(void); ++void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, ++ const char *subsystem, const char *driver); ++struct sysfs_device *sysfs_device_get(const char *devpath); ++struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); ++struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem); ++void sysfs_device_put(struct sysfs_device *dev); ++char *sysfs_attr_get_value(const char *devpath, const char *attr_name); ++int sysfs_resolve_link(char *path, size_t size); ++ ++#endif +diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c +index 6482698..a4028d8 100644 +--- a/libmultipath/uevent.c ++++ b/libmultipath/uevent.c +@@ -26,12 +26,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include +-#include ++#include ++#include + #include + #include + #include +@@ -105,6 +107,8 @@ int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data), + { + int sock; + struct sockaddr_nl snl; ++ struct sockaddr_un sun; ++ socklen_t addrlen; + int retval; + int rcvbufsz = 128*1024; + int rcvsz = 0; +@@ -131,43 +135,72 @@ int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data), + pthread_attr_setstacksize(&attr, 64 * 1024); + pthread_create(&uevq_thr, &attr, uevq_thread, NULL); - vector_foreach_slot (pgp->paths, pp, j) { -- if (pp->state != PATH_DOWN) -+ if (pp->state == PATH_UP) - priority += pp->priority; - } - pgp->priority = priority; +- memset(&snl, 0x00, sizeof(struct sockaddr_nl)); +- snl.nl_family = AF_NETLINK; +- snl.nl_pid = getpid(); +- snl.nl_groups = 0xffffffff; +- +- sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); +- if (sock == -1) { +- condlog(0, "error getting socket, exit"); +- return 1; +- } +- + /* +- * try to avoid dropping uevents, even so, this is not a guarantee, +- * but it does help to change the netlink uevent socket's +- * receive buffer threshold from the default value of 106,496 to +- * the maximum value of 262,142. ++ * First check whether we have a udev socket + */ +- retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, +- sizeof(rcvbufsz)); ++ memset(&sun, 0x00, sizeof(struct sockaddr_un)); ++ sun.sun_family = AF_LOCAL; ++ strcpy(&sun.sun_path[1], "/org/kernel/dm/multipath_event"); ++ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path+1) + 1; ++ ++ sock = socket(AF_LOCAL, SOCK_DGRAM, 0); ++ if (sock >= 0) { ++ const int feature_on = 1; ++ ++ condlog(3, "reading events from udev socket."); ++ ++ /* the bind takes care of ensuring only one copy running */ ++ retval = bind(sock, (struct sockaddr *) &sun, addrlen); ++ if (retval < 0) { ++ condlog(0, "bind failed, exit"); ++ goto exit; ++ } + +- if (retval < 0) { +- condlog(0, "error setting receive buffer size for socket, exit"); +- exit(1); +- } +- retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); ++ /* enable receiving of the sender credentials */ ++ setsockopt(sock, SOL_SOCKET, SO_PASSCRED, ++ &feature_on, sizeof(feature_on)); ++ ++ } else { ++ /* Fallback to read kernel netlink events */ ++ memset(&snl, 0x00, sizeof(struct sockaddr_nl)); ++ snl.nl_family = AF_NETLINK; ++ snl.nl_pid = getpid(); ++ snl.nl_groups = 0xffffffff; ++ ++ sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); ++ if (sock == -1) { ++ condlog(0, "error getting socket, exit"); ++ return 1; ++ } + +- if (retval < 0) { +- condlog(0, "error setting receive buffer size for socket, exit"); +- exit(1); +- } +- condlog(3, "receive buffer size for socket is %u.", rcvsz); ++ condlog(3, "reading events from kernel."); + +- retval = bind(sock, (struct sockaddr *) &snl, +- sizeof(struct sockaddr_nl)); +- if (retval < 0) { +- condlog(0, "bind failed, exit"); +- goto exit; ++ /* ++ * try to avoid dropping uevents, even so, this is not a guarantee, ++ * but it does help to change the netlink uevent socket's ++ * receive buffer threshold from the default value of 106,496 to ++ * the maximum value of 262,142. ++ */ ++ retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, ++ sizeof(rcvbufsz)); ++ ++ if (retval < 0) { ++ condlog(0, "error setting receive buffer size for socket, exit"); ++ exit(1); ++ } ++ retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); ++ if (retval < 0) { ++ condlog(0, "error setting receive buffer size for socket, exit"); ++ exit(1); ++ } ++ condlog(3, "receive buffer size for socket is %u.", rcvsz); ++ ++ retval = bind(sock, (struct sockaddr *) &snl, ++ sizeof(struct sockaddr_nl)); ++ if (retval < 0) { ++ condlog(0, "bind failed, exit"); ++ goto exit; ++ } + } + + while (1) { diff --git a/libmultipath/util.c b/libmultipath/util.c -index 376ca04..911ec55 100644 +index 376ca04..eaf2266 100644 --- a/libmultipath/util.c +++ b/libmultipath/util.c @@ -30,6 +30,15 @@ strcmp_chomp(char *str1, char *str2) @@ -4315,11 +7367,67 @@ index 376ca04..911ec55 100644 basename (char * str1, char * str2) { char *p = str1 + (strlen(str1) - 1); +@@ -94,3 +103,55 @@ get_word (char * sentence, char ** word) + return skip + len; + } + ++size_t strlcpy(char *dst, const char *src, size_t size) ++{ ++ size_t bytes = 0; ++ char *q = dst; ++ const char *p = src; ++ char ch; ++ ++ while ((ch = *p++)) { ++ if (bytes+1 < size) ++ *q++ = ch; ++ bytes++; ++ } ++ ++ /* If size == 0 there is no space for a final null... */ ++ if (size) ++ *q = '\0'; ++ return bytes; ++} ++ ++size_t strlcat(char *dst, const char *src, size_t size) ++{ ++ size_t bytes = 0; ++ char *q = dst; ++ const char *p = src; ++ char ch; ++ ++ while (bytes < size && *q) { ++ q++; ++ bytes++; ++ } ++ if (bytes == size) ++ return (bytes + strlen(src)); ++ ++ while ((ch = *p++)) { ++ if (bytes+1 < size) ++ *q++ = ch; ++ bytes++; ++ } ++ ++ *q = '\0'; ++ return bytes; ++} ++ ++void remove_trailing_chars(char *path, char c) ++{ ++ size_t len; ++ ++ len = strlen(path); ++ while (len > 0 && path[len-1] == c) ++ path[--len] = '\0'; ++} ++ diff --git a/libmultipath/util.h b/libmultipath/util.h -index 51f052a..e86bae2 100644 +index 51f052a..d0df8aa 100644 --- a/libmultipath/util.h +++ b/libmultipath/util.h -@@ -2,6 +2,7 @@ +@@ -2,10 +2,13 @@ #define _UTIL_H int strcmp_chomp(char *, char *); @@ -4327,6 +7435,26 @@ index 51f052a..e86bae2 100644 void basename (char * src, char * dst); int filepresent (char * run); int get_word (char * sentence, char ** word); +- ++size_t strlcpy(char *dst, const char *src, size_t size); ++size_t strlcat(char *dst, const char *src, size_t size); ++void remove_trailing_chars(char *path, char c); + + #define safe_sprintf(var, format, args...) \ + snprintf(var, sizeof(var), format, ##args) >= sizeof(var) +diff --git a/libmultipath/vector.h b/libmultipath/vector.h +index 294f0b1..993ba79 100644 +--- a/libmultipath/vector.h ++++ b/libmultipath/vector.h +@@ -37,6 +37,8 @@ typedef struct _vector *vector; + + #define vector_foreach_slot(v,p,i) \ + for (i = 0; i < (v)->allocated && ((p) = (v)->slot[i]); i++) ++#define vector_foreach_slot_after(v,p,i) \ ++ for (; i < (v)->allocated && ((p) = (v)->slot[i]); i++) + + /* Prototypes */ + extern vector vector_alloc(void); diff --git a/libmultipath/version.h b/libmultipath/version.h new file mode 100644 index 0000000..d577ec9 @@ -4372,10 +7500,10 @@ index 0000000..d577ec9 +#endif /* _VERSION_H */ diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c new file mode 100644 -index 0000000..75ed90c +index 0000000..d7af0d1 --- /dev/null +++ b/libmultipath/waiter.c -@@ -0,0 +1,234 @@ +@@ -0,0 +1,233 @@ +/* + * Copyright (c) 2004, 2005 Christophe Varoqui + * Copyright (c) 2005 Kiyoshi Ueda, NEC @@ -4495,15 +7623,11 @@ index 0000000..75ed90c + /* accept wait interruption */ + set = unblock_signals(); + -+ /* interruption spits messages */ -+ dm_shut_log(); -+ + /* wait */ + r = dm_task_run(waiter->dmt); + + /* wait is over : event or interrupt */ + pthread_sigmask(SIG_SETMASK, &set, NULL); -+ //dm_restore_log(); + + if (!r) /* wait interrupted by signal */ + return -1; @@ -4535,8 +7659,11 @@ index 0000000..75ed90c + r = update_multipath(waiter->vecs, waiter->mapname); + lock_cleanup_pop(waiter->vecs->lock); + -+ if (r) ++ if (r) { ++ condlog(2, "%s: event checker exit", ++ waiter->mapname); + return -1; /* stop the thread */ ++ } + + event_nr = dm_geteventnr(waiter->mapname); + @@ -4640,21 +7767,56 @@ index 0000000..0223924 +#endif /* DAEMON */ +#endif /* _WAITER_H */ diff --git a/multipath-tools.spec.in b/multipath-tools.spec.in -index 494f09e..9d6a7ea 100644 +index 494f09e..3caede6 100644 --- a/multipath-tools.spec.in +++ b/multipath-tools.spec.in -@@ -50,6 +50,7 @@ rm -rf $RPM_BUILD_ROOT +@@ -49,7 +49,8 @@ rm -rf $RPM_BUILD_ROOT + %{prefix}/sbin/mpath_prio_random %{prefix}/sbin/mpath_prio_balance_units %{prefix}/sbin/mpath_prio_netapp - %{prefix}/sbin/mpath_prio_tpc +-%{prefix}/sbin/mpath_prio_tpc ++%{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 diff --git a/multipath.conf.annotated b/multipath.conf.annotated -index a1f04b7..649ff8c 100644 +index a1f04b7..e6cfe9a 100644 --- a/multipath.conf.annotated +++ b/multipath.conf.annotated +@@ -11,7 +11,7 @@ + # # + # # name : udev_dir + # # desc : directory where udev creates its device nodes +-# # default : /udev ++# # default : /dev + # # + # udev_dir /dev + # +@@ -47,9 +47,9 @@ + # # scope : multipath + # # desc : the default program and args to callout to obtain a unique + # # path identifier. Absolute path required +-# # default : /sbin/scsi_id -g -u -s ++# # default : /lib/udev/scsi_id -g -u -s + # # +-# getuid_callout "/sbin/scsi_id -g -u -s /block/%n" ++# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n" + # + # # + # # name : prio_callout +@@ -66,9 +66,9 @@ + # # scope : multipath & multipathd + # # desc : the default method used to determine the paths' state + # # values : readsector0|tur|emc_clariion|hp_sw|directio +-# # default : readsector0 ++# # default : directio + # # +-# #path_checker readsector0 ++# #path_checker directio + # + # # + # # name : rr_min_io @@ -142,6 +142,22 @@ # product MSA[15]00 # } @@ -4678,6 +7840,20 @@ index a1f04b7..649ff8c 100644 # ## ## name : multipaths +@@ -182,10 +198,10 @@ + # # name : path_checker + # # scope : multipathd + # # desc : path checking alorithm to use to check path state +-# # values : readsector0, tur +-# # default : readsector0 ++# # values : readsector0|tur|emc_clariion|hp_sw|directio ++# # default : directio + # # +-# # path_checker readsector0 ++# # path_checker directio + # + # # + # # name : path_selector @@ -237,7 +253,7 @@ ## ## name : devices @@ -4705,11 +7881,48 @@ index a1f04b7..649ff8c 100644 # # values : failover = 1 path per priority group # # multibus = all valid paths in 1 priority # # group +@@ -275,9 +291,9 @@ + # # scope : multipath + # # desc : the program and args to callout to obtain a unique + # # path identifier. Absolute path required +-# # default : /sbin/scsi_id -g -u -s ++# # default : /lib/udev/scsi_id -g -u -s + # # +-# getuid_callout "/sbin/scsi_id -g -u -s /block/%n" ++# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n" + # + # # + # # name : prio_callout +@@ -294,10 +310,10 @@ + # # name : path_checker + # # scope : multipathd + # # desc : path checking alorithm to use to check path state +-# # values : readsector0, tur +-# # default : readsector0 ++# # values : readsector0|tur|emc_clariion|hp_sw|directio ++# # default : directio + # # +-# path_checker readsector0 ++# path_checker directio + # + # # + # # name : path_selector diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic -index 4a1f5a4..e5e6cd0 100644 +index 4a1f5a4..633d625 100644 --- a/multipath.conf.synthetic +++ b/multipath.conf.synthetic -@@ -16,7 +16,7 @@ +@@ -7,16 +7,16 @@ + # polling_interval 10 + # selector "round-robin 0" + # path_grouping_policy multibus +-# getuid_callout "/sbin/scsi_id -g -u -s /block/%n" ++# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n" + # prio_callout /bin/true +-# path_checker readsector0 ++# path_checker directio + # rr_min_io 100 + # rr_weight priorities + # failback immediate # no_path_retry fail # user_friendly_names no #} @@ -4718,7 +7931,7 @@ index 4a1f5a4..e5e6cd0 100644 # wwid 26353900f02796769 # devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" # devnode "^hd[a-z][[0-9]*]" -@@ -26,6 +26,10 @@ +@@ -26,12 +26,16 @@ # product MSA[15]00 # } #} @@ -4729,10 +7942,118 @@ index 4a1f5a4..e5e6cd0 100644 #multipaths { # multipath { # wwid 3600508b4000156d700012000000b0000 + # alias yellow + # path_grouping_policy multibus +-# path_checker readsector0 ++# path_checker directio + # path_selector "round-robin 0" + # failback manual + # rr_weight priorities +@@ -48,8 +52,8 @@ + # vendor "COMPAQ " + # product "HSV110 (C)COMPAQ" + # path_grouping_policy multibus +-# getuid_callout "/sbin/scsi_id -g -u -s /block/%n" +-# path_checker readsector0 ++# getuid_callout "/lib/udev/scsi_id -g -u -s /block/%n" ++# path_checker directio + # path_selector "round-robin 0" + # hardware_handler "0" + # failback 15 +diff --git a/multipath/02_multipath b/multipath/02_multipath +index 1a5d5a1..067c582 100755 +--- a/multipath/02_multipath ++++ b/multipath/02_multipath +@@ -12,10 +12,10 @@ cp /sbin/kpartx $INITRDDIR/sbin + # feed the dependencies too + # scsi_id is dynamicaly linked, so store the libs too + # +-cp /sbin/scsi_id $INITRDDIR/sbin ++cp /lib/udev/scsi_id $INITRDDIR/lib/udev/ + cp /bin/mountpoint $INITRDDIR/bin + +-PROGS="/sbin/scsi_id /bin/mountpoint" ++PROGS="/lib/udev/scsi_id /bin/mountpoint" + LIBS=`ldd $PROGS | grep -v linux-gate.so | sort -u | \ + awk '{print $3}'` + for i in $LIBS +diff --git a/multipath/Makefile b/multipath/Makefile +index 646dfc2..4923b2f 100644 +--- a/multipath/Makefile ++++ b/multipath/Makefile +@@ -8,11 +8,12 @@ include ../Makefile.inc + OBJS = main.o $(MULTIPATHLIB)-$(BUILD).a $(CHECKERSLIB)-$(BUILD).a + + CFLAGS += -I$(multipathdir) -I$(checkersdir) ++LDFLAGS += -laio + + ifeq ($(strip $(BUILD)),klibc) +- OBJS += $(libdm) $(libsysfs) ++ OBJS += $(libdm) + else +- LDFLAGS += -ldevmapper -lsysfs ++ LDFLAGS += -ldevmapper + endif + + EXEC = multipath +@@ -22,14 +23,14 @@ all: $(BUILD) + prepare: + make -C $(multipathdir) prepare + rm -f core *.o *.gz ++ $(GZIP) $(EXEC).8 > $(EXEC).8.gz ++ $(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz + + glibc: prepare $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + klibc: prepare $(OBJS) + $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz + + $(CHECKERSLIB)-$(BUILD).a: + make -C $(checkersdir) BUILD=$(BUILD) $(BUILD) +@@ -39,16 +40,19 @@ $(MULTIPATHLIB)-$(BUILD).a: + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(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) + + uninstall: + rm $(DESTDIR)/etc/udev/rules.d/multipath.rules + rm $(DESTDIR)$(bindir)/$(EXEC) + rm $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz + + clean: + rm -f core *.o $(EXEC) *.gz diff --git a/multipath/main.c b/multipath/main.c -index 98f7207..67076db 100644 +index 98f7207..815c307 100644 --- a/multipath/main.c +++ b/multipath/main.c +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -37,6 +36,7 @@ + #include + #include + #include ++#include + #include + #include + #include @@ -46,8 +46,7 @@ #include #include @@ -4824,7 +8145,7 @@ index 98f7207..67076db 100644 /* * core logic entry point -@@ -305,14 +313,14 @@ main (int argc, char *argv[]) +@@ -305,24 +313,24 @@ main (int argc, char *argv[]) int arg; extern char *optarg; extern int optind; @@ -4840,12 +8161,18 @@ index 98f7207..67076db 100644 + if (dm_prereq(DEFAULT_TARGET)) exit(1); - if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { -@@ -322,7 +330,7 @@ main (int argc, char *argv[]) +- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { +- condlog(0, "multipath tools need sysfs mounted"); +- exit(1); +- } if (load_config(DEFAULT_CONFIGFILE)) exit(1); - while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) { ++ 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 ) { switch(arg) { case 1: printf("optarg : %s\n",optarg); @@ -4859,6 +8186,22 @@ index 98f7207..67076db 100644 case ':': fprintf(stderr, "Missing option arguement\n"); usage(argv[0]); +@@ -391,6 +401,7 @@ main (int argc, char *argv[]) + conf->dev_type = DEV_DEVMAP; + + } ++ dm_init(); + + if (conf->remove == FLUSH_ONE) { + if (conf->dev_type == DEV_DEVMAP) +@@ -408,6 +419,7 @@ main (int argc, char *argv[]) + condlog(3, "restart multipath configuration process"); + + out: ++ sysfs_cleanup(); + free_config(conf); + dm_lib_release(); + dm_lib_exit(); diff --git a/multipath/main.h b/multipath/main.h deleted file mode 100644 index 8d5b285..0000000 @@ -4914,7 +8257,7 @@ index 7133598..693872b 100644 .SH NAME multipath \- Device mapper target autoconfig .SH SYNOPSIS -@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco +@@ -6,7 +6,7 @@ multipath \- Device mapper target autoconfig .RB [\| \-v\ \c .IR verbosity \|] .RB [\| \-d \|] @@ -4923,7 +8266,7 @@ index 7133598..693872b 100644 .RB [\| \-p\ \c .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] .RB [\| device \|] -@@ -29,6 +29,9 @@ print the created or updated multipath n +@@ -29,6 +29,9 @@ print the created or updated multipath names only, for use to feed other tools l print all info : detected paths, coalesced paths (ie multipaths) and device maps .RE .TP @@ -4933,7 +8276,7 @@ index 7133598..693872b 100644 .B \-d dry run, do not create or update devmaps .TP -@@ -38,12 +41,6 @@ show the current multipath topology from +@@ -38,12 +41,6 @@ show the current multipath topology from information fetched in sysfs and the de .B \-ll show the current multipath topology from all available information (sysfs, the device mapper, path checkers ...) .TP @@ -4955,6 +8298,445 @@ index 7133598..693872b 100644 .TP .B group_by_node_name 1 priority group per target node name. Target node names are fetched in /sys/class/fc_transport/target*/node_name. +diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 +new file mode 100644 +index 0000000..c8ab6b0 +--- /dev/null ++++ b/multipath/multipath.conf.5 +@@ -0,0 +1,384 @@ ++.TH MULTIPATH.CONF 5 "30 November 2006" ++.SH NAME ++multipath.conf \- multipath daemon configuration file ++.SH DESCRIPTION ++.B "multipath.conf" ++is the configuration file for the multipath daemon. It is used to ++overwrite the built-in configuration table of \fBmultipathd\fP. ++Any line whose first non-white-space character is a '#' is considered ++a comment line. Empty lines are ignored. ++.SH SYNTAX ++The configuration file contains entries of the form: ++.RS ++.nf ++.ft B ++.sp ++
{ ++.RS ++.ft B ++ ++.I "..." ++.ft B ++ { ++.RS ++.ft B ++ ++.I "..." ++.RE ++} ++.RE ++} ++.ft R ++.fi ++.RE ++.LP ++Each \fIsection\fP contains one or more attributes or subsections. The ++recognized keywords for attributes or subsections depend on the ++section in which they occor. ++.LP ++The following \fIsection\fP keywords are recognized: ++.TP 17 ++.B defaults ++This section defines default values for attributes which are used ++whenever no specific setting is given. ++.TP ++.B blacklist ++This section defines which devices should be excluded from the ++multipath topology discovery. ++.TP ++.B blacklist_exceptions ++This section defines which devices should be included in the ++multipath topology discovery, despite being listed in the ++.I blacklist ++section. ++.TP ++.B multipaths ++This section defines the multipath topologies. They are indexed by a ++\fIWorld Wide Identifier\fR(wwid), which is the result of the ++\fIgetuid_callout\fR program. ++.TP ++.B devices ++This section defines the device-specific settings. ++.RE ++.LP ++.SH "defaults section" ++The ++.B defaults ++section recognizes the following keywords: ++.TP 17 ++.B polling_interval ++interval between two path checks in seconds; default is ++.I 5 ++.TP ++.B udev_dir ++directory where udev creates its device nodes; default is ++.I /dev ++.TP ++.B selector ++The default path selector algorithm to use; they are offered by the ++kernel multipath target. The only currently implemented is ++.I "round-robin 0" ++.TP ++.B path_grouping_policy ++The default path grouping policy to apply to unspecified ++multipaths. Possible values are ++.RS ++.TP 12 ++.B failover ++1 path per priority group ++.TP ++.B multibus ++all paths in 1 priority group ++.TP ++.B group_by_serial ++1 priority group per serial number ++.TP ++.B group_by_prio ++1 priority group per priority value. Priorities are determined by ++callout programs specified as a global, per-controller or ++per-multipath option in the configuration file. ++.TP ++.B group_by_node_name ++1 priority group per target node name. Target node names are fetched ++in /sys/class/fc_transport/target*/node_name. ++.TP ++Default value is \fImultibus\fR. ++.RE ++.TP ++.B getuid_callout ++The default program and args to callout to obtain a unique path ++identifier. Should be specified with an absolute path. Default value ++is ++.I /lib/udev/scsi_id -g -u -s ++.TP ++.B prio_callout ++The default program and args to callout to obtain a path priority ++value. The specified program will be executed and should return a ++numeric value specifying the relative priority of this path. Higher ++number have a higher priority. A '%n' in the command line will be expanded ++to the device name, a '%b' will be expanded to the device number in ++.I major:minor ++format. ++.I "none" ++is a valid value. Currently the following path priority programs are ++implemented: ++.RS ++.TP 12 ++.B mpath_prio_emc /dev/%n ++Generate the path priority for EMC arrays ++.TP ++.B mpath_prio_alua /dev/%n ++Generate the path priority based on the SCSI-3 ALUA settings. ++.TP ++.B mpath_prio_netapp /dev/%n ++Generate the path priority for NetApp arrays. ++.TP ++.B mpath_prio_rdac /dev/%n ++Generate the path priority for LSI/Engenio RDAC controller. ++.TP ++.B mpath_prio_hp_sw /dev/%n ++Generate the path priority for Compaq/HP controller in ++active/standby mode. ++.TP ++.B mpath_prio_hds_modular %b ++Generate the path priority for Hitachi HDS Modular storage arrays. ++.TP ++Default value is \fBnone\fR. ++.RE ++.TP ++.B features ++Specify any device-mapper features to be used. The most common of ++these features is ++.I "1 queue_if_no_path" ++Note that this can also be set via the ++.I no_path_retry ++keyword. ++.TP ++.B path_checker ++The default method used to determine the paths' state. Possible values ++are ++.RS ++.TP 12 ++.B readsector0 ++Read the first sector of the device ++.TP ++.B tur ++Issue a ++.I TEST UNIT READY ++command to the device. ++.TP ++.B emc_clariion ++Query the EMC Clariion specific EVPD page 0xC0 to determine the path ++state. ++.TP ++.B hp_sw ++Check the path state for HP storage arrays with Active/Standby firmware. ++.TP ++.B rdac ++Check the path state for LSI/Engenio RDAC storage controller. ++.TP ++.B directio ++Read the first sector with direct I/O. ++.TP ++Default value is \fIreadsector0\fR. ++.RE ++.TP ++.B failback ++Tell the daemon to manage path group failback, or not to. 0 or ++.I immediate ++means immediate failback, values >0 means deferred failback (in ++seconds). ++.I manual ++means no failback. Default value is ++.I manual ++.TP ++.B rr_min_io ++The number of IO to route to a path before switching to the next in ++the same path group. Default is ++.I 1000 ++.TP ++.B rr_weight ++If set to \fIpriorities\fR the multipath configurator will assign ++path weights as "path prio * rr_min_io". Possible values are ++.I priorities ++or ++.I uniform ++. Default is ++.I uniform ++.TP ++.B no_path_retry ++Specify the number of retries until disable queueing, or ++.I fail ++for immediate failure (no queueing), ++.I queue ++for never stop queueing. Default is 0. ++.TP ++.B user_friendly_names ++If set to ++.I yes ++, using the bindings file ++.I /var/lib/multipath/bindings ++to assign a persistent and unique alias to the multipath, in the form of mpath. ++If set to ++.I no ++use the WWID as the alias. In either case this be will ++be overriden by any specific aliases in the \fImultipaths\fR section. ++Default is ++.I no ++. ++.SH "blacklist section" ++The ++.I blacklist ++section is used to exclude specific device from inclusion in the ++multipath topology. It is most commonly used to exclude local disks or ++LUNs for the array controller. ++.LP ++The following keywords are recognized: ++.TP 17 ++.B wwid ++The \fIWorld Wide Identification\fR of a device. ++.TP ++.B devnode ++Regular expression of the device nodes to be excluded. ++.TP ++.B device ++Subsection for the device description. This subsection recognizes the ++.I vendor ++and ++.I product ++keywords. For a full description of these keywords please see the ++.I devices ++section description. ++.SH "blacklist_exceptions section" ++The ++.I blacklist_exceptions ++section is used to revert the actions of the ++.I blacklist ++section, ie to include specific device in the ++multipath topology. This allows to selectively include devices which ++would normally be excluded via the ++.I blacklist ++section. ++.LP ++The following keywords are recognized: ++.TP 17 ++.B wwid ++The \fIWorld Wide Identification\fR of a device. ++.TP ++.B devnode ++Regular expression of the device nodes to be excluded. ++.TP ++.B device ++Subsection for the device description. This subsection recognizes the ++.I vendor ++and ++.I product ++keywords. For a full description of these keywords please see the ++.I devices ++section description. ++.SH "multipaths section" ++The only recognized attribute for the ++.B multipaths ++section is the ++.I multipath ++subsection. ++.LP ++The ++.B multipath ++subsection recognizes the following attributes: ++.TP 17 ++.B wwid ++Index of the container. Mandatory for this subsection. ++.TP ++.B alias ++(Optional) symbolic name for the multipath map. ++.LP ++The following attributes are optional; if not set the default values ++are taken from the ++.I defaults ++section: ++.sp 1 ++.PD .1v ++.RS ++.TP 18 ++.B path_grouping_policy ++.TP ++.B path_checker ++.TP ++.B path_selector ++.TP ++.B failback ++.TP ++.B no_path_retry ++.TP ++.B rr_min_io ++.RE ++.PD ++.LP ++.SH "devices section" ++The only recognized attribute for the ++.B devices ++section is the ++.I device ++subsection. ++.LP ++The ++.I device ++subsection recognizes the following attributes: ++.TP 17 ++.B vendor ++(Mandatory) Vendor identifier ++.TP ++.B product ++(Mandatory) Product identifier ++.TP ++.B product_blacklist ++Product strings to blacklist for this vendor ++.TP ++.B hardware_handler ++(Optional) The hardware handler to use for this device type. ++The following hardware handler are implemented: ++.RS ++.TP 12 ++.B 1 emc ++Hardware handler for EMC storage arrays. ++.RE ++.LP ++The following attributes are optional; if not set the default values ++are taken from the ++.I defaults ++section: ++.sp 1 ++.PD .1v ++.RS ++.TP 18 ++.B path_grouping_policy ++.TP ++.B getuid_callout ++.TP ++.B path_selector ++.TP ++.B path_checker ++.TP ++.B features ++.TP ++.B prio_callout ++.TP ++.B failback ++.TP ++.B rr_weight ++.TP ++.B no_path_retry ++.TP ++.B rr_min_io ++.RE ++.PD ++.LP ++.SH "SEE ALSO" ++.BR udev (8), ++.BR dmsetup (8) ++.BR multipath (8) ++.BR multipathd (8) ++.SH AUTHORS ++.B multipath ++was developed by Christophe Varoqui, and others. +diff --git a/multipath/multipath.rules b/multipath/multipath.rules +index 10751ce..9d3579f 100644 +--- a/multipath/multipath.rules ++++ b/multipath/multipath.rules +@@ -1,18 +1,7 @@ + # +-# multipath and multipath partitions nodes are created in /dev/mapper/ +-# this file should be installed in /etc/udev/rules.d ++# udev rules for multipathing. ++# The persistent symlinks are created with the kpartx rules + # +-# !! udev must not discard DM events !! +-# !! check the other installed rules !! +-# +- +-# lookup the devmap name +-#ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ +-# PROGRAM="/sbin/devmap_name %M %m" +-ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ +- PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info" +- +-# take care of devmap partitioning +-ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ +- RUN+="/sbin/kpartx -a /dev/mapper/%c" + ++# socket for uevents ++RUN+="socket:/org/kernel/dm/multipath_event" +diff --git a/multipathd/Makefile b/multipathd/Makefile +index 8ad25ee..b430b94 100644 +--- a/multipathd/Makefile ++++ b/multipathd/Makefile +@@ -7,7 +7,7 @@ include ../Makefile.inc + # basic flags setting + # + CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir) +-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses ++LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses -laio + + # + # debuging stuff +@@ -45,7 +45,7 @@ $(MULTIPATHLIB)-glibc.a: + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(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) diff --git a/multipathd/cli.c b/multipathd/cli.c index 475819b..d786eef 100644 --- a/multipathd/cli.c @@ -4968,7 +8750,7 @@ index 475819b..d786eef 100644 #include "cli.h" -@@ -72,6 +74,30 @@ add_handler (int fp, int (*fn)(void *, c +@@ -72,6 +74,30 @@ add_handler (int fp, int (*fn)(void *, char **, int *, void *)) return 0; } @@ -5150,7 +8932,7 @@ index 475819b..d786eef 100644 vector_foreach_slot (handlers, h, i) { fp = h->fingerprint; -@@ -329,9 +355,13 @@ parse_cmd (char * cmd, char ** reply, in +@@ -329,9 +355,13 @@ parse_cmd (char * cmd, char ** reply, int * len, void * data) { int r; struct handler * h; @@ -5343,10 +9125,18 @@ index ef1e3b8..a2397df 100644 +int cli_init (void); +char * key_generator (const char * str, int state); diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c -index 92d8221..4938e84 100644 +index 92d8221..7bae02a 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c -@@ -71,7 +71,7 @@ show_map_topology (char ** r, int * len, +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "main.h" + #include "cli.h" +@@ -71,7 +72,7 @@ show_map_topology (char ** r, int * len, struct multipath * mpp) c = reply; @@ -5355,7 +9145,7 @@ index 92d8221..4938e84 100644 again = ((c - reply) == (maxlen - 1)); if (again) -@@ -92,7 +92,8 @@ show_maps_topology (char ** r, int * len +@@ -92,7 +93,8 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs) char * reply; unsigned int maxlen = INITIAL_REPLY_LEN; int again = 1; @@ -5365,7 +9155,7 @@ index 92d8221..4938e84 100644 reply = MALLOC(maxlen); while (again) { -@@ -142,6 +143,12 @@ show_config (char ** r, int * len) +@@ -142,6 +144,12 @@ show_config (char ** r, int * len) reply = REALLOC(reply, maxlen *= 2); continue; } @@ -5378,7 +9168,7 @@ index 92d8221..4938e84 100644 c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable); again = ((c - reply) == maxlen); if (again) { -@@ -183,6 +190,7 @@ cli_list_map_topology (void * v, char ** +@@ -183,6 +191,7 @@ cli_list_map_topology (void * v, char ** reply, int * len, void * data) struct vectors * vecs = (struct vectors *)data; char * param = get_keyparam(v, MAP); @@ -5386,7 +9176,7 @@ index 92d8221..4938e84 100644 mpp = find_mp_by_str(vecs->mpvec, param); if (!mpp) -@@ -278,8 +286,8 @@ cli_add_path (void * v, char ** reply, i +@@ -278,8 +287,8 @@ cli_add_path (void * v, char ** reply, int * len, void * data) condlog(2, "%s: add path (operator)", param); @@ -5397,7 +9187,13 @@ index 92d8221..4938e84 100644 *reply = strdup("blacklisted"); *len = strlen(*reply) + 1; condlog(2, "%s: path blacklisted", param); -@@ -307,7 +315,7 @@ cli_add_map (void * v, char ** reply, in +@@ -304,16 +313,30 @@ cli_add_map (void * v, char ** reply, int * len, void * data) + { + struct vectors * vecs = (struct vectors *)data; + char * param = get_keyparam(v, MAP); ++ int minor; ++ char dev_path[PATH_SIZE]; ++ struct sysfs_device *sysdev; condlog(2, "%s: add map (operator)", param); @@ -5406,7 +9202,25 @@ index 92d8221..4938e84 100644 *reply = strdup("blacklisted"); *len = strlen(*reply) + 1; condlog(2, "%s: map blacklisted", param); -@@ -431,3 +439,79 @@ cli_fail(void * v, char ** reply, int * + return 0; + } +- return ev_add_map(param, vecs); ++ minor = dm_get_minor(param); ++ if (minor < 0) { ++ condlog(2, "%s: not a device mapper table", param); ++ return 0; ++ } ++ sprintf(dev_path,"/block/dm-%d", minor); ++ sysdev = sysfs_device_get(dev_path); ++ if (!sysdev) { ++ condlog(2, "%s: not found in sysfs", param); ++ return 0; ++ } ++ return ev_add_map(sysdev, vecs); + } + + int +@@ -431,3 +454,79 @@ cli_fail(void * v, char ** reply, int * len, void * data) return dm_fail_path(pp->mpp->alias, pp->dev_t); } @@ -5490,7 +9304,7 @@ diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h index 8768724..863694b 100644 --- a/multipathd/cli_handlers.h +++ b/multipathd/cli_handlers.h -@@ -5,6 +5,8 @@ int cli_list_maps_stats (void * v, char +@@ -5,6 +5,8 @@ int cli_list_maps_stats (void * v, char ** reply, int * len, void * data); int cli_list_map_topology (void * v, char ** reply, int * len, void * data); int cli_list_maps_topology (void * v, char ** reply, int * len, void * data); int cli_list_config (void * v, char ** reply, int * len, void * data); @@ -5500,10 +9314,31 @@ index 8768724..863694b 100644 int cli_del_path (void * v, char ** reply, int * len, void * data); int cli_add_map (void * v, char ** reply, int * len, void * data); diff --git a/multipathd/main.c b/multipathd/main.c -index 55a2c49..f2f9a96 100644 +index 55a2c49..da5fd8f 100644 --- a/multipathd/main.c +++ b/multipathd/main.c -@@ -55,136 +55,29 @@ +@@ -14,12 +14,6 @@ + #include + + /* +- * libsysfs +- */ +-#include +-#include +- +-/* + * libcheckers + */ + #include +@@ -40,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -55,136 +50,29 @@ #include "uxclnt.h" #include "cli.h" #include "cli_handlers.h" @@ -5646,7 +9481,7 @@ index 55a2c49..f2f9a96 100644 if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL) return 0; -@@ -219,7 +112,8 @@ coalesce_maps(struct vectors *vecs, vect +@@ -219,7 +107,8 @@ coalesce_maps(struct vectors *vecs, vector nmpv) { struct multipath * ompp; vector ompv = vecs->mpvec; @@ -5656,7 +9491,7 @@ index 55a2c49..f2f9a96 100644 vector_foreach_slot (ompv, ompp, i) { if (!find_mp_by_wwid(nmpv, ompp->wwid)) { -@@ -253,234 +147,12 @@ coalesce_maps(struct vectors *vecs, vect +@@ -253,234 +142,12 @@ coalesce_maps(struct vectors *vecs, vector nmpv) return 0; } @@ -5887,12 +9722,13 @@ index 55a2c49..f2f9a96 100644 { - int i, j; struct pathgroup *pgp; - struct path *pp; +- struct path *pp; ++ struct path *pp; + unsigned int i, j; vector_foreach_slot (mpp->pg, pgp, i){ vector_foreach_slot (pgp->paths, pp, j){ -@@ -502,7 +174,7 @@ sync_map_state(struct multipath *mpp) +@@ -502,10 +169,10 @@ sync_map_state(struct multipath *mpp) static void sync_maps_state(vector mpvec) { @@ -5900,8 +9736,155 @@ index 55a2c49..f2f9a96 100644 + unsigned int i; struct multipath *mpp; - vector_foreach_slot (mpvec, mpp, i) -@@ -704,7 +376,7 @@ ev_add_path (char * devname, struct vect +- vector_foreach_slot (mpvec, mpp, i) ++ vector_foreach_slot (mpvec, mpp, i) + sync_map_state(mpp); + } + +@@ -536,52 +203,50 @@ flush_map(struct multipath * mpp, struct vectors * vecs) + } + + static int +-uev_add_map (char * devname, struct vectors * vecs) ++uev_add_map (struct sysfs_device * dev, struct vectors * vecs) + { +- condlog(2, "%s: add map (uevent)", devname); +- return ev_add_map(devname, vecs); ++ condlog(2, "%s: add map (uevent)", dev->kernel); ++ return ev_add_map(dev, vecs); + } + + int +-ev_add_map (char * devname, struct vectors * vecs) ++ev_add_map (struct sysfs_device * dev, struct vectors * vecs) + { +- int major, minor; +- char dev_t[BLK_DEV_SIZE]; + char * alias; ++ char *dev_t; ++ int major, minor; + char * refwwid; + struct multipath * mpp; + int map_present; + int r = 1; + +- if (sscanf(devname, "dm-%d", &minor) == 1 && +- !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) && +- sscanf(dev_t, "%d:%d", &major, &minor) == 2) +- alias = dm_mapname(major, minor); +- else +- alias = STRDUP(devname); +- ++ dev_t = sysfs_attr_get_value(dev->devpath, "dev"); ++ ++ if (!dev_t || sscanf(dev_t, "%d:%d", &major, &minor) != 2) ++ return 1; ++ ++ alias = dm_mapname(major, minor); ++ + if (!alias) + return 1; +- ++ + map_present = dm_map_present(alias); + + if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) { + condlog(4, "%s: not a multipath map", alias); +- FREE(alias); + return 0; + } + + mpp = find_mp_by_alias(vecs->mpvec, alias); + + if (mpp) { +- /* ++ /* + * Not really an error -- we generate our own uevent + * if we create a multipath mapped device as a result + * of uev_add_path + */ + condlog(0, "%s: devmap already registered", +- devname); +- FREE(alias); ++ dev->kernel); + return 0; + } + +@@ -591,31 +256,30 @@ ev_add_map (char * devname, struct vectors * vecs) + if (map_present && (mpp = add_map_without_path(vecs, minor, alias, + start_waiter_thread))) { + sync_map_state(mpp); +- condlog(3, "%s: devmap %s added", alias, devname); ++ condlog(3, "%s: devmap %s added", alias, dev->kernel); + return 0; + } +- refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec); ++ refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec); + + if (refwwid) { + r = coalesce_paths(vecs, NULL, refwwid); + dm_lib_release(); + } +- ++ + if (!r) +- condlog(3, "%s: devmap %s added", alias, devname); ++ condlog(3, "%s: devmap %s added", alias, dev->kernel); + else +- condlog(0, "%s: uev_add_map %s failed", alias, devname); ++ condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel); + + FREE(refwwid); +- FREE(alias); + return r; + } + + static int +-uev_remove_map (char * devname, struct vectors * vecs) ++uev_remove_map (struct sysfs_device * dev, struct vectors * vecs) + { +- condlog(2, "%s: remove map (uevent)", devname); +- return ev_remove_map(devname, vecs); ++ condlog(2, "%s: remove map (uevent)", dev->kernel); ++ return ev_remove_map(dev->kernel, vecs); + } + + int +@@ -636,13 +300,13 @@ ev_remove_map (char * devname, struct vectors * vecs) + } + + static int +-uev_umount_map (char * devname, struct vectors * vecs) ++uev_umount_map (struct sysfs_device * dev, struct vectors * vecs) + { + struct multipath * mpp; + +- condlog(2, "%s: umount map (uevent)", devname); ++ condlog(2, "%s: umount map (uevent)", dev->kernel); + +- mpp = find_mp_by_str(vecs->mpvec, devname); ++ mpp = find_mp_by_str(vecs->mpvec, dev->kernel); + + if (!mpp) + return 0; +@@ -655,12 +319,12 @@ uev_umount_map (char * devname, struct vectors * vecs) + + return 0; + } +- ++ + static int +-uev_add_path (char * devname, struct vectors * vecs) ++uev_add_path (struct sysfs_device * dev, struct vectors * vecs) + { +- condlog(2, "%s: add path (uevent)", devname); +- return (ev_add_path(devname, vecs) != 1)? 0 : 1; ++ condlog(2, "%s: add path (uevent)", dev->kernel); ++ return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1; + } + + +@@ -704,13 +368,13 @@ ev_add_path (char * devname, struct vectors * vecs) condlog(0, "%s: failed to get path uid", devname); return 1; /* leave path added to pathvec */ } @@ -5910,7 +9893,69 @@ index 55a2c49..f2f9a96 100644 int i = find_slot(vecs->pathvec, (void *)pp); if (i != -1) vector_del_slot(vecs->pathvec, i); -@@ -863,7 +535,7 @@ ev_remove_path (char * devname, struct v + free_path(pp); + return 2; +- } ++ } + mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); + rescan: + if (mpp) { +@@ -742,8 +406,8 @@ rescan: + condlog(0, "%s: failed in domap for addition of new " + "path %s", mpp->alias, devname); + /* +- * deal with asynchronous uevents :(( +- */ ++ * deal with asynchronous uevents :(( ++ */ + if (mpp->action == ACT_RELOAD) { + condlog(0, "%s: uev_add_path sleep", mpp->alias); + sleep(1); +@@ -776,10 +440,16 @@ out: + } + + static int +-uev_remove_path (char * devname, struct vectors * vecs) ++uev_remove_path (struct sysfs_device * dev, struct vectors * vecs) + { +- condlog(2, "%s: remove path (uevent)", devname); +- return ev_remove_path(devname, vecs); ++ int retval; ++ ++ condlog(2, "%s: remove path (uevent)", dev->kernel); ++ retval = ev_remove_path(dev->kernel, vecs); ++ if (!retval) ++ sysfs_device_put(dev); ++ ++ return retval; + } + + int +@@ -809,9 +479,9 @@ ev_remove_path (char * devname, struct vectors * vecs) + vector rpvec = vector_alloc(); + + /* +- * transform the mp->pg vector of vectors of paths +- * into a mp->params string to feed the device-mapper +- */ ++ * transform the mp->pg vector of vectors of paths ++ * into a mp->params string to feed the device-mapper ++ */ + update_mpp_paths(mpp, vecs->pathvec); + if ((i = find_slot(mpp->paths, (void *)pp)) != -1) + vector_del_slot(mpp->paths, i); +@@ -837,8 +507,8 @@ ev_remove_path (char * devname, struct vectors * vecs) + goto out; + } + /* +- * reload the map +- */ ++ * reload the map ++ */ + mpp->action = ACT_RELOAD; + if (domap(mpp) <= 0) { + condlog(0, "%s: failed in domap for " +@@ -863,7 +533,7 @@ ev_remove_path (char * devname, struct vectors * vecs) } sync_map_state(mpp); @@ -5919,7 +9964,7 @@ index 55a2c49..f2f9a96 100644 devname, mpp->alias); } free_pathvec(rpvec, KEEP_PATHS); -@@ -898,8 +570,8 @@ out: +@@ -898,8 +568,8 @@ out: static int map_discovery (struct vectors * vecs) { @@ -5929,17 +9974,96 @@ index 55a2c49..f2f9a96 100644 if (dm_get_maps(vecs->mpvec, "multipath")) return 1; -@@ -995,7 +667,8 @@ uev_trigger (struct uevent * uev, void * +@@ -916,7 +586,7 @@ uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data) + { + struct vectors * vecs; + int r; +- ++ + *reply = NULL; + *len = 0; + vecs = (struct vectors *)trigger_data; +@@ -958,11 +628,11 @@ uev_discard(char * devpath) + return 0; + } + +-int ++int + uev_trigger (struct uevent * uev, void * trigger_data) + { + int r = 0; +- char devname[32]; ++ struct sysfs_device *sysdev; + struct vectors * vecs; + + vecs = (struct vectors *)trigger_data; +@@ -970,40 +640,46 @@ uev_trigger (struct uevent * uev, void * trigger_data) + if (uev_discard(uev->devpath)) + return 0; + +- basename(uev->devpath, devname); ++ sysdev = sysfs_device_get(uev->devpath); ++ if(!sysdev) ++ return 0; ++ + lock(vecs->lock); + + /* +- * device map add/remove event ++ * device map event ++ * Add events are ignored here as the tables ++ * are not fully initialised then. + */ +- if (!strncmp(devname, "dm-", 3)) { +- if (!strncmp(uev->action, "add", 3)) { +- r = uev_add_map(devname, vecs); ++ if (!strncmp(sysdev->kernel, "dm-", 3)) { ++ if (!strncmp(uev->action, "change", 6)) { ++ r = uev_add_map(sysdev, vecs); + goto out; + } + if (!strncmp(uev->action, "remove", 6)) { +- r = uev_remove_map(devname, vecs); ++ r = uev_remove_map(sysdev, vecs); + goto out; + } + if (!strncmp(uev->action, "umount", 6)) { +- r = uev_umount_map(devname, vecs); ++ r = uev_umount_map(sysdev, vecs); + goto out; + } + goto out; + } +- ++ /* * path add/remove event */ - if (blacklist(conf->blist_devnode, devname)) + if (filter_devnode(conf->blist_devnode, conf->elist_devnode, -+ devname) > 0) ++ sysdev->kernel) > 0) goto out; if (!strncmp(uev->action, "add", 3)) { -@@ -1024,30 +697,29 @@ ueventloop (void * ap) +- r = uev_add_path(devname, vecs); ++ r = uev_add_path(sysdev, vecs); + goto out; + } + if (!strncmp(uev->action, "remove", 6)) { +- r = uev_remove_path(devname, vecs); ++ r = uev_remove_path(sysdev, vecs); + goto out; + } + +@@ -1017,37 +693,36 @@ ueventloop (void * ap) + { + if (uevent_listen(&uev_trigger, ap)) + fprintf(stderr, "error starting uevent listener"); +- ++ + return NULL; + } + static void * uxlsnrloop (void * ap) { @@ -5991,7 +10115,22 @@ index 55a2c49..f2f9a96 100644 uxsock_listen(&uxsock_trigger, ap); -@@ -1129,7 +801,7 @@ static void +@@ -1113,12 +788,12 @@ enable_group(struct path * pp) + * + * we can safely return here, because upon map reload, all + * PG will be enabled. +- */ ++ */ + if (!pp->mpp->pg || !pp->pgindex) + return; + + pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1); +- ++ + if (pgp->status == PGSTATE_DISABLED) { + condlog(2, "%s: enable group #%i", pp->mpp->alias, pp->pgindex); + dm_enablegroup(pp->mpp->alias, pp->pgindex); +@@ -1129,7 +804,7 @@ static void mpvec_garbage_collector (struct vectors * vecs) { struct multipath * mpp; @@ -6000,7 +10139,7 @@ index 55a2c49..f2f9a96 100644 vector_foreach_slot (vecs->mpvec, mpp, i) { if (mpp && mpp->alias && !dm_map_present(mpp->alias)) { -@@ -1144,7 +816,7 @@ static void +@@ -1144,7 +819,7 @@ static void defered_failback_tick (vector mpvec) { struct multipath * mpp; @@ -6009,7 +10148,7 @@ index 55a2c49..f2f9a96 100644 vector_foreach_slot (mpvec, mpp, i) { /* -@@ -1163,7 +835,7 @@ static void +@@ -1163,7 +838,7 @@ static void retry_count_tick(vector mpvec) { struct multipath *mpp; @@ -6018,7 +10157,7 @@ index 55a2c49..f2f9a96 100644 vector_foreach_slot (mpvec, mpp, i) { if (mpp->retry_tick) { -@@ -1182,8 +854,9 @@ checkerloop (void *ap) +@@ -1182,8 +857,9 @@ checkerloop (void *ap) { struct vectors *vecs; struct path *pp; @@ -6029,20 +10168,83 @@ index 55a2c49..f2f9a96 100644 mlockall(MCL_CURRENT | MCL_FUTURE); vecs = (struct vectors *)ap; -@@ -1351,10 +1024,10 @@ configure (struct vectors * vecs, int st +@@ -1213,24 +889,36 @@ checkerloop (void *ap) + * in case we exit abnormaly from here + */ + 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); + continue; + } ++ /* ++ * Set checker in async mode. ++ * Honored only by checker implementing the said mode. ++ */ ++ checker_set_async(&pp->checker); ++ + newstate = checker_check(&pp->checker); +- ++ + 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; +@@ -1245,7 +933,7 @@ checkerloop (void *ap) + if (newstate == PATH_DOWN || + newstate == PATH_SHAKY || + update_multipath_strings(pp->mpp, +- vecs->pathvec)) { ++ vecs->pathvec)) { + /* + * proactively fail path in the DM + */ +@@ -1336,7 +1024,7 @@ checkerloop (void *ap) + mpvec_garbage_collector(vecs); + count = MAPGCINT; + } +- ++ + lock_cleanup_pop(vecs->lock); + sleep(1); + } +@@ -1351,12 +1039,12 @@ configure (struct vectors * vecs, int start_waiters) vector mpvec; int i; - if (!(vecs->pathvec = vector_alloc())) + if (!vecs->pathvec && !(vecs->pathvec = vector_alloc())) return 1; - +- - if (!(vecs->mpvec = vector_alloc())) ++ + if (!vecs->mpvec && !(vecs->mpvec = vector_alloc())) return 1; - +- ++ if (!(mpvec = vector_alloc())) -@@ -1366,7 +1039,7 @@ configure (struct vectors * vecs, int st + return 1; + +@@ -1366,11 +1054,11 @@ configure (struct vectors * vecs, int start_waiters) path_discovery(vecs->pathvec, conf, DI_ALL); vector_foreach_slot (vecs->pathvec, pp, i){ @@ -6051,7 +10253,12 @@ index 55a2c49..f2f9a96 100644 vector_del_slot(vecs->pathvec, i); free_path(pp); i--; -@@ -1394,10 +1067,6 @@ configure (struct vectors * vecs, int st +- } ++ } + else + pp->checkint = conf->checkint; + } +@@ -1394,10 +1082,6 @@ configure (struct vectors * vecs, int start_waiters) sync_maps_state(mpvec); @@ -6062,7 +10269,7 @@ index 55a2c49..f2f9a96 100644 /* * purge dm of old maps */ -@@ -1406,6 +1075,7 @@ configure (struct vectors * vecs, int st +@@ -1406,6 +1090,7 @@ configure (struct vectors * vecs, int start_waiters) /* * save new set of maps formed by considering current path state */ @@ -6070,7 +10277,7 @@ index 55a2c49..f2f9a96 100644 vecs->mpvec = mpvec; /* -@@ -1435,6 +1105,7 @@ reconfigure (struct vectors * vecs) +@@ -1435,6 +1120,7 @@ reconfigure (struct vectors * vecs) if (VECTOR_SIZE(vecs->pathvec)) free_pathvec(vecs->pathvec, FREE_PATHS); @@ -6078,7 +10285,14 @@ index 55a2c49..f2f9a96 100644 conf = NULL; if (load_config(DEFAULT_CONFIGFILE)) -@@ -1467,24 +1138,10 @@ init_vecs (void) +@@ -1461,30 +1147,16 @@ init_vecs (void) + if (!vecs) + return NULL; + +- vecs->lock = ++ vecs->lock = + (pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t)); + if (!vecs->lock) goto out; @@ -6103,7 +10317,7 @@ index 55a2c49..f2f9a96 100644 out: FREE(vecs); condlog(0, "failed to init paths"); -@@ -1543,7 +1200,7 @@ signal_init(void) +@@ -1543,21 +1215,21 @@ signal_init(void) signal_set(SIGUSR1, sigusr1); signal_set(SIGINT, sigend); signal_set(SIGTERM, sigend); @@ -6112,15 +10326,103 @@ index 55a2c49..f2f9a96 100644 } static void -@@ -1551,7 +1208,7 @@ setscheduler (void) + setscheduler (void) { - int res; +- int res; ++ int res; static struct sched_param sched_param = { - sched_priority: 99 + .sched_priority = 99 }; - res = sched_setscheduler (0, SCHED_RR, &sched_param); +- res = sched_setscheduler (0, SCHED_RR, &sched_param); ++ res = sched_setscheduler (0, SCHED_RR, &sched_param); + +- if (res == -1) +- condlog(LOG_WARNING, "Could not set SCHED_RR at priority 99"); ++ if (res == -1) ++ condlog(LOG_WARNING, "Could not set SCHED_RR at priority 99"); + return; + } + +@@ -1574,7 +1246,7 @@ set_oom_adj (int val) + fprintf(fp, "%i", val); + fclose(fp); + } +- ++ + static int + child (void * param) + { +@@ -1617,7 +1289,7 @@ child (void * param) + if (!vecs) + exit(1); + +- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { ++ if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { + condlog(0, "can not find sysfs mount point"); + exit(1); + } +@@ -1636,7 +1308,7 @@ child (void * param) + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 64 * 1024); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- ++ + pthread_create(&check_thr, &attr, checkerloop, vecs); + pthread_create(&uevent_thr, &attr, ueventloop, vecs); + pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, vecs); +@@ -1654,6 +1326,8 @@ child (void * param) + pthread_cancel(uevent_thr); + pthread_cancel(uxlsnr_thr); + ++ sysfs_cleanup(); ++ + free_keys(keys); + keys = NULL; + free_handlers(handlers); +@@ -1670,7 +1344,7 @@ child (void * param) + conf = NULL; + + condlog(2, "--------shut down-------"); +- ++ + if (logsink) + log_thread_stop(); + +@@ -1738,8 +1412,9 @@ main (int argc, char *argv[]) + extern int optind; + int arg; + int err; +- ++ + logsink = 1; ++ dm_init(); + + if (getuid() != 0) { + fprintf(stderr, "need to be root\n"); +@@ -1780,7 +1455,7 @@ main (int argc, char *argv[]) + err = 0; + else + err = daemonize(); +- ++ + if (err < 0) + /* error */ + exit(1); +diff --git a/multipathd/main.h b/multipathd/main.h +index d0cce3a..1a6dc55 100644 +--- a/multipathd/main.h ++++ b/multipathd/main.h +@@ -7,7 +7,7 @@ + int reconfigure (struct vectors *); + int ev_add_path (char *, struct vectors *); + int ev_remove_path (char *, struct vectors *); +-int ev_add_map (char *, struct vectors *); ++int ev_add_map (struct sysfs_device *, struct vectors *); + int ev_remove_map (char *, struct vectors *); + + #endif /* MAIN_H */ diff --git a/multipathd/multipathd.8 b/multipathd/multipathd.8 index 48b1b04..480b8ed 100644 --- a/multipathd/multipathd.8 @@ -6260,6 +10562,19 @@ index ff7b578..009e5cb 100644 while ((line = readline("multipathd> "))) { size_t len; size_t llen = strlen(line); +diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile +index 983ffe3..6f356a1 100644 +--- a/path_priority/pp_alua/Makefile ++++ b/path_priority/pp_alua/Makefile +@@ -35,7 +35,7 @@ glibc: $(OBJS) + klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + +-install: $(BUILD) $(EXEC).8.gz ++install: $(EXEC) $(EXEC).8.gz + $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz + diff --git a/path_priority/pp_alua/main.c b/path_priority/pp_alua/main.c index 190fbdc..ba8da99 100644 --- a/path_priority/pp_alua/main.c @@ -6313,7 +10628,7 @@ index 9aea560..701f9d5 100644 /* * Macro used to print debug messaged. -@@ -251,14 +252,38 @@ do_rtpg(int fd, void* resp, long resplen +@@ -251,14 +252,38 @@ do_rtpg(int fd, void* resp, long resplen) int get_asymmetric_access_state(int fd, unsigned int tpg) { @@ -6355,7 +10670,7 @@ index 9aea560..701f9d5 100644 tpgd = (struct rtpg_data *) buf; rc = -RTPG_TPG_NOT_FOUND; -@@ -274,7 +299,8 @@ get_asymmetric_access_state(int fd, unsi +@@ -274,7 +299,8 @@ get_asymmetric_access_state(int fd, unsigned int tpg) } } } @@ -6382,6 +10697,19 @@ index 11f5dbd..bddbbdd 100644 /* ....xx.. = clocking */ /* ......x. = qas */ /* .......x = ius */ +diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile +index bed7fb0..cb1e6c6 100644 +--- a/path_priority/pp_balance_units/Makefile ++++ b/path_priority/pp_balance_units/Makefile +@@ -35,7 +35,7 @@ $(MULTIPATHLIB)-$(BUILD).a: + + install: + install -d $(DESTDIR)$(bindir) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ ++ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) diff --git a/path_priority/pp_balance_units/pp_balance_units.c b/path_priority/pp_balance_units/pp_balance_units.c index 307a959..ea70f13 100644 --- a/path_priority/pp_balance_units/pp_balance_units.c @@ -6426,7 +10754,7 @@ index 307a959..ea70f13 100644 char serial[SERIAL_SIZE]; int path_count; }; -@@ -172,7 +172,7 @@ do_inq(int sg_fd, int cmddt, int evpd, u +@@ -172,7 +172,7 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, } static int @@ -6522,7 +10850,7 @@ index 307a959..ea70f13 100644 strncpy(cp->serial, pp->serial, SERIAL_SIZE); } cp->path_count++; -@@ -411,17 +413,17 @@ get_controlers (vector controlers, vecto +@@ -411,17 +413,17 @@ get_controlers (vector controlers, vector pathvec) } static int @@ -6581,9 +10909,41 @@ index 307a959..ea70f13 100644 if (!cp) { debug("no other active path on serial %s\n", +diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile +index 651bdcd..93e6075 100644 +--- a/path_priority/pp_emc/Makefile ++++ b/path_priority/pp_emc/Makefile +@@ -14,7 +14,7 @@ klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +diff --git a/path_priority/pp_emc/pp_emc.c b/path_priority/pp_emc/pp_emc.c +index dd58424..4031720 100644 +--- a/path_priority/pp_emc/pp_emc.c ++++ b/path_priority/pp_emc/pp_emc.c +@@ -60,8 +60,12 @@ int emc_clariion_prio(const char *dev) + + if ( /* Effective initiator type */ + sense_buffer[27] != 0x03 +- /* Failover mode should be set to 1 */ +- || (sense_buffer[28] & 0x07) != 0x04 ++ /* ++ * Failover mode should be set to 1 (PNR failover mode) ++ * or 4 (ALUA failover mode). ++ */ ++ || (((sense_buffer[28] & 0x07) != 0x04) && ++ ((sense_buffer[28] & 0x07) != 0x06)) + /* Arraycommpath should be set to 1 */ + || (sense_buffer[30] & 0x04) != 0x04) { + fprintf(stderr, "Path not correctly configured for failover"); diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile new file mode 100644 -index 0000000..a0249a5 +index 0000000..ca00ca7 --- /dev/null +++ b/path_priority/pp_hds_modular/Makefile @@ -0,0 +1,22 @@ @@ -6603,7 +10963,7 @@ index 0000000..a0249a5 + $(CC) -static -o $(EXEC) $(OBJS) + +install: $(EXEC) -+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + +uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) @@ -6611,48 +10971,48 @@ index 0000000..a0249a5 + rm -f *.o $(EXEC) diff --git a/path_priority/pp_hds_modular/pp_hds_modular.c b/path_priority/pp_hds_modular/pp_hds_modular.c new file mode 100644 -index 0000000..f38ebcf +index 0000000..7411508 --- /dev/null +++ b/path_priority/pp_hds_modular/pp_hds_modular.c -@@ -0,0 +1,252 @@ +@@ -0,0 +1,211 @@ +/* + * (C) Copyright HDS GmbH 2006. All Rights Reserved. + * + * pp_hds_modular.c -+ * Version 1.12 ++ * Version 2.00 + * -+ * Prioritizer for multipath tools device mapper and HDS Storage ++ * 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 ++ * 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 ++ * controller is stand-by. It is also possible to allocate more as one path ++ * for a LDEV per controller. Here is active/active access allowed. The other + * pathes via the other controller are stand-by. -+ * -+ * This prioritizer checks with inquiry commands the represented LDEV and -+ * Controller number and gives back a priority followed by this scheme : ++ * ++ * 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 ++ * 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 ++ * 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. ++ * 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 : ++ * You can run the prioritizer manually in verbose mode: + * # pp_hds_modular -v 8:224 + * VENDOR: HITACHI + * PRODUCT: DF600F-CM @@ -6662,31 +11022,21 @@ index 0000000..f38ebcf + * PORT: B + * CTRL ODD, LDEV EVEN, PRIO 0 + * -+ * The items VENDOR and PRODUCT helps you to make the correct entries in file -+ * /etc/multipath.conf : -+ * # cat /etc/multipath.conf -+ * ... -+ * devices { -+ * device { -+ * vendor "HITACHI" -+ * product "DF600F" -+ * path_grouping_policy group_by_prio -+ * prio_callout "/sbin/pp_hds_modular %d" -+ * path_checker readsector0 -+ * getuid_callout "/sbin/scsi_id -g -u -s /block/%n" -+ * failback immediate -+ * } -+ * device { -+ * vendor "HITACHI" -+ * product "DF600F-CM" -+ * path_grouping_policy group_by_prio -+ * prio_callout "/sbin/pp_hds_modular %d" -+ * path_checker readsector0 -+ * getuid_callout "/sbin/scsi_id -g -u -s /block/%n" -+ * failback immediate ++ * To compile this source please execute # cc pp_hds_modular.c -o /sbin/mpath_prio_hds_modular + * -+ * -+ * Author: Matthias Rudolph ++ * 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. + * @@ -6703,210 +11053,616 @@ index 0000000..f38ebcf +#include +#include +#include -+#include /* take care: fetches glibc's /usr/include/scsi/sg.h */ ++#include + +#define INQ_REPLY_LEN 255 +#define INQ_CMD_CODE 0x12 +#define INQ_CMD_LEN 6 +#define FILE_NAME_SIZE 255 -+#define safe_sprintf(var, format, args...) \ -+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var) -+#define safe_snprintf(var, size, format, args...) \ -+ snprintf(var, size, format, ##args) >= size + -+int verbose; ++int verbose=0; + -+int hds_modular_prio(char * major_minor) ++void print_help (void); ++int hds_modular_prio (const char *); ++ ++int main (int argc, char **argv) +{ -+ int sg_fd, k, i; -+ char vendor[32]; ++ 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]; -+ char devpath[FILE_NAME_SIZE]; -+ unsigned int major; -+ unsigned int minor; -+ unsigned char inqCmdBlk[INQ_CMD_LEN] = -+ {INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0}; ++ unsigned char 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; + -+ sscanf(major_minor, "%u:%u", &major, &minor); -+ memset(devpath, 0, FILE_NAME_SIZE); ++ if ((sg_fd = open (dev, O_RDONLY)) < 0) exit (1); ++ if ((ioctl (sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) exit (1); + -+ if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode", -+ major, minor)) -+ exit(1); -+ -+ unlink (devpath); -+ mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor)); -+ -+ if ((sg_fd = open(devpath, O_RDONLY)) < 0) exit(1); -+ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) -+ exit(1); -+ -+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); ++ 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.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 */ ++ 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); ++ if (ioctl (sg_fd, SG_IO, &io_hdr) < 0) exit (1); ++ if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) exit (1); + -+ for (i = 0; i < 8 ; i++) vendor[i] = inqBuff[i+8]; -+ vendor[8] = 0; -+ for (i = 0; i < 16 ; i++) product[i] = inqBuff[i+16]; -+ product[16] = 0; -+ for (i = 0; i < 4 ; i++) serial[i] = inqBuff[i+40]; -+ serial[4] = 0; -+ for (i = 0; i < 4 ; i++) ldev[i] = inqBuff[i+44]; -+ ldev[4] = 0; -+ ctrl[0] = inqBuff[49]; -+ ctrl[1] = 0; -+ port[0] = inqBuff[50]; -+ port[1] = 0; ++ 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); ++ close (sg_fd); + -+ if (1 == verbose) { -+ printf("VENDOR: %s\n", vendor); -+ printf("PRODUCT: %s\n", product); -+ printf("SERIAL: 0x%s\n", serial); -+ printf("LDEV: 0x%s\n", ldev); -+ printf("CTRL: %s\n", ctrl); -+ printf("PORT: %s\n", port); ++ 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; -+ } ++ switch (ctrl[0]) { ++ case '0': case '2': case '4': case '6': case '8': ++ switch (ldev[3]) { ++ case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E': ++ if (1 == verbose) printf("CTRL EVEN, LDEV EVEN, PRIO 1\n"); ++ return 1; ++ break; ++ case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F': ++ if (1 == verbose) printf("CTRL EVEN, LDEV ODD, PRIO 0\n"); ++ return 0; ++ break; ++ } ++ case '1': case '3': case '5': case '7': case '9': ++ switch (ldev[3]) { ++ case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E': ++ if (1 == verbose) printf("CTRL ODD, LDEV EVEN, PRIO 0\n"); ++ return 0; ++ break; ++ case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F': ++ if (1 == verbose) printf("CTRL ODD, LDEV ODD, PRIO 1\n"); ++ return 1; ++ break; ++ } + } -+ exit(1); ++ return 0; +} + -+void print_help(void) ++void print_help (void) +{ -+ printf("Usage: " -+ "pp_hds_modular [-v] \n"); -+ printf("Option: " -+ "-v verbose mode\n"); -+ printf("Description: " -+ "Prioritizer for Multipath Tools and HDS Storage\n"); -+ printf("Version: " -+ "1.12\n"); -+ printf("Author: " -+ "Matthias Rudolph \n"); ++ 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; +} + -+int main(int argc, char * argv[]) +diff --git a/path_priority/pp_hp_sw/Makefile b/path_priority/pp_hp_sw/Makefile +new file mode 100644 +index 0000000..e7debf5 +--- /dev/null ++++ b/path_priority/pp_hp_sw/Makefile +@@ -0,0 +1,25 @@ ++EXEC = mpath_prio_hp_sw ++BUILD = glibc ++OBJS = pp_hp_sw.o ++ ++TOPDIR = ../.. ++include $(TOPDIR)/Makefile.inc ++ ++all: $(BUILD) ++ ++glibc: $(OBJS) ++ $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS) ++ ++klibc: $(OBJS) ++ $(CC) -static -o $(EXEC) $(OBJS) ++ ++install: $(EXEC) ++ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ ++uninstall: ++ rm $(DESTDIR)$(bindir)/$(EXEC) ++clean: ++ rm -f *.o $(EXEC) ++ ++%.o: %.c ++ $(CC) $(CFLAGS) -c -o $@ $< +diff --git a/path_priority/pp_hp_sw/pp_hp_sw.c b/path_priority/pp_hp_sw/pp_hp_sw.c +new file mode 100644 +index 0000000..e4a18b1 +--- /dev/null ++++ b/path_priority/pp_hp_sw/pp_hp_sw.c +@@ -0,0 +1,119 @@ ++/* ++ * Path priority checker for HP active/standby controller ++ * ++ * Check the path state and sort them into groups. ++ * There is actually a preferred path in the controller; ++ * we should ask HP on how to retrieve that information. ++ */ ++#include ++#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) +{ -+ int prio; ++ 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; + -+ if (2 == argc) { -+ if (0 == strcmp(argv[1], "-h")) { -+ print_help(); -+ exit(0); -+ } -+ else { -+ verbose = 0; -+ prio = hds_modular_prio(argv[1]); -+ printf("%d\n", prio); -+ exit(0); -+ } ++ fd = open(dev, O_RDWR|O_NONBLOCK); ++ ++ if (fd <= 0) { ++ fprintf(stderr, "Opening the device failed.\n"); ++ goto out; + } + -+ if ((3 == argc) && (0 == strcmp(argv[1], "-v"))) { -+ verbose = 1; -+ prio = hds_modular_prio(argv[2]); -+ printf("%d\n", prio); -+ exit(0); ++ 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; + } -+ print_help(); -+ exit(1); ++ 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 +index 9e7d3a3..b29d002 100644 +--- a/path_priority/pp_netapp/Makefile ++++ b/path_priority/pp_netapp/Makefile +@@ -14,7 +14,7 @@ klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile +index 85f42a2..85d7c2f 100644 +--- a/path_priority/pp_random/Makefile ++++ b/path_priority/pp_random/Makefile +@@ -14,7 +14,7 @@ klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + + install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) ++ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) + + uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) +diff --git a/path_priority/pp_rdac/Makefile b/path_priority/pp_rdac/Makefile +new file mode 100644 +index 0000000..64ed4c3 +--- /dev/null ++++ b/path_priority/pp_rdac/Makefile +@@ -0,0 +1,22 @@ ++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 +new file mode 100644 +index 0000000..49a13cf +--- /dev/null ++++ b/path_priority/pp_rdac/pp_rdac.c +@@ -0,0 +1,112 @@ ++#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); ++} +diff --git a/path_priority/pp_tpc/Makefile b/path_priority/pp_tpc/Makefile +deleted file mode 100644 +index 86841dd..0000000 +--- a/path_priority/pp_tpc/Makefile ++++ /dev/null +@@ -1,22 +0,0 @@ +-EXEC = mpath_prio_tpc +-BUILD = glibc +-OBJS = pp_tpc.o +- +-TOPDIR = ../.. +-include $(TOPDIR)/Makefile.inc +- +-all: $(BUILD) +- +-glibc: $(OBJS) +- $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS) +- +-klibc: $(OBJS) +- $(CC) -static -o $(EXEC) $(OBJS) +- +-install: $(EXEC) +- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) +- +-uninstall: +- rm $(DESTDIR)$(bindir)/$(EXEC) +-clean: +- rm -f *.o $(EXEC) diff --git a/path_priority/pp_tpc/pp_tpc.c b/path_priority/pp_tpc/pp_tpc.c -index 76e7c47..a7ed7ad 100644 +deleted file mode 100644 +index 76e7c47..0000000 --- a/path_priority/pp_tpc/pp_tpc.c -+++ b/path_priority/pp_tpc/pp_tpc.c -@@ -62,18 +62,13 @@ int sgi_tpc_prio(const char *dev) - goto out; - } - ++++ /dev/null +@@ -1,118 +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 sgi_tpc_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 ( /* Auto-volume Transfer Enabled */ - (sense_buffer[8] & 0x80) != 0x80 ) { - fprintf(stderr, "Auto-volume Transfer not enabled"); - } - - if ( /* Current Volume Path Bit */ - ( sense_buffer[8] & 0x01) == 0x01 ) { - /* - * This volume was owned by the controller receiving - * the inquiry command. - */ +- if ( /* Current Volume Path Bit */ +- ( sense_buffer[8] & 0x01) == 0x01 ) { +- /* +- * This volume was owned by the controller receiving +- * the inquiry command. +- */ - ret |= 0x02; -+ ret |= 0x01; - } - - /* Volume Preferred Path Priority */ -@@ -83,7 +78,7 @@ int sgi_tpc_prio(const char *dev) - * Access to this volume is most preferred through - * this path and other paths with this value. - */ +- } +- +- /* 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 |= 0x04; -+ ret |= 0x02; - break; - case 0x02: - /* -@@ -91,8 +86,7 @@ int sgi_tpc_prio(const char *dev) - * as a secondary path. Typically this path would be used - * for fail-over situations. - */ +- 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. +- */ - ret |= 0x01; - break; -+ /* Fallthrough */ - default: - /* Reserved values */ - break; +- 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 = sgi_tpc_prio(argv[1]); +- +- printf("%d\n", prio); +- exit(0); +-} diff --git a/multipath-tools-local-fixes b/multipath-tools-local-fixes deleted file mode 100644 index 275c60b..0000000 --- a/multipath-tools-local-fixes +++ /dev/null @@ -1,2036 +0,0 @@ - Makefile.inc | 1 + - devmap_name/Makefile | 10 +- - kpartx/Makefile | 8 +- - kpartx/devmapper.c | 7 +- - kpartx/kpartx.c | 16 ++- - libcheckers/directio.c | 119 ++++++++---- - libcheckers/emc_clariion.c | 8 +- - libcheckers/libaio.h | 222 +++++++++++++++++++++ - libmultipath/config.c | 5 +- - libmultipath/configure.c | 2 - - libmultipath/debug.c | 2 +- - libmultipath/debug.h | 2 +- - libmultipath/devmapper.c | 60 +++++-- - libmultipath/devmapper.h | 3 +- - libmultipath/dict.c | 2 +- - libmultipath/hwtable.c | 81 +++++--- - libmultipath/log.c | 5 + - libmultipath/log_pthread.c | 2 +- - libmultipath/log_pthread.h | 2 +- - libmultipath/parser.c | 15 +- - libmultipath/parser.h | 1 + - libmultipath/print.c | 2 +- - libmultipath/structs_vec.c | 32 ++-- - libmultipath/waiter.c | 9 +- - multipath/Makefile | 7 +- - multipath/main.c | 58 ++++++- - multipath/multipath.8 | 8 +- - multipath/multipath.conf.5 | 384 +++++++++++++++++++++++++++++++++++++ - multipathd/Makefile | 5 +- - multipathd/cli.c | 2 +- - multipathd/main.c | 9 +- - path_priority/pp_alua/Makefile | 9 +- - path_priority/pp_emc/pp_emc.c | 8 +- - path_priority/pp_hp_sw/Makefile | 25 +++ - path_priority/pp_hp_sw/pp_hp_sw.c | 119 ++++++++++++ - 35 files changed, 1092 insertions(+), 158 deletions(-) - -diff --git a/Makefile.inc b/Makefile.inc -index 4a705aa..fe6cbdf 100644 ---- a/Makefile.inc -+++ b/Makefile.inc -@@ -26,6 +26,7 @@ bindir = $(exec_prefix)/sbin - checkersdir = $(TOPDIR)/libcheckers - multipathdir = $(TOPDIR)/libmultipath - mandir = $(prefix)/usr/share/man/man8 -+man5dir = $(prefix)/usr/share/man/man5 - rcdir = $(prefix)/etc/init.d - - GZIP = /bin/gzip -9 -c -diff --git a/devmap_name/Makefile b/devmap_name/Makefile -index 380c85b..8b0c678 100644 ---- a/devmap_name/Makefile -+++ b/devmap_name/Makefile -@@ -22,21 +22,19 @@ prepare: - - glibc: prepare $(OBJS) - $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - - klibc: prepare $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - --install: -+install: $(EXEC) $(EXEC).8 - install -d $(DESTDIR)$(bindir) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ - install -d $(DESTDIR)$(mandir) -- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) -+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz -+ rm $(DESTDIR)$(mandir)/$(EXEC).8 - - clean: - rm -f core *.o $(EXEC) *.gz -diff --git a/kpartx/Makefile b/kpartx/Makefile -index bf6e6c1..522a6a0 100644 ---- a/kpartx/Makefile -+++ b/kpartx/Makefile -@@ -27,20 +27,18 @@ prepare: - - glibc: prepare $(OBJS) - $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz -- -+ - klibc: prepare $(OBJS) - $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - - $(MULTIPATHLIB)-$(BUILD).a: - make -C $(multipathdir) BUILD=$(BUILD) - --install: -+install: $(EXEC) $(EXEC).8 - install -d $(DESTDIR)$(bindir) - install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) - install -d $(DESTDIR)$(mandir) -- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) -+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) - - uninstall: - rm -f $(DESTDIR)$(bindir)/$(EXEC) -diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c -index 5b27487..4b228ed 100644 ---- a/kpartx/devmapper.c -+++ b/kpartx/devmapper.c -@@ -95,19 +95,16 @@ dm_addmap (int task, const char *name, c - } - sprintf(prefixed_uuid, UUID_PREFIX "%s", part, uuid); - if (!dm_task_set_uuid(dmt, prefixed_uuid)) -- goto freeout; -+ goto addout; - } - - dm_task_no_open_count(dmt); - - r = dm_task_run (dmt); - -- freeout: -- if (prefixed_uuid) -- free(prefixed_uuid); -- - addout: - dm_task_destroy (dmt); -+ - return r; - } - -diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c -index 0ee0cb3..b406b95 100644 ---- a/kpartx/kpartx.c -+++ b/kpartx/kpartx.c -@@ -193,6 +193,7 @@ main(int argc, char **argv){ - char * loopdev = NULL; - char * delim = NULL; - char *uuid = NULL; -+ char *mapname = NULL; - int loopro = 0; - int hotplug = 0; - struct stat buf; -@@ -310,12 +311,19 @@ main(int argc, char **argv){ - - off = find_devname_offset(device); - -- if (!loopdev) -+ if (!loopdev) { - uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev), - (unsigned int)MINOR(buf.st_rdev)); -+ mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev), -+ (unsigned int)MINOR(buf.st_rdev)); -+ } -+ - if (!uuid) - uuid = device + off; - -+ if (!mapname) -+ mapname = device + off; -+ - fd = open(device, O_RDONLY); - - if (fd == -1) { -@@ -365,7 +373,7 @@ main(int argc, char **argv){ - continue; - - printf("%s%s%d : 0 %lu %s %lu\n", -- device + off, delim, j+1, -+ mapname, delim, j+1, - (unsigned long) slices[j].size, device, - (unsigned long) slices[j].start); - } -@@ -374,7 +382,7 @@ main(int argc, char **argv){ - case DELETE: - for (j = 0; j < n; j++) { - if (safe_sprintf(partname, "%s%s%d", -- device + off , delim, j+1)) { -+ mapname, delim, j+1)) { - fprintf(stderr, "partname too small\n"); - exit(1); - } -@@ -407,7 +415,7 @@ main(int argc, char **argv){ - continue; - - if (safe_sprintf(partname, "%s%s%d", -- device + off , delim, j+1)) { -+ mapname, delim, j+1)) { - fprintf(stderr, "partname too small\n"); - exit(1); - } -diff --git a/libcheckers/directio.c b/libcheckers/directio.c -index b53c1c3..2251515 100644 ---- a/libcheckers/directio.c -+++ b/libcheckers/directio.c -@@ -12,28 +12,44 @@ - #include - #include - #include -+#include -+#include - -+#include "libaio.h" - #include "checkers.h" -+#include "../libmultipath/debug.h" - - #define MSG_DIRECTIO_UNKNOWN "directio checker is not available" - #define MSG_DIRECTIO_UP "directio checker reports path is up" - #define MSG_DIRECTIO_DOWN "directio checker reports path is down" - - struct directio_context { -- int blksize; -- unsigned char *buf; -- unsigned char *ptr; -+ int running; -+ int reset_flags; -+ int blksize; -+ unsigned char * buf; -+ unsigned char * ptr; -+ io_context_t ioctx; -+ struct iocb io; - }; - -+ - int directio_init (struct checker * c) - { - unsigned long pgsize = getpagesize(); - struct directio_context * ct; -+ long flags; - - ct = malloc(sizeof(struct directio_context)); - if (!ct) - return 1; -- c->context = (void *)ct; -+ memset(ct, 0, sizeof(struct directio_context)); -+ -+ if (syscall(__NR_io_setup, 1, &ct->ioctx) != 0) { -+ condlog(1, "io_setup failed"); -+ free(ct); -+ return 1; -+ } - - if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) { - MSG(c, "cannot get blocksize, set default"); -@@ -50,11 +66,28 @@ int directio_init (struct checker * c) - ct->buf = (unsigned char *)malloc(ct->blksize + pgsize); - if (!ct->buf) - goto out; -- ct->ptr = (unsigned char *)(((unsigned long)ct->buf + pgsize - 1) & -- (~(pgsize - 1))); - -+ flags = fcntl(c->fd, F_GETFL); -+ if (flags < 0) -+ goto out; -+ if (!(flags & O_DIRECT)) { -+ flags |= O_DIRECT; -+ if (fcntl(c->fd, F_SETFL, flags) < 0) -+ goto out; -+ ct->reset_flags = 1; -+ } -+ -+ ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) & -+ (~(pgsize - 1))); -+ -+ /* Sucessfully initialized, return the context. */ -+ c->context = (void *) ct; - return 0; -+ - out: -+ if (ct->buf) -+ free(ct->buf); -+ syscall(__NR_io_destroy, ct->ioctx); - free(ct); - return 1; - } -@@ -62,56 +95,63 @@ out: - void directio_free (struct checker * c) - { - struct directio_context * ct = (struct directio_context *)c->context; -+ long flags; - - if (!ct) - return; -+ -+ if (ct->reset_flags) { -+ if ((flags = fcntl(c->fd, F_GETFL)) >= 0) { -+ flags &= ~O_DIRECT; -+ /* No point in checking for errors */ -+ fcntl(c->fd, F_SETFL, flags); -+ } -+ } -+ - if (ct->buf) - free(ct->buf); -+ syscall(__NR_io_destroy, ct->ioctx); - free(ct); - } - - static int --direct_read (int fd, unsigned char * buff, int size) -+check_state(int fd, struct directio_context *ct) - { -- long flags; -- int reset_flags = 0; -- int res, retval; -- -- flags = fcntl(fd,F_GETFL); -- -- if (flags < 0) { -- return PATH_UNCHECKED; -+ struct timespec timeout = { .tv_sec = 2 }; -+ struct io_event event; -+ struct stat sb; -+ int rc = PATH_UNCHECKED; -+ long r; -+ -+ if (fstat(fd, &sb) == 0) { -+ condlog(4, "directio: called for %x", (unsigned) sb.st_rdev); - } - -- if (!(flags & O_DIRECT)) { -- flags |= O_DIRECT; -- if (fcntl(fd,F_SETFL,flags) < 0) { -+ if (!ct->running) { -+ struct iocb *ios[1] = { &ct->io }; -+ -+ condlog(3, "directio: starting new request"); -+ memset(&ct->io, 0, sizeof(struct iocb)); -+ io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0); -+ if (syscall(__NR_io_submit, ct->ioctx, 1, ios) != 1) { -+ condlog(3, "directio: io_submit error %i", errno); - return PATH_UNCHECKED; - } -- reset_flags = 1; - } -+ ct->running = 1; - -- while ( (res = read(fd,buff,size)) < 0 && errno == EINTR ); -- if (res < 0) { -- if (errno == EINVAL) { -- /* O_DIRECT is not available */ -- retval = PATH_UNCHECKED; -- } else if (errno == ENOMEM) { -- retval = PATH_UP; -- } else { -- retval = PATH_DOWN; -- } -+ r = syscall(__NR_io_getevents, ct->ioctx, 1L, 1L, &event, &timeout); -+ if (r < 1L) { -+ condlog(3, "directio: timeout r=%li errno=%i", r, errno); -+ rc = PATH_DOWN; - } else { -- retval = PATH_UP; -- } -- -- if (reset_flags) { -- flags &= ~O_DIRECT; -- /* No point in checking for errors */ -- fcntl(fd,F_SETFL,flags); -+ condlog(3, "directio: io finished %lu/%lu", event.res, -+ event.res2); -+ ct->running = 0; -+ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN; - } - -- return retval; -+ return rc; - } - - int directio (struct checker * c) -@@ -119,7 +159,10 @@ int directio (struct checker * c) - int ret; - struct directio_context * ct = (struct directio_context *)c->context; - -- ret = direct_read(c->fd, ct->ptr, ct->blksize); -+ if (!ct) -+ return PATH_UNCHECKED; -+ -+ ret = check_state(c->fd, ct); - - switch (ret) - { -diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c -index 384a943..d801b42 100644 ---- a/libcheckers/emc_clariion.c -+++ b/libcheckers/emc_clariion.c -@@ -129,8 +129,12 @@ int emc_clariion(struct checker * c) - - if ( /* Effective initiator type */ - sense_buffer[27] != 0x03 -- /* Failover mode should be set to 1 */ -- || (sense_buffer[28] & 0x07) != 0x04 -+ /* -+ * Failover mode should be set to 1 (PNR failover mode) -+ * or 4 (ALUA failover mode). -+ */ -+ || (((sense_buffer[28] & 0x07) != 0x04) && -+ ((sense_buffer[28] & 0x07) != 0x06)) - /* Arraycommpath should be set to 1 */ - || (sense_buffer[30] & 0x04) != 0x04) { - MSG(c, "emc_clariion_checker: Path not correctly configured " -diff --git a/libcheckers/libaio.h b/libcheckers/libaio.h -new file mode 100644 -index 0000000..6574601 ---- /dev/null -+++ b/libcheckers/libaio.h -@@ -0,0 +1,222 @@ -+/* /usr/include/libaio.h -+ * -+ * Copyright 2000,2001,2002 Red Hat, Inc. -+ * -+ * Written by Benjamin LaHaise -+ * -+ * libaio Linux async I/O interface -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+#ifndef __LIBAIO_H -+#define __LIBAIO_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#include -+#include -+ -+struct timespec; -+struct sockaddr; -+struct iovec; -+struct iocb; -+ -+typedef struct io_context *io_context_t; -+ -+typedef enum io_iocb_cmd { -+ IO_CMD_PREAD = 0, -+ IO_CMD_PWRITE = 1, -+ -+ IO_CMD_FSYNC = 2, -+ IO_CMD_FDSYNC = 3, -+ -+ IO_CMD_POLL = 5, -+ IO_CMD_NOOP = 6, -+} io_iocb_cmd_t; -+ -+#if defined(__i386__) /* little endian, 32 bits */ -+#define PADDED(x, y) x; unsigned y -+#define PADDEDptr(x, y) x; unsigned y -+#define PADDEDul(x, y) unsigned long x; unsigned y -+#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__) -+#define PADDED(x, y) x, y -+#define PADDEDptr(x, y) x -+#define PADDEDul(x, y) unsigned long x -+#elif defined(__powerpc64__) /* big endian, 64 bits */ -+#define PADDED(x, y) unsigned y; x -+#define PADDEDptr(x,y) x -+#define PADDEDul(x, y) unsigned long x -+#elif defined(__PPC__) /* big endian, 32 bits */ -+#define PADDED(x, y) unsigned y; x -+#define PADDEDptr(x, y) unsigned y; x -+#define PADDEDul(x, y) unsigned y; unsigned long x -+#elif defined(__s390x__) /* big endian, 64 bits */ -+#define PADDED(x, y) unsigned y; x -+#define PADDEDptr(x,y) x -+#define PADDEDul(x, y) unsigned long x -+#elif defined(__s390__) /* big endian, 32 bits */ -+#define PADDED(x, y) unsigned y; x -+#define PADDEDptr(x, y) unsigned y; x -+#define PADDEDul(x, y) unsigned y; unsigned long x -+#else -+#error endian? -+#endif -+ -+struct io_iocb_poll { -+ PADDED(int events, __pad1); -+}; /* result code is the set of result flags or -'ve errno */ -+ -+struct io_iocb_sockaddr { -+ struct sockaddr *addr; -+ int len; -+}; /* result code is the length of the sockaddr, or -'ve errno */ -+ -+struct io_iocb_common { -+ PADDEDptr(void *buf, __pad1); -+ PADDEDul(nbytes, __pad2); -+ long long offset; -+ long long __pad3, __pad4; -+}; /* result code is the amount read or -'ve errno */ -+ -+struct io_iocb_vector { -+ const struct iovec *vec; -+ int nr; -+ long long offset; -+}; /* result code is the amount read or -'ve errno */ -+ -+struct iocb { -+ PADDEDptr(void *data, __pad1); /* Return in the io completion event */ -+ PADDED(unsigned key, __pad2); /* For use in identifying io requests */ -+ -+ short aio_lio_opcode; -+ short aio_reqprio; -+ int aio_fildes; -+ -+ union { -+ struct io_iocb_common c; -+ struct io_iocb_vector v; -+ struct io_iocb_poll poll; -+ struct io_iocb_sockaddr saddr; -+ } u; -+}; -+ -+struct io_event { -+ PADDEDptr(void *data, __pad1); -+ PADDEDptr(struct iocb *obj, __pad2); -+ PADDEDul(res, __pad3); -+ PADDEDul(res2, __pad4); -+}; -+ -+#undef PADDED -+#undef PADDEDptr -+#undef PADDEDul -+ -+typedef void (*io_callback_t)(io_context_t ctx, struct iocb *iocb, long res, long res2); -+ -+/* library wrappers */ -+extern int io_queue_init(int maxevents, io_context_t *ctxp); -+/*extern int io_queue_grow(io_context_t ctx, int new_maxevents);*/ -+extern int io_queue_release(io_context_t ctx); -+/*extern int io_queue_wait(io_context_t ctx, struct timespec *timeout);*/ -+extern int io_queue_run(io_context_t ctx); -+ -+/* Actual syscalls */ -+extern int io_setup(int maxevents, io_context_t *ctxp); -+extern int io_destroy(io_context_t ctx); -+extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]); -+extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt); -+extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout); -+ -+ -+static inline void io_set_callback(struct iocb *iocb, io_callback_t cb) -+{ -+ iocb->data = (void *)cb; -+} -+ -+static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) -+{ -+ memset(iocb, 0, sizeof(*iocb)); -+ iocb->aio_fildes = fd; -+ iocb->aio_lio_opcode = IO_CMD_PREAD; -+ iocb->aio_reqprio = 0; -+ iocb->u.c.buf = buf; -+ iocb->u.c.nbytes = count; -+ iocb->u.c.offset = offset; -+} -+ -+static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) -+{ -+ memset(iocb, 0, sizeof(*iocb)); -+ iocb->aio_fildes = fd; -+ iocb->aio_lio_opcode = IO_CMD_PWRITE; -+ iocb->aio_reqprio = 0; -+ iocb->u.c.buf = buf; -+ iocb->u.c.nbytes = count; -+ iocb->u.c.offset = offset; -+} -+ -+static inline void io_prep_poll(struct iocb *iocb, int fd, int events) -+{ -+ memset(iocb, 0, sizeof(*iocb)); -+ iocb->aio_fildes = fd; -+ iocb->aio_lio_opcode = IO_CMD_POLL; -+ iocb->aio_reqprio = 0; -+ iocb->u.poll.events = events; -+} -+ -+static inline int io_poll(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd, int events) -+{ -+ io_prep_poll(iocb, fd, events); -+ io_set_callback(iocb, cb); -+ return io_submit(ctx, 1, &iocb); -+} -+ -+static inline void io_prep_fsync(struct iocb *iocb, int fd) -+{ -+ memset(iocb, 0, sizeof(*iocb)); -+ iocb->aio_fildes = fd; -+ iocb->aio_lio_opcode = IO_CMD_FSYNC; -+ iocb->aio_reqprio = 0; -+} -+ -+static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd) -+{ -+ io_prep_fsync(iocb, fd); -+ io_set_callback(iocb, cb); -+ return io_submit(ctx, 1, &iocb); -+} -+ -+static inline void io_prep_fdsync(struct iocb *iocb, int fd) -+{ -+ memset(iocb, 0, sizeof(*iocb)); -+ iocb->aio_fildes = fd; -+ iocb->aio_lio_opcode = IO_CMD_FDSYNC; -+ iocb->aio_reqprio = 0; -+} -+ -+static inline int io_fdsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd) -+{ -+ io_prep_fdsync(iocb, fd); -+ io_set_callback(iocb, cb); -+ return io_submit(ctx, 1, &iocb); -+} -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __LIBAIO_H */ -diff --git a/libmultipath/config.c b/libmultipath/config.c -index a39af8a..1dfc18c 100644 ---- a/libmultipath/config.c -+++ b/libmultipath/config.c -@@ -366,12 +366,15 @@ load_config (char * file) - /* - * read the config file - */ -+ set_current_keywords(&conf->keywords); -+ alloc_keywords(); - if (filepresent(file)) { -- set_current_keywords(&conf->keywords); - if (init_data(file, init_keywords)) { - condlog(0, "error parsing config file"); - goto out; - } -+ } else { -+ init_keywords(); - } - - /* -diff --git a/libmultipath/configure.c b/libmultipath/configure.c -index 9632fb4..a5bad4c 100644 ---- a/libmultipath/configure.c -+++ b/libmultipath/configure.c -@@ -324,7 +324,6 @@ domap (struct multipath * mpp) - mpp->alias); - return DOMAP_RETRY; - } -- dm_shut_log(); - - if (dm_map_present(mpp->alias)) - break; -@@ -345,7 +344,6 @@ domap (struct multipath * mpp) - } - - lock_multipath(mpp, 0); -- dm_restore_log(); - break; - - case ACT_RELOAD: -diff --git a/libmultipath/debug.c b/libmultipath/debug.c -index fa06cbd..05dfb06 100644 ---- a/libmultipath/debug.c -+++ b/libmultipath/debug.c -@@ -14,7 +14,7 @@ - #include "vector.h" - #include "config.h" - --void dlog (int sink, int prio, char * fmt, ...) -+void dlog (int sink, int prio, const char * fmt, ...) - { - va_list ap; - int thres; -diff --git a/libmultipath/debug.h b/libmultipath/debug.h -index 74ed531..082fff1 100644 ---- a/libmultipath/debug.h -+++ b/libmultipath/debug.h -@@ -1,4 +1,4 @@ --void dlog (int sink, int prio, char * fmt, ...) -+void dlog (int sink, int prio, const char * fmt, ...) - __attribute__((format(printf, 3, 4))); - - #if DAEMON -diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c -index dece079..d762cc1 100644 ---- a/libmultipath/devmapper.c -+++ b/libmultipath/devmapper.c -@@ -20,6 +20,13 @@ - #include "debug.h" - #include "memory.h" - #include "devmapper.h" -+#include "config.h" -+ -+#if DAEMON -+#include "log_pthread.h" -+#include -+#include -+#endif - - #define MAX_WAIT 5 - #define LOOPS_PER_SEC 5 -@@ -28,21 +35,50 @@ - #define UUID_PREFIX_LEN 6 - - static void --dm_dummy_log (int level, const char *file, int line, const char *f, ...) -+dm_write_log (int level, const char *file, int line, const char *f, ...) - { -- return; --} -+ va_list ap; -+ int thres; -+ -+ if (level > 6) -+ level = 6; -+ -+ thres = (conf) ? conf->verbosity : 0; -+ if (thres <= 3 || level > thres) -+ return; -+ -+ va_start(ap, f); -+#if DAEMON -+ if (!logsink) { -+ time_t t = time(NULL); -+ struct tm *tb = localtime(&t); -+ char buff[16]; -+ -+ strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb); -+ buff[sizeof(buff)-1] = '\0'; -+ -+ fprintf(stdout, "%s | ", buff); -+ fprintf(stdout, "libdevmapper: %s(%i): ", file, line); -+ vfprintf(stdout, f, ap); -+ fprintf(stdout, "\n"); -+ } else { -+ condlog(level, "libdevmapper: %s(%i): ", file, line); -+ log_safe(level + 3, f, ap); -+ } -+#else -+ fprintf(stdout, "libdevmapper: %s(%i): ", file, line); -+ vfprintf(stdout, f, ap); -+ fprintf(stdout, "\n"); -+#endif -+ va_end(ap); - --void --dm_restore_log (void) --{ -- dm_log_init(NULL); -+ return; - } - --void --dm_shut_log (void) --{ -- dm_log_init(&dm_dummy_log); -+extern void -+dm_init(void) { -+ dm_log_init(&dm_write_log); -+ dm_log_init_verbose(conf ? conf->verbosity + 3 : 0); - } - - static int -@@ -764,9 +800,7 @@ dm_mapname(int major, int minor) - * daemon uev_trigger -> uev_add_map - */ - while (--loop) { -- dm_shut_log(); - r = dm_task_run(dmt); -- dm_restore_log(); - - if (r) - break; -diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h -index 59afd01..8438034 100644 ---- a/libmultipath/devmapper.h -+++ b/libmultipath/devmapper.h -@@ -1,5 +1,4 @@ --void dm_shut_log(void); --void dm_restore_log(void); -+void dm_init(void); - int dm_prereq (char *); - int dm_simplecmd (int, const char *); - int dm_addmap (int, const char *, const char *, const char *, -diff --git a/libmultipath/dict.c b/libmultipath/dict.c -index c705cc6..4572a7d 100644 ---- a/libmultipath/dict.c -+++ b/libmultipath/dict.c -@@ -270,7 +270,7 @@ blacklist_exceptions_handler(vector strv - conf->elist_wwid = vector_alloc(); - conf->elist_device = vector_alloc(); - -- if (!conf->elist_devnode || !conf->elist_wwid || !conf->blist_device) -+ if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device) - return 1; - - return 0; -diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c -index df6f5aa..d5b227f 100644 ---- a/libmultipath/hwtable.c -+++ b/libmultipath/hwtable.c -@@ -63,11 +63,11 @@ static struct hwentry default_hw[] = { - .vendor = "DEC", - .product = "HSG80", - .getuid = DEFAULT_GETUID, -- .getprio = NULL, -- .features = DEFAULT_FEATURES, -- .hwhandler = "1 hp_sw", -+ .getprio = "mpath_prio_hp_sw /dev/%n", -+ .features = "1 queue_if_no_path", -+ .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -- .pgpolicy = GROUP_BY_SERIAL, -+ .pgpolicy = GROUP_BY_PRIO, - .pgfailback = FAILBACK_UNDEF, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, -@@ -75,61 +75,62 @@ static struct hwentry default_hw[] = { - .checker_name = HP_SW, - }, - { -- .vendor = "(COMPAQ|HP)", -- .product = "(MSA|HSV)1.*", -+ .vendor = "HP", -+ .product = "A6189A", - .getuid = DEFAULT_GETUID, - .getprio = NULL, - .features = DEFAULT_FEATURES, -- .hwhandler = "1 hp_sw", -+ .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, - .pgpolicy = MULTIBUS, - .pgfailback = FAILBACK_UNDEF, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, - .minio = DEFAULT_MINIO, -- .checker_name = HP_SW, -+ .checker_name = READSECTOR0, - }, - { -- .vendor = "HP", -- .product = "A6189A", -+ /* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */ -+ .vendor = "(COMPAQ|HP)", -+ .product = "(MSA|HSV)1.0.*", - .getuid = DEFAULT_GETUID, -- .getprio = NULL, -- .features = DEFAULT_FEATURES, -+ .getprio = "mpath_prio_hp_sw /dev/%n", -+ .features = "1 queue_if_no_path", - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -- .pgpolicy = MULTIBUS, -+ .pgpolicy = GROUP_BY_PRIO, - .pgfailback = FAILBACK_UNDEF, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, - .minio = DEFAULT_MINIO, -- .checker_name = READSECTOR0, -+ .checker_name = HP_SW, - }, - { -+ /* MSA 1000/1500 with new firmware */ - .vendor = "HP", -- .product = "HSV20.*", -- .revision = "[123].*", -+ .product = "MSA VOLUME", - .getuid = DEFAULT_GETUID, -- .getprio = NULL, -+ .getprio = "mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -- .pgpolicy = MULTIBUS, -- .pgfailback = FAILBACK_UNDEF, -+ .pgpolicy = GROUP_BY_PRIO, -+ .pgfailback = -FAILBACK_IMMEDIATE, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, - .minio = DEFAULT_MINIO, -- .checker_name = HP_SW, -+ .checker_name = TUR, - }, - { -- .vendor = "HP", -- .product = "HSV20.*", -- .revision = "[^123].*", -+ /* EVA 3000/5000 with new firmware */ -+ .vendor = "(COMPAQ|HP)", -+ .product = "(MSA|HSV)1.1.*", - .getuid = DEFAULT_GETUID, -- .getprio = "/sbin/mpath_prio_alua /dev/%n", -+ .getprio = "mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -- .pgpolicy = MULTIBUS, -+ .pgpolicy = GROUP_BY_PRIO, - .pgfailback = -FAILBACK_IMMEDIATE, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, -@@ -137,15 +138,16 @@ static struct hwentry default_hw[] = { - .checker_name = TUR, - }, - { -+ /* EVA 4000/6000/8000 */ - .vendor = "HP", -- .product = "HSV21.*", -+ .product = "HSV2.*", - .getuid = DEFAULT_GETUID, -- .getprio = "/sbin/mpath_prio_alua /dev/%n", -+ .getprio = "mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, - .pgpolicy = GROUP_BY_PRIO, -- .pgfailback = FAILBACK_UNDEF, -+ .pgfailback = -FAILBACK_IMMEDIATE, - .rr_weight = RR_WEIGHT_NONE, - .no_path_retry = NO_PATH_RETRY_UNDEF, - .minio = DEFAULT_MINIO, -@@ -404,9 +406,9 @@ static struct hwentry default_hw[] = { - .vendor = "IBM", - .product = "S/390 DASD ECKD", - .bl_product = "S/390.*", -- .getuid = "/sbin/dasd_id /dev/%n", -+ .getuid = "dasdinfo -u -b %n", - .getprio = NULL, -- .features = DEFAULT_FEATURES, -+ .features = "1 queue_if_no_path", - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, - .pgpolicy = MULTIBUS, -@@ -511,9 +513,24 @@ static struct hwentry default_hw[] = { - .pgpolicy = GROUP_BY_PRIO, - .pgfailback = -FAILBACK_IMMEDIATE, - .rr_weight = RR_WEIGHT_NONE, -- .no_path_retry = NO_PATH_RETRY_UNDEF, -+ .no_path_retry = NO_PATH_RETRY_QUEUE, - .minio = DEFAULT_MINIO, -- .checker_name = TUR, -+ .checker_name = RDAC, -+ }, -+ { -+ .vendor = "SGI", -+ .product = "IS.*", -+ .getuid = DEFAULT_GETUID, -+ .getprio = "mpath_prio_tpc /dev/%n", -+ .features = DEFAULT_FEATURES, -+ .hwhandler = DEFAULT_HWHANDLER, -+ .selector = DEFAULT_SELECTOR, -+ .pgpolicy = GROUP_BY_PRIO, -+ .pgfailback = -FAILBACK_IMMEDIATE, -+ .rr_weight = RR_WEIGHT_NONE, -+ .no_path_retry = NO_PATH_RETRY_QUEUE, -+ .minio = DEFAULT_MINIO, -+ .checker_name = RDAC, - }, - /* - * STK arrays -diff --git a/libmultipath/log.c b/libmultipath/log.c -index 8b339d7..90e4d1f 100644 ---- a/libmultipath/log.c -+++ b/libmultipath/log.c -@@ -118,6 +118,11 @@ int log_enqueue (int prio, const char * - /* not enough space on tail : rewind */ - if (la->head <= la->tail && len > (la->end - la->tail)) { - logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail); -+ if (la->head == la->start ) { -+ logdbg(stderr, "enqueue: can not rewind tail, drop msg\n"); -+ la->tail = lastmsg; -+ return 1; /* can't reuse */ -+ } - la->tail = la->start; - - if (la->empty) -diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c -index f98cfa4..5a82b6a 100644 ---- a/libmultipath/log_pthread.c -+++ b/libmultipath/log_pthread.c -@@ -12,7 +12,7 @@ - #include "log_pthread.h" - #include "log.h" - --void log_safe (int prio, char * fmt, va_list ap) -+void log_safe (int prio, const char * fmt, va_list ap) - { - pthread_mutex_lock(logq_lock); - //va_start(ap, fmt); -diff --git a/libmultipath/log_pthread.h b/libmultipath/log_pthread.h -index 7c902c7..2b18f59 100644 ---- a/libmultipath/log_pthread.h -+++ b/libmultipath/log_pthread.h -@@ -7,7 +7,7 @@ pthread_mutex_t *logq_lock; - pthread_mutex_t *logev_lock; - pthread_cond_t *logev_cond; - --void log_safe(int prio, char * fmt, va_list ap); -+void log_safe(int prio, const char * fmt, va_list ap); - void log_thread_start(void); - void log_thread_stop(void); - -diff --git a/libmultipath/parser.c b/libmultipath/parser.c -index f9c555e..5302970 100644 ---- a/libmultipath/parser.c -+++ b/libmultipath/parser.c -@@ -455,16 +455,23 @@ process_stream(vector keywords) - return r; - } - -+int alloc_keywords(void) -+{ -+ if (!keywords) -+ keywords = vector_alloc(); -+ -+ if (!keywords) -+ return 1; -+ -+ return 0; -+} -+ - /* Data initialization */ - int - init_data(char *conf_file, void (*init_keywords) (void)) - { - int r; - -- if (!keywords) -- keywords = vector_alloc(); -- if (!keywords) -- return 1; - stream = fopen(conf_file, "r"); - if (!stream) { - syslog(LOG_WARNING, "Configuration file open problem"); -diff --git a/libmultipath/parser.h b/libmultipath/parser.h -index 95d4e6f..8496684 100644 ---- a/libmultipath/parser.h -+++ b/libmultipath/parser.h -@@ -74,6 +74,7 @@ extern vector read_value_block(void); - extern int alloc_value_block(vector strvec, void (*alloc_func) (vector)); - extern void *set_value(vector strvec); - extern int process_stream(vector keywords); -+extern int alloc_keywords(void); - extern int init_data(char *conf_file, void (*init_keywords) (void)); - extern struct keyword * find_keyword(vector v, char * name); - void set_current_keywords (vector *k); -diff --git a/libmultipath/print.c b/libmultipath/print.c -index e50f37d..dc8af48 100644 ---- a/libmultipath/print.c -+++ b/libmultipath/print.c -@@ -734,7 +734,7 @@ snprint_hwentry (char * buff, int len, s - if (fwd > len) - return len; - iterate_sub_keywords(rootkw, kw, i) { -- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n", -+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k \"%v\"\n", - kw, hwe); - if (fwd > len) - return len; -diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c -index 53b7e17..a4a996a 100644 ---- a/libmultipath/structs_vec.c -+++ b/libmultipath/structs_vec.c -@@ -16,7 +16,6 @@ - #include "discovery.h" - #include "waiter.h" - -- - /* - * creates or updates mpp->paths reading mpp->pg - */ -@@ -118,6 +117,8 @@ remove_map (struct multipath * mpp, stru - { - int i; - -+ condlog(4, "%s: remove multipath map", mpp->alias); -+ - /* - * stop the DM event waiter thread - */ -@@ -245,8 +246,17 @@ extern int - setup_multipath (struct vectors * vecs, struct multipath * mpp) - { - retry: -- if (dm_get_info(mpp->alias, &mpp->dmi)) -+ if (dm_get_info(mpp->alias, &mpp->dmi)) { -+ /* Error accessing table */ -+ condlog(3, "%s: cannot access table", mpp->alias); -+ goto out; -+ } -+ -+ if (!dm_map_present(mpp->alias)) { -+ /* Table has been removed */ -+ condlog(3, "%s: table does not exist", mpp->alias); - goto out; -+ } - - set_multipath_wwid(mpp); - mpp->mpe = find_mpe(mpp->wwid); -@@ -270,6 +280,7 @@ retry: - #endif - goto retry; - } -+ condlog(0, "%s: failed to setup multipath", mpp->alias); - goto out; - } - -@@ -282,7 +293,6 @@ retry: - - return 0; - out: -- condlog(0, "%s: failed to setup multipath", mpp->alias); - remove_map(mpp, vecs, NULL, 1); - return 1; - } -@@ -390,18 +400,19 @@ int update_multipath (struct vectors *ve - struct pathgroup *pgp; - struct path *pp; - int i, j; -- int r = 1; - - mpp = find_mp_by_alias(vecs->mpvec, mapname); - -- if (!mpp) -- goto out; -+ if (!mpp) { -+ condlog(3, "%s: multipath map not found\n", mapname); -+ return 2; -+ } - - free_pgvec(mpp->pg, KEEP_PATHS); - mpp->pg = NULL; - - if (setup_multipath(vecs, mpp)) -- goto out; /* mpp freed in setup_multipath */ -+ return 1; /* mpp freed in setup_multipath */ - - /* - * compare checkers states with DM states -@@ -429,11 +440,8 @@ int update_multipath (struct vectors *ve - } - } - } -- r = 0; --out: -- if (r) -- condlog(0, "failed to update multipath"); -- return r; -+ -+ return 0; - } - - /* -diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c -index 75ed90c..d7af0d1 100644 ---- a/libmultipath/waiter.c -+++ b/libmultipath/waiter.c -@@ -117,15 +117,11 @@ int waiteventloop (struct event_thread * - /* accept wait interruption */ - set = unblock_signals(); - -- /* interruption spits messages */ -- dm_shut_log(); -- - /* wait */ - r = dm_task_run(waiter->dmt); - - /* wait is over : event or interrupt */ - pthread_sigmask(SIG_SETMASK, &set, NULL); -- //dm_restore_log(); - - if (!r) /* wait interrupted by signal */ - return -1; -@@ -157,8 +153,11 @@ int waiteventloop (struct event_thread * - r = update_multipath(waiter->vecs, waiter->mapname); - lock_cleanup_pop(waiter->vecs->lock); - -- if (r) -+ if (r) { -+ condlog(2, "%s: event checker exit", -+ waiter->mapname); - return -1; /* stop the thread */ -+ } - - event_nr = dm_geteventnr(waiter->mapname); - -diff --git a/multipath/Makefile b/multipath/Makefile -index 646dfc2..947d481 100644 ---- a/multipath/Makefile -+++ b/multipath/Makefile -@@ -25,11 +25,9 @@ prepare: - - glibc: prepare $(OBJS) - $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - - klibc: prepare $(OBJS) - $(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - - $(CHECKERSLIB)-$(BUILD).a: - make -C $(checkersdir) BUILD=$(BUILD) $(BUILD) -@@ -43,12 +41,13 @@ install: - install -d $(DESTDIR)/etc/udev/rules.d - install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/ - install -d $(DESTDIR)$(mandir) -- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) -+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) -+ install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir) - - uninstall: - rm $(DESTDIR)/etc/udev/rules.d/multipath.rules - rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz -+ rm $(DESTDIR)$(mandir)/$(EXEC).8 - - clean: - rm -f core *.o $(EXEC) *.gz -diff --git a/multipath/main.c b/multipath/main.c -index 67076db..c3d0dac 100644 ---- a/multipath/main.c -+++ b/multipath/main.c -@@ -72,7 +72,7 @@ static void - usage (char * progname) - { - fprintf (stderr, VERSION_STRING); -- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n", -+ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F|-t]\n", - progname); - fprintf (stderr, - "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \ -@@ -90,6 +90,7 @@ usage (char * progname) - "\t-ll\t\tshow multipath topology (maximum info)\n" \ - "\t-f\t\tflush a multipath device map\n" \ - "\t-F\t\tflush all multipath device maps\n" \ -+ "\t-t\t\tprint internal hardware table\n" \ - "\t-p policy\tforce all maps to specified policy :\n" \ - "\t failover\t\t1 path per priority group\n" \ - "\t multibus\t\tall paths in 1 priority group\n" \ -@@ -307,6 +308,55 @@ out: - return r; - } - -+static int -+dump_config (void) -+{ -+ char * c; -+ char * reply; -+ unsigned int maxlen = 256; -+ int again = 1; -+ -+ reply = MALLOC(maxlen); -+ -+ while (again) { -+ if (!reply) -+ return 1; -+ c = reply; -+ c += snprint_defaults(c, reply + maxlen - c); -+ again = ((c - reply) == maxlen); -+ if (again) { -+ reply = REALLOC(reply, maxlen *= 2); -+ continue; -+ } -+ c += snprint_blacklist(c, reply + maxlen - c); -+ again = ((c - reply) == maxlen); -+ if (again) { -+ reply = REALLOC(reply, maxlen *= 2); -+ continue; -+ } -+ c += snprint_blacklist_except(c, reply + maxlen - c); -+ again = ((c - reply) == maxlen); -+ if (again) { -+ reply = REALLOC(reply, maxlen *= 2); -+ continue; -+ } -+ c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable); -+ again = ((c - reply) == maxlen); -+ if (again) { -+ reply = REALLOC(reply, maxlen *= 2); -+ continue; -+ } -+ c += snprint_mptable(c, reply + maxlen - c, conf->mptable); -+ again = ((c - reply) == maxlen); -+ if (again) -+ reply = REALLOC(reply, maxlen *= 2); -+ } -+ -+ printf("%s", reply); -+ FREE(reply); -+ return 0; -+} -+ - int - main (int argc, char *argv[]) - { -@@ -330,7 +380,7 @@ main (int argc, char *argv[]) - if (load_config(DEFAULT_CONFIGFILE)) - exit(1); - -- while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) { -+ while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:t")) != EOF ) { - switch(arg) { - case 1: printf("optarg : %s\n",optarg); - break; -@@ -373,6 +423,9 @@ main (int argc, char *argv[]) - usage(argv[0]); - } - break; -+ case 't': -+ dump_config(); -+ goto out; - case 'h': - usage(argv[0]); - case ':': -@@ -401,6 +454,7 @@ main (int argc, char *argv[]) - conf->dev_type = DEV_DEVMAP; - - } -+ dm_init(); - - if (conf->remove == FLUSH_ONE) { - if (conf->dev_type == DEV_DEVMAP) -diff --git a/multipath/multipath.8 b/multipath/multipath.8 -index 693872b..e72cc45 100644 ---- a/multipath/multipath.8 -+++ b/multipath/multipath.8 -@@ -6,7 +6,7 @@ multipath \- Device mapper target autoco - .RB [\| \-v\ \c - .IR verbosity \|] - .RB [\| \-d \|] --.RB [\| \-h | \-l | \-ll | \-f | \-F \|] -+.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F \|] - .RB [\| \-p\ \c - .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] - .RB [\| device \|] -@@ -47,6 +47,9 @@ flush a multipath device map specified a - .B \-F - flush all unused multipath device maps - .TP -+.B \-t -+print internal hardware table to stdout -+.TP - .BI \-p " policy" - force maps to specified policy: - .RS 1.2i -@@ -76,6 +79,9 @@ is in the /dev/sdb (as shown by udev in - .I device - may alternatively be a multipath mapname - .SH "SEE ALSO" -+.BR multipathd (8), -+.BR multipath.conf (5), -+.BR kpartx (8), - .BR udev (8), - .BR dmsetup (8) - .BR hotplug (8) -diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 -new file mode 100644 -index 0000000..1c1c0db ---- /dev/null -+++ b/multipath/multipath.conf.5 -@@ -0,0 +1,384 @@ -+.TH MULTIPATH.CONF 5 "30 November 2006" -+.SH NAME -+multipath.conf \- multipath daemon configuration file -+.SH DESCRIPTION -+.B "multipath.conf" -+is the configuration file for the multipath daemon. It is used to -+overwrite the built-in configuration table of \fBmultipathd\fP. -+Any line whose first non-white-space character is a '#' is considered -+a comment line. Empty lines are ignored. -+.SH SYNTAX -+The configuration file contains entries of the form: -+.RS -+.nf -+.ft B -+.sp -+
{ -+.RS -+.ft B -+ -+.I "..." -+.ft B -+ { -+.RS -+.ft B -+ -+.I "..." -+.RE -+} -+.RE -+} -+.ft R -+.fi -+.RE -+.LP -+Each \fIsection\fP contains one or more attributes or subsections. The -+recognized keywords for attributes or subsections depend on the -+section in which they occor. -+.LP -+The following \fIsection\fP keywords are recognized: -+.TP 17 -+.B defaults -+This section defines default values for attributes which are used -+whenever no specific setting is given. -+.TP -+.B blacklist -+This section defines which devices should be excluded from the -+multipath topology discovery. -+.TP -+.B blacklist_exceptions -+This section defines which devices should be included in the -+multipath topology discovery, despite being listed in the -+.I blacklist -+section. -+.TP -+.B multipaths -+This section defines the multipath topologies. They are indexed by a -+\fIWorld Wide Identifier\fR(wwid), which is the result of the -+\fIgetuid_callout\fR program. -+.TP -+.B devices -+This section defines the device-specific settings. -+.RE -+.LP -+.SH "defaults section" -+The -+.B defaults -+section recognizes the following keywords: -+.TP 17 -+.B polling_interval -+interval between two path checks in seconds; default is -+.I 5 -+.TP -+.B udev_dir -+directory where udev creates its device nodes; default is -+.I /dev -+.TP -+.B selector -+The default path selector algorithm to use; they are offered by the -+kernel multipath target. The only currently implemented is -+.I "round-robin 0" -+.TP -+.B path_grouping_policy -+The default path grouping policy to apply to unspecified -+multipaths. Possible values are -+.RS -+.TP 12 -+.B failover -+1 path per priority group -+.TP -+.B multibus -+all paths in 1 priority group -+.TP -+.B group_by_serial -+1 priority group per serial number -+.TP -+.B group_by_prio -+1 priority group per priority value. Priorities are determined by -+callout programs specified as a global, per-controller or -+per-multipath option in the configuration file. -+.TP -+.B group_by_node_name -+1 priority group per target node name. Target node names are fetched -+in /sys/class/fc_transport/target*/node_name. -+.TP -+Default value is \fImultibus\fR. -+.RE -+.TP -+.B getuid_callout -+The default program and args to callout to obtain a unique path -+identifier. Should be specified with an absolute path. Default value -+is -+.I /sbin/scsi_id -g -u -s -+.TP -+.B prio_callout -+The default program and args to callout to obtain a path priority -+value. The specified program will be executed and should return a -+numeric value specifying the relative priority of this path. Higher -+number have a higher priority. A '%n' in the command line will be expanded -+to the device name, a '%b' will be expanded to the device number in -+.I major:minor -+format. -+.I "none" -+is a valid value. Currently the following path priority programs are -+implemented: -+.RS -+.TP 12 -+.B mpath_prio_emc /dev/%n -+Generate the path priority for EMC arrays -+.TP -+.B mpath_prio_alua /dev/%n -+Generate the path priority based on the SCSI-3 ALUA settings. -+.TP -+.B mpath_prio_netapp /dev/%n -+Generate the path priority for NetApp arrays. -+.TP -+.B mpath_prio_tpc /dev/%n -+Generate the path priority for LSI/Engenio RDAC controller. -+.TP -+.B mpath_prio_hp_sw /dev/%n -+Generate the path priority for Compaq/HP controller in -+active/standby mode. -+.TP -+.B mpath_prio_hds_modular %b -+Generate the path priority for Hitachi HDS Modular storage arrays. -+.TP -+Default value is \fBnone\fR. -+.RE -+.TP -+.B features -+Specify any device-mapper features to be used. The most common of -+these features is -+.I "1 queue_if_no_path" -+Note that this can also be set via the -+.I no_path_retry -+keyword. -+.TP -+.B path_checker -+The default method used to determine the paths' state. Possible values -+are -+.RS -+.TP 12 -+.B readsector0 -+Read the first sector of the device -+.TP -+.B tur -+Issue a -+.I TEST UNIT READY -+command to the device. -+.TP -+.B emc_clariion -+Query the EMC Clariion specific EVPD page 0xC0 to determine the path -+state. -+.TP -+.B hp_sw -+Check the path state for HP storage arrays with Active/Standby firmware. -+.TP -+.B rdac -+Check the path state for LSI/Engenio RDAC storage controller. -+.TP -+.B directio -+Read the first sector with direct I/O. -+.TP -+Default value is \fIreadsector0\fR. -+.RE -+.TP -+.B failback -+Tell the daemon to manage path group failback, or not to. 0 or -+.I immediate -+means immediate failback, values >0 means deferred failback (in -+seconds). -+.I manual -+means no failback. Default value is -+.I manual -+.TP -+.B rr_min_io -+The number of IO to route to a path before switching to the next in -+the same path group. Default is -+.I 1000 -+.TP -+.B rr_weight -+If set to \fIpriorities\fR the multipath configurator will assign -+path weights as "path prio * rr_min_io". Possible values are -+.I priorities -+or -+.I uniform -+. Default is -+.I uniform -+.TP -+.B no_path_retry -+Specify the number of retries until disable queueing, or -+.I fail -+for immediate failure (no queueing), -+.I queue -+for never stop queueing. Default is 0. -+.TP -+.B user_friendly_names -+If set to -+.I yes -+, using the bindings file -+.I /var/lib/multipath/bindings -+to assign a persistent and unique alias to the multipath, in the form of mpath. -+If set to -+.I no -+use the WWID as the alias. In either case this be will -+be overriden by any specific aliases in the \fImultipaths\fR section. -+Default is -+.I no -+. -+.SH "blacklist section" -+The -+.I blacklist -+section is used to exclude specific device from inclusion in the -+multipath topology. It is most commonly used to exclude local disks or -+LUNs for the array controller. -+.LP -+The following keywords are recognized: -+.TP 17 -+.B wwid -+The \fIWorld Wide Identification\fR of a device. -+.TP -+.B devnode -+Regular expression of the device nodes to be excluded. -+.TP -+.B device -+Subsection for the device description. This subsection recognizes the -+.I vendor -+and -+.I product -+keywords. For a full description of these keywords please see the -+.I devices -+section description. -+.SH "blacklist_exceptions section" -+The -+.I blacklist_exceptions -+section is used to revert the actions of the -+.I blacklist -+section, ie to include specific device in the -+multipath topology. This allows to selectively include devices which -+would normally be excluded via the -+.I blacklist -+section. -+.LP -+The following keywords are recognized: -+.TP 17 -+.B wwid -+The \fIWorld Wide Identification\fR of a device. -+.TP -+.B devnode -+Regular expression of the device nodes to be excluded. -+.TP -+.B device -+Subsection for the device description. This subsection recognizes the -+.I vendor -+and -+.I product -+keywords. For a full description of these keywords please see the -+.I devices -+section description. -+.SH "multipaths section" -+The only recognized attribute for the -+.B multipaths -+section is the -+.I multipath -+subsection. -+.LP -+The -+.B multipath -+subsection recognizes the following attributes: -+.TP 17 -+.B wwid -+Index of the container. Mandatory for this subsection. -+.TP -+.B alias -+(Optional) symbolic name for the multipath map. -+.LP -+The following attributes are optional; if not set the default values -+are taken from the -+.I defaults -+section: -+.sp 1 -+.PD .1v -+.RS -+.TP 18 -+.B path_grouping_policy -+.TP -+.B path_checker -+.TP -+.B path_selector -+.TP -+.B failback -+.TP -+.B no_path_retry -+.TP -+.B rr_min_io -+.RE -+.PD -+.LP -+.SH "devices section" -+The only recognized attribute for the -+.B devices -+section is the -+.I device -+subsection. -+.LP -+The -+.I device -+subsection recognizes the following attributes: -+.TP 17 -+.B vendor -+(Mandatory) Vendor identifier -+.TP -+.B product -+(Mandatory) Product identifier -+.TP -+.B product_blacklist -+Product strings to blacklist for this vendor -+.TP -+.B hardware_handler -+(Optional) The hardware handler to use for this device type. -+The following hardware handler are implemented: -+.RS -+.TP 12 -+.B 1 emc -+Hardware handler for EMC storage arrays. -+.RE -+.LP -+The following attributes are optional; if not set the default values -+are taken from the -+.I defaults -+section: -+.sp 1 -+.PD .1v -+.RS -+.TP 18 -+.B path_grouping_policy -+.TP -+.B getuid_callout -+.TP -+.B path_selector -+.TP -+.B path_checker -+.TP -+.B features -+.TP -+.B prio_callout -+.TP -+.B failback -+.TP -+.B rr_weight -+.TP -+.B no_path_retry -+.TP -+.B rr_min_io -+.RE -+.PD -+.LP -+.SH "SEE ALSO" -+.BR udev (8), -+.BR dmsetup (8) -+.BR multipath (8) -+.BR multipathd (8) -+.SH AUTHORS -+.B multipath -+was developed by Christophe Varoqui, and others. -diff --git a/multipathd/Makefile b/multipathd/Makefile -index 8ad25ee..da351dc 100644 ---- a/multipathd/Makefile -+++ b/multipathd/Makefile -@@ -35,7 +35,6 @@ klibc: - - $(EXEC): clean $(OBJS) - $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - - $(CHECKERSLIB)-glibc.a: - $(MAKE) -C $(checkersdir) BUILD=glibc glibc -@@ -48,12 +47,12 @@ install: - install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) - install -d $(DESTDIR)$(rcdir) - install -d $(DESTDIR)$(mandir) -- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) -+ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) - - uninstall: - rm -f $(DESTDIR)$(bindir)/$(EXEC) - rm -f $(DESTDIR)$(rcdir)/$(EXEC) -- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz -+ rm -f $(DESTDIR)$(mandir)/$(EXEC).8 - - clean: - $(MAKE) -C $(multipathdir) prepare DAEMON=1 -diff --git a/multipathd/cli.c b/multipathd/cli.c -index d786eef..587514f 100644 ---- a/multipathd/cli.c -+++ b/multipathd/cli.c -@@ -498,7 +498,7 @@ key_generator (const char * str, int sta - /* - * Loop through keywords for completion candidates - */ -- vector_foreach_slot_after (keys, kw, index) { -+ vector_foreach_slot (keys, kw, index) { - if (!strncmp(kw->str, str, len)) { - /* - * Discard keywords already in the command line -diff --git a/multipathd/main.c b/multipathd/main.c -index f2f9a96..94b0b95 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -225,6 +225,8 @@ ev_add_map (char * devname, struct vecto - int map_present; - int r = 1; - -+ /* libsysfs seems to forget to terminate the string... */ -+ memset(dev_t, 0, BLK_DEV_SIZE); - if (sscanf(devname, "dm-%d", &minor) == 1 && - !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) && - sscanf(dev_t, "%d:%d", &major, &minor) == 2) -@@ -646,10 +648,12 @@ uev_trigger (struct uevent * uev, void * - lock(vecs->lock); - - /* -- * device map add/remove event -+ * device map event -+ * Add events are ignored here as the tables -+ * are not fully initialised then. - */ - if (!strncmp(devname, "dm-", 3)) { -- if (!strncmp(uev->action, "add", 3)) { -+ if (!strncmp(uev->action, "change", 6)) { - r = uev_add_map(devname, vecs); - goto out; - } -@@ -1397,6 +1401,7 @@ main (int argc, char *argv[]) - int err; - - logsink = 1; -+ dm_init(); - - if (getuid() != 0) { - fprintf(stderr, "need to be root\n"); -diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile -index 983ffe3..6c58529 100644 ---- a/path_priority/pp_alua/Makefile -+++ b/path_priority/pp_alua/Makefile -@@ -35,20 +35,17 @@ glibc: $(OBJS) - klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - --install: $(BUILD) $(EXEC).8.gz -+install: $(EXEC) $(EXEC).8 - $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -- $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz -+ $(INSTALL) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/$(EXEC).8 - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz -+ rm $(DESTDIR)$(mandir)/$(EXEC).8 - - clean: - rm -f *.o *.gz $(EXEC) - --$(EXEC).8.gz: $(EXEC).8 -- $(GZIP) $< >$@ -- - main.o: main.c rtpg.h spc3.h - - rtpg.o: rtpg.c rtpg.h spc3.h -diff --git a/path_priority/pp_emc/pp_emc.c b/path_priority/pp_emc/pp_emc.c -index dd58424..4031720 100644 ---- a/path_priority/pp_emc/pp_emc.c -+++ b/path_priority/pp_emc/pp_emc.c -@@ -60,8 +60,12 @@ int emc_clariion_prio(const char *dev) - - if ( /* Effective initiator type */ - sense_buffer[27] != 0x03 -- /* Failover mode should be set to 1 */ -- || (sense_buffer[28] & 0x07) != 0x04 -+ /* -+ * Failover mode should be set to 1 (PNR failover mode) -+ * or 4 (ALUA failover mode). -+ */ -+ || (((sense_buffer[28] & 0x07) != 0x04) && -+ ((sense_buffer[28] & 0x07) != 0x06)) - /* Arraycommpath should be set to 1 */ - || (sense_buffer[30] & 0x04) != 0x04) { - fprintf(stderr, "Path not correctly configured for failover"); -diff --git a/path_priority/pp_hp_sw/Makefile b/path_priority/pp_hp_sw/Makefile -new file mode 100644 -index 0000000..e7debf5 ---- /dev/null -+++ b/path_priority/pp_hp_sw/Makefile -@@ -0,0 +1,25 @@ -+EXEC = mpath_prio_hp_sw -+BUILD = glibc -+OBJS = pp_hp_sw.o -+ -+TOPDIR = ../.. -+include $(TOPDIR)/Makefile.inc -+ -+all: $(BUILD) -+ -+glibc: $(OBJS) -+ $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS) -+ -+klibc: $(OBJS) -+ $(CC) -static -o $(EXEC) $(OBJS) -+ -+install: $(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ -+uninstall: -+ rm $(DESTDIR)$(bindir)/$(EXEC) -+clean: -+ rm -f *.o $(EXEC) -+ -+%.o: %.c -+ $(CC) $(CFLAGS) -c -o $@ $< -diff --git a/path_priority/pp_hp_sw/pp_hp_sw.c b/path_priority/pp_hp_sw/pp_hp_sw.c -new file mode 100644 -index 0000000..e4a18b1 ---- /dev/null -+++ b/path_priority/pp_hp_sw/pp_hp_sw.c -@@ -0,0 +1,119 @@ -+/* -+ * Path priority checker for HP active/standby controller -+ * -+ * Check the path state and sort them into groups. -+ * There is actually a preferred path in the controller; -+ * we should ask HP on how to retrieve that information. -+ */ -+#include -+#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/multipath-tools-suse-update b/multipath-tools-suse-update index 2b36c34..36699c7 100644 --- a/multipath-tools-suse-update +++ b/multipath-tools-suse-update @@ -1,66 +1,8 @@ - Makefile.inc | 1 - - devmap_name/Makefile | 5 +- - kpartx/Makefile | 16 +- - kpartx/bsd.c | 39 +++- - kpartx/devmapper.c | 32 +++- - kpartx/devmapper.h | 1 + - kpartx/dos.c | 7 +- - kpartx/kpartx.c | 158 +++++++++--- - kpartx/kpartx.h | 4 + - kpartx/kpartx.rules | 36 +++ - kpartx/kpartx_id | 93 +++++++ - kpartx/sun.c | 131 ++++++++++ - libcheckers/Makefile | 4 +- - libmultipath/Makefile | 8 +- - libmultipath/config.h | 1 + - libmultipath/configure.c | 4 +- - libmultipath/discovery.c | 422 ++++++++++++------------------- - libmultipath/discovery.h | 7 +- - libmultipath/hwtable.c | 14 +- - libmultipath/list.h | 289 +++++++++++++++++++++ - libmultipath/print.c | 47 ++-- - libmultipath/structs.h | 15 +- - libmultipath/structs_vec.c | 7 +- - libmultipath/sysfs.c | 405 +++++++++++++++++++++++++++++ - libmultipath/sysfs.h | 20 ++ - libmultipath/uevent.c | 99 +++++--- - libmultipath/util.c | 52 ++++ - libmultipath/util.h | 4 +- - multipath/Makefile | 12 +- - multipath/main.c | 11 +- - multipath/multipath.init.suse | 104 ++++++++ - multipath/multipath.rules | 19 +- - multipathd/Makefile | 7 +- - multipathd/cli_handlers.c | 17 ++- - multipathd/main.c | 92 +++---- - multipathd/main.h | 2 +- - multipathd/multipathd.init.suse | 155 +++++++++++ - path_priority/pp_alua/Makefile | 3 +- - path_priority/pp_balance_units/Makefile | 6 +- - path_priority/pp_emc/Makefile | 2 +- - path_priority/pp_hds_modular/Makefile | 2 +- - path_priority/pp_netapp/Makefile | 2 +- - path_priority/pp_random/Makefile | 2 +- - path_priority/pp_tpc/Makefile | 2 +- - 44 files changed, 1881 insertions(+), 478 deletions(-) - -diff --git a/Makefile.inc b/Makefile.inc -index fe6cbdf..786565c 100644 ---- a/Makefile.inc -+++ b/Makefile.inc -@@ -17,7 +17,6 @@ ifeq ($(strip $(BUILD)),klibc) - CC = klcc - klibcdir = /usr/lib/klibc - libdm = $(klibcdir)/lib/libdevmapper.a -- libsysfs = $(klibcdir)/lib/libsysfs.a - endif - - prefix = diff --git a/devmap_name/Makefile b/devmap_name/Makefile -index 8b0c678..57051d9 100644 +index d8d8b09..57051d9 100644 --- a/devmap_name/Makefile +++ b/devmap_name/Makefile -@@ -18,7 +18,7 @@ EXEC = devmap_name +@@ -18,25 +18,22 @@ EXEC = devmap_name all: $(BUILD) prepare: @@ -69,34 +11,31 @@ index 8b0c678..57051d9 100644 glibc: prepare $(OBJS) $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -@@ -34,7 +34,6 @@ install: $(EXEC) $(EXEC).8 +- $(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) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) uninstall: rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8 +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz clean: - rm -f core *.o $(EXEC) *.gz + rm -f core *.o $(EXEC) diff --git a/kpartx/Makefile b/kpartx/Makefile -index 522a6a0..a8ea2be 100644 +index b4cca6c..d970d29 100644 --- a/kpartx/Makefile +++ b/kpartx/Makefile -@@ -10,11 +10,11 @@ CFLAGS += -I. -D_LARGEFILE64_SOURCE - - 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 \ -+ 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 \ -+ 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 - -@@ -23,7 +23,7 @@ EXEC = kpartx +@@ -23,32 +23,29 @@ EXEC = kpartx all: $(BUILD) prepare: @@ -105,20 +44,28 @@ index 522a6a0..a8ea2be 100644 glibc: prepare $(OBJS) $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -@@ -34,15 +34,17 @@ klibc: prepare $(OBJS) +- $(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: $(EXEC) kpartx_id $(EXEC).8 install -d $(DESTDIR)$(bindir) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir) -+ install -m 755 kpartx_id $(DESTDIR)$(bindir) - install -d $(DESTDIR)$(mandir) - install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) -+ install -d $(DESTDIR)/etc/udev/rules.d + $(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 -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/70-kpartx.rules + install -d $(DESTDIR)$(mandir) +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) uninstall: rm -f $(DESTDIR)$(bindir)/$(EXEC) @@ -127,211 +74,11 @@ index 522a6a0..a8ea2be 100644 clean: - rm -f core *.o $(EXEC) *.gz + rm -f core *.o $(EXEC) -diff --git a/kpartx/bsd.c b/kpartx/bsd.c -index 3ae2dc4..f87175e 100644 ---- a/kpartx/bsd.c -+++ b/kpartx/bsd.c -@@ -10,7 +10,7 @@ struct bsd_disklabel { - short int d_type; /* drive type */ - short int d_subtype; /* controller/d_type specific */ - char d_typename[16]; /* type name, e.g. "eagle" */ -- char d_packname[16]; /* pack identifier */ -+ char d_packname[16]; /* pack identifier */ - unsigned int d_secsize; /* # of bytes per sector */ - unsigned int d_nsectors; /* # of data sectors per track */ - unsigned int d_ntracks; /* # of tracks per cylinder */ -@@ -50,12 +50,12 @@ int - read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) { - struct bsd_disklabel *l; - struct bsd_partition *p; -- unsigned int offset = all.start; -+ unsigned int offset = all.start, end; - int max_partitions; - char *bp; -- int n = 0; -+ int n = 0, i, j; - -- bp = getblock(fd, offset+1); /* 1 sector suffices */ -+ bp = getblock(fd, offset+1); /* 1 sector suffices */ - if (bp == NULL) - return -1; - -@@ -79,5 +79,36 @@ read_bsd_pt(int fd, struct slice all, st - break; - } - } -+ /* -+ * Convention has it that the bsd disklabel will always have -+ * the 'c' partition spanning the entire disk. -+ * So we have to check for contained slices. -+ */ -+ for(i = 0; i < n; i++) { -+ if (sp[i].size == 0) -+ continue; -+ -+ end = sp[i].start + sp[i].size; -+ for(j = 0; j < n; j ++) { -+ if ( i == j ) -+ continue; -+ if (sp[j].size == 0) -+ continue; -+ -+ if (sp[i].start < sp[j].start) { -+ if (end > sp[j].start && -+ end < sp[j].start + sp[j].size) { -+ /* Invalid slice */ -+ fprintf(stderr, -+ "bsd_disklabel: slice %d overlaps with %d\n", i , j); -+ sp[i].size = 0; -+ } -+ } else { -+ if (end <= sp[j].start + sp[j].size) { -+ sp[i].container = j + 1; -+ } -+ } -+ } -+ } - return n; - } -diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c -index 4b228ed..6e3e198 100644 ---- a/kpartx/devmapper.c -+++ b/kpartx/devmapper.c -@@ -200,7 +200,8 @@ char * - dm_mapuuid(int major, int minor) - { - struct dm_task *dmt; -- char *tmp, *uuid = NULL; -+ const char *tmp; -+ char *uuid = NULL; - - if (!(dmt = dm_task_create(DM_DEVICE_INFO))) - return NULL; -@@ -219,3 +220,32 @@ out: - dm_task_destroy(dmt); - return uuid; - } -+ -+int -+dm_devn (char * mapname, int *major, int *minor) -+{ -+ int r = 1; -+ struct dm_task *dmt; -+ struct dm_info info; -+ -+ if (!(dmt = dm_task_create(DM_DEVICE_INFO))) -+ return 0; -+ -+ if (!dm_task_set_name(dmt, mapname)) -+ goto out; -+ -+ if (!dm_task_run(dmt)) -+ goto out; -+ -+ if (!dm_task_get_info(dmt, &info)) -+ goto out; -+ -+ *major = info.major; -+ *minor = info.minor; -+ -+ r = 0; -+out: -+ dm_task_destroy(dmt); -+ return r; -+} -+ -diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h -index e20e456..ccdbead 100644 ---- a/kpartx/devmapper.h -+++ b/kpartx/devmapper.h -@@ -6,3 +6,4 @@ int dm_map_present (char *); - char * dm_mapname(int major, int minor); - dev_t dm_get_first_dep(char *devname); - char * dm_mapuuid(int major, int minor); -+int dm_devn (char * mapname, int *major, int *minor); -diff --git a/kpartx/dos.c b/kpartx/dos.c -index a707423..1691105 100644 ---- a/kpartx/dos.c -+++ b/kpartx/dos.c -@@ -16,7 +16,7 @@ is_extended(int type) { - } - - static int --read_extended_partition(int fd, struct partition *ep, -+read_extended_partition(int fd, struct partition *ep, int en, - struct slice *sp, int ns) - { - struct partition p; -@@ -53,6 +53,7 @@ read_extended_partition(int fd, struct p - if (n < ns) { - sp[n].start = here + le32_to_cpu(p.start_sect); - sp[n].size = le32_to_cpu(p.nr_sects); -+ sp[n].container = en + 1; - n++; - } else { - fprintf(stderr, -@@ -97,9 +98,7 @@ read_dos_pt(int fd, struct slice all, st - break; - } - if (is_extended(p.sys_type)) { -- n += read_extended_partition(fd, &p, sp+n, ns-n); -- /* hide the extended partition itself */ -- sp[i].size = 0; -+ n += read_extended_partition(fd, &p, i, sp+n, ns-n); - } - } - return n; diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c -index b406b95..52dfe93 100644 +index dbe2ee2..f60e5f4 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c -@@ -79,6 +79,7 @@ initpts(void) - addpts("unixware", read_unixware_pt); - addpts("dasd", read_dasd_pt); - addpts("mac", read_mac_pt); -+ addpts("sun", read_sun_pt); - } - - static char short_opts[] = "ladgvnp:t:"; -@@ -115,7 +116,6 @@ strip_slash (char * device) - char * p = device; - - while (*(p++) != 0x0) { -- - if (*p == '/') - *p = '!'; - } -@@ -125,9 +125,9 @@ static int - find_devname_offset (char * device) - { - char *p, *q = NULL; -- -+ - p = device; -- -+ - while (*p++) - if (*p == '/') - q = p; -@@ -182,7 +182,7 @@ get_hotplug_device(void) - - int - main(int argc, char **argv){ -- int fd, i, j, k, n, op, off, arg; -+ int fd, i, j, m, n, op, off, arg, c, d; - struct slice all; - struct pt *ptp; - enum action what = LIST; -@@ -205,7 +205,7 @@ main(int argc, char **argv){ - type = device = diskdevice = NULL; - memset(&all, 0, sizeof(all)); - memset(&partname, 0, sizeof(partname)); -- -+ - /* Check whether hotplug mode. */ - progname = strrchr(argv[0], '/'); - -@@ -264,7 +264,7 @@ main(int argc, char **argv){ +@@ -265,7 +265,7 @@ main(int argc, char **argv){ } if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE)) { @@ -340,537 +87,113 @@ index b406b95..52dfe93 100644 exit(1); } -@@ -291,7 +291,7 @@ main(int argc, char **argv){ +@@ -387,10 +387,10 @@ main(int argc, char **argv){ + slices[j].minor = m++; - if (!loopdev && what == DELETE) - exit (0); -- -+ - if (!loopdev) { - loopdev = find_unused_loop_device(); - -@@ -308,7 +308,7 @@ main(int argc, char **argv){ - memset(delim, 0, DELIM_SIZE); - set_delimiter(device, delim); - } -- -+ - off = find_devname_offset(device); - - if (!loopdev) { -@@ -320,7 +320,7 @@ main(int argc, char **argv){ - - if (!uuid) - uuid = device + off; -- -+ - if (!mapname) - mapname = device + off; - -@@ -339,7 +339,7 @@ main(int argc, char **argv){ - - if (type && strcmp(type, ptp->type)) - continue; -- -+ - /* here we get partitions */ - n = ptp->fn(fd, all, slices, SIZE(slices)); - -@@ -353,30 +353,50 @@ main(int argc, char **argv){ - else - continue; - -- /* -- * test for overlap, as in the case of an extended partition -- * zero their size to avoid mapping -- */ -- for (j=0; j slices[j].start && -- slices[k].start < slices[j].start + -- slices[j].size) -- slices[j].size = 0; -- } -- } -- - switch(what) { - case LIST: -- for (j = 0; j < n; j++) { -+ for (j = 0, c = 0, m = 0; j < n; j++) { - if (slices[j].size == 0) - continue; -+ if (slices[j].container > 0) { -+ c++; -+ continue; -+ } -+ -+ slices[j].minor = m++; - - printf("%s%s%d : 0 %lu %s %lu\n", -- mapname, delim, j+1, -- (unsigned long) slices[j].size, device, -- (unsigned long) slices[j].start); -+ mapname, delim, j+1, -+ (unsigned long) slices[j].size, device, -+ (unsigned long) slices[j].start); - } -+ /* Loop to resolve contained slices */ -+ d = c; -+ while (c) { -+ for (j = 0; j < n; j++) { -+ unsigned long start; -+ int k = slices[j].container - 1; -+ -+ if (slices[j].size == 0) -+ continue; -+ if (slices[j].minor > 0) -+ continue; -+ if (slices[j].container == 0) -+ continue; -+ slices[j].minor = m++; -+ -+ start = slices[j].start - slices[k].start; -+ printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n", -+ mapname, delim, j+1, -+ (unsigned long) slices[j].size, -+ slices[k].minor, start); -+ c--; -+ } -+ /* Terminate loop if nothing more to resolve */ -+ if (d == c) -+ break; -+ } -+ - break; - - case DELETE: -@@ -401,7 +421,7 @@ main(int argc, char **argv){ - if (S_ISREG (buf.st_mode)) { - if (del_loop(device)) { - if (verbose) -- printf("can't del loop : %s\n", -+ printf("can't del loop : %s\n", - device); - exit(1); + start = slices[j].start - slices[k].start; +- printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n", ++ printf("%s%s%d : 0 %lu %s%s%d %lu\n", + mapname, delim, j+1, + (unsigned long) slices[j].size, +- slices[k].minor, start); ++ mapname, delim, k, start); + c--; } -@@ -410,17 +430,23 @@ main(int argc, char **argv){ + /* Terminate loop if nothing more to resolve */ +@@ -431,7 +431,7 @@ main(int argc, char **argv){ break; case ADD: -- for (j=0; j 0) { -+ c++; -+ continue; -+ } -+ - if (safe_sprintf(partname, "%s%s%d", - mapname, delim, j+1)) { - fprintf(stderr, "partname too small\n"); - exit(1); +@@ -477,6 +477,7 @@ main(int argc, char **argv){ + d = c; + while (c) { + for (j = 0; j < n; j++) { ++ unsigned long start; + int k = slices[j].container - 1; + + if (slices[j].size == 0) +@@ -487,7 +488,7 @@ main(int argc, char **argv){ + continue; + + /* Skip all simple slices */ +- if (k < 0) ++ if (slices[j].container == 0) + continue; + + /* Check container slice */ +@@ -502,10 +503,11 @@ main(int argc, char **argv){ + } + strip_slash(partname); + ++ start = slices[j].start - slices[k].start; + if (safe_sprintf(params, "%d:%d %lu", + slices[k].major, + slices[k].minor, +- (unsigned long)slices[j].start)) { ++ start)) { + fprintf(stderr, "params too small\n"); + exit(1); + } +@@ -524,9 +526,12 @@ main(int argc, char **argv){ + &slices[j].minor); + + if (verbose) +- printf("add map %s : 0 %lu %s %s\n", +- partname, slices[j].size, +- DM_TARGET, params); ++ printf("add map %s (%d:%d): 0 %lu %s\n", ++ partname, ++ slices[j].major, ++ slices[j].minor, ++ slices[j].size, ++ params); + c--; } - strip_slash(partname); -- -+ - if (safe_sprintf(params, "%s %lu", device, - (unsigned long)slices[j].start)) { - fprintf(stderr, "params too small\n"); -@@ -437,10 +463,74 @@ main(int argc, char **argv){ - dm_simplecmd(DM_DEVICE_RESUME, - partname); - -+ dm_devn(partname, &slices[j].major, -+ &slices[j].minor); -+ - if (verbose) -- printf("add map %s : 0 %lu %s %s\n", -- partname, slices[j].size, -- DM_TARGET, params); -+ printf("add map %s (%d:%d): 0 %lu %s %s\n", -+ partname, slices[j].major, -+ slices[j].minor, slices[j].size, -+ DM_TARGET, params); -+ } -+ /* Loop to resolve contained slices */ -+ d = c; -+ while (c) { -+ for (j = 0; j < n; j++) { -+ int k = slices[j].container - 1; -+ -+ if (slices[j].size == 0) -+ continue; -+ -+ /* Skip all existing slices */ -+ if (slices[j].minor > 0) -+ continue; -+ -+ /* Skip all simple slices */ -+ if (k < 0) -+ continue; -+ -+ /* Check container slice */ -+ if (slices[k].size == 0) -+ fprintf(stderr, "Invalid slice %d\n", -+ k); -+ -+ if (safe_sprintf(partname, "%s%s%d", -+ mapname, delim, j+1)) { -+ fprintf(stderr, "partname too small\n"); -+ exit(1); -+ } -+ strip_slash(partname); -+ -+ if (safe_sprintf(params, "%d:%d %lu", -+ slices[k].major, -+ slices[k].minor, -+ (unsigned long)slices[j].start)) { -+ fprintf(stderr, "params too small\n"); -+ exit(1); -+ } -+ -+ 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); -+ -+ dm_devn(partname, &slices[j].major, -+ &slices[j].minor); -+ -+ if (verbose) -+ printf("add map %s : 0 %lu %s %s\n", -+ partname, slices[j].size, -+ DM_TARGET, params); -+ c--; -+ } -+ /* Terminate loop */ -+ if (d == c) -+ break; - } - break; - -@@ -516,7 +606,7 @@ getblock (int fd, unsigned int secnr) { - bp->next = blockhead; - blockhead = bp; - bp->block = (char *) xmalloc(READ_SIZE); -- -+ - if (read(fd, bp->block, READ_SIZE) != READ_SIZE) { - fprintf(stderr, "read error, sector %d\n", secnr); - bp->block = NULL; -diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h -index 6a715de..9b3aeca 100644 ---- a/kpartx/kpartx.h -+++ b/kpartx/kpartx.h -@@ -22,6 +22,9 @@ - struct slice { - unsigned long start; - unsigned long size; -+ int container; -+ int major; -+ int minor; - }; - - typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns); -@@ -33,6 +36,7 @@ extern ptreader read_unixware_pt; - extern ptreader read_gpt_pt; - extern ptreader read_dasd_pt; - extern ptreader read_mac_pt; -+extern ptreader read_sun_pt; - - char *getblock(int fd, unsigned int secnr); - + /* Terminate loop */ diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules -new file mode 100644 -index 0000000..8666d45 ---- /dev/null +index f32c718..9ab9a49 100644 +--- a/kpartx/kpartx.rules +++ b/kpartx/kpartx.rules -@@ -0,0 +1,36 @@ -+# -+# persistent links for device-mapper devices -+# only hardware-backed device-mapper devices (ie multipath, dmraid, -+# and kpartx) have meaningful persistent device names -+# -+ -+KERNEL!="dm-*", GOTO="multipath_end" -+ACTION=="remove", GOTO="multipath_end" -+ -+ENV{DM_TABLE_STATE}!="LIVE", GOTO="multipath_end" -+ -+ENV{DM_UUID}=="?*", IMPORT{program}=="/sbin/kpartx_id %M %m $env{DM_UUID}" -+ -+OPTIONS="link_priority=50" -+ -+# Create persistent links for multipath tables -+ENV{DM_UUID}=="mpath-*", \ -+ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" -+ -+# Create persistent links for dmraid tables -+ENV{DM_UUID}=="mpath-*", \ -+ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" -+ -+# Create persistent links for partitions -+ENV{DM_PART}=="?*", \ -+ SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}-part$env{DM_PART}" -+ -+# Create dm tables for partitions -+ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="mpath-*", \ -+ RUN+="/sbin/kpartx -a -p -part /dev/$kernel" -+ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="dmraid-*", \ -+ RUN+="/sbin/kpartx -a -p -part /dev/$kernel" -+ -+LABEL="multipath_end" -+ -+ -diff --git a/kpartx/kpartx_id b/kpartx/kpartx_id -new file mode 100644 -index 0000000..e876b98 ---- /dev/null -+++ b/kpartx/kpartx_id -@@ -0,0 +1,93 @@ -+#!/bin/bash -+# -+# kpartx_id -+# -+# Generates ID information for device-mapper tables. -+# -+# Copyright (C) 2006 SUSE Linux Products GmbH -+# Author: -+# Hannes Reinecke -+# -+# -+# 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 script generates ID information used to generate persistent symlinks. -+# It relies on the UUID strings generated by the various programs; the name -+# of the tables are of no consequence. -+# -+# Please note that dmraid does not provide the UUIDs (yet); a patch has been -+# sent upstream but has not been accepted yet. -+# -+ -+DMSETUP=/sbin/dmsetup -+ -+MAJOR=$1 -+MINOR=$2 -+UUID=$3 -+ -+if [ -z "$MAJOR" -o -z "$MINOR" ]; then -+ echo "usage: $0 major minor" -+ exit 1; -+fi -+ -+# Device-mapper not installed; not an error -+if [ ! -x $DMSETUP ] ; then -+ exit 0 -+fi -+ -+ -+# Table UUIDs are always '-'. -+dmuuid=${UUID#*-} -+dmtbl=${UUID%%-*} -+dmpart=${dmtbl#part} -+# kpartx types are 'part' -+if [ "$dmpart" == "$dmtbl" ] ; then -+ dmpart= -+else -+ dmtbl=part -+fi -+ -+# Set the name of the table. We're only interested in dmraid, -+# multipath, and kpartx tables; everything else is ignored. -+if [ "$dmtbl" == "part" ] ; then -+ # The name of the kpartx table is the name of the parent table -+ dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid) -+ echo "DM_NAME=$dmname" -+ # We need the dependencies of the parent table to figure out -+ # the type if the parent is a multipath table -+ case "$dmuuid" in -+ mpath-*) -+ dmdeps=$($DMSETUP deps -u $dmuuid) -+ ;; -+ esac -+elif [ "$dmtbl" == "mpath" ] ; then -+ dmname=$tblname -+ # We need the dependencies of the table to figure out the type -+ dmdeps=$($DMSETUP deps -u $UUID) -+elif [ "$dmtbl" == "dmraid" ] ; then -+ dmname=$tblname -+fi -+ -+[ -n "$dmpart" ] && echo "DM_PART=$dmpart" -+ -+# Figure out the type of the map. For non-multipath maps it's -+# always 'raid'. -+if [ -n "$dmdeps" ] ; then -+ case "$dmdeps" in -+ *\(94,*) -+ echo "DM_TYPE=dasd" -+ ;; -+ *\(9*) -+ echo "DM_TYPE=raid" -+ ;; -+ *) -+ echo "DM_TYPE=scsi" -+ ;; -+ esac -+else -+ echo "DM_TYPE=raid" -+fi -+ -+exit 0 -diff --git a/kpartx/sun.c b/kpartx/sun.c -new file mode 100644 -index 0000000..3d88b21 ---- /dev/null -+++ b/kpartx/sun.c -@@ -0,0 +1,131 @@ -+/* -+ * Lifted from util-linux' partx sun.c -+ * -+ * Copyrights of the original file apply -+ * Copyright (c) 2007 Hannes Reinecke -+ */ -+#include "kpartx.h" -+#include "byteorder.h" -+#include -+#include -+#include /* time_t */ -+ -+#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */ -+#define SUN_DISK_MAXPARTITIONS 8 -+ -+struct __attribute__ ((packed)) sun_raw_part { -+ u_int32_t start_cylinder; /* where the part starts... */ -+ u_int32_t num_sectors; /* ...and it's length */ -+}; -+ -+struct __attribute__ ((packed)) sun_part_info { -+ u_int8_t spare1; -+ u_int8_t id; /* Partition type */ -+ u_int8_t spare2; -+ u_int8_t flags; /* Partition flags */ -+}; -+ -+struct __attribute__ ((packed)) sun_disk_label { -+ char info[128]; /* Informative text string */ -+ u_int8_t spare0[14]; -+ struct sun_part_info infos[SUN_DISK_MAXPARTITIONS]; -+ u_int8_t spare1[246]; /* Boot information etc. */ -+ u_int16_t rspeed; /* Disk rotational speed */ -+ u_int16_t pcylcount; /* Physical cylinder count */ -+ u_int16_t sparecyl; /* extra sects per cylinder */ -+ u_int8_t spare2[4]; /* More magic... */ -+ u_int16_t ilfact; /* Interleave factor */ -+ u_int16_t ncyl; /* Data cylinder count */ -+ u_int16_t nacyl; /* Alt. cylinder count */ -+ u_int16_t ntrks; /* Tracks per cylinder */ -+ u_int16_t nsect; /* Sectors per track */ -+ u_int8_t spare3[4]; /* Even more magic... */ -+ struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS]; -+ u_int16_t magic; /* Magic number */ -+ u_int16_t csum; /* Label xor'd checksum */ -+}; -+ -+/* Checksum Verification */ -+static int -+sun_verify_checksum (struct sun_disk_label *label) -+{ -+ u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1; -+ u_int16_t csum = 0; -+ -+ while (ush >= (u_int16_t *)label) -+ csum ^= *ush--; -+ -+ return !csum; -+} -+ -+int -+read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) { -+ struct sun_disk_label *l; -+ struct sun_raw_part *s; -+ unsigned int offset = all.start, end; -+ int i, j, n; -+ char *bp; -+ -+ bp = getblock(fd, offset); -+ if (bp == NULL) -+ return -1; -+ -+ l = (struct sun_disk_label *) bp; -+ if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC) -+ return -1; -+ -+ if (!sun_verify_checksum(l)) { -+ fprintf(stderr, "Corrupted Sun disk label\n"); -+ return -1; -+ } -+ -+ for(i=0, n=0; ipartitions[i]; -+ -+ if (s->num_sectors == 0) -+ continue; -+ if (n < ns) { -+ sp[n].start = offset + -+ be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks); -+ sp[n].size = be32_to_cpu(s->num_sectors); -+ n++; -+ } else { -+ fprintf(stderr, -+ "sun_disklabel: too many slices\n"); -+ break; -+ } -+ } -+ /* -+ * Convention has it that the SUN disklabel will always have -+ * the 'c' partition spanning the entire disk. -+ * So we have to check for contained slices. -+ */ -+ for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { -+ if (sp[i].size == 0) -+ continue; -+ -+ end = sp[i].start + sp[i].size; -+ for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) { -+ if ( i == j ) -+ continue; -+ if (sp[j].size == 0) -+ continue; -+ -+ if (sp[i].start < sp[j].start) { -+ if (end > sp[j].start && -+ end < sp[j].start + sp[j].size) { -+ /* Invalid slice */ -+ fprintf(stderr, -+ "sun_disklabel: slice %d overlaps with %d\n", i , j); -+ sp[i].size = 0; -+ } -+ } else { -+ if (end <= sp[j].start + sp[j].size) { -+ sp[i].container = j + 1; -+ } -+ } -+ } -+ } -+ return n; -+} -+ +@@ -9,7 +9,7 @@ ACTION=="remove", GOTO="kpartx_end" + + ENV{DM_TABLE_STATE}!="LIVE", GOTO="kpartx_end" + +-ENV{DM_UUID}=="?*", IMPORT{program}=="/lib/udev/kpartx_id %M %m $env{DM_UUID}" ++ENV{DM_UUID}=="?*", IMPORT{program}=="kpartx_id %M %m $env{DM_UUID}" + + OPTIONS="link_priority=50" + +@@ -18,7 +18,7 @@ ENV{DM_UUID}=="mpath-*", \ + SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" + + # Create persistent links for dmraid tables +-ENV{DM_UUID}=="mpath-*", \ ++ENV{DM_UUID}=="dmraid-*", \ + SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}" + + # Create persistent links for partitions +@@ -27,9 +27,9 @@ ENV{DM_PART}=="?*", \ + + # Create dm tables for partitions + ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="mpath-*", \ +- RUN+="/sbin/kpartx -a -p -part /dev/$kernel" ++ RUN+="/sbin/kpartx -a -p _part /dev/$kernel" + ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="dmraid-*", \ +- RUN+="/sbin/kpartx -a -p -part /dev/$kernel" ++ RUN+="/sbin/kpartx -a -p _part /dev/$kernel" + + LABEL="kpartx_end" + diff --git a/libcheckers/Makefile b/libcheckers/Makefile index 6340a68..bdd423f 100644 --- a/libcheckers/Makefile +++ b/libcheckers/Makefile -@@ -11,7 +11,7 @@ OBJS = libsg.o checkers.o readsector0.o +@@ -11,7 +11,7 @@ OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o all: $(BUILD) prepare: @@ -886,18 +209,9 @@ index 6340a68..bdd423f 100644 - rm -f core *.a *.o *.gz + rm -f core *.a *.o diff --git a/libmultipath/Makefile b/libmultipath/Makefile -index ef561a8..3ab059a 100644 +index 511f5ad..3ab059a 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile -@@ -13,7 +13,7 @@ OBJS = memory.o parser.o vector.o devmap - 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 -+ log.o configure.o structs_vec.o sysfs.o - - PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe) - @@ -25,7 +25,7 @@ else CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi) endif @@ -922,1894 +236,256 @@ index ef561a8..3ab059a 100644 clean: - rm -f core *.a *.o *.gz + rm -f core *.a *.o -diff --git a/libmultipath/config.h b/libmultipath/config.h -index 7caa11d..a25b3ad 100644 ---- a/libmultipath/config.h -+++ b/libmultipath/config.h -@@ -66,6 +66,7 @@ struct config { - int pg_timeout; - - char * dev; -+ char * sysfs_dir; - char * udev_dir; - char * selector; - char * getuid; -diff --git a/libmultipath/configure.c b/libmultipath/configure.c -index a5bad4c..3cd6041 100644 ---- a/libmultipath/configure.c -+++ b/libmultipath/configure.c -@@ -325,8 +325,10 @@ domap (struct multipath * mpp) - return DOMAP_RETRY; +diff --git a/libmultipath/config.c b/libmultipath/config.c +index a39af8a..1dfc18c 100644 +--- a/libmultipath/config.c ++++ b/libmultipath/config.c +@@ -366,12 +366,15 @@ load_config (char * file) + /* + * read the config file + */ ++ set_current_keywords(&conf->keywords); ++ alloc_keywords(); + if (filepresent(file)) { +- set_current_keywords(&conf->keywords); + if (init_data(file, init_keywords)) { + condlog(0, "error parsing config file"); + goto out; } - -- if (dm_map_present(mpp->alias)) -+ if (dm_map_present(mpp->alias)) { -+ condlog(3, "%s: map already present", mpp->alias); - break; -+ } - - r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET, - mpp->params, mpp->size, mpp->wwid); -diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c -index a196583..52e0621 100644 ---- a/libmultipath/discovery.c -+++ b/libmultipath/discovery.c -@@ -8,9 +8,8 @@ - #include - #include - #include -+#include - #include --#include --#include - - #include - -@@ -24,6 +23,7 @@ - #include "debug.h" - #include "propsel.h" - #include "sg_include.h" -+#include "sysfs.h" - #include "discovery.h" - - struct path * -@@ -87,127 +87,117 @@ path_discover (vector pathvec, struct co - int - path_discovery (vector pathvec, struct config * conf, int flag) - { -- struct dlist * ls; -- struct sysfs_class * class; -- struct sysfs_class_device * dev; -- int r = 1; -- -- if (!(class = sysfs_open_class("block"))) -+ DIR *blkdir; -+ struct dirent *blkdev; -+ struct stat statbuf; -+ char devpath[PATH_MAX]; -+ char *devptr; -+ int r = 0; -+ -+ if (!(blkdir = opendir("/sys/block"))) - return 1; - -- if (!(ls = sysfs_get_class_devices(class))) -- goto out; -+ strcpy(devpath,"/sys/block"); -+ while ((blkdev = readdir(blkdir)) != NULL) { -+ if ((strcmp(blkdev->d_name,".") == 0) || -+ (strcmp(blkdev->d_name,"..") == 0)) -+ continue; - -- r = 0; -+ devptr = devpath + 10; -+ *devptr = '\0'; -+ strcat(devptr,"/"); -+ strcat(devptr,blkdev->d_name); -+ if (stat(devpath, &statbuf) < 0) -+ continue; - -- dlist_for_each_data(ls, dev, struct sysfs_class_device) -- r += path_discover(pathvec, conf, dev->name, flag); -+ if (S_ISDIR(statbuf.st_mode) == 0) -+ continue; - --out: -- sysfs_close_class(class); -- return r; --} -+ condlog(4, "Discover device %s", devpath); - --/* -- * the daemon can race udev upon path add, -- * not multipath(8), ran by udev -- */ --#if DAEMON --#define WAIT_MAX_SECONDS 60 --#define WAIT_LOOP_PER_SECOND 5 -- --static int --wait_for_file (char * filename) --{ -- int loop; -- struct stat stats; -- -- loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND; -- -- while (--loop) { -- if (stat(filename, &stats) == 0) -- return 0; -- -- if (errno != ENOENT) -- return 1; -- -- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); -+ r += path_discover(pathvec, conf, blkdev->d_name, flag); ++ } else { ++ init_keywords(); } -- return 1; --} --#else --static int --wait_for_file (char * filename) --{ -- return 0; -+ closedir(blkdir); -+ condlog(4, "Discovery status %d", r); -+ return r; - } --#endif - --#define declare_sysfs_get_str(fname, fmt) \ -+#define declare_sysfs_get_str(fname) \ - extern int \ --sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \ -+sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \ - { \ -- struct sysfs_attribute * attr; \ -- char attr_path[SYSFS_PATH_SIZE]; \ -+ char *attr; \ - \ -- if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \ -+ attr = sysfs_attr_get_value(dev->devpath, #fname); \ -+ if (!attr) \ - return 1; \ - \ -- if (wait_for_file(attr_path)) \ -- return 1; \ --\ -- if (!(attr = sysfs_open_attribute(attr_path))) \ -- return 1; \ --\ -- if (0 > sysfs_read_attribute(attr)) \ -- goto out; \ --\ -- if (attr->len < 2 || attr->len - 1 > len) \ -- goto out; \ --\ -- strncpy(buff, attr->value, attr->len - 1); \ -- strchop(buff); \ -- sysfs_close_attribute(attr); \ -+ if (strlcpy(buff, attr, len) != strlen(attr)) \ -+ return 2; \ - return 0; \ --out: \ -- sysfs_close_attribute(attr); \ -- return 1; \ - } - --declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype"); --declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype"); --declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor"); --declare_sysfs_get_str(model, "%s/block/%s/device/model"); --declare_sysfs_get_str(rev, "%s/block/%s/device/rev"); --declare_sysfs_get_str(dev, "%s/block/%s/dev"); -+declare_sysfs_get_str(devtype); -+declare_sysfs_get_str(cutype); -+declare_sysfs_get_str(vendor); -+declare_sysfs_get_str(model); -+declare_sysfs_get_str(rev); - - int --sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size) -+sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len) - { -- struct sysfs_attribute * attr; -- char attr_path[SYSFS_PATH_SIZE]; -- int r; -+ char *attr; - -- if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev)) -+ attr = sysfs_attr_get_value(dev->devpath, "dev"); -+ if (!attr) { -+ condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel); - return 1; -+ } -+ if (strlcpy(buff, attr, len) != strlen(attr)) { -+ condlog(3, "%s: overflow in 'dev' attribute", dev->kernel); -+ return 2; -+ } -+ return 0; -+} - -- attr = sysfs_open_attribute(attr_path); -+int -+sysfs_get_size (struct sysfs_device * dev, unsigned long long * size) -+{ -+ char *attr; -+ int r; - -+ attr = sysfs_attr_get_value(dev->devpath, "size"); - if (!attr) - return 1; - -- if (0 > sysfs_read_attribute(attr)) -- goto out; -- -- r = sscanf(attr->value, "%llu\n", size); -- sysfs_close_attribute(attr); -+ r = sscanf(attr, "%llu\n", size); - - if (r != 1) - return 1; - - return 0; --out: -- sysfs_close_attribute(attr); -+} -+ -+int -+sysfs_get_fc_nodename (struct sysfs_device * dev, char * node, -+ unsigned int host, unsigned int channel, -+ unsigned int target) -+{ -+ char attr_path[SYSFS_PATH_SIZE], *attr; -+ -+ if (safe_sprintf(attr_path, -+ "/class/fc_transport/target%i:%i:%i", -+ host, channel, target)) { -+ condlog(0, "attr_path too small"); -+ return 1; -+ } -+ -+ attr = sysfs_attr_get_value(attr_path, "node_name"); -+ if (attr) { -+ strlcpy(node, attr, strlen(attr)); -+ return 0; -+ } -+ - return 1; - } -@@ -224,68 +214,52 @@ opennode (char * dev, int mode) - return -1; - } - -- if (wait_for_file(devpath)) { -- condlog(3, "failed to open %s", devpath); -- return -1; -- } -- - return open(devpath, mode); + /* +diff --git a/libmultipath/parser.c b/libmultipath/parser.c +index f9c555e..5302970 100644 +--- a/libmultipath/parser.c ++++ b/libmultipath/parser.c +@@ -455,16 +455,23 @@ process_stream(vector keywords) + return r; } - extern int - devt2devname (char *devname, char *devt) - { -- struct dlist * ls; -- char attr_path[FILE_NAME_SIZE]; -+ FILE *fd; -+ unsigned int tmpmaj, tmpmin, major, minor; -+ char dev[FILE_NAME_SIZE]; - char block_path[FILE_NAME_SIZE]; -- struct sysfs_attribute * attr = NULL; -- struct sysfs_class * class; -- struct sysfs_class_device * dev; -+ struct stat statbuf; - -- if(safe_sprintf(block_path, "%s/block", sysfs_path)) { -- condlog(0, "block_path too small"); -+ if (sscanf(devt, "%u:%u", &major, &minor) != 2) { -+ condlog(0, "Invalid device number %s", devt); - return 1; - } -- if (!(class = sysfs_open_class("block"))) -- return 1; - -- if (!(ls = sysfs_get_class_devices(class))) -- goto err; -+ if ((fd = fopen("/proc/partitions", "r")) < 0) { -+ condlog(0, "Cannot open /proc/partitions"); -+ return 1; -+ } -+ -+ while (!feof(fd)) { -+ if (fscanf(fd," %u %u %*d %s",&tmpmaj, &tmpmin, dev) != 3) -+ continue; - -- dlist_for_each_data(ls, dev, struct sysfs_class_device) { -- if(safe_sprintf(attr_path, "%s/%s/dev", -- block_path, dev->name)) { -- condlog(0, "attr_path too small"); -- goto err; -- } -- if (!(attr = sysfs_open_attribute(attr_path))) -- goto err; -- -- if (sysfs_read_attribute(attr)) -- goto err1; -- -- /* discard newline */ -- if (attr->len > 1) attr->len--; -- -- if (strlen(devt) == attr->len && -- strncmp(attr->value, devt, attr->len) == 0) { -- if(safe_sprintf(attr_path, "%s/%s", -- block_path, dev->name)) { -- condlog(0, "attr_path too small"); -- goto err1; -- } -- sysfs_get_name_from_path(attr_path, devname, -- FILE_NAME_SIZE); -- sysfs_close_attribute(attr); -- sysfs_close_class(class); -- return 0; -+ if ((major == tmpmaj) && (minor == tmpmin)) { -+ sprintf(block_path, "/sys/block/%s", dev); -+ break; - } - } --err1: -- sysfs_close_attribute(attr); --err: -- sysfs_close_class(class); -- return 1; -+ fclose(fd); ++int alloc_keywords(void) ++{ ++ if (!keywords) ++ keywords = vector_alloc(); + -+ if (strncpy(block_path,"/sys/block", 10)) ++ if (!keywords) + return 1; + -+ if (stat(block_path, &statbuf) < 0) { -+ condlog(0, "No sysfs entry for %s\n", block_path); -+ return 1; -+ } -+ -+ if (S_ISDIR(statbuf.st_mode) == 0) { -+ condlog(0, "sysfs entry %s is not a directory\n", block_path); -+ return 1; -+ } + return 0; - } - - static int -@@ -363,79 +337,21 @@ get_serial (char * str, int maxlen, int - } - - static int --sysfs_get_bus (char * sysfs_path, struct path * pp) --{ -- struct sysfs_device *sdev; -- char attr_path[FILE_NAME_SIZE]; -- char attr_buff[FILE_NAME_SIZE]; -- -- pp->bus = SYSFS_BUS_UNDEF; -- -- /* -- * This is ugly : we should be able to do a simple -- * get_link("%s/block/%s/device/bus", ...) but it just -- * won't work -- */ -- if(safe_sprintf(attr_path, "%s/block/%s/device", -- sysfs_path, pp->dev)) { -- condlog(0, "attr_path too small"); -- return 1; -- } -- -- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) -- return 1; -- --#if DAEMON -- int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND; -- -- while (loop--) { -- sdev = sysfs_open_device_path(attr_buff); -- -- if (strlen(sdev->bus)) -- break; -- -- sysfs_close_device(sdev); -- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); -- } --#else -- sdev = sysfs_open_device_path(attr_buff); --#endif -- -- if (!strncmp(sdev->bus, "scsi", 4)) -- pp->bus = SYSFS_BUS_SCSI; -- else if (!strncmp(sdev->bus, "ide", 3)) -- pp->bus = SYSFS_BUS_IDE; -- else if (!strncmp(sdev->bus, "ccw", 3)) -- pp->bus = SYSFS_BUS_CCW; -- else -- return 1; -- -- sysfs_close_device(sdev); -- -- return 0; --} -- --static int --scsi_sysfs_pathinfo (struct path * pp) -+scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) ++} ++ + /* Data initialization */ + int + init_data(char *conf_file, void (*init_keywords) (void)) { - char attr_path[FILE_NAME_SIZE]; -- char attr_buff[FILE_NAME_SIZE]; -- struct sysfs_attribute * attr; - -- if (sysfs_get_vendor(sysfs_path, pp->dev, -- pp->vendor_id, SCSI_VENDOR_SIZE)) -+ if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE)) - return 1; - - condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); - -- if (sysfs_get_model(sysfs_path, pp->dev, -- pp->product_id, SCSI_PRODUCT_SIZE)) -+ if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE)) - return 1; - - condlog(3, "%s: product = %s", pp->dev, pp->product_id); - -- if (sysfs_get_rev(sysfs_path, pp->dev, -- pp->rev, SCSI_REV_SIZE)) -+ if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE)) - return 1; - - condlog(3, "%s: rev = %s", pp->dev, pp->rev); -@@ -448,15 +364,7 @@ scsi_sysfs_pathinfo (struct path * pp) - /* - * host / bus / target / lun - */ -- if(safe_sprintf(attr_path, "%s/block/%s/device", -- sysfs_path, pp->dev)) { -- condlog(0, "attr_path too small"); -- return 1; -- } -- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) -- return 1; -- -- basename(attr_buff, attr_path); -+ basename(parent->devpath, attr_path); - - sscanf(attr_path, "%i:%i:%i:%i", - &pp->sg_id.host_no, -@@ -473,35 +381,19 @@ scsi_sysfs_pathinfo (struct path * pp) - /* - * target node name - */ -- if(safe_sprintf(attr_path, -- "%s/class/fc_transport/target%i:%i:%i/node_name", -- sysfs_path, -- pp->sg_id.host_no, -- pp->sg_id.channel, -- pp->sg_id.scsi_id)) { -- condlog(0, "attr_path too small"); -- return 1; -+ if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name, -+ pp->sg_id.host_no, -+ pp->sg_id.channel, -+ pp->sg_id.scsi_id)) { -+ condlog(3, "%s: tgt_node_name = %s", -+ pp->dev, pp->tgt_node_name); - } -- if (!(attr = sysfs_open_attribute(attr_path))) -- return 0; -- -- if (sysfs_read_attribute(attr)) -- goto err; -- -- if (attr->len > 0) -- strncpy(pp->tgt_node_name, attr->value, attr->len - 1); -- -- condlog(3, "%s: tgt_node_name = %s", -- pp->dev, pp->tgt_node_name); - - return 0; --err: -- sysfs_close_attribute(attr); -- return 1; - } - - static int --ccw_sysfs_pathinfo (struct path * pp) -+ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent) - { - char attr_path[FILE_NAME_SIZE]; - char attr_buff[FILE_NAME_SIZE]; -@@ -510,8 +402,7 @@ ccw_sysfs_pathinfo (struct path * pp) - - condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); - -- if (sysfs_get_devtype(sysfs_path, pp->dev, -- attr_buff, FILE_NAME_SIZE)) -+ if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE)) - return 1; - - if (!strncmp(attr_buff, "3370", 4)) { -@@ -531,16 +422,8 @@ ccw_sysfs_pathinfo (struct path * pp) - - /* - * host / bus / target / lun -- */ -- if(safe_sprintf(attr_path, "%s/block/%s/device", -- sysfs_path, pp->dev)) { -- condlog(0, "attr_path too small"); -- return 1; -- } -- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff))) -- return 1; -- -- basename(attr_buff, attr_path); -+ */ -+ basename(parent->devpath, attr_path); - pp->sg_id.lun = 0; - sscanf(attr_path, "%i.%i.%x", - &pp->sg_id.host_no, -@@ -557,20 +440,20 @@ ccw_sysfs_pathinfo (struct path * pp) - } - - static int --common_sysfs_pathinfo (struct path * pp) -+common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev) - { -- if (sysfs_get_bus(sysfs_path, pp)) -- return 1; -- -- condlog(3, "%s: bus = %i", pp->dev, pp->bus); -+ char *attr; - -- if (sysfs_get_dev(sysfs_path, pp->dev, -- pp->dev_t, BLK_DEV_SIZE)) -+ attr = sysfs_attr_get_value(dev->devpath, "dev"); -+ if (!attr) { -+ condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); - return 1; -+ } -+ strlcpy(pp->dev_t, attr, BLK_DEV_SIZE); - - condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); - -- if (sysfs_get_size(sysfs_path, pp->dev, &pp->size)) -+ if (sysfs_get_size(dev, &pp->size)) - return 1; - - condlog(3, "%s: size = %llu", pp->dev, pp->size); -@@ -578,19 +461,46 @@ common_sysfs_pathinfo (struct path * pp) - return 0; - } - -+struct sysfs_device *sysfs_device_from_path(struct path *pp) -+{ -+ char sysdev[FILE_NAME_SIZE]; -+ -+ strlcpy(sysdev,"/block/", FILE_NAME_SIZE); -+ strlcat(sysdev,pp->dev, FILE_NAME_SIZE); -+ -+ return sysfs_device_get(sysdev); -+} -+ - extern int - sysfs_pathinfo(struct path * pp) - { -- if (common_sysfs_pathinfo(pp)) -+ struct sysfs_device *parent; -+ -+ pp->sysdev = sysfs_device_from_path(pp); -+ if (!pp->sysdev) { -+ condlog(1, "%s: failed to get sysfs information", pp->dev); - return 1; -+ } -+ -+ parent = sysfs_device_get_parent(pp->sysdev); -+ -+ if (common_sysfs_pathinfo(pp, pp->sysdev)) -+ return 1; -+ -+ condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem); -+ -+ if (!strncmp(parent->subsystem, "scsi",4)) -+ pp->bus = SYSFS_BUS_SCSI; -+ if (!strncmp(parent->subsystem, "ccw",3)) -+ pp->bus = SYSFS_BUS_CCW; - - if (pp->bus == SYSFS_BUS_UNDEF) - return 0; - else if (pp->bus == SYSFS_BUS_SCSI) { -- if (scsi_sysfs_pathinfo(pp)) -+ if (scsi_sysfs_pathinfo(pp, parent)) - return 1; - } else if (pp->bus == SYSFS_BUS_CCW) { -- if (ccw_sysfs_pathinfo(pp)) -+ if (ccw_sysfs_pathinfo(pp, parent)) - return 1; - } - return 0; -diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h -index ab62a59..c7cf7e8 100644 ---- a/libmultipath/discovery.h -+++ b/libmultipath/discovery.h -@@ -24,12 +24,7 @@ - #define SCSI_COMMAND_TERMINATED 0x22 - #define SG_ERR_DRIVER_SENSE 0x08 - --int sysfs_get_vendor (char * sysfs_path, char * dev, char * buff, int len); --int sysfs_get_model (char * sysfs_path, char * dev, char * buff, int len); --int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len); --int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len); -- --int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *); -+int sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len); - int path_discovery (vector pathvec, struct config * conf, int flag); - - void basename (char *, char *); -diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c -index d5b227f..27098b2 100644 ---- a/libmultipath/hwtable.c -+++ b/libmultipath/hwtable.c -@@ -63,7 +63,7 @@ static struct hwentry default_hw[] = { - .vendor = "DEC", - .product = "HSG80", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_hp_sw /dev/%n", -+ .getprio = "/sbin/mpath_prio_hp_sw /dev/%n", - .features = "1 queue_if_no_path", - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -@@ -94,7 +94,7 @@ static struct hwentry default_hw[] = { - .vendor = "(COMPAQ|HP)", - .product = "(MSA|HSV)1.0.*", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_hp_sw /dev/%n", -+ .getprio = "/sbin/mpath_prio_hp_sw /dev/%n", - .features = "1 queue_if_no_path", - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -@@ -110,7 +110,7 @@ static struct hwentry default_hw[] = { - .vendor = "HP", - .product = "MSA VOLUME", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_alua /dev/%n", -+ .getprio = "/sbin/mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -@@ -126,7 +126,7 @@ static struct hwentry default_hw[] = { - .vendor = "(COMPAQ|HP)", - .product = "(MSA|HSV)1.1.*", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_alua /dev/%n", -+ .getprio = "/sbin/mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -@@ -142,7 +142,7 @@ static struct hwentry default_hw[] = { - .vendor = "HP", - .product = "HSV2.*", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_alua /dev/%n", -+ .getprio = "/sbin/mpath_prio_alua /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -@@ -406,7 +406,7 @@ static struct hwentry default_hw[] = { - .vendor = "IBM", - .product = "S/390 DASD ECKD", - .bl_product = "S/390.*", -- .getuid = "dasdinfo -u -b %n", -+ .getuid = "/sbin/dasdinfo -u -b %n", - .getprio = NULL, - .features = "1 queue_if_no_path", - .hwhandler = DEFAULT_HWHANDLER, -@@ -521,7 +521,7 @@ static struct hwentry default_hw[] = { - .vendor = "SGI", - .product = "IS.*", - .getuid = DEFAULT_GETUID, -- .getprio = "mpath_prio_tpc /dev/%n", -+ .getprio = "/sbin/mpath_prio_tpc /dev/%n", - .features = DEFAULT_FEATURES, - .hwhandler = DEFAULT_HWHANDLER, - .selector = DEFAULT_SELECTOR, -diff --git a/libmultipath/list.h b/libmultipath/list.h -new file mode 100644 -index 0000000..8626630 ---- /dev/null -+++ b/libmultipath/list.h -@@ -0,0 +1,289 @@ -+/* -+ * Copied from the Linux kernel source tree, version 2.6.0-test1. -+ * -+ * Licensed under the GPL v2 as per the whole kernel source tree. -+ * -+ */ -+ -+#ifndef _LIST_H -+#define _LIST_H -+ -+/** -+ * container_of - cast a member of a structure out to the containing structure -+ * -+ * @ptr: the pointer to the member. -+ * @type: the type of the container struct this is embedded in. -+ * @member: the name of the member within the struct. -+ * -+ */ -+#define container_of(ptr, type, member) ({ \ -+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ -+ (type *)( (char *)__mptr - offsetof(type,member) );}) -+ -+/* -+ * These are non-NULL pointers that will result in page faults -+ * under normal circumstances, used to verify that nobody uses -+ * non-initialized list entries. -+ */ -+#define LIST_POISON1 ((void *) 0x00100100) -+#define LIST_POISON2 ((void *) 0x00200200) -+ -+/* -+ * Simple doubly linked list implementation. -+ * -+ * Some of the internal functions ("__xxx") are useful when -+ * manipulating whole lists rather than single entries, as -+ * sometimes we already know the next/prev entries and we can -+ * generate better code by using them directly rather than -+ * using the generic single-entry routines. -+ */ -+ -+struct list_head { -+ struct list_head *next, *prev; -+}; -+ -+#define LIST_HEAD_INIT(name) { &(name), &(name) } -+ -+#define LIST_HEAD(name) \ -+ struct list_head name = LIST_HEAD_INIT(name) -+ -+#define INIT_LIST_HEAD(ptr) do { \ -+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -+} while (0) -+ -+/* -+ * Insert a new entry between two known consecutive entries. -+ * -+ * This is only for internal list manipulation where we know -+ * the prev/next entries already! -+ */ -+static inline void __list_add(struct list_head *new, -+ struct list_head *prev, -+ struct list_head *next) -+{ -+ next->prev = new; -+ new->next = next; -+ new->prev = prev; -+ prev->next = new; -+} -+ -+/** -+ * list_add - add a new entry -+ * @new: new entry to be added -+ * @head: list head to add it after -+ * -+ * Insert a new entry after the specified head. -+ * This is good for implementing stacks. -+ */ -+static inline void list_add(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head, head->next); -+} -+ -+/** -+ * list_add_tail - add a new entry -+ * @new: new entry to be added -+ * @head: list head to add it before -+ * -+ * Insert a new entry before the specified head. -+ * This is useful for implementing queues. -+ */ -+static inline void list_add_tail(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head->prev, head); -+} -+ -+/* -+ * Delete a list entry by making the prev/next entries -+ * point to each other. -+ * -+ * This is only for internal list manipulation where we know -+ * the prev/next entries already! -+ */ -+static inline void __list_del(struct list_head * prev, struct list_head * next) -+{ -+ next->prev = prev; -+ prev->next = next; -+} -+ -+/** -+ * list_del - deletes entry from list. -+ * @entry: the element to delete from the list. -+ * Note: list_empty on entry does not return true after this, the entry is -+ * in an undefined state. -+ */ -+static inline void list_del(struct list_head *entry) -+{ -+ __list_del(entry->prev, entry->next); -+ entry->next = LIST_POISON1; -+ entry->prev = LIST_POISON2; -+} -+ -+/** -+ * list_del_init - deletes entry from list and reinitialize it. -+ * @entry: the element to delete from the list. -+ */ -+static inline void list_del_init(struct list_head *entry) -+{ -+ __list_del(entry->prev, entry->next); -+ INIT_LIST_HEAD(entry); -+} -+ -+/** -+ * list_move - delete from one list and add as another's head -+ * @list: the entry to move -+ * @head: the head that will precede our entry -+ */ -+static inline void list_move(struct list_head *list, struct list_head *head) -+{ -+ __list_del(list->prev, list->next); -+ list_add(list, head); -+} -+ -+/** -+ * list_move_tail - delete from one list and add as another's tail -+ * @list: the entry to move -+ * @head: the head that will follow our entry -+ */ -+static inline void list_move_tail(struct list_head *list, -+ struct list_head *head) -+{ -+ __list_del(list->prev, list->next); -+ list_add_tail(list, head); -+} -+ -+/** -+ * list_empty - tests whether a list is empty -+ * @head: the list to test. -+ */ -+static inline int list_empty(struct list_head *head) -+{ -+ return head->next == head; -+} -+ -+static inline void __list_splice(struct list_head *list, -+ struct list_head *head) -+{ -+ struct list_head *first = list->next; -+ struct list_head *last = list->prev; -+ struct list_head *at = head->next; -+ -+ first->prev = head; -+ head->next = first; -+ -+ last->next = at; -+ at->prev = last; -+} -+ -+/** -+ * list_splice - join two lists -+ * @list: the new list to add. -+ * @head: the place to add it in the first list. -+ */ -+static inline void list_splice(struct list_head *list, struct list_head *head) -+{ -+ if (!list_empty(list)) -+ __list_splice(list, head); -+} -+ -+/** -+ * list_splice_init - join two lists and reinitialise the emptied list. -+ * @list: the new list to add. -+ * @head: the place to add it in the first list. -+ * -+ * The list at @list is reinitialised -+ */ -+static inline void list_splice_init(struct list_head *list, -+ struct list_head *head) -+{ -+ if (!list_empty(list)) { -+ __list_splice(list, head); -+ INIT_LIST_HEAD(list); -+ } -+} -+ -+/** -+ * list_entry - get the struct for this entry -+ * @ptr: the &struct list_head pointer. -+ * @type: the type of the struct this is embedded in. -+ * @member: the name of the list_struct within the struct. -+ */ -+#define list_entry(ptr, type, member) \ -+ container_of(ptr, type, member) -+ -+/** -+ * list_for_each - iterate over a list -+ * @pos: the &struct list_head to use as a loop counter. -+ * @head: the head for your list. -+ */ -+#define list_for_each(pos, head) \ -+ for (pos = (head)->next; pos != (head); \ -+ pos = pos->next) -+ -+/** -+ * __list_for_each - iterate over a list -+ * @pos: the &struct list_head to use as a loop counter. -+ * @head: the head for your list. -+ * -+ * This variant differs from list_for_each() in that it's the -+ * simplest possible list iteration code. -+ * Use this for code that knows the list to be very short (empty -+ * or 1 entry) most of the time. -+ */ -+#define __list_for_each(pos, head) \ -+ for (pos = (head)->next; pos != (head); pos = pos->next) -+ -+/** -+ * list_for_each_prev - iterate over a list backwards -+ * @pos: the &struct list_head to use as a loop counter. -+ * @head: the head for your list. -+ */ -+#define list_for_each_prev(pos, head) \ -+ for (pos = (head)->prev; pos != (head); pos = pos->prev) -+ -+/** -+ * list_for_each_safe - iterate over a list safe against removal of list entry -+ * @pos: the &struct list_head to use as a loop counter. -+ * @n: another &struct list_head to use as temporary storage -+ * @head: the head for your list. -+ */ -+#define list_for_each_safe(pos, n, head) \ -+ for (pos = (head)->next, n = pos->next; pos != (head); \ -+ pos = n, n = pos->next) -+ -+/** -+ * list_for_each_entry - iterate over list of given type -+ * @pos: the type * to use as a loop counter. -+ * @head: the head for your list. -+ * @member: the name of the list_struct within the struct. -+ */ -+#define list_for_each_entry(pos, head, member) \ -+ for (pos = list_entry((head)->next, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = list_entry(pos->member.next, typeof(*pos), member)) -+ -+/** -+ * list_for_each_entry_reverse - iterate backwards over list of given type. -+ * @pos: the type * to use as a loop counter. -+ * @head: the head for your list. -+ * @member: the name of the list_struct within the struct. -+ */ -+#define list_for_each_entry_reverse(pos, head, member) \ -+ for (pos = list_entry((head)->prev, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = list_entry(pos->member.prev, typeof(*pos), member)) -+ -+/** -+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry -+ * @pos: the type * to use as a loop counter. -+ * @n: another type * to use as temporary storage -+ * @head: the head for your list. -+ * @member: the name of the list_struct within the struct. -+ */ -+#define list_for_each_entry_safe(pos, n, head, member) \ -+ for (pos = list_entry((head)->next, typeof(*pos), member), \ -+ n = list_entry(pos->member.next, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = n, n = list_entry(n->member.next, typeof(*n), member)) -+ -+#endif /* _LIST_H */ -diff --git a/libmultipath/print.c b/libmultipath/print.c -index dc8af48..1d80e48 100644 ---- a/libmultipath/print.c -+++ b/libmultipath/print.c -@@ -5,8 +5,8 @@ - #include - #include - #include --#include --#include -+#include -+#include - - #include - -@@ -1096,35 +1096,46 @@ snprint_blacklist_except (char * buff, i - extern int - snprint_devices (char * buff, int len, struct vectors *vecs) - { -- struct dlist * ls; -- struct sysfs_class * class; -- struct sysfs_class_device * dev; -+ DIR *blkdir; -+ struct dirent *blkdev; -+ struct stat statbuf; -+ char devpath[PATH_MAX]; -+ char *devptr; - int threshold = MAX_LINE_LEN; - int fwd = 0; int r; - struct path * pp; - -- if (!(class = sysfs_open_class("block"))) -- return 0; -- -- if (!(ls = sysfs_get_class_devices(class))) { -- sysfs_close_class(class); -- return 0; -- } -+ if (!(blkdir = opendir("/sys/block"))) -+ return 1; - - if ((len - fwd - threshold) <= 0) - return len; - fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n"); - -- dlist_for_each_data(ls, dev, struct sysfs_class_device) { -+ strcpy(devpath,"/sys/block"); -+ devptr = devpath + 10; -+ 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) -+ continue; -+ -+ if (S_ISDIR(statbuf.st_mode) == 0) -+ continue; -+ - if ((len - fwd - threshold) <= 0) - return len; -- fwd += snprintf(buff + fwd, len - fwd, " %s", dev->name); -- pp = find_path_by_dev(vecs->pathvec, dev->name); -+ -+ fwd += snprintf(buff + fwd, len - fwd, " %s", devpath); -+ pp = find_path_by_dev(vecs->pathvec, devpath); - if (!pp) { - r = filter_devnode(conf->blist_devnode, -- conf->elist_devnode, dev->name); -+ conf->elist_devnode, devpath); - if (r > 0) - fwd += snprintf(buff + fwd, len - fwd, - " (blacklisted)"); -@@ -1133,8 +1144,8 @@ snprint_devices (char * buff, int len, s - " (whitelisted)"); - } - fwd += snprintf(buff + fwd, len - fwd, "\n"); -- } -- sysfs_close_class(class); -+ } -+ closedir(blkdir); - +- if (!keywords) +- keywords = vector_alloc(); +- if (!keywords) +- return 1; + stream = fopen(conf_file, "r"); + if (!stream) { + syslog(LOG_WARNING, "Configuration file open problem"); +diff --git a/libmultipath/parser.h b/libmultipath/parser.h +index 95d4e6f..8496684 100644 +--- a/libmultipath/parser.h ++++ b/libmultipath/parser.h +@@ -74,6 +74,7 @@ extern vector read_value_block(void); + extern int alloc_value_block(vector strvec, void (*alloc_func) (vector)); + extern void *set_value(vector strvec); + extern int process_stream(vector keywords); ++extern int alloc_keywords(void); + extern int init_data(char *conf_file, void (*init_keywords) (void)); + extern struct keyword * find_keyword(vector v, char * name); + void set_current_keywords (vector *k); +diff --git a/libmultipath/print.c b/libmultipath/print.c +index 01a157a..489bc2b 100644 +--- a/libmultipath/print.c ++++ b/libmultipath/print.c +@@ -738,7 +738,7 @@ snprint_hwentry (char * buff, int len, struct hwentry * hwe) if (fwd > len) return len; -diff --git a/libmultipath/structs.h b/libmultipath/structs.h -index 46dcdee..75322aa 100644 ---- a/libmultipath/structs.h -+++ b/libmultipath/structs.h -@@ -9,6 +9,9 @@ - #define FILE_NAME_SIZE 256 - #define CALLOUT_MAX_SIZE 128 - #define BLK_DEV_SIZE 33 -+#define PATH_SIZE 512 -+#define NAME_SIZE 128 -+ - - #define SCSI_VENDOR_SIZE 9 - #define SCSI_PRODUCT_SIZE 17 -@@ -86,9 +89,19 @@ struct scsi_dev { - int host_no; - }; - -+struct sysfs_device { -+ struct sysfs_device *parent; /* parent device */ -+ char devpath[PATH_SIZE]; -+ char subsystem[NAME_SIZE]; /* $class, $bus, drivers, module */ -+ char kernel[NAME_SIZE]; /* device instance name */ -+ char kernel_number[NAME_SIZE]; -+ char driver[NAME_SIZE]; /* device driver name */ -+}; -+ - struct path { - char dev[FILE_NAME_SIZE]; - char dev_t[BLK_DEV_SIZE]; -+ struct sysfs_device *sysdev; - struct scsi_idlun scsi_id; - struct sg_id sg_id; - char wwid[WWID_SIZE]; -@@ -200,6 +213,6 @@ struct path * first_path (struct multipa - int pathcountgr (struct pathgroup *, int); - int pathcount (struct multipath *, int); - --char sysfs_path[FILE_NAME_SIZE]; -+extern char sysfs_path[PATH_SIZE]; - - #endif /* _STRUCTS_H */ -diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c -index a4a996a..1cc6028 100644 ---- a/libmultipath/structs_vec.c -+++ b/libmultipath/structs_vec.c -@@ -13,6 +13,7 @@ - #include "dmparser.h" - #include "config.h" - #include "propsel.h" -+#include "sysfs.h" - #include "discovery.h" - #include "waiter.h" - -@@ -373,10 +374,10 @@ verify_paths(struct multipath * mpp, str - /* - * see if path is in sysfs - */ -- if (!pp->dev || sysfs_get_dev(sysfs_path, -- pp->dev, pp->dev_t, BLK_DEV_SIZE)) { -+ if (!pp->sysdev || sysfs_get_dev(pp->sysdev, -+ pp->dev_t, BLK_DEV_SIZE)) { - condlog(0, "%s: failed to access path %s", mpp->alias, -- pp->dev ? pp->dev : pp->dev_t); -+ pp->sysdev ? pp->sysdev->devpath : pp->dev_t); - count++; - vector_del_slot(mpp->paths, i); - i--; -diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c -new file mode 100644 -index 0000000..e24aa34 ---- /dev/null -+++ b/libmultipath/sysfs.c -@@ -0,0 +1,405 @@ -+/* -+ * Copyright (C) 2005-2006 Kay Sievers -+ * -+ * 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. -+ * -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "checkers.h" -+#include "vector.h" -+#include "structs.h" -+#include "sysfs.h" -+#include "list.h" -+#include "util.h" -+ -+char sysfs_path[PATH_SIZE]; -+ -+/* attribute value cache */ -+static LIST_HEAD(attr_list); -+struct sysfs_attr { -+ struct list_head node; -+ char path[PATH_SIZE]; -+ char *value; /* points to value_local if value is cached */ -+ char value_local[NAME_SIZE]; -+}; -+ -+int sysfs_init(char *path, size_t len) -+{ -+ if (path) { -+ strlcpy(sysfs_path, path, len); -+ remove_trailing_chars(sysfs_path, '/'); -+ } else -+ strlcpy(sysfs_path, "/sys", len); -+ dbg("sysfs_path='%s'", sysfs_path); -+ -+ INIT_LIST_HEAD(&attr_list); -+ return 0; -+} -+ -+void sysfs_cleanup(void) -+{ -+ struct sysfs_attr *attr_loop; -+ struct sysfs_attr *attr_temp; -+ -+ list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) { -+ list_del(&attr_loop->node); -+ free(attr_loop); -+ } -+ -+} -+ -+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, -+ const char *subsystem, const char *driver) -+{ -+ char *pos; -+ -+ strlcpy(dev->devpath, devpath, sizeof(dev->devpath)); -+ if (subsystem != NULL) -+ strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem)); -+ if (driver != NULL) -+ strlcpy(dev->driver, driver, sizeof(dev->driver)); -+ -+ /* set kernel name */ -+ pos = strrchr(dev->devpath, '/'); -+ if (pos == NULL) -+ return; -+ strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); -+ dbg("kernel='%s'", dev->kernel); -+ -+ /* some devices have '!' in their name, change that to '/' */ -+ pos = dev->kernel; -+ while (pos[0] != '\0') { -+ if (pos[0] == '!') -+ pos[0] = '/'; -+ pos++; -+ } -+ -+ /* get kernel number */ -+ pos = &dev->kernel[strlen(dev->kernel)]; -+ while (isdigit(pos[-1])) -+ pos--; -+ strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number)); -+ dbg("kernel_number='%s'", dev->kernel_number); -+} -+ -+int sysfs_resolve_link(char *devpath, size_t size) -+{ -+ char link_path[PATH_SIZE]; -+ char link_target[PATH_SIZE]; -+ int len; -+ int i; -+ int back; -+ -+ strlcpy(link_path, sysfs_path, sizeof(link_path)); -+ strlcat(link_path, devpath, sizeof(link_path)); -+ len = readlink(link_path, link_target, sizeof(link_target)); -+ if (len <= 0) -+ return -1; -+ link_target[len] = '\0'; -+ dbg("path link '%s' points to '%s'", devpath, link_target); -+ -+ for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) -+ ; -+ dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back); -+ for (i = 0; i <= back; i++) { -+ char *pos = strrchr(devpath, '/'); -+ -+ if (pos == NULL) -+ return -1; -+ pos[0] = '\0'; -+ } -+ dbg("after moving back '%s'", devpath); -+ strlcat(devpath, "/", size); -+ strlcat(devpath, &link_target[back * 3], size); -+ return 0; -+} -+ -+struct sysfs_device *sysfs_device_get(const char *devpath) -+{ -+ char path[PATH_SIZE]; -+ char devpath_real[PATH_SIZE]; -+ struct sysfs_device *dev; -+ struct stat statbuf; -+ char link_path[PATH_SIZE]; -+ char link_target[PATH_SIZE]; -+ int len; -+ char *pos; -+ -+ dbg("open '%s'", devpath); -+ strlcpy(devpath_real, devpath, sizeof(devpath_real)); -+ remove_trailing_chars(devpath_real, '/'); -+ -+ /* if we got a link, resolve it to the real device */ -+ strlcpy(path, sysfs_path, sizeof(path)); -+ strlcat(path, devpath_real, sizeof(path)); -+ if (lstat(path, &statbuf) != 0) { -+ dbg("stat '%s' failed: %s", path, strerror(errno)); -+ return NULL; -+ } -+ if (S_ISLNK(statbuf.st_mode)) { -+ if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0) -+ return NULL; -+ -+ } -+ -+ /* it is a new device */ -+ dbg("new device '%s'", devpath_real); -+ dev = malloc(sizeof(struct sysfs_device)); -+ if (dev == NULL) -+ return NULL; -+ memset(dev, 0x00, sizeof(struct sysfs_device)); -+ -+ sysfs_device_set_values(dev, devpath_real, NULL, NULL); -+ -+ /* get subsystem name */ -+ strlcpy(link_path, sysfs_path, sizeof(link_path)); -+ strlcat(link_path, dev->devpath, sizeof(link_path)); -+ strlcat(link_path, "/subsystem", sizeof(link_path)); -+ len = readlink(link_path, link_target, sizeof(link_target)); -+ if (len > 0) { -+ /* get subsystem from "subsystem" link */ -+ link_target[len] = '\0'; -+ dbg("subsystem 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 (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)); -+ } -+ -+ /* get driver name */ -+ strlcpy(link_path, sysfs_path, sizeof(link_path)); -+ strlcat(link_path, dev->devpath, sizeof(link_path)); -+ strlcat(link_path, "/driver", sizeof(link_path)); -+ len = readlink(link_path, link_target, sizeof(link_target)); -+ if (len > 0) { -+ link_target[len] = '\0'; -+ dbg("driver link '%s' points to '%s'", link_path, link_target); -+ pos = strrchr(link_target, '/'); -+ if (pos != NULL) -+ strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); -+ } -+ -+ return dev; -+} -+ -+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) -+{ -+ char parent_devpath[PATH_SIZE]; -+ char *pos; -+ -+ dbg("open '%s'", dev->devpath); -+ -+ /* look if we already know the parent */ -+ 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); -+ -+ /* strip last element */ -+ pos = strrchr(parent_devpath, '/'); -+ if (pos == NULL || pos == parent_devpath) -+ 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) { -+ dbg("/class top level, look for device link"); -+ goto device_link; -+ } -+ } -+ if (strcmp(parent_devpath, "/block") == 0) { -+ dbg("/block top level, look for device link"); -+ goto device_link; -+ } -+ -+ /* get parent and remember it */ -+ dev->parent = sysfs_device_get(parent_devpath); -+ return dev->parent; -+ -+device_link: -+ strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); -+ strlcat(parent_devpath, "/device", sizeof(parent_devpath)); -+ if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0) -+ return NULL; -+ -+ /* get parent and remember it */ -+ dev->parent = sysfs_device_get(parent_devpath); -+ return dev->parent; -+} -+ -+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem) -+{ -+ struct sysfs_device *dev_parent; -+ -+ dev_parent = sysfs_device_get_parent(dev); -+ while (dev_parent != NULL) { -+ if (strcmp(dev_parent->subsystem, subsystem) == 0) -+ return dev_parent; -+ dev_parent = sysfs_device_get_parent(dev_parent); -+ } -+ return NULL; -+} -+ -+char *sysfs_attr_get_value(const char *devpath, const char *attr_name) -+{ -+ char path_full[PATH_SIZE]; -+ const char *path; -+ char value[NAME_SIZE]; -+ struct sysfs_attr *attr_loop; -+ struct sysfs_attr *attr; -+ struct stat statbuf; -+ int fd; -+ ssize_t size; -+ size_t sysfs_len; -+ -+ dbg("open '%s'/'%s'", devpath, attr_name); -+ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); -+ path = &path_full[sysfs_len]; -+ strlcat(path_full, devpath, sizeof(path_full)); -+ strlcat(path_full, "/", sizeof(path_full)); -+ strlcat(path_full, attr_name, sizeof(path_full)); -+ -+ /* look for attribute in cache */ -+ list_for_each_entry(attr_loop, &attr_list, node) { -+ if (strcmp(attr_loop->path, path) == 0) { -+ dbg("found in cache '%s'", attr_loop->path); -+ return attr_loop->value; -+ } -+ } -+ -+ /* store attribute in cache (also negatives are kept in cache) */ -+ dbg("new uncached attribute '%s'", path_full); -+ attr = malloc(sizeof(struct sysfs_attr)); -+ if (attr == NULL) -+ return NULL; -+ memset(attr, 0x00, sizeof(struct sysfs_attr)); -+ strlcpy(attr->path, path, sizeof(attr->path)); -+ dbg("add to cache '%s'", path_full); -+ list_add(&attr->node, &attr_list); -+ -+ if (lstat(path_full, &statbuf) != 0) { -+ dbg("stat '%s' failed: %s", path_full, strerror(errno)); -+ goto out; -+ } -+ -+ if (S_ISLNK(statbuf.st_mode)) { -+ /* links return the last element of the target path */ -+ char link_target[PATH_SIZE]; -+ int len; -+ const char *pos; -+ -+ len = readlink(path_full, link_target, sizeof(link_target)); -+ if (len > 0) { -+ 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)); -+ attr->value = attr->value_local; -+ } -+ } -+ goto out; -+ } -+ -+ /* skip directories */ -+ if (S_ISDIR(statbuf.st_mode)) -+ goto out; -+ -+ /* skip non-readable files */ -+ if ((statbuf.st_mode & S_IRUSR) == 0) -+ goto out; -+ -+ /* read attribute value */ -+ fd = open(path_full, O_RDONLY); -+ if (fd < 0) { -+ dbg("attribute '%s' does not exist", path_full); -+ goto out; -+ } -+ size = read(fd, value, sizeof(value)); -+ close(fd); -+ if (size < 0) -+ goto out; -+ if (size == sizeof(value)) -+ goto out; -+ -+ /* got a valid value, store and return it */ -+ value[size] = '\0'; -+ remove_trailing_chars(value, '\n'); -+ dbg("cache '%s' with attribute value '%s'", path_full, value); -+ strlcpy(attr->value_local, value, sizeof(attr->value_local)); -+ attr->value = attr->value_local; -+ -+out: -+ return attr->value; -+} -diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h -new file mode 100644 -index 0000000..4ac30db ---- /dev/null -+++ b/libmultipath/sysfs.h -@@ -0,0 +1,20 @@ -+/* -+ * sysfs.h -+ */ -+ -+#ifndef _LIBMULTIPATH_SYSFS_H -+#define _LIBMULTIPATH_SYSFS_H -+ -+#define dbg(format, arg...) do {} while (0) -+ -+int sysfs_init(char *path, size_t len); -+void sysfs_cleanup(void); -+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, -+ const char *subsystem, const char *driver); -+struct sysfs_device *sysfs_device_get(const char *devpath); -+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); -+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem); -+char *sysfs_attr_get_value(const char *devpath, const char *attr_name); -+int sysfs_resolve_link(char *path, size_t size); -+ -+#endif -diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c -index 6482698..a4028d8 100644 ---- a/libmultipath/uevent.c -+++ b/libmultipath/uevent.c -@@ -26,12 +26,14 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include --#include -+#include -+#include - #include - #include - #include -@@ -105,6 +107,8 @@ int uevent_listen(int (*uev_trigger)(str - { - int sock; - struct sockaddr_nl snl; -+ struct sockaddr_un sun; -+ socklen_t addrlen; - int retval; - int rcvbufsz = 128*1024; - int rcvsz = 0; -@@ -131,43 +135,72 @@ int uevent_listen(int (*uev_trigger)(str - pthread_attr_setstacksize(&attr, 64 * 1024); - pthread_create(&uevq_thr, &attr, uevq_thread, NULL); - -- memset(&snl, 0x00, sizeof(struct sockaddr_nl)); -- snl.nl_family = AF_NETLINK; -- snl.nl_pid = getpid(); -- snl.nl_groups = 0xffffffff; -- -- sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); -- if (sock == -1) { -- condlog(0, "error getting socket, exit"); -- return 1; -- } -- - /* -- * try to avoid dropping uevents, even so, this is not a guarantee, -- * but it does help to change the netlink uevent socket's -- * receive buffer threshold from the default value of 106,496 to -- * the maximum value of 262,142. -+ * First check whether we have a udev socket - */ -- retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, -- sizeof(rcvbufsz)); -+ memset(&sun, 0x00, sizeof(struct sockaddr_un)); -+ sun.sun_family = AF_LOCAL; -+ strcpy(&sun.sun_path[1], "/org/kernel/dm/multipath_event"); -+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path+1) + 1; -+ -+ sock = socket(AF_LOCAL, SOCK_DGRAM, 0); -+ if (sock >= 0) { -+ const int feature_on = 1; -+ -+ condlog(3, "reading events from udev socket."); -+ -+ /* the bind takes care of ensuring only one copy running */ -+ retval = bind(sock, (struct sockaddr *) &sun, addrlen); -+ if (retval < 0) { -+ condlog(0, "bind failed, exit"); -+ goto exit; -+ } - -- if (retval < 0) { -- condlog(0, "error setting receive buffer size for socket, exit"); -- exit(1); -- } -- retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); -+ /* enable receiving of the sender credentials */ -+ setsockopt(sock, SOL_SOCKET, SO_PASSCRED, -+ &feature_on, sizeof(feature_on)); -+ -+ } else { -+ /* Fallback to read kernel netlink events */ -+ memset(&snl, 0x00, sizeof(struct sockaddr_nl)); -+ snl.nl_family = AF_NETLINK; -+ snl.nl_pid = getpid(); -+ snl.nl_groups = 0xffffffff; -+ -+ sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); -+ if (sock == -1) { -+ condlog(0, "error getting socket, exit"); -+ return 1; -+ } - -- if (retval < 0) { -- condlog(0, "error setting receive buffer size for socket, exit"); -- exit(1); -- } -- condlog(3, "receive buffer size for socket is %u.", rcvsz); -+ condlog(3, "reading events from kernel."); - -- retval = bind(sock, (struct sockaddr *) &snl, -- sizeof(struct sockaddr_nl)); -- if (retval < 0) { -- condlog(0, "bind failed, exit"); -- goto exit; -+ /* -+ * try to avoid dropping uevents, even so, this is not a guarantee, -+ * but it does help to change the netlink uevent socket's -+ * receive buffer threshold from the default value of 106,496 to -+ * the maximum value of 262,142. -+ */ -+ retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, -+ sizeof(rcvbufsz)); -+ -+ if (retval < 0) { -+ condlog(0, "error setting receive buffer size for socket, exit"); -+ exit(1); -+ } -+ retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); -+ if (retval < 0) { -+ condlog(0, "error setting receive buffer size for socket, exit"); -+ exit(1); -+ } -+ condlog(3, "receive buffer size for socket is %u.", rcvsz); -+ -+ retval = bind(sock, (struct sockaddr *) &snl, -+ sizeof(struct sockaddr_nl)); -+ if (retval < 0) { -+ condlog(0, "bind failed, exit"); -+ goto exit; -+ } - } - - while (1) { -diff --git a/libmultipath/util.c b/libmultipath/util.c -index 911ec55..eaf2266 100644 ---- a/libmultipath/util.c -+++ b/libmultipath/util.c -@@ -103,3 +103,55 @@ get_word (char * sentence, char ** word) - return skip + len; - } - -+size_t strlcpy(char *dst, const char *src, size_t size) -+{ -+ size_t bytes = 0; -+ char *q = dst; -+ const char *p = src; -+ char ch; -+ -+ while ((ch = *p++)) { -+ if (bytes+1 < size) -+ *q++ = ch; -+ bytes++; -+ } -+ -+ /* If size == 0 there is no space for a final null... */ -+ if (size) -+ *q = '\0'; -+ return bytes; -+} -+ -+size_t strlcat(char *dst, const char *src, size_t size) -+{ -+ size_t bytes = 0; -+ char *q = dst; -+ const char *p = src; -+ char ch; -+ -+ while (bytes < size && *q) { -+ q++; -+ bytes++; -+ } -+ if (bytes == size) -+ return (bytes + strlen(src)); -+ -+ while ((ch = *p++)) { -+ if (bytes+1 < size) -+ *q++ = ch; -+ bytes++; -+ } -+ -+ *q = '\0'; -+ return bytes; -+} -+ -+void remove_trailing_chars(char *path, char c) -+{ -+ size_t len; -+ -+ len = strlen(path); -+ while (len > 0 && path[len-1] == c) -+ path[--len] = '\0'; -+} -+ -diff --git a/libmultipath/util.h b/libmultipath/util.h -index e86bae2..d0df8aa 100644 ---- a/libmultipath/util.h -+++ b/libmultipath/util.h -@@ -6,7 +6,9 @@ void strchop(char *); - void basename (char * src, char * dst); - int filepresent (char * run); - int get_word (char * sentence, char ** word); -- -+size_t strlcpy(char *dst, const char *src, size_t size); -+size_t strlcat(char *dst, const char *src, size_t size); -+void remove_trailing_chars(char *path, char c); - - #define safe_sprintf(var, format, args...) \ - snprintf(var, sizeof(var), format, ##args) >= sizeof(var) + iterate_sub_keywords(rootkw, kw, i) { +- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n", ++ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k \"%v\"\n", + kw, hwe); + if (fwd > len) + return len; diff --git a/multipath/Makefile b/multipath/Makefile -index 947d481..3f32c41 100644 +index 4923b2f..bad9da7 100644 --- a/multipath/Makefile +++ b/multipath/Makefile -@@ -12,7 +12,7 @@ CFLAGS += -I$(multipathdir) -I$(checkers - ifeq ($(strip $(BUILD)),klibc) - OBJS += $(libdm) $(libsysfs) - else -- LDFLAGS += -ldevmapper -lsysfs -+ LDFLAGS += -ldevmapper - endif - - EXEC = multipath -@@ -21,7 +21,7 @@ all: $(BUILD) +@@ -22,9 +22,7 @@ all: $(BUILD) prepare: make -C $(multipathdir) prepare - rm -f core *.o *.gz +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz +- $(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz + rm -f core *.o glibc: prepare $(OBJS) $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) -@@ -37,17 +37,17 @@ $(MULTIPATHLIB)-$(BUILD).a: - - install: +@@ -42,17 +40,15 @@ install: install -d $(DESTDIR)$(bindir) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ -+ install -m 755 $(EXEC) $(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 -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/71-multipath.rules install -d $(DESTDIR)$(mandir) - install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) -+ install -d $(DESTDIR)$(man5dir) - install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir) +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + install -d $(DESTDIR)$(man5dir) +- install -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir) ++ install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir) uninstall: rm $(DESTDIR)/etc/udev/rules.d/multipath.rules rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8 +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz +- rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz clean: - rm -f core *.o $(EXEC) *.gz + rm -f core *.o $(EXEC) diff --git a/multipath/main.c b/multipath/main.c -index c3d0dac..e2d7f41 100644 +index 815c307..e2d7f41 100644 --- a/multipath/main.c +++ b/multipath/main.c -@@ -25,7 +25,6 @@ - #include - #include - #include --#include +@@ -72,7 +72,7 @@ static void + usage (char * progname) + { + fprintf (stderr, VERSION_STRING); +- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n", ++ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F|-t]\n", + progname); + fprintf (stderr, + "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \ +@@ -90,6 +90,7 @@ usage (char * progname) + "\t-ll\t\tshow multipath topology (maximum info)\n" \ + "\t-f\t\tflush a multipath device map\n" \ + "\t-F\t\tflush all multipath device maps\n" \ ++ "\t-t\t\tprint internal hardware table\n" \ + "\t-p policy\tforce all maps to specified policy :\n" \ + "\t failover\t\t1 path per priority group\n" \ + "\t multibus\t\tall paths in 1 priority group\n" \ +@@ -307,6 +308,55 @@ out: + return r; + } - #include - #include -@@ -37,6 +36,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -373,13 +373,13 @@ main (int argc, char *argv[]) - if (dm_prereq(DEFAULT_TARGET)) - exit(1); - -- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { -- condlog(0, "multipath tools need sysfs mounted"); -- exit(1); -- } - if (load_config(DEFAULT_CONFIGFILE)) - exit(1); - -+ if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { -+ condlog(0, "multipath tools need sysfs mounted"); -+ exit(1); ++static int ++dump_config (void) ++{ ++ char * c; ++ char * reply; ++ unsigned int maxlen = 256; ++ int again = 1; ++ ++ reply = MALLOC(maxlen); ++ ++ while (again) { ++ if (!reply) ++ return 1; ++ c = reply; ++ c += snprint_defaults(c, reply + maxlen - c); ++ again = ((c - reply) == maxlen); ++ if (again) { ++ reply = REALLOC(reply, maxlen *= 2); ++ continue; ++ } ++ c += snprint_blacklist(c, reply + maxlen - c); ++ again = ((c - reply) == maxlen); ++ if (again) { ++ reply = REALLOC(reply, maxlen *= 2); ++ continue; ++ } ++ c += snprint_blacklist_except(c, reply + maxlen - c); ++ again = ((c - reply) == maxlen); ++ if (again) { ++ reply = REALLOC(reply, maxlen *= 2); ++ continue; ++ } ++ c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable); ++ again = ((c - reply) == maxlen); ++ if (again) { ++ reply = REALLOC(reply, maxlen *= 2); ++ continue; ++ } ++ c += snprint_mptable(c, reply + maxlen - c, conf->mptable); ++ again = ((c - reply) == maxlen); ++ if (again) ++ reply = REALLOC(reply, maxlen *= 2); + } - while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:t")) != EOF ) { ++ ++ printf("%s", reply); ++ FREE(reply); ++ return 0; ++} ++ + int + main (int argc, char *argv[]) + { +@@ -330,7 +380,7 @@ main (int argc, char *argv[]) + 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:t")) != EOF ) { switch(arg) { case 1: printf("optarg : %s\n",optarg); -@@ -472,6 +472,7 @@ main (int argc, char *argv[]) - condlog(3, "restart multipath configuration process"); - - out: -+ sysfs_cleanup(); - free_config(conf); - dm_lib_release(); - dm_lib_exit(); + break; +@@ -373,6 +423,9 @@ main (int argc, char *argv[]) + usage(argv[0]); + } + break; ++ case 't': ++ dump_config(); ++ goto out; + case 'h': + usage(argv[0]); + case ':': +diff --git a/multipath/multipath.8 b/multipath/multipath.8 +index 693872b..e72cc45 100644 +--- a/multipath/multipath.8 ++++ b/multipath/multipath.8 +@@ -6,7 +6,7 @@ multipath \- Device mapper target autoconfig + .RB [\| \-v\ \c + .IR verbosity \|] + .RB [\| \-d \|] +-.RB [\| \-h | \-l | \-ll | \-f | \-F \|] ++.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F \|] + .RB [\| \-p\ \c + .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] + .RB [\| device \|] +@@ -47,6 +47,9 @@ flush a multipath device map specified as parameter, if unused + .B \-F + flush all unused multipath device maps + .TP ++.B \-t ++print internal hardware table to stdout ++.TP + .BI \-p " policy" + force maps to specified policy: + .RS 1.2i +@@ -76,6 +79,9 @@ is in the /dev/sdb (as shown by udev in the $DEVNAME variable) or major:minor fo + .I device + may alternatively be a multipath mapname + .SH "SEE ALSO" ++.BR multipathd (8), ++.BR multipath.conf (5), ++.BR kpartx (8), + .BR udev (8), + .BR dmsetup (8) + .BR hotplug (8) diff --git a/multipath/multipath.init.suse b/multipath/multipath.init.suse new file mode 100755 -index 0000000..34a128c +index 0000000..daea61f --- /dev/null +++ b/multipath/multipath.init.suse -@@ -0,0 +1,104 @@ +@@ -0,0 +1,130 @@ +#! /bin/sh +# Copyright (c) 2005 SuSE GmbH Nuernberg, Germany. +# @@ -2823,7 +499,8 @@ index 0000000..34a128c +# Required-Stop: +# Default-Start: B +# Default-Stop: -+# Description: Create multipath device targets ++# Short-Description: Create multipath device targets ++# Description: Setup initial multipath device-mapper targets +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin @@ -2862,9 +539,11 @@ index 0000000..34a128c +# with force-reload (in case signalling is not supported) are +# considered a success. + ++maplist=$(/sbin/dmsetup ls --target multipath | sed '/No devices/d' | cut -f 1) ++ +case "$1" in + start) -+ echo -n "Creating multipath targets" ++ echo -n "Creating multipath targets:" + # Check whether multipath daemon is already running + if /sbin/multipathd -k"list paths" > /dev/null 2>&1 ; then + echo -n " (multipathd running)" @@ -2876,7 +555,9 @@ index 0000000..34a128c + modprobe dm-multipath + + # Be a chicken and flush all existing maps -+ $PROGRAM -F ++ for map in $maplist ; do ++ $PROGRAM -f $map ++ done + + # Clear /dev/disk/by-name/ prior to start-up; multipath will + # recreate them. @@ -2898,395 +579,82 @@ index 0000000..34a128c + sleep 1 + ;; + stop) ++ echo -n "Removing multipath targets:" ++ + # Remove all partition mappings -+ if dmsetup ls | grep -q -- -part; then -+ /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -d -p -part" ++ if /sbin/dmsetup ls | sed '/No devices/d' | grep -q -- -part; then ++ /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -d -p -part" 2> /dev/null + fi + -+ # And remove the multipath mappings themselves -+ for map in $(/sbin/dmsetup ls --target multipath | cut -f 1); do -+ /sbin/dmsetup remove $map ++ # Flush all existing maps ++ for map in $maplist ; do ++ $PROGRAM -f $map + done ++ ++ rc_failed 0 ++ rc_status -v ++ ;; ++ status) ++ echo -n "Checking multipath targets: " ++ # Display active multipath tables ++ tblnum=$(/sbin/dmsetup ls --target multipath | sed '/No devices/d' | wc --lines) ++ if [ "$tblnum" ] && [ $tblnum -gt 0 ] ; then ++ echo -n "($tblnum multipath devices) " ++ rc_failed 0 ++ else ++ rc_failed 3 ++ fi ++ rc_status -v ++ ;; ++ reload) ++ $0 stop ++ $0 start + ;; + *) -+ echo "Usage: $0 {start|stop}" ++ echo "Usage: $0 {start|stop|status}" + exit 1 + ;; +esac +rc_exit -diff --git a/multipath/multipath.rules b/multipath/multipath.rules -index 10751ce..9d3579f 100644 ---- a/multipath/multipath.rules -+++ b/multipath/multipath.rules -@@ -1,18 +1,7 @@ - # --# multipath and multipath partitions nodes are created in /dev/mapper/ --# this file should be installed in /etc/udev/rules.d -+# udev rules for multipathing. -+# The persistent symlinks are created with the kpartx rules - # --# !! udev must not discard DM events !! --# !! check the other installed rules !! --# -- --# lookup the devmap name --#ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ --# PROGRAM="/sbin/devmap_name %M %m" --ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ -- PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info" -- --# take care of devmap partitioning --ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \ -- RUN+="/sbin/kpartx -a /dev/mapper/%c" - -+# socket for uevents -+RUN+="socket:/org/kernel/dm/multipath_event" diff --git a/multipathd/Makefile b/multipathd/Makefile -index da351dc..bbab8da 100644 +index b430b94..e076d56 100644 --- a/multipathd/Makefile +++ b/multipathd/Makefile -@@ -7,7 +7,7 @@ include ../Makefile.inc - # basic flags setting - # - CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir) --LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses -+LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses +@@ -35,7 +35,6 @@ klibc: - # - # debuging stuff -@@ -44,7 +44,7 @@ $(MULTIPATHLIB)-glibc.a: + $(EXEC): clean $(OBJS) + $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) +- $(GZIP) $(EXEC).8 > $(EXEC).8.gz - install: - install -d $(DESTDIR)$(bindir) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir) + $(CHECKERSLIB)-glibc.a: + $(MAKE) -C $(checkersdir) BUILD=glibc glibc +@@ -48,14 +47,13 @@ install: + $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) install -d $(DESTDIR)$(rcdir) install -d $(DESTDIR)$(mandir) - install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) -@@ -52,9 +52,8 @@ install: +- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir) ++ install -m 644 $(EXEC).8 $(DESTDIR)$(mandir) + uninstall: rm -f $(DESTDIR)$(bindir)/$(EXEC) rm -f $(DESTDIR)$(rcdir)/$(EXEC) -- rm -f $(DESTDIR)$(mandir)/$(EXEC).8 +- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz clean: $(MAKE) -C $(multipathdir) prepare DAEMON=1 - rm -f core *.o $(EXEC) *.gz + rm -f core *.o $(EXEC) -diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c -index 4938e84..7bae02a 100644 ---- a/multipathd/cli_handlers.c -+++ b/multipathd/cli_handlers.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "main.h" - #include "cli.h" -@@ -312,6 +313,9 @@ cli_add_map (void * v, char ** reply, in - { - struct vectors * vecs = (struct vectors *)data; - char * param = get_keyparam(v, MAP); -+ int minor; -+ char dev_path[PATH_SIZE]; -+ struct sysfs_device *sysdev; - - condlog(2, "%s: add map (operator)", param); - -@@ -321,7 +325,18 @@ cli_add_map (void * v, char ** reply, in - condlog(2, "%s: map blacklisted", param); - return 0; - } -- return ev_add_map(param, vecs); -+ minor = dm_get_minor(param); -+ if (minor < 0) { -+ condlog(2, "%s: not a device mapper table", param); -+ return 0; -+ } -+ sprintf(dev_path,"/block/dm-%d", minor); -+ sysdev = sysfs_device_get(dev_path); -+ if (!sysdev) { -+ condlog(2, "%s: not found in sysfs", param); -+ return 0; -+ } -+ return ev_add_map(sysdev, vecs); - } - - int -diff --git a/multipathd/main.c b/multipathd/main.c -index 94b0b95..a173da3 100644 ---- a/multipathd/main.c -+++ b/multipathd/main.c -@@ -14,12 +14,6 @@ - #include - - /* -- * libsysfs -- */ --#include --#include -- --/* - * libcheckers - */ - #include -@@ -40,6 +34,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -208,31 +203,29 @@ flush_map(struct multipath * mpp, struct - } - - static int --uev_add_map (char * devname, struct vectors * vecs) -+uev_add_map (struct sysfs_device * dev, struct vectors * vecs) - { -- condlog(2, "%s: add map (uevent)", devname); -- return ev_add_map(devname, vecs); -+ condlog(2, "%s: add map (uevent)", dev->kernel); -+ return ev_add_map(dev, vecs); - } - - int --ev_add_map (char * devname, struct vectors * vecs) -+ev_add_map (struct sysfs_device * dev, struct vectors * vecs) - { -- int major, minor; -- char dev_t[BLK_DEV_SIZE]; - char * alias; -+ char *dev_t; -+ int major, minor; - char * refwwid; - struct multipath * mpp; - int map_present; - int r = 1; - -- /* libsysfs seems to forget to terminate the string... */ -- memset(dev_t, 0, BLK_DEV_SIZE); -- if (sscanf(devname, "dm-%d", &minor) == 1 && -- !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) && -- sscanf(dev_t, "%d:%d", &major, &minor) == 2) -- alias = dm_mapname(major, minor); -- else -- alias = STRDUP(devname); -+ dev_t = sysfs_attr_get_value(dev->devpath, "dev"); -+ -+ if (!dev_t || sscanf(dev_t, "%d:%d", &major, &minor) != 2) -+ return 1; -+ -+ alias = dm_mapname(major, minor); - - if (!alias) - return 1; -@@ -241,7 +234,6 @@ ev_add_map (char * devname, struct vecto - - if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) { - condlog(4, "%s: not a multipath map", alias); -- FREE(alias); - return 0; - } - -@@ -254,8 +246,7 @@ ev_add_map (char * devname, struct vecto - * of uev_add_path - */ - condlog(0, "%s: devmap already registered", -- devname); -- FREE(alias); -+ dev->kernel); - return 0; - } - -@@ -265,10 +256,10 @@ ev_add_map (char * devname, struct vecto - if (map_present && (mpp = add_map_without_path(vecs, minor, alias, - start_waiter_thread))) { - sync_map_state(mpp); -- condlog(3, "%s: devmap %s added", alias, devname); -+ condlog(3, "%s: devmap %s added", alias, dev->kernel); - return 0; - } -- refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec); -+ refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec); - - if (refwwid) { - r = coalesce_paths(vecs, NULL, refwwid); -@@ -276,20 +267,19 @@ ev_add_map (char * devname, struct vecto - } - - if (!r) -- condlog(3, "%s: devmap %s added", alias, devname); -+ condlog(3, "%s: devmap %s added", alias, dev->kernel); - else -- condlog(0, "%s: uev_add_map %s failed", alias, devname); -+ condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel); - - FREE(refwwid); -- FREE(alias); - return r; - } - - static int --uev_remove_map (char * devname, struct vectors * vecs) -+uev_remove_map (struct sysfs_device * dev, struct vectors * vecs) - { -- condlog(2, "%s: remove map (uevent)", devname); -- return ev_remove_map(devname, vecs); -+ condlog(2, "%s: remove map (uevent)", dev->kernel); -+ return ev_remove_map(dev->kernel, vecs); - } - - int -@@ -310,13 +300,13 @@ ev_remove_map (char * devname, struct ve - } - - static int --uev_umount_map (char * devname, struct vectors * vecs) -+uev_umount_map (struct sysfs_device * dev, struct vectors * vecs) - { - struct multipath * mpp; - -- condlog(2, "%s: umount map (uevent)", devname); -+ condlog(2, "%s: umount map (uevent)", dev->kernel); - -- mpp = find_mp_by_str(vecs->mpvec, devname); -+ mpp = find_mp_by_str(vecs->mpvec, dev->kernel); - - if (!mpp) - return 0; -@@ -331,10 +321,10 @@ uev_umount_map (char * devname, struct v - } - - static int --uev_add_path (char * devname, struct vectors * vecs) -+uev_add_path (struct sysfs_device * dev, struct vectors * vecs) - { -- condlog(2, "%s: add path (uevent)", devname); -- return (ev_add_path(devname, vecs) != 1)? 0 : 1; -+ condlog(2, "%s: add path (uevent)", dev->kernel); -+ return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1; - } - - -@@ -450,10 +440,10 @@ out: - } - - static int --uev_remove_path (char * devname, struct vectors * vecs) -+uev_remove_path (struct sysfs_device * dev, struct vectors * vecs) - { -- condlog(2, "%s: remove path (uevent)", devname); -- return ev_remove_path(devname, vecs); -+ condlog(2, "%s: remove path (uevent)", dev->kernel); -+ return ev_remove_path(dev->kernel, vecs); - } - - int -@@ -636,7 +626,7 @@ int - uev_trigger (struct uevent * uev, void * trigger_data) - { - int r = 0; -- char devname[32]; -+ struct sysfs_device *sysdev; - struct vectors * vecs; - - vecs = (struct vectors *)trigger_data; -@@ -644,7 +634,7 @@ uev_trigger (struct uevent * uev, void * - if (uev_discard(uev->devpath)) - return 0; - -- basename(uev->devpath, devname); -+ sysdev = sysfs_device_get(uev->devpath); - lock(vecs->lock); - - /* -@@ -652,17 +642,17 @@ uev_trigger (struct uevent * uev, void * - * Add events are ignored here as the tables - * are not fully initialised then. - */ -- if (!strncmp(devname, "dm-", 3)) { -+ if (!strncmp(sysdev->kernel, "dm-", 3)) { - if (!strncmp(uev->action, "change", 6)) { -- r = uev_add_map(devname, vecs); -+ r = uev_add_map(sysdev, vecs); - goto out; - } - if (!strncmp(uev->action, "remove", 6)) { -- r = uev_remove_map(devname, vecs); -+ r = uev_remove_map(sysdev, vecs); - goto out; - } - if (!strncmp(uev->action, "umount", 6)) { -- r = uev_umount_map(devname, vecs); -+ r = uev_umount_map(sysdev, vecs); - goto out; - } - goto out; -@@ -672,15 +662,15 @@ uev_trigger (struct uevent * uev, void * - * path add/remove event - */ - if (filter_devnode(conf->blist_devnode, conf->elist_devnode, -- devname) > 0) -+ sysdev->kernel) > 0) - goto out; - - if (!strncmp(uev->action, "add", 3)) { -- r = uev_add_path(devname, vecs); -+ r = uev_add_path(sysdev, vecs); - goto out; - } - if (!strncmp(uev->action, "remove", 6)) { -- r = uev_remove_path(devname, vecs); -+ r = uev_remove_path(sysdev, vecs); - goto out; - } - -@@ -1278,7 +1268,7 @@ child (void * param) - if (!vecs) - exit(1); - -- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) { -+ if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) { - condlog(0, "can not find sysfs mount point"); - exit(1); - } -@@ -1315,6 +1305,8 @@ child (void * param) - pthread_cancel(uevent_thr); - pthread_cancel(uxlsnr_thr); - -+ sysfs_cleanup(); -+ - free_keys(keys); - keys = NULL; - free_handlers(handlers); -diff --git a/multipathd/main.h b/multipathd/main.h -index d0cce3a..1a6dc55 100644 ---- a/multipathd/main.h -+++ b/multipathd/main.h -@@ -7,7 +7,7 @@ - int reconfigure (struct vectors *); - int ev_add_path (char *, struct vectors *); - int ev_remove_path (char *, struct vectors *); --int ev_add_map (char *, struct vectors *); -+int ev_add_map (struct sysfs_device *, struct vectors *); - int ev_remove_map (char *, struct vectors *); - - #endif /* MAIN_H */ diff --git a/multipathd/multipathd.init.suse b/multipathd/multipathd.init.suse new file mode 100755 -index 0000000..a297956 +index 0000000..c850896 --- /dev/null +++ b/multipathd/multipathd.init.suse -@@ -0,0 +1,155 @@ +@@ -0,0 +1,133 @@ +#! /bin/sh +# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany. +# -+# Author: Thorsten Kukuk ++# Author: Hannes Reinecke +# +# init.d/routed +# @@ -3300,7 +668,8 @@ index 0000000..a297956 +# Required-Stop: +# Default-Start: 3 5 +# Default-Stop: 0 1 2 4 6 -+# Description: Starts multipath daemon ++# Short-Description: Starts multipath daemon ++# Description: Starts the multipath daemon +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin @@ -3312,34 +681,11 @@ index 0000000..a297956 + +test -x $DAEMON || exit 5 + -+# Shell functions sourced from /etc/rc.status: -+# rc_check check and set local and overall rc status -+# rc_status check and set local and overall rc status -+# rc_status -v ditto but be verbose in local rc status -+# rc_status -v -r ditto and clear the local rc status -+# rc_failed set local and overall rc status to failed -+# rc_reset clear local rc status (overall remains) -+# rc_exit exit appropriate to overall rc status +. /etc/rc.status + +# First reset status of this service +rc_reset + -+# Return values acc. to LSB for all commands but status: -+# 0 - success -+# 1 - misc error -+# 2 - invalid or excess args -+# 3 - unimplemented feature (e.g. reload) -+# 4 - insufficient privilege -+# 5 - program not installed -+# 6 - program not configured -+# 7 - program is not running -+# -+# Note that starting an already running service, stopping -+# or restarting a not-running service as well as the restart -+# with force-reload (in case signalling is not supported) are -+# considered a success. -+ +case "$1" in + start) + echo -n "Starting multipathd" @@ -3439,23 +785,34 @@ index 0000000..a297956 +esac +rc_exit diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile -index 6c58529..ce78455 100644 +index 6f356a1..ce78455 100644 --- a/path_priority/pp_alua/Makefile +++ b/path_priority/pp_alua/Makefile -@@ -41,10 +41,9 @@ install: $(EXEC) $(EXEC).8 +@@ -35,19 +35,15 @@ glibc: $(OBJS) + klibc: $(OBJS) + $(CC) -static -o $(EXEC) $(OBJS) + +-install: $(EXEC) $(EXEC).8.gz ++install: $(EXEC) $(EXEC).8 + $(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) +- $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz ++ $(INSTALL) -m 644 $(EXEC).8 $(DESTDIR)$(mandir)/$(EXEC).8 uninstall: rm $(DESTDIR)$(bindir)/$(EXEC) -- rm $(DESTDIR)$(mandir)/$(EXEC).8 +- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz clean: - rm -f *.o *.gz $(EXEC) +- +-$(EXEC).8.gz: $(EXEC).8 +- $(GZIP) $< >$@ + rm -f *.o $(EXEC) main.o: main.c rtpg.h spc3.h diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile -index bed7fb0..b0fee28 100644 +index cb1e6c6..43a0fc2 100644 --- a/path_priority/pp_balance_units/Makefile +++ b/path_priority/pp_balance_units/Makefile @@ -22,7 +22,7 @@ EXEC = mpath_prio_balance_units @@ -3467,81 +824,22 @@ index bed7fb0..b0fee28 100644 glibc: prepare $(OBJS) $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS) -@@ -35,10 +35,10 @@ $(MULTIPATHLIB)-$(BUILD).a: - - install: - install -d $(DESTDIR)$(bindir) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/ -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ - - uninstall: +@@ -41,4 +41,4 @@ uninstall: rm $(DESTDIR)$(bindir)/$(EXEC) clean: - rm -f core *.o $(EXEC) *.gz + rm -f core *.o $(EXEC) -diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile -index 651bdcd..8c6e922 100644 ---- a/path_priority/pp_emc/Makefile -+++ b/path_priority/pp_emc/Makefile -@@ -14,7 +14,7 @@ klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - - install: $(EXEC) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile -index a0249a5..1c276e6 100644 ---- a/path_priority/pp_hds_modular/Makefile -+++ b/path_priority/pp_hds_modular/Makefile -@@ -14,7 +14,7 @@ klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - - install: $(EXEC) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -diff --git a/path_priority/pp_netapp/Makefile b/path_priority/pp_netapp/Makefile -index 9e7d3a3..2d571b0 100644 ---- a/path_priority/pp_netapp/Makefile -+++ b/path_priority/pp_netapp/Makefile -@@ -14,7 +14,7 @@ klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - - install: $(EXEC) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile -index 85f42a2..ca7974e 100644 ---- a/path_priority/pp_random/Makefile -+++ b/path_priority/pp_random/Makefile -@@ -14,7 +14,7 @@ klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - - install: $(EXEC) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) -diff --git a/path_priority/pp_tpc/Makefile b/path_priority/pp_tpc/Makefile -index 86841dd..624f76d 100644 ---- a/path_priority/pp_tpc/Makefile -+++ b/path_priority/pp_tpc/Makefile -@@ -14,7 +14,7 @@ klibc: $(OBJS) - $(CC) -static -o $(EXEC) $(OBJS) - - install: $(EXEC) -- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) -+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC) - - uninstall: - rm $(DESTDIR)$(bindir)/$(EXEC) +diff --git a/path_priority/pp_hds_modular/pp_hds_modular.c b/path_priority/pp_hds_modular/pp_hds_modular.c +index 7411508..10b28b8 100644 +--- a/path_priority/pp_hds_modular/pp_hds_modular.c ++++ b/path_priority/pp_hds_modular/pp_hds_modular.c +@@ -120,7 +120,7 @@ int main (int argc, char **argv) + int hds_modular_prio (const char *dev) + { + int sg_fd, k; +- char vendor[8]; ++ char vendor[9]; + char product[32]; + char serial[32]; + char ldev[32]; diff --git a/multipath-tools.changes b/multipath-tools.changes index 7bce919..8dc1ff7 100644 --- a/multipath-tools.changes +++ b/multipath-tools.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Thu Aug 2 11:10:35 CEST 2007 - hare@suse.de + +- Merge in latest fixes from upstream +- Remove local patches; merge with upstream +- Fix kpartx handling of extended partitions +- Use underscores for partition names (#293792) + ------------------------------------------------------------------- Mon May 21 15:34:07 CEST 2007 - hare@suse.de diff --git a/multipath-tools.spec b/multipath-tools.spec index de04c38..390d702 100644 --- a/multipath-tools.spec +++ b/multipath-tools.spec @@ -11,22 +11,19 @@ # norootforbuild Name: multipath-tools -BuildRequires: device-mapper-devel readline-devel +BuildRequires: device-mapper-devel libaio-devel readline-devel URL: http://christophe.varoqui.free.fr/ -License: BSD License and BSD-like, GNU General Public License (GPL) +License: BSD 3-Clause, GPL v2 or later Group: System/Base Requires: device-mapper kpartx -%if %suse_version > 800 PreReq: %insserv_prereq -%endif Autoreqprov: on Version: 0.4.7 -Release: 50 +Release: 65 Summary: Tools to Manage Multipathed Devices with the device-mapper Source: multipath-tools-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build Patch0: %{name}-git-update.patch -Patch1: %{name}-local-fixes Patch10: %{name}-suse-update %description @@ -53,6 +50,7 @@ Authors: %package -n kpartx Summary: Manages partition tables on device-mapper devices Group: System/Base +Requires: device-mapper %description -n kpartx The kpartx program maps linear devmaps to device partitions, which @@ -67,7 +65,6 @@ Authors: %prep %setup -n multipath-tools-%{version} %patch0 -p1 -%patch1 -p1 %patch10 -p1 %build @@ -89,6 +86,9 @@ mkdir -p $RPM_BUILD_ROOT/var/cache/multipath/ #%{insserv /etc/init.d/multipathd} #%{fillup_and_insserv boot.multipath} +%preun +%stop_on_removal multipathd + %postun %{insserv_cleanup} @@ -109,7 +109,7 @@ mkdir -p $RPM_BUILD_ROOT/var/cache/multipath/ /sbin/mpath_prio_random /sbin/mpath_prio_alua /sbin/mpath_prio_emc -/sbin/mpath_prio_tpc +/sbin/mpath_prio_rdac /sbin/mpath_prio_hds_modular /sbin/mpath_prio_hp_sw %attr (0700, root, root) /var/cache/multipath @@ -123,12 +123,18 @@ mkdir -p $RPM_BUILD_ROOT/var/cache/multipath/ %defattr(-,root,root) %dir /etc/udev %dir /etc/udev/rules.d +%dir /lib/udev %config /etc/udev/rules.d/70-kpartx.rules /sbin/kpartx -/sbin/kpartx_id +/lib/udev/kpartx_id %{_mandir}/man8/kpartx.8* %changelog +* Thu Aug 02 2007 - hare@suse.de +- Merge in latest fixes from upstream +- Remove local patches; merge with upstream +- Fix kpartx handling of extended partitions +- Use underscores for partition names (#293792) * Mon May 21 2007 - hare@suse.de - Rework udev handling - Split off kpartx package