r252 - in multipath-tools/trunk: . devmap_name kpartx libmultipath
multipath multipathd path_priority/pp_alua
path_priority/pp_balance_units path_priority/pp_emc
path_priority/pp_random
Bastian Blank
waldi at costa.debian.org
Wed Feb 1 23:59:45 UTC 2006
Author: waldi
Date: Wed Feb 1 23:59:42 2006
New Revision: 252
Added:
multipath-tools/trunk/libmultipath/alias.c
multipath-tools/trunk/libmultipath/alias.h
multipath-tools/trunk/libmultipath/log.c
multipath-tools/trunk/libmultipath/log.h
multipath-tools/trunk/libmultipath/log_pthread.c
multipath-tools/trunk/libmultipath/log_pthread.h
multipath-tools/trunk/path_priority/pp_random/ (props changed)
multipath-tools/trunk/path_priority/pp_random/Makefile
multipath-tools/trunk/path_priority/pp_random/pp_random.c
Removed:
multipath-tools/trunk/kpartx/gpt.c.orig
multipath-tools/trunk/multipathd/log.c
multipath-tools/trunk/multipathd/log.h
multipath-tools/trunk/multipathd/log_pthread.c
multipath-tools/trunk/multipathd/log_pthread.h
Modified:
multipath-tools/trunk/ (props changed)
multipath-tools/trunk/ChangeLog
multipath-tools/trunk/Makefile
multipath-tools/trunk/Makefile.inc
multipath-tools/trunk/devmap_name/Makefile
multipath-tools/trunk/kpartx/Makefile
multipath-tools/trunk/kpartx/kpartx.c
multipath-tools/trunk/libmultipath/Makefile
multipath-tools/trunk/libmultipath/blacklist.c
multipath-tools/trunk/libmultipath/cache.c
multipath-tools/trunk/libmultipath/config.c
multipath-tools/trunk/libmultipath/config.h
multipath-tools/trunk/libmultipath/debug.c
multipath-tools/trunk/libmultipath/debug.h
multipath-tools/trunk/libmultipath/defaults.h
multipath-tools/trunk/libmultipath/devmapper.c
multipath-tools/trunk/libmultipath/devmapper.h
multipath-tools/trunk/libmultipath/dict.c
multipath-tools/trunk/libmultipath/discovery.c
multipath-tools/trunk/libmultipath/discovery.h
multipath-tools/trunk/libmultipath/dmparser.c
multipath-tools/trunk/libmultipath/hwtable.c
multipath-tools/trunk/libmultipath/pgpolicies.c
multipath-tools/trunk/libmultipath/pgpolicies.h
multipath-tools/trunk/libmultipath/print.c
multipath-tools/trunk/libmultipath/print.h
multipath-tools/trunk/libmultipath/propsel.c
multipath-tools/trunk/libmultipath/propsel.h
multipath-tools/trunk/libmultipath/structs.c
multipath-tools/trunk/libmultipath/structs.h
multipath-tools/trunk/libmultipath/switchgroup.c
multipath-tools/trunk/libmultipath/switchgroup.h
multipath-tools/trunk/libmultipath/uevent.c
multipath-tools/trunk/libmultipath/uxsock.c
multipath-tools/trunk/libmultipath/uxsock.h
multipath-tools/trunk/libmultipath/vector.c
multipath-tools/trunk/multipath.conf.annotated
multipath-tools/trunk/multipath.conf.synthetic
multipath-tools/trunk/multipath/Makefile
multipath-tools/trunk/multipath/main.c
multipath-tools/trunk/multipath/main.h
multipath-tools/trunk/multipath/multipath.rules
multipath-tools/trunk/multipathd/Makefile
multipath-tools/trunk/multipathd/cli.c
multipath-tools/trunk/multipathd/cli.h
multipath-tools/trunk/multipathd/cli_handlers.c
multipath-tools/trunk/multipathd/cli_handlers.h
multipath-tools/trunk/multipathd/main.c
multipath-tools/trunk/multipathd/main.h
multipath-tools/trunk/multipathd/uxclnt.c
multipath-tools/trunk/path_priority/pp_alua/Makefile
multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8
multipath-tools/trunk/path_priority/pp_balance_units/Makefile
multipath-tools/trunk/path_priority/pp_emc/Makefile
Log:
Merge /multipath-tools/upstream/current (0.4.6)
Modified: multipath-tools/trunk/ChangeLog
==============================================================================
--- multipath-tools/trunk/ChangeLog (original)
+++ multipath-tools/trunk/ChangeLog Wed Feb 1 23:59:42 2006
@@ -662,7 +662,7 @@
* [multipathd] setsched prio to RT
* [multipath] massive include cleanup
- * [multipath] add a "default_prio_callout" keyword
+ * [multipath] add a "prio_callout" keyword
first user will be SPC-3 ALUA priority field fetcher
from IBM
* [multipath] reenable stdout on some error paths
@@ -700,9 +700,9 @@
pathvecs
* [multipath] push WWID_SIZE to 64 char (scsi_id w/ JBODs)
* [multipath] add a exit_tool() wrapper fn for runfile unlink
- * [multipath] add a "default_path_grouping_policy" keyword in the
+ * [multipath] add a "path_grouping_policy" keyword in the
"defaults" block.
- * [multipath] add a "default_getuid_callout" keyword in the
+ * [multipath] add a "getuid_callout" keyword in the
"defaults" block. Now multipath is going to work with JBODs
* [multipath] fix segfault when pathvec is empty after
get_pathvec()
Modified: multipath-tools/trunk/Makefile
==============================================================================
--- multipath-tools/trunk/Makefile (original)
+++ multipath-tools/trunk/Makefile Wed Feb 1 23:59:42 2006
@@ -20,7 +20,7 @@
export KRNLSRC
export KRNLOBJ
-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \;)
+BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib)
VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
Modified: multipath-tools/trunk/Makefile.inc
==============================================================================
--- multipath-tools/trunk/Makefile.inc (original)
+++ multipath-tools/trunk/Makefile.inc Wed Feb 1 23:59:42 2006
@@ -28,7 +28,6 @@
mandir = /usr/share/man/man8
GZIP = /bin/gzip -9 -c
-STRIP = strip --strip-all -R .comment -R .note
CHECKERSLIB = $(checkersdir)/libcheckers
MULTIPATHLIB = $(multipathdir)/libmultipath
Modified: multipath-tools/trunk/devmap_name/Makefile
==============================================================================
--- multipath-tools/trunk/devmap_name/Makefile (original)
+++ multipath-tools/trunk/devmap_name/Makefile Wed Feb 1 23:59:42 2006
@@ -23,17 +23,15 @@
glibc: prepare $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(OBJS)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
install:
install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
install -d $(DESTDIR)$(mandir)
install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
Modified: multipath-tools/trunk/kpartx/Makefile
==============================================================================
--- multipath-tools/trunk/kpartx/Makefile (original)
+++ multipath-tools/trunk/kpartx/Makefile Wed Feb 1 23:59:42 2006
@@ -27,12 +27,10 @@
glibc: prepare $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(MULTIPATHLIB)-$(BUILD).a:
@@ -40,7 +38,7 @@
install:
install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
install -d $(DESTDIR)$(mandir)
install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
Modified: multipath-tools/trunk/kpartx/kpartx.c
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.c (original)
+++ multipath-tools/trunk/kpartx/kpartx.c Wed Feb 1 23:59:42 2006
@@ -315,7 +315,7 @@
for (i = 0; i < ptct; i++) {
ptp = &pts[i];
- if (type && strcmp(type, ptp->type) > 0)
+ if (type && strcmp(type, ptp->type))
continue;
/* here we get partitions */
Modified: multipath-tools/trunk/libmultipath/Makefile
==============================================================================
--- multipath-tools/trunk/libmultipath/Makefile (original)
+++ multipath-tools/trunk/libmultipath/Makefile Wed Feb 1 23:59:42 2006
@@ -10,18 +10,23 @@
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o cache.o discovery.o propsel.o dict.o \
pgpolicies.o debug.o regex.o defaults.o uevent.o \
- switchgroup.o uxsock.o print.o
+ switchgroup.o uxsock.o print.o alias.o log_pthread.o \
+ log.o
CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
+PREVBUILD = $(shell nm debug.o|grep log_safe)
+
ifeq ($(strip $(DAEMON)),1)
CFLAGS += -DDAEMON
+ CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
+else
+ CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
endif
all: $(BUILD)
-prepare:
- @rm -f debug.o
+prepare: $(CLEAN)
@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
@rm -f *-$(BUILD).a
Added: multipath-tools/trunk/libmultipath/alias.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/alias.c Wed Feb 1 23:59:42 2006
@@ -0,0 +1,369 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "debug.h"
+#include "uxsock.h"
+#include "alias.h"
+
+
+/*
+ * significant parts of this file were taken from iscsi-bindings.c of the
+ * linux-iscsi project.
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+static int
+ensure_directories_exist(char *str, mode_t dir_mode)
+{
+ char *pathname;
+ char *end;
+ int err;
+
+ pathname = strdup(str);
+ if (!pathname){
+ condlog(0, "Cannot copy bindings file pathname : %s",
+ strerror(errno));
+ return -1;
+ }
+ end = pathname;
+ /* skip leading slashes */
+ while (end && *end && (*end == '/'))
+ end++;
+
+ while ((end = strchr(end, '/'))) {
+ /* if there is another slash, make the dir. */
+ *end = '\0';
+ err = mkdir(pathname, dir_mode);
+ if (err && errno != EEXIST) {
+ condlog(0, "Cannot make directory [%s] : %s",
+ pathname, strerror(errno));
+ free(pathname);
+ return -1;
+ }
+ if (!err)
+ condlog(3, "Created dir [%s]", pathname);
+ *end = '/';
+ end++;
+ }
+ free(pathname);
+ return 0;
+}
+
+static void
+sigalrm(int sig)
+{
+ /* do nothing */
+}
+
+static int
+lock_bindings_file(int fd)
+{
+ struct sigaction act, oldact;
+ sigset_t set, oldset;
+ struct flock lock;
+ int err;
+
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+
+ act.sa_handler = sigalrm;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+
+ sigaction(SIGALRM, &act, &oldact);
+ sigprocmask(SIG_UNBLOCK, &set, &oldset);
+
+ alarm(BINDINGS_FILE_TIMEOUT);
+ err = fcntl(fd, F_SETLKW, &lock);
+ alarm(0);
+
+ if (err) {
+ if (errno != EINTR)
+ condlog(0, "Cannot lock bindings file : %s");
+ else
+ condlog(0, "Bindings file is locked. Giving up.");
+ }
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ sigaction(SIGALRM, &oldact, NULL);
+ return err;
+
+}
+
+
+static int
+open_bindings_file(char *file)
+{
+ int fd;
+ struct stat s;
+
+ if (ensure_directories_exist(file, 0700))
+ return -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 (lock_bindings_file(fd) < 0)
+ goto fail;
+
+ memset(&s, 0, sizeof(s));
+ if (fstat(fd, &s) < 0){
+ condlog(0, "Cannot stat bindings file : %s", strerror(errno));
+ goto fail;
+ }
+ if (s.st_size == 0) {
+ /* If bindings file is empty, write the header */
+ size_t len = strlen(BINDINGS_FILE_HEADER);
+ if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) {
+ condlog(0,
+ "Cannot write header to bindings file : %s",
+ strerror(errno));
+ /* cleanup partially written header */
+ ftruncate(fd, 0);
+ goto fail;
+ }
+ fsync(fd);
+ condlog(3, "Initialized new bindings file [%s]", file);
+ }
+
+ return fd;
+
+fail:
+ close(fd);
+ return -1;
+}
+
+
+static int
+lookup_binding(int fd, char *map_wwid, char **map_alias)
+{
+ char buf[LINE_MAX];
+ FILE *f;
+ unsigned int line_nr = 0;
+ int scan_fd;
+ int id = 0;
+
+ *map_alias = NULL;
+ scan_fd = dup(fd);
+ if (scan_fd < 0) {
+ condlog(0, "Cannot dup bindings file descriptor : %s",
+ strerror(errno));
+ return -1;
+ }
+ f = fdopen(scan_fd, "r");
+ if (!f) {
+ condlog(0, "cannot fdopen on bindings file descriptor : %s",
+ strerror(errno));
+ close(scan_fd);
+ return -1;
+ }
+ while (fgets(buf, LINE_MAX, f)) {
+ char *c, *alias, *wwid;
+ int curr_id;
+
+ line_nr++;
+ c = strpbrk(buf, "#\n\r");
+ if (c)
+ *c = '\0';
+ alias = strtok(buf, " \t");
+ if (!alias) /* blank line */
+ continue;
+ if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+ id = curr_id + 1;
+ wwid = strtok(NULL, " \t");
+ if (!wwid){
+ condlog(3,
+ "Ignoring malformed line %u in bindings file",
+ line_nr);
+ continue;
+ }
+ if (strcmp(wwid, map_wwid) == 0){
+ condlog(3, "Found matching wwid [%s] in bindings file."
+ "\nSetting alias to %s", wwid, alias);
+ *map_alias = strdup(alias);
+ if (*map_alias == NULL)
+ condlog(0, "Cannot copy alias from bindings "
+ "file : %s", strerror(errno));
+ fclose(f);
+ return id;
+ }
+ }
+ condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
+ fclose(f);
+ return id;
+}
+
+static int
+rlookup_binding(int fd, char **map_wwid, char *map_alias)
+{
+ char buf[LINE_MAX];
+ FILE *f;
+ unsigned int line_nr = 0;
+ int scan_fd;
+ int id = 0;
+
+ *map_wwid = NULL;
+ scan_fd = dup(fd);
+ if (scan_fd < 0) {
+ condlog(0, "Cannot dup bindings file descriptor : %s",
+ strerror(errno));
+ return -1;
+ }
+ f = fdopen(scan_fd, "r");
+ if (!f) {
+ condlog(0, "cannot fdopen on bindings file descriptor : %s",
+ strerror(errno));
+ close(scan_fd);
+ return -1;
+ }
+ while (fgets(buf, LINE_MAX, f)) {
+ char *c, *alias, *wwid;
+ int curr_id;
+
+ line_nr++;
+ c = strpbrk(buf, "#\n\r");
+ if (c)
+ *c = '\0';
+ alias = strtok(buf, " \t");
+ if (!alias) /* blank line */
+ continue;
+ if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+ id = curr_id + 1;
+ wwid = strtok(NULL, " \t");
+ if (!wwid){
+ condlog(3,
+ "Ignoring malformed line %u in bindings file",
+ line_nr);
+ continue;
+ }
+ if (strcmp(alias, map_alias) == 0){
+ condlog(3, "Found matching alias [%s] in bindings file."
+ "\nSetting wwid to %s", alias, wwid);
+ *map_wwid = strdup(wwid);
+ if (*map_wwid == NULL)
+ condlog(0, "Cannot copy alias from bindings "
+ "file : %s", strerror(errno));
+ fclose(f);
+ return id;
+ }
+ }
+ condlog(3, "No matching alias [%s] in bindings file.", map_alias);
+ fclose(f);
+ return id;
+}
+
+static char *
+allocate_binding(int fd, char *wwid, int id)
+{
+ char buf[LINE_MAX];
+ off_t offset;
+ char *alias, *c;
+
+ if (id < 0) {
+ condlog(0, "Bindings file full. Cannot allocate new binding");
+ return NULL;
+ }
+
+ snprintf(buf, LINE_MAX, "mpath%d %s\n", id, wwid);
+ buf[LINE_MAX - 1] = '\0';
+
+ offset = lseek(fd, 0, SEEK_END);
+ if (offset < 0){
+ condlog(0, "Cannot seek to end of bindings file : %s",
+ strerror(errno));
+ return NULL;
+ }
+ if (write_all(fd, buf, strlen(buf)) != strlen(buf)){
+ condlog(0, "Cannot write binding to bindings file : %s",
+ strerror(errno));
+ /* clear partial write */
+ ftruncate(fd, offset);
+ return NULL;
+ }
+ c = strchr(buf, ' ');
+ *c = '\0';
+ alias = strdup(buf);
+ if (alias == NULL)
+ condlog(0, "cannot copy new alias from bindings file : %s",
+ strerror(errno));
+ else
+ condlog(3, "Created new binding [%s] for WWID [%s]", alias,
+ wwid);
+ return alias;
+}
+
+char *
+get_user_friendly_alias(char *wwid, char *file)
+{
+ char *alias;
+ int fd, id;
+
+ if (!wwid || *wwid == '\0') {
+ condlog(3, "Cannot find binding for empty WWID");
+ return NULL;
+ }
+
+ fd = open_bindings_file(file);
+ if (fd < 0)
+ return NULL;
+ id = lookup_binding(fd, wwid, &alias);
+ if (id < 0) {
+ close(fd);
+ return NULL;
+ }
+ if (!alias)
+ alias = allocate_binding(fd, wwid, id);
+
+ close(fd);
+ return alias;
+}
+
+char *
+get_user_friendly_wwid(char *alias, char *file)
+{
+ char *wwid;
+ int fd, id;
+
+ if (!alias || *alias == '\0') {
+ condlog(3, "Cannot find binding for empty alias");
+ return NULL;
+ }
+
+ fd = open_bindings_file(file);
+ if (fd < 0)
+ return NULL;
+ id = rlookup_binding(fd, &wwid, alias);
+ if (id < 0) {
+ close(fd);
+ return NULL;
+ }
+
+ close(fd);
+ return wwid;
+}
Added: multipath-tools/trunk/libmultipath/alias.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/alias.h Wed Feb 1 23:59:42 2006
@@ -0,0 +1,12 @@
+#define BINDINGS_FILE_TIMEOUT 3
+#define BINDINGS_FILE_HEADER \
+"# Multipath bindings, Version : 1.0\n" \
+"# NOTE: this file is automatically maintained by the multipath program.\n" \
+"# You should not need to edit this file in normal circumstances.\n" \
+"#\n" \
+"# Format:\n" \
+"# alias wwid\n" \
+"#\n"
+
+char *get_user_friendly_alias(char *wwid, char *file);
+char *get_user_friendly_wwid(char *alias, char *file);
Modified: multipath-tools/trunk/libmultipath/blacklist.c
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.c (original)
+++ multipath-tools/trunk/libmultipath/blacklist.c Wed Feb 1 23:59:42 2006
@@ -82,9 +82,12 @@
if (!blist)
return;
- vector_foreach_slot (blist, ble, i)
- if (ble)
+ vector_foreach_slot (blist, ble, i) {
+ if (ble) {
+ regfree(ble);
FREE(ble);
+ }
+ }
vector_free(blist);
}
Modified: multipath-tools/trunk/libmultipath/cache.c
==============================================================================
--- multipath-tools/trunk/libmultipath/cache.c (original)
+++ multipath-tools/trunk/libmultipath/cache.c Wed Feb 1 23:59:42 2006
@@ -12,7 +12,7 @@
revoke_cache_info(struct path * pp)
{
pp->checker_context = NULL;
- pp->fd = 0;
+ pp->fd = -1;
pp->mpp = NULL;
pp->getuid = NULL;
pp->getprio = NULL;
Modified: multipath-tools/trunk/libmultipath/config.c
==============================================================================
--- multipath-tools/trunk/libmultipath/config.c (original)
+++ multipath-tools/trunk/libmultipath/config.c Wed Feb 1 23:59:42 2006
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
+#include "regex.h"
#include "memory.h"
#include "util.h"
#include "debug.h"
@@ -18,15 +19,27 @@
find_hwe (vector hwtable, char * vendor, char * product)
{
int i;
- struct hwentry * hwe;
+ struct hwentry *hwe, *ret = NULL;
+ regex_t vre, pre;
vector_foreach_slot (hwtable, hwe, i) {
- if (strcmp_chomp(hwe->vendor, vendor) == 0 &&
- (hwe->product[0] == '*' ||
- strcmp_chomp(hwe->product, product) == 0))
- return hwe;
+ if (regcomp(&vre, hwe->vendor, REG_EXTENDED|REG_NOSUB))
+ break;
+ if (regcomp(&pre, hwe->product, REG_EXTENDED|REG_NOSUB)) {
+ regfree(&vre);
+ break;
+ }
+ if (!regexec(&vre, vendor, 0, NULL, 0) &&
+ !regexec(&pre, product, 0, NULL, 0))
+ ret = hwe;
+
+ regfree(&pre);
+ regfree(&vre);
+
+ if (ret)
+ break;
}
- return NULL;
+ return ret;
}
extern struct mpentry *
@@ -183,12 +196,26 @@
return dst;
}
+static int
+dup_hwe (vector hwtable, char * vendor, char * product)
+{
+ struct hwentry * hwe = find_hwe(hwtable, vendor, product);
+
+ if (hwe)
+ return 1;
+
+ return 0;
+}
+
int
store_hwe (vector hwtable, char * vendor, char * product, int pgp,
char * getuid)
{
struct hwentry * hwe;
+ if (dup_hwe(hwtable, vendor, product))
+ return 0;
+
hwe = alloc_hwe();
if (!hwe)
@@ -228,10 +255,13 @@
int
store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
char * getuid, char * getprio, char * hwhandler,
- char * features, char * checker)
+ char * features, char * checker, int pgfailback)
{
struct hwentry * hwe;
+ if (dup_hwe(hwtable, vendor, product))
+ return 0;
+
hwe = alloc_hwe();
if (!hwe)
@@ -284,6 +314,8 @@
else
hwe->checker_index = get_checker_id(DEFAULT_CHECKER);
+ hwe->pgfailback = pgfailback;
+
if (!vector_alloc_slot(hwtable))
goto out;
@@ -309,14 +341,11 @@
if (conf->dev)
FREE(conf->dev);
- if (conf->multipath)
- FREE(conf->multipath);
-
if (conf->udev_dir)
FREE(conf->udev_dir);
- if (conf->default_selector)
- FREE(conf->default_selector);
+ if (conf->selector)
+ FREE(conf->selector);
if (conf->default_getuid)
FREE(conf->default_getuid);
@@ -324,8 +353,8 @@
if (conf->default_getprio)
FREE(conf->default_getprio);
- if (conf->default_features)
- FREE(conf->default_features);
+ if (conf->features)
+ FREE(conf->features);
if (conf->default_hwhandler)
FREE(conf->default_hwhandler);
@@ -354,6 +383,7 @@
conf->dev_type = DEV_NONE;
conf->minio = 1000;
+ conf->bindings_file = DEFAULT_BINDINGS_FILE;
/*
* read the config file
@@ -374,9 +404,10 @@
if (!conf->hwtable)
goto out;
- if (setup_default_hwtable(conf->hwtable))
- goto out;
}
+ if (setup_default_hwtable(conf->hwtable))
+ goto out;
+
if (conf->blist == NULL) {
conf->blist = vector_alloc();
@@ -392,8 +423,8 @@
if (!conf->mptable)
goto out;
}
- if (conf->default_selector == NULL)
- conf->default_selector = set_default(DEFAULT_SELECTOR);
+ if (conf->selector == NULL)
+ conf->selector = set_default(DEFAULT_SELECTOR);
if (conf->udev_dir == NULL)
conf->udev_dir = set_default(DEFAULT_UDEVDIR);
@@ -401,17 +432,20 @@
if (conf->default_getuid == NULL)
conf->default_getuid = set_default(DEFAULT_GETUID);
- if (conf->default_features == NULL)
- conf->default_features = set_default(DEFAULT_FEATURES);
+ if (conf->features == NULL)
+ conf->features = set_default(DEFAULT_FEATURES);
if (conf->default_hwhandler == NULL)
conf->default_hwhandler = set_default(DEFAULT_HWHANDLER);
- if (!conf->default_selector || !conf->udev_dir ||
- !conf->default_getuid || !conf->default_features ||
+ if (!conf->selector || !conf->udev_dir ||
+ !conf->default_getuid || !conf->features ||
!conf->default_hwhandler)
goto out;
+ if (!conf->default_checker_index)
+ conf->default_checker_index = READSECTOR0;
+
return 0;
out:
free_config(conf);
Modified: multipath-tools/trunk/libmultipath/config.h
==============================================================================
--- multipath-tools/trunk/libmultipath/config.h (original)
+++ multipath-tools/trunk/libmultipath/config.h Wed Feb 1 23:59:42 2006
@@ -18,6 +18,7 @@
int checker_index;
int pgfailback;
int rr_weight;
+ int no_path_retry;
char * vendor;
char * product;
@@ -33,6 +34,7 @@
int pgpolicy;
int pgfailback;
int rr_weight;
+ int no_path_retry;
char * wwid;
char * selector;
@@ -46,8 +48,9 @@
int list;
int pgpolicy_flag;
int with_sysfs;
- int default_selector_args;
+ int selector_args;
int default_pgpolicy;
+ int default_checker_index;
int dev_type;
int minio;
int checkint;
@@ -55,15 +58,17 @@
int pgfailback;
int remove;
int rr_weight;
+ int no_path_retry;
+ int user_friendly_names;
char * dev;
- char * multipath;
char * udev_dir;
- char * default_selector;
+ char * selector;
char * default_getuid;
char * default_getprio;
- char * default_features;
+ char * features;
char * default_hwhandler;
+ char * bindings_file;
vector mptable;
vector hwtable;
@@ -87,7 +92,7 @@
char * getuid);
int store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
char * getuid, char * getprio, char * hwhandler,
- char * features, char * checker);
+ char * features, char * checker, int pgfailback);
int load_config (char * file);
struct config * alloc_config (void);
Modified: multipath-tools/trunk/libmultipath/debug.c
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.c (original)
+++ multipath-tools/trunk/libmultipath/debug.c Wed Feb 1 23:59:42 2006
@@ -3,7 +3,7 @@
#include <stdarg.h>
#if DAEMON
-#include "../multipathd/log_pthread.h"
+#include "log_pthread.h"
#endif
#include "config.h"
Modified: multipath-tools/trunk/libmultipath/debug.h
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.h (original)
+++ multipath-tools/trunk/libmultipath/debug.h Wed Feb 1 23:59:42 2006
@@ -4,7 +4,8 @@
#include <pthread.h>
#include <stdarg.h>
-#include "../multipathd/log_pthread.h"
+
+#include "log_pthread.h"
int logsink;
Modified: multipath-tools/trunk/libmultipath/defaults.h
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.h (original)
+++ multipath-tools/trunk/libmultipath/defaults.h Wed Feb 1 23:59:42 2006
@@ -9,5 +9,6 @@
#define DEFAULT_PIDFILE "/var/run/multipathd.pid"
#define DEFAULT_SOCKET "/var/run/multipathd.sock"
#define DEFAULT_CONFIGFILE "/etc/multipath.conf"
+#define DEFAULT_BINDINGS_FILE "/var/lib/multipath/bindings"
char * set_default (char * str);
Modified: multipath-tools/trunk/libmultipath/devmapper.c
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.c (original)
+++ multipath-tools/trunk/libmultipath/devmapper.c Wed Feb 1 23:59:42 2006
@@ -15,6 +15,24 @@
#define MAX_WAIT 5
#define LOOPS_PER_SEC 5
+static void
+dm_dummy_log (int level, const char *file, int line, const char *f, ...)
+{
+ return;
+}
+
+void
+dm_restore_log (void)
+{
+ dm_log_init(NULL);
+}
+
+void
+dm_shut_log (void)
+{
+ dm_log_init(&dm_dummy_log);
+}
+
extern int
dm_prereq (char * str, int x, int y, int z)
{
@@ -84,7 +102,7 @@
extern int
dm_addmap (int task, const char *name, const char *target,
- const char *params, unsigned long long size) {
+ const char *params, unsigned long long size, const char *uuid) {
int r = 0;
struct dm_task *dmt;
@@ -97,6 +115,9 @@
if (!dm_task_add_target (dmt, 0, size, target, params))
goto addout;
+ if (uuid && !dm_task_set_uuid(dmt, uuid))
+ goto addout;
+
dm_task_no_open_count(dmt);
r = dm_task_run (dmt);
@@ -170,6 +191,34 @@
}
extern int
+dm_get_uuid(char *name, char *uuid)
+{
+ struct dm_task *dmt;
+ const char *uuidtmp;
+
+ dmt = dm_task_create(DM_DEVICE_INFO);
+ if (!dmt)
+ return 1;
+
+ if (!dm_task_set_name (dmt, name))
+ goto uuidout;
+
+ if (!dm_task_run(dmt))
+ goto uuidout;
+
+ uuidtmp = dm_task_get_uuid(dmt);
+ if (uuidtmp)
+ strcpy(uuid, uuidtmp);
+ else
+ uuid[0] = '\0';
+
+uuidout:
+ dm_task_destroy(dmt);
+
+ return 0;
+}
+
+extern int
dm_get_status(char * name, char * outstatus)
{
int r = 1;
@@ -204,6 +253,12 @@
return r;
}
+/*
+ * returns:
+ * 1 : match
+ * 0 : no match
+ * -1 : empty map
+ */
extern int
dm_type(char * name, char * type)
{
@@ -229,7 +284,9 @@
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, ¶ms);
- if (0 == strcmp(target_type, type))
+ if (!target_type)
+ r = -1;
+ else if (!strcmp(target_type, type))
r = 1;
out:
@@ -330,8 +387,10 @@
if (dm_remove_partmaps(mapname))
return 1;
- if (dm_get_opencount(mapname))
+ if (dm_get_opencount(mapname)) {
+ condlog(2, "%s: map in use", mapname);
return 1;
+ }
r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
@@ -376,11 +435,10 @@
}
int
-dm_fail_path(char * mapname, char * path)
+dm_message(char * mapname, char * message)
{
int r = 1;
struct dm_task *dmt;
- char str[32];
if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
return 1;
@@ -391,10 +449,7 @@
if (!dm_task_set_sector(dmt, 0))
goto out;
- if (snprintf(str, 32, "fail_path %s\n", path) > 32)
- goto out;
-
- if (!dm_task_set_message(dmt, str))
+ if (!dm_task_set_message(dmt, message))
goto out;
dm_task_no_open_count(dmt);
@@ -404,97 +459,75 @@
r = 0;
out:
+ if (r)
+ condlog(0, "DM message failed [%s]", message);
+
dm_task_destroy(dmt);
return r;
}
int
-dm_reinstate(char * mapname, char * path)
+dm_fail_path(char * mapname, char * path)
{
- int r = 1;
- struct dm_task *dmt;
- char str[32];
+ char message[32];
- if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
+ if (snprintf(message, 32, "fail_path %s\n", path) > 32)
return 1;
- if (!dm_task_set_name(dmt, mapname))
- goto out;
+ return dm_message(mapname, message);
+}
- if (!dm_task_set_sector(dmt, 0))
- goto out;
+int
+dm_reinstate_path(char * mapname, char * path)
+{
+ char message[32];
- if (snprintf(str, 32, "reinstate_path %s\n", path) > 32)
- goto out;
+ if (snprintf(message, 32, "reinstate_path %s\n", path) > 32)
+ return 1;
- if (!dm_task_set_message(dmt, str))
- goto out;
+ return dm_message(mapname, message);
+}
- dm_task_no_open_count(dmt);
+int
+dm_queue_if_no_path(char *mapname, int enable)
+{
+ char *message;
- if (!dm_task_run(dmt))
- goto out;
+ if (enable)
+ message = "queue_if_no_path\n";
+ else
+ message = "fail_if_no_path\n";
- r = 0;
-out:
- dm_task_destroy(dmt);
- return r;
+ return dm_message(mapname, message);
}
static int
dm_groupmsg (char * msg, char * mapname, int index)
{
- int r = 0;
- struct dm_task *dmt;
- char str[24];
-
- if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
- return 0;
-
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- if (!dm_task_set_sector(dmt, 0))
- goto out;
-
- snprintf(str, 24, "%s_group %i\n", msg, index);
-
- if (!dm_task_set_message(dmt, str))
- goto out;
-
- dm_task_no_open_count(dmt);
-
- if (!dm_task_run(dmt))
- goto out;
+ char message[32];
- condlog(3, "message %s 0 %s", mapname, str);
- r = 1;
-
- out:
- if (!r)
- condlog(3, "message %s 0 %s failed", mapname, str);
-
- dm_task_destroy(dmt);
+ if (snprintf(message, 32, "%s_group %i\n", msg, index) > 32)
+ return 1;
- return r;
+ return dm_message(mapname, message);
}
int
dm_switchgroup(char * mapname, int index)
{
- return dm_groupmsg("switch", mapname,index);
+ return dm_groupmsg("switch", mapname, index);
}
int
dm_enablegroup(char * mapname, int index)
{
- return dm_groupmsg("enable", mapname,index);
+ return dm_groupmsg("enable", mapname, index);
}
int
dm_disablegroup(char * mapname, int index)
{
- return dm_groupmsg("disable", mapname,index);
+ return dm_groupmsg("disable", mapname, index);
}
int
@@ -502,6 +535,7 @@
{
struct multipath * mpp;
int r = 1;
+ int info;
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
@@ -526,31 +560,37 @@
}
do {
- if (dm_type(names->name, type)) {
- mpp = alloc_multipath();
+ info = dm_type(names->name, type);
+
+ if (!info)
+ goto next;
+
+ mpp = alloc_multipath();
- if (!mpp)
- goto out;
+ if (!mpp)
+ goto out;
+ mpp->alias = STRDUP(names->name);
+
+ if (!mpp->alias)
+ goto out1;
+
+ if (info > 0) {
if (dm_get_map(names->name, &mpp->size, mpp->params))
goto out1;
if (dm_get_status(names->name, mpp->status))
goto out1;
- mpp->alias = MALLOC(strlen(names->name) + 1);
-
- if (!mpp->alias)
- goto out1;
+ dm_get_uuid(names->name, mpp->wwid);
+ }
- strncat(mpp->alias, names->name, strlen(names->name));
+ if (!vector_alloc_slot(mp))
+ goto out1;
- if (!vector_alloc_slot(mp))
- goto out1;
-
- vector_set_slot(mp, mpp);
- mpp = NULL;
- }
+ vector_set_slot(mp, mpp);
+ mpp = NULL;
+next:
next = names->next;
names = (void *) names + next;
} while (next);
@@ -616,10 +656,12 @@
/*
* device map might not be ready when we get here from
- * uevent trigger
+ * daemon uev_trigger -> uev_add_map
*/
while (--loop) {
+ dm_shut_log();
r = dm_task_run(dmt);
+ dm_restore_log();
if (r)
break;
@@ -718,6 +760,52 @@
return r;
}
+static struct dm_info *
+alloc_dminfo (void)
+{
+ return MALLOC(sizeof(struct dm_info));
+}
+
+int
+dm_get_info (char * mapname, struct dm_info ** dmi)
+{
+ int r = 1;
+ struct dm_task *dmt = NULL;
+
+ if (!mapname)
+ return 1;
+
+ if (!*dmi)
+ *dmi = alloc_dminfo();
+
+ if (!*dmi)
+ return 1;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ goto out;
+
+ if (!dm_task_set_name(dmt, mapname))
+ goto out;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, *dmi))
+ goto out;
+
+ r = 0;
+out:
+ if (r)
+ memset(*dmi, 0, sizeof(struct dm_info));
+
+ if (dmt)
+ dm_task_destroy(dmt);
+
+ return r;
+}
+
#if 0
int
dm_rename (char * old, char * new)
Modified: multipath-tools/trunk/libmultipath/devmapper.h
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.h (original)
+++ multipath-tools/trunk/libmultipath/devmapper.h Wed Feb 1 23:59:42 2006
@@ -1,7 +1,9 @@
+void dm_shut_log(void);
+void dm_restore_log(void);
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 long);
+ unsigned long long, const char *uuid);
int dm_map_present (char *);
int dm_get_map(char *, unsigned long long *, char *);
int dm_get_status(char *, char *);
@@ -9,7 +11,8 @@
int dm_flush_map (char *, char *);
int dm_flush_maps (char *);
int dm_fail_path(char * mapname, char * path);
-int dm_reinstate(char * mapname, char * path);
+int dm_reinstate_path(char * mapname, char * path);
+int dm_queue_if_no_path(char *mapname, int enable);
int dm_switchgroup(char * mapname, int index);
int dm_enablegroup(char * mapname, int index);
int dm_disablegroup(char * mapname, int index);
@@ -18,6 +21,8 @@
int dm_get_minor (char *name);
char * dm_mapname(int major, int minor);
int dm_remove_partmaps (char * mapname);
+int dm_get_uuid(char *name, char *uuid);
+int dm_get_info (char * mapname, struct dm_info ** dmi);
#if 0
int dm_rename (char * old, char * new);
Modified: multipath-tools/trunk/libmultipath/dict.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.c (original)
+++ multipath-tools/trunk/libmultipath/dict.c Wed Feb 1 23:59:42 2006
@@ -14,17 +14,6 @@
* default block handlers
*/
static int
-multipath_tool_handler(vector strvec)
-{
- conf->multipath = set_value(strvec);
-
- if (!conf->multipath)
- return 1;
-
- return 0;
-}
-
-static int
polling_interval_handler(vector strvec)
{
char * buff;
@@ -50,9 +39,9 @@
static int
def_selector_handler(vector strvec)
{
- conf->default_selector = set_value(strvec);
+ conf->selector = set_value(strvec);
- if (!conf->default_selector)
+ if (!conf->selector)
return 1;
return 0;
@@ -104,10 +93,26 @@
static int
def_features_handler(vector strvec)
{
- conf->default_features = set_value(strvec);
+ conf->features = set_value(strvec);
+
+ if (!conf->features)
+ return 1;
+
+ return 0;
+}
+
+static int
+def_path_checker_handler(vector strvec)
+{
+ char * buff;
- if (!conf->default_features)
+ buff = set_value(strvec);
+
+ if (!buff)
return 1;
+
+ conf->default_checker_index = get_checker_id(buff);
+ FREE(buff);
return 0;
}
@@ -166,6 +171,45 @@
return 0;
}
+static int
+def_no_path_retry_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ conf->no_path_retry = NO_PATH_RETRY_FAIL;
+ else if (!strncmp(buff, "queue", 5))
+ conf->no_path_retry = NO_PATH_RETRY_QUEUE;
+ else if ((conf->no_path_retry = atoi(buff)) < 1)
+ conf->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
+static int
+names_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ if (!strncmp(buff, "no", 2) || !strncmp(buff, "0", 1))
+ conf->user_friendly_names = 0;
+ else if (!strncmp(buff, "yes", 2) || !strncmp(buff, "1", 1))
+ conf->user_friendly_names = 1;
+
+ FREE(buff);
+ return 0;
+}
+
/*
* blacklist block handlers
*/
@@ -427,6 +471,30 @@
return 0;
}
+static int
+hw_no_path_retry_handler(vector strvec)
+{
+ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+ char *buff;
+
+ if (!hwe)
+ return 1;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ hwe->no_path_retry = NO_PATH_RETRY_FAIL;
+ else if (!strncmp(buff, "queue", 5))
+ hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
+ else if ((hwe->no_path_retry = atoi(buff)) < 1)
+ hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
/*
* multipaths block handlers
*/
@@ -574,6 +642,30 @@
return 0;
}
+static int
+mp_no_path_retry_handler(vector strvec)
+{
+ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+ char *buff;
+
+ if (!mpe)
+ return 1;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ mpe->no_path_retry = NO_PATH_RETRY_FAIL;
+ else if (!strncmp(buff, "queue", 5))
+ mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
+ else if ((mpe->no_path_retry = atoi(buff)) < 1)
+ mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
+
+ FREE(buff);
+ return 0;
+}
+
vector
init_keywords(void)
{
@@ -581,17 +673,29 @@
install_keyword_root("defaults", NULL);
install_keyword("polling_interval", &polling_interval_handler);
- install_keyword("multipath_tool", &multipath_tool_handler);
install_keyword("udev_dir", &udev_dir_handler);
+ install_keyword("selector", &def_selector_handler);
+ install_keyword("path_grouping_policy", &def_pgpolicy_handler);
+ install_keyword("getuid_callout", &def_getuid_callout_handler);
+ install_keyword("prio_callout", &def_prio_callout_handler);
+ install_keyword("features", &def_features_handler);
+ install_keyword("path_checker", &def_path_checker_handler);
+ install_keyword("failback", &default_failback_handler);
+ install_keyword("rr_min_io", &def_minio_handler);
+ install_keyword("rr_weight", &def_weight_handler);
+ install_keyword("no_path_retry", &def_no_path_retry_handler);
+ install_keyword("user_friendly_names", &names_handler);
+
+ /*
+ * deprecated synonyms
+ */
install_keyword("default_selector", &def_selector_handler);
install_keyword("default_path_grouping_policy", &def_pgpolicy_handler);
install_keyword("default_getuid_callout", &def_getuid_callout_handler);
install_keyword("default_prio_callout", &def_prio_callout_handler);
install_keyword("default_features", &def_features_handler);
- install_keyword("failback", &default_failback_handler);
- install_keyword("rr_min_io", &def_minio_handler);
- install_keyword("rr_weight", &def_weight_handler);
-
+ install_keyword("default_path_checker", &def_path_checker_handler);
+
install_keyword_root("devnode_blacklist", &blacklist_handler);
install_keyword("devnode", &ble_handler);
install_keyword("wwid", &ble_handler);
@@ -610,6 +714,7 @@
install_keyword("prio_callout", &prio_callout_handler);
install_keyword("failback", &hw_failback_handler);
install_keyword("rr_weight", &hw_weight_handler);
+ install_keyword("no_path_retry", &hw_no_path_retry_handler);
install_sublevel_end();
install_keyword_root("multipaths", &multipaths_handler);
@@ -621,6 +726,7 @@
install_keyword("path_selector", &mp_selector_handler);
install_keyword("failback", &mp_failback_handler);
install_keyword("rr_weight", &mp_weight_handler);
+ install_keyword("no_path_retry", &mp_no_path_retry_handler);
install_sublevel_end();
return keywords;
Modified: multipath-tools/trunk/libmultipath/discovery.c
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.c (original)
+++ multipath-tools/trunk/libmultipath/discovery.c Wed Feb 1 23:59:42 2006
@@ -20,6 +20,8 @@
#include "sg_include.h"
#include "discovery.h"
+#include "../libcheckers/path_state.h"
+
#define readattr(a,b) \
sysfs_read_attribute_value(a, b, sizeof(b))
@@ -56,23 +58,31 @@
struct sysfs_directory * devp;
char path[FILE_NAME_SIZE];
struct path * pp;
- int r = 1;
+ int r = 0;
if(safe_sprintf(path, "%s/block", sysfs_path)) {
condlog(0, "path too small");
- exit(1);
+ return 1;
}
sdir = sysfs_open_directory(path);
+
+ if (!sdir)
+ return 1;
+
sysfs_read_directory(sdir);
dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
+ if (!devp)
+ continue;
+
if (blacklist(conf->blist, devp->name))
continue;
if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
devp->name)) {
condlog(0, "path too small");
- exit(1);
+ sysfs_close_directory(sdir);
+ return 1;
}
if (!filepresent(path))
@@ -86,28 +96,35 @@
* the caller wants
*/
if (!store_pathinfo(pathvec, conf->hwtable,
- devp->name, flag))
- goto out;
+ devp->name, flag)) {
+ r++;
+ continue;
+ }
} else {
/*
* path already known :
* refresh only what the caller wants
*/
- if (pathinfo(pp, conf->hwtable, flag))
- goto out;
+ if (pathinfo(pp, conf->hwtable, flag)) {
+ r++;
+ continue;
+ }
}
}
- r = 0;
-out:
sysfs_close_directory(sdir);
return r;
}
+/*
+ * 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
static int
-wait_sysfs_attr (char * filename)
+wait_for_file (char * filename)
{
int loop;
struct stat stats;
@@ -118,10 +135,20 @@
if (stat(filename, &stats) == 0)
return 0;
+ if (errno != ENOENT)
+ return 1;
+
usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
}
return 1;
-}
+}
+#else
+static int
+wait_for_file (char * filename)
+{
+ return 0;
+}
+#endif
#define declare_sysfs_get_str(fname, fmt) \
extern int \
@@ -134,7 +161,7 @@
if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
return 1; \
\
- if (wait_sysfs_attr(attr_path)) \
+ if (wait_for_file(attr_path)) \
return 1; \
\
if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
@@ -166,7 +193,7 @@
if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
return 0; \
\
- if (wait_sysfs_attr(attr_path)) \
+ if (wait_for_file(attr_path)) \
return 0; \
\
if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
@@ -189,43 +216,19 @@
opennode (char * dev, int mode)
{
char devpath[FILE_NAME_SIZE];
- int fd;
- int loop;
if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
condlog(0, "devpath too small");
return -1;
}
- loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
-
- while (--loop) {
- fd = open(devpath, mode);
-
- if (fd <= 0 && errno != ENOENT) {
- condlog(3, "open error (%s)\n", strerror(errno));
- return fd;
- }
- if (fd > 0)
- return fd;
-
- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+ if (wait_for_file(devpath)) {
+ condlog(3, "failed to open %s", devpath);
+ return -1;
}
- condlog(0, "failed to open %s", devpath);
- return -1;
-}
-
-int
-get_claimed(char * devname)
-{
- int fd = opennode(devname, O_EXCL);
-
- if (fd < 0)
- return 1;
- close(fd);
- return 0;
-}
+ return open(devpath, mode);
+}
extern int
devt2devname (char *devname, char *devt)
@@ -239,7 +242,7 @@
if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
condlog(0, "block_path too small");
- exit(1);
+ return 1;
}
sdir = sysfs_open_directory(block_path);
sysfs_read_directory(sdir);
@@ -248,7 +251,7 @@
if(safe_sprintf(attr_path, "%s/%s/dev",
block_path, devp->name)) {
condlog(0, "attr_path too small");
- exit(1);
+ goto err;
}
sysfs_read_attribute_value(attr_path, attr_value,
sizeof(attr_value));
@@ -263,7 +266,7 @@
if(safe_sprintf(attr_path, "%s/%s",
block_path, devp->name)) {
condlog(0, "attr_path too small");
- exit(1);
+ goto err;
}
sysfs_get_name_from_path(attr_path, devname,
FILE_NAME_SIZE);
@@ -271,6 +274,7 @@
return 0;
}
}
+err:
sysfs_close_directory(sdir);
return 1;
}
@@ -377,6 +381,8 @@
else if (!strncmp(sdev->bus, "ide", 3))
curpath->bus = SYSFS_BUS_IDE;
+ sysfs_close_device(sdev);
+
return;
}
@@ -451,7 +457,6 @@
static int
common_sysfs_pathinfo (struct path * curpath)
{
-
sysfs_get_bus(sysfs_path, curpath);
condlog(3, "bus = %i", curpath->bus);
@@ -502,10 +507,6 @@
return 1;
dst = cmd;
-
- if (!dst)
- return 1;
-
p = dst;
pos = strchr(string, '%');
myfree = CALLOUT_MAX_SIZE;
@@ -582,7 +583,7 @@
char buff[CALLOUT_MAX_SIZE];
char prio[16];
- condlog(3, "===== path %s =====", pp->dev);
+ condlog(3, "===== path info %s (mask 0x%x) =====", pp->dev, mask);
/*
* fetch info available in sysfs
@@ -591,21 +592,17 @@
return 1;
/*
- * then those not available through sysfs
+ * fetch info not available through sysfs
*/
- if (mask & DI_CLAIMED) {
- pp->claimed = get_claimed(pp->dev);
- condlog(3, "claimed = %i", pp->claimed);
- }
- if (pp->fd <= 0)
+ if (pp->fd < 0)
pp->fd = opennode(pp->dev, O_RDONLY);
- if (pp->fd <= 0)
- return 1;
+ if (pp->fd < 0)
+ goto out;
- if (pp->bus == SYSFS_BUS_SCSI)
- if (scsi_ioctl_pathinfo(pp, mask))
- return 1;
+ if (pp->bus == SYSFS_BUS_SCSI &&
+ scsi_ioctl_pathinfo(pp, mask))
+ goto out;
/* get and store hwe pointer */
pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id);
@@ -662,4 +659,13 @@
condlog(3, "uid = %s (cache)", pp->wwid);
return 0;
+
+out:
+ /*
+ * Recoverable error, for example faulty or offline path
+ * Set up safe defaults, don't trust the cache
+ */
+ memset(pp->wwid, 0, WWID_SIZE);
+ pp->state = PATH_DOWN;
+ return 0;
}
Modified: multipath-tools/trunk/libmultipath/discovery.h
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.h (original)
+++ multipath-tools/trunk/libmultipath/discovery.h Wed Feb 1 23:59:42 2006
@@ -40,14 +40,21 @@
/*
* discovery bitmask
*/
-#define DI_SYSFS 1
-#define DI_SERIAL 2
-#define DI_CLAIMED 4
-#define DI_CHECKER 8
-#define DI_PRIO 16
-#define DI_WWID 32
+enum discovery_mode {
+ __DI_SYSFS,
+ __DI_SERIAL,
+ __DI_CHECKER,
+ __DI_PRIO,
+ __DI_WWID
+};
-#define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CLAIMED | DI_CHECKER | \
- DI_PRIO | DI_WWID)
+#define DI_SYSFS (1 << __DI_SYSFS)
+#define DI_SERIAL (1 << __DI_SERIAL)
+#define DI_CHECKER (1 << __DI_CHECKER)
+#define DI_PRIO (1 << __DI_PRIO)
+#define DI_WWID (1 << __DI_WWID)
+
+#define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CHECKER | DI_PRIO | \
+ DI_WWID)
#endif /* DISCOVERY_H */
Modified: multipath-tools/trunk/libmultipath/dmparser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.c (original)
+++ multipath-tools/trunk/libmultipath/dmparser.c Wed Feb 1 23:59:42 2006
@@ -250,7 +250,7 @@
{
char * word;
char * p;
- int i, j;
+ int i, j, k;
int num_feature_args;
int num_hwhandler_args;
int num_pg;
@@ -405,12 +405,13 @@
pp->failcount = atoi(word);
FREE(word);
+
+ /*
+ * selector args
+ */
+ for (k = 0; k < num_pg_args; k++)
+ p += get_word(p, NULL);
}
- /*
- * selector args
- */
- for (j = 0; j < num_pg_args; j++)
- p += get_word(p, NULL);
}
return 0;
}
Modified: multipath-tools/trunk/libmultipath/hwtable.c
==============================================================================
--- multipath-tools/trunk/libmultipath/hwtable.c (original)
+++ multipath-tools/trunk/libmultipath/hwtable.c Wed Feb 1 23:59:42 2006
@@ -17,7 +17,8 @@
r += store_hwe(hw, "COMPAQ", "MSA1000 VOLUME", GROUP_BY_SERIAL, DEFAULT_GETUID);
r += store_hwe(hw, "DDN", "SAN DataDirector", MULTIBUS, DEFAULT_GETUID);
r += store_hwe(hw, "DEC", "HSG80", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS, DEFAULT_GETUID);
+ r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS,
+ "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n");
r += store_hwe(hw, "FSC", "CentricStor", GROUP_BY_SERIAL, DEFAULT_GETUID);
r += store_hwe(hw, "HITACHI", "DF400", MULTIBUS, DEFAULT_GETUID);
r += store_hwe(hw, "HITACHI", "DF500", MULTIBUS, DEFAULT_GETUID);
@@ -36,13 +37,13 @@
r += store_hwe_ext(hw, "DGC", "*", GROUP_BY_PRIO, DEFAULT_GETUID,
"/sbin/mpath_prio_emc /dev/%n", "1 emc",
- "1 queue_if_no_path", "emc_clariion");
+ "1 queue_if_no_path", "emc_clariion", FAILBACK_IMMEDIATE);
r += store_hwe_ext(hw, "IBM", "3542", GROUP_BY_SERIAL, DEFAULT_GETUID,
- NULL, "0", "0", "tur");
+ NULL, "0", "0", "tur", FAILBACK_UNDEF);
r += store_hwe_ext(hw, "SGI", "TP9400", MULTIBUS, DEFAULT_GETUID,
- NULL, "0", "0", "tur");
+ NULL, "0", "0", "tur", FAILBACK_UNDEF);
r += store_hwe_ext(hw, "SGI", "TP9500", FAILOVER, DEFAULT_GETUID,
- NULL, "0", "0", "tur");
+ NULL, "0", "0", "tur", FAILBACK_UNDEF);
return r;
}
Added: multipath-tools/trunk/libmultipath/log.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/log.c Wed Feb 1 23:59:42 2006
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "memory.h"
+#include "log.h"
+
+#define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
+
+#if LOGDBG
+static void dump_logarea (void)
+{
+ struct logmsg * msg;
+
+ logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
+ la->start, la->end);
+ logdbg(stderr, "|addr |next |prio|msg\n");
+
+ for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
+ msg = msg->next)
+ logdbg(stderr, "|%p |%p |%i |%s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+ logdbg(stderr, "|%p |%p |%i |%s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+ logdbg(stderr, "\n\n");
+}
+#endif
+
+static int logarea_init (int size)
+{
+ logdbg(stderr,"enter logarea_init\n");
+ la = (struct logarea *)MALLOC(sizeof(struct logarea));
+
+ if (!la)
+ return 1;
+
+ if (size < MAX_MSG_SIZE)
+ size = DEFAULT_AREA_SIZE;
+
+ la->start = MALLOC(size);
+ memset(la->start, 0, size);
+
+ if (!la->start) {
+ FREE(la);
+ return 1;
+ }
+
+ la->empty = 1;
+ la->end = la->start + size;
+ la->head = la->start;
+ la->tail = la->start;
+
+ la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
+
+ if (!la->buff) {
+ FREE(la->start);
+ FREE(la);
+ return 1;
+ }
+ return 0;
+
+}
+
+int log_init(char *program_name, int size)
+{
+ logdbg(stderr,"enter log_init\n");
+ openlog(program_name, 0, LOG_DAEMON);
+
+ if (logarea_init(size))
+ return 1;
+
+ return 0;
+}
+
+void free_logarea (void)
+{
+ FREE(la->start);
+ FREE(la->buff);
+ FREE(la);
+ return;
+}
+
+void log_close (void)
+{
+ free_logarea();
+ closelog();
+
+ return;
+}
+
+int log_enqueue (int prio, const char * fmt, va_list ap)
+{
+ int len, fwd;
+ char buff[MAX_MSG_SIZE];
+ struct logmsg * msg;
+ struct logmsg * lastmsg;
+
+ lastmsg = (struct logmsg *)la->tail;
+
+ if (!la->empty) {
+ fwd = sizeof(struct logmsg) +
+ strlen((char *)&lastmsg->str) * sizeof(char) + 1;
+ la->tail += ALIGN(fwd, sizeof(void *));
+ }
+ vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
+ len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
+ sizeof(void *));
+
+ /* 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);
+ la->tail = la->start;
+
+ if (la->empty)
+ la->head = la->start;
+ }
+
+ /* not enough space on head : drop msg */
+ if (la->head > la->tail && len >= (la->head - la->tail)) {
+ logdbg(stderr, "enqueue: log area overrun, drop msg\n");
+
+ if (!la->empty)
+ la->tail = lastmsg;
+
+ return 1;
+ }
+
+ /* ok, we can stage the msg in the area */
+ la->empty = 0;
+ msg = (struct logmsg *)la->tail;
+ msg->prio = prio;
+ memcpy((void *)&msg->str, buff, strlen(buff));
+ lastmsg->next = la->tail;
+ msg->next = la->head;
+
+ logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
+ msg->prio, (char *)&msg->str);
+
+#if LOGDBG
+ dump_logarea();
+#endif
+ return 0;
+}
+
+int log_dequeue (void * buff)
+{
+ struct logmsg * src = (struct logmsg *)la->head;
+ struct logmsg * dst = (struct logmsg *)buff;
+ struct logmsg * lst = (struct logmsg *)la->tail;
+
+ if (la->empty)
+ return 1;
+
+ int len = strlen((char *)&src->str) * sizeof(char) +
+ sizeof(struct logmsg) + 1;
+
+ dst->prio = src->prio;
+ memcpy(dst, src, len);
+
+ if (la->tail == la->head)
+ la->empty = 1; /* we purge the last logmsg */
+ else {
+ la->head = src->next;
+ lst->next = la->head;
+ }
+ logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
+ (void *)src, src->next, src->prio, (char *)&src->str);
+
+ memset((void *)src, 0, len);
+
+ return la->empty;
+}
+
+/*
+ * this one can block under memory pressure
+ */
+void log_syslog (void * buff)
+{
+ struct logmsg * msg = (struct logmsg *)buff;
+
+ syslog(msg->prio, "%s", (char *)&msg->str);
+}
Added: multipath-tools/trunk/libmultipath/log.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/log.h Wed Feb 1 23:59:42 2006
@@ -0,0 +1,42 @@
+#ifndef LOG_H
+#define LOG_H
+
+#define DEFAULT_AREA_SIZE 8192
+#define MAX_MSG_SIZE 128
+
+#ifndef LOGLEVEL
+#define LOGLEVEL 5
+#endif
+
+#if LOGDBG
+#define logdbg(file, fmt, args...) fprintf(file, fmt, ##args)
+#else
+#define logdbg(file, fmt, args...) do {} while (0)
+#endif
+
+struct logmsg {
+ short int prio;
+ void * next;
+ char * str;
+};
+
+struct logarea {
+ int empty;
+ void * head;
+ void * tail;
+ void * start;
+ void * end;
+ char * buff;
+};
+
+struct logarea * la;
+
+int log_init (char * progname, int size);
+void log_close (void);
+int log_enqueue (int prio, const char * fmt, va_list ap);
+int log_dequeue (void *);
+void log_syslog (void *);
+void dump_logmsg (void *);
+void free_logarea (void);
+
+#endif /* LOG_H */
Added: multipath-tools/trunk/libmultipath/log_pthread.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/log_pthread.c Wed Feb 1 23:59:42 2006
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <sys/mman.h>
+
+#include <memory.h>
+
+#include "log_pthread.h"
+#include "log.h"
+
+void log_safe (int prio, char * fmt, va_list ap)
+{
+ pthread_mutex_lock(logq_lock);
+ //va_start(ap, fmt);
+ log_enqueue(prio, fmt, ap);
+ va_end(ap);
+ pthread_mutex_unlock(logq_lock);
+
+ pthread_mutex_lock(logev_lock);
+ pthread_cond_signal(logev_cond);
+ pthread_mutex_unlock(logev_lock);
+}
+
+static void flush_logqueue (void)
+{
+ int empty;
+
+ do {
+ pthread_mutex_lock(logq_lock);
+ empty = log_dequeue(la->buff);
+ pthread_mutex_unlock(logq_lock);
+ log_syslog(la->buff);
+ } while (empty == 0);
+}
+
+static void * log_thread (void * et)
+{
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+ logdbg(stderr,"enter log_thread\n");
+
+ while (1) {
+ pthread_mutex_lock(logev_lock);
+ pthread_cond_wait(logev_cond, logev_lock);
+ pthread_mutex_unlock(logev_lock);
+
+ flush_logqueue();
+ }
+}
+
+void log_thread_start (void)
+{
+ pthread_attr_t attr;
+
+ logdbg(stderr,"enter log_thread_start\n");
+
+ logq_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ logev_lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+ logev_cond = (pthread_cond_t *) malloc(sizeof(pthread_cond_t));
+
+ pthread_mutex_init(logq_lock, NULL);
+ pthread_mutex_init(logev_lock, NULL);
+ pthread_cond_init(logev_cond, NULL);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 64 * 1024);
+
+ if (log_init("multipathd", 0)) {
+ fprintf(stderr,"can't initialize log buffer\n");
+ exit(1);
+ }
+ pthread_create(&log_thr, &attr, log_thread, NULL);
+
+ return;
+}
+
+void log_thread_stop (void)
+{
+ logdbg(stderr,"enter log_thread_stop\n");
+
+ pthread_mutex_lock(logq_lock);
+ pthread_cancel(log_thr);
+ pthread_mutex_unlock(logq_lock);
+
+ flush_logqueue();
+
+ pthread_mutex_destroy(logq_lock);
+ pthread_mutex_destroy(logev_lock);
+ pthread_cond_destroy(logev_cond);
+
+ free_logarea();
+}
Added: multipath-tools/trunk/libmultipath/log_pthread.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/log_pthread.h Wed Feb 1 23:59:42 2006
@@ -0,0 +1,14 @@
+#ifndef _LOG_PTHREAD_H
+#define _LOG_PTHREAD_H
+
+pthread_t log_thr;
+
+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_thread_start(void);
+void log_thread_stop(void);
+
+#endif /* _LOG_PTHREAD_H */
Modified: multipath-tools/trunk/libmultipath/pgpolicies.c
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.c (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.c Wed Feb 1 23:59:42 2006
@@ -30,7 +30,7 @@
return -1;
}
-extern void
+extern int
get_pgpolicy_name (char * buff, int id)
{
char * s;
@@ -57,8 +57,9 @@
}
if(safe_snprintf(buff, POLICY_NAME_SIZE, "%s", s)) {
fprintf(stderr, "get_pgpolicy_name: buff too small\n");
- exit(1);
+ return 1;
}
+ return 0;
}
/*
Modified: multipath-tools/trunk/libmultipath/pgpolicies.h
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.h (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.h Wed Feb 1 23:59:42 2006
@@ -20,7 +20,7 @@
};
int get_pgpolicy_id(char *);
-void get_pgpolicy_name (char *, int);
+int get_pgpolicy_name (char *, int);
/*
* policies
Modified: multipath-tools/trunk/libmultipath/print.c
==============================================================================
--- multipath-tools/trunk/libmultipath/print.c (original)
+++ multipath-tools/trunk/libmultipath/print.c Wed Feb 1 23:59:42 2006
@@ -1,5 +1,7 @@
#include <stdio.h>
#include <string.h>
+#include <math.h>
+#include <libdevmapper.h>
#include "vector.h"
#include "structs.h"
@@ -10,22 +12,30 @@
#define MAX_FIELD_LEN 64
-#define MAX(x,y) (x > y) ? x : y;
+#define MAX(x,y) (x > y) ? x : y
void
get_path_layout (struct path_layout * pl, vector pathvec)
{
int i;
- int hbtl_len, dev_len, dev_t_len;
char buff[MAX_FIELD_LEN];
struct path * pp;
+ int uuid_len;
+ int hbtl_len;
+ int dev_len;
+ int dev_t_len;
+ int prio_len;
+
/* reset max col lengths */
+ pl->uuid_len = 0;
pl->hbtl_len = 0;
pl->dev_len = 0;
pl->dev_t_len = 0;
+ pl->prio_len = 0;
vector_foreach_slot (pathvec, pp, i) {
+ uuid_len = strlen(pp->wwid);
hbtl_len = snprintf(buff, MAX_FIELD_LEN, "%i:%i:%i:%i",
pp->sg_id.host_no,
pp->sg_id.channel,
@@ -33,10 +43,13 @@
pp->sg_id.lun);
dev_len = strlen(pp->dev);
dev_t_len = strlen(pp->dev_t);
+ prio_len = 1 + (int)log10(pp->priority);
+ pl->uuid_len = MAX(uuid_len, pl->uuid_len);
pl->hbtl_len = MAX(hbtl_len, pl->hbtl_len);
pl->dev_len = MAX(dev_len, pl->dev_len);
pl->dev_t_len = MAX(dev_t_len, pl->dev_t_len);
+ pl->prio_len = MAX(prio_len, pl->prio_len);
}
return;
}
@@ -46,32 +59,126 @@
{
int i;
char buff[MAX_FIELD_LEN];
- int mapname_len, mapdev_len;
struct multipath * mpp;
+ int mapname_len;
+ int mapdev_len;
+ int failback_progress_len;
+ int queueing_progress_len;
+ int nr_active_len;
+
/* reset max col lengths */
ml->mapname_len = 0;
ml->mapdev_len = 0;
+ ml->failback_progress_len = 0;
+ ml->queueing_progress_len = 0;
+ ml->nr_active_len = 0;
vector_foreach_slot (mpvec, mpp, i) {
mapname_len = (mpp->alias) ?
strlen(mpp->alias) : strlen(mpp->wwid);
- ml->mapname_len = MAX(mapname_len, ml->mapname_len);
+ if (mpp->dmi) mapdev_len = snprintf(buff, MAX_FIELD_LEN,
+ "dm-%i", mpp->dmi->minor);
+ failback_progress_len = 4 + PROGRESS_LEN +
+ (int)log10(mpp->failback_tick) +
+ (int)log10(mpp->pgfailback);
+ queueing_progress_len = 5 + (int)log10(mpp->retry_tick);
+ nr_active_len = (int)log10(mpp->nr_active);
- mapdev_len = snprintf(buff, MAX_FIELD_LEN,
- "dm-%i", mpp->minor);
+ ml->mapname_len = MAX(mapname_len, ml->mapname_len);
ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len);
+ ml->failback_progress_len = MAX(failback_progress_len,
+ ml->failback_progress_len);
+ ml->queueing_progress_len = MAX(queueing_progress_len,
+ ml->queueing_progress_len);
+ ml->nr_active_len = MAX(nr_active_len, ml->nr_active_len);
}
return;
}
#define TAIL (line + len - 1 - c)
-#define PAD(x) while ((int)(c - s) < (x)) *c++ = ' '; s = c
+#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
+ *c++ = ' '; s = c
#define NOPAD s = c
+
#define PRINT(var, size, format, args...) \
fwd = snprintf(var, size, format, ##args); \
c += (fwd >= size) ? size : fwd;
+#define PRINT_PROGRESS(cur, total) \
+ int i = PROGRESS_LEN * cur / total; \
+ int j = PROGRESS_LEN - i; \
+ \
+ while (i-- > 0) { \
+ PRINT(c, TAIL, "X"); \
+ } \
+ while (j-- > 0) { \
+ PRINT(c, TAIL, "."); \
+ } \
+ PRINT(c, TAIL, " %i/%i", cur, total)
+
+int
+snprint_map_header (char * line, int len, char * format,
+ struct map_layout * ml)
+{
+ char * c = line; /* line cursor */
+ char * s = line; /* for padding */
+ char * f = format; /* format string cursor */
+ int fwd;
+
+ do {
+ if (!TAIL)
+ break;
+
+ if (*f != '%') {
+ *c++ = *f;
+ NOPAD;
+ continue;
+ }
+ f++;
+ switch (*f) {
+ case 'w':
+ PRINT(c, TAIL, "name");
+ ml->mapname_len = MAX(ml->mapname_len, 4);
+ PAD(ml->mapname_len);
+ break;
+ case 'd':
+ PRINT(c, TAIL, "sysfs");
+ ml->mapdev_len = MAX(ml->mapdev_len, 5);
+ PAD(ml->mapdev_len);
+ break;
+ case 'F':
+ PRINT(c, TAIL, "failback");
+ ml->failback_progress_len =
+ MAX(ml->failback_progress_len, 8);
+ PAD(ml->failback_progress_len);
+ break;
+ case 'Q':
+ PRINT(c, TAIL, "queueing");
+ ml->queueing_progress_len =
+ MAX(ml->queueing_progress_len, 8);
+ PAD(ml->queueing_progress_len);
+ break;
+ case 'n':
+ PRINT(c, TAIL, "paths");
+ ml->nr_active_len = MAX(ml->nr_active_len, 5);
+ PAD(ml->nr_active_len);
+ break;
+ case 't':
+ PRINT(c, TAIL, "dm-st");
+ PAD(7);
+ break;
+ default:
+ break;
+ }
+ } while (*f++);
+
+ line[c - line - 1] = '\n';
+ line[c - line] = '\0';
+
+ return (c - line);
+}
+
int
snprint_map (char * line, int len, char * format,
struct multipath * mpp, struct map_layout * ml)
@@ -79,7 +186,6 @@
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
- int i, j;
int fwd;
do {
@@ -102,27 +208,119 @@
PAD(ml->mapname_len);
break;
case 'd':
- PRINT(c, TAIL, "dm-%i", mpp->minor);
+ if (mpp->dmi) {
+ PRINT(c, TAIL, "dm-%i", mpp->dmi->minor);
+ }
PAD(ml->mapdev_len);
break;
case 'F':
if (!mpp->failback_tick) {
- PRINT(c, TAIL, "[no scheduled failback]");
- NOPAD;
- break;
- }
- i = mpp->failback_tick;
- j = mpp->pgfailback - mpp->failback_tick;
-
- while (i-- > 0) {
- PRINT(c, TAIL, "X");
+ PRINT(c, TAIL, "-");
+ } else {
+ PRINT_PROGRESS(mpp->failback_tick,
+ mpp->pgfailback);
}
- while (j-- > 0) {
- PRINT(c, TAIL, ".");
+ PAD(ml->failback_progress_len);
+ break;
+ case 'Q':
+ if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) {
+ PRINT(c, TAIL, "off");
+ } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
+ PRINT(c, TAIL, "on");
+ } else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF) {
+ PRINT(c, TAIL, "-");
+ } else if (mpp->no_path_retry > 0) {
+ if (mpp->retry_tick) {
+ PRINT(c, TAIL, "%i sec",
+ mpp->retry_tick);
+ } else {
+ PRINT(c, TAIL, "%i chk",
+ mpp->no_path_retry);
+ }
+ }
+ PAD(ml->queueing_progress_len);
+ break;
+ case 'n':
+ PRINT(c, TAIL, "%i", mpp->nr_active);
+ PAD(ml->nr_active_len);
+ break;
+ case 't':
+ if (mpp->dmi && mpp->dmi->suspended) {
+ PRINT(c, TAIL, "suspend");
+ } else {
+ PRINT(c, TAIL, "active");
}
- PRINT(c, TAIL, " %i/%i",
- mpp->failback_tick, mpp->pgfailback);
+ PAD(7);
+ break;
+ default:
+ break;
+ }
+ } while (*f++);
+
+ line[c - line - 1] = '\n';
+ line[c - line] = '\0';
+
+ return (c - line);
+}
+
+int
+snprint_path_header (char * line, int len, char * format,
+ struct path_layout * pl)
+{
+ char * c = line; /* line cursor */
+ char * s = line; /* for padding */
+ char * f = format; /* format string cursor */
+ int fwd;
+
+ do {
+ if (!TAIL)
+ break;
+
+ if (*f != '%') {
+ *c++ = *f;
NOPAD;
+ continue;
+ }
+ f++;
+ switch (*f) {
+ case 'w':
+ PRINT(c, TAIL, "uuid");
+ PAD(pl->uuid_len);
+ break;
+ case 'i':
+ PRINT(c, TAIL, "hcil");
+ PAD(pl->hbtl_len);
+ break;
+ case 'd':
+ PRINT(c, TAIL, "dev");
+ pl->dev_len = MAX(pl->dev_len, 3);
+ PAD(pl->dev_len);
+ break;
+ case 'D':
+ PRINT(c, TAIL, "dev_t");
+ pl->dev_t_len = MAX(pl->dev_t_len, 5);
+ PAD(pl->dev_t_len);
+ break;
+ case 'T':
+ PRINT(c, TAIL, "chk-st");
+ PAD(8);
+ break;
+ case 't':
+ PRINT(c, TAIL, "dm-st");
+ PAD(8);
+ break;
+ case 's':
+ PRINT(c, TAIL, "vendor/product/rev");
+ NOPAD;
+ break;
+ case 'C':
+ PRINT(c, TAIL, "next-check");
+ NOPAD;
+ break;
+ case 'p':
+ PRINT(c, TAIL, "pri");
+ pl->prio_len = MAX(pl->prio_len, 3);
+ PAD(pl->prio_len);
break;
default:
break;
@@ -142,7 +340,6 @@
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
- int i, j;
int fwd;
do {
@@ -157,12 +354,12 @@
f++;
switch (*f) {
case 'w':
- PRINT(c, TAIL, "%s ", pp->wwid);
- NOPAD;
+ PRINT(c, TAIL, "%s", pp->wwid);
+ PAD(pl->uuid_len);
break;
case 'i':
if (pp->sg_id.host_no < 0) {
- PRINT(c, TAIL, "#:#:#:# ");
+ PRINT(c, TAIL, "#:#:#:#");
} else {
PRINT(c, TAIL, "%i:%i:%i:%i",
pp->sg_id.host_no,
@@ -173,7 +370,11 @@
PAD(pl->hbtl_len);
break;
case 'd':
- PRINT(c, TAIL, "%s", pp->dev);
+ if (!strlen(pp->dev)) {
+ PRINT(c, TAIL, "-");
+ } else {
+ PRINT(c, TAIL, "%s", pp->dev);
+ }
PAD(pl->dev_len);
break;
case 'D':
@@ -195,9 +396,10 @@
PRINT(c, TAIL, "[ghost]");
break;
default:
+ PRINT(c, TAIL, "[undef]");
break;
}
- NOPAD;
+ PAD(8);
break;
case 't':
switch (pp->dmstate) {
@@ -208,15 +410,10 @@
PRINT(c, TAIL, "[failed]");
break;
default:
+ PRINT(c, TAIL, "[undef]");
break;
}
- NOPAD;
- break;
- case 'c':
- if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
- PRINT(c, TAIL, "[claimed]");
- }
- NOPAD;
+ PAD(8);
break;
case 's':
PRINT(c, TAIL, "%s/%s/%s",
@@ -226,27 +423,18 @@
case 'C':
if (!pp->mpp) {
PRINT(c, TAIL, "[orphan]");
- NOPAD;
- break;
- }
- i = pp->tick;
- j = pp->checkint - pp->tick;
-
- while (i-- > 0) {
- PRINT(c, TAIL, "X");
- }
- while (j-- > 0) {
- PRINT(c, TAIL, ".");
+ } else {
+ PRINT_PROGRESS(pp->tick, pp->checkint);
}
- PRINT(c, TAIL, " %i/%i",
- pp->tick, pp->checkint);
NOPAD;
break;
case 'p':
if (pp->priority) {
PRINT(c, TAIL, "%i", pp->priority);
+ } else {
+ PRINT(c, TAIL, "#");
}
- NOPAD;
+ PAD(pl->prio_len);
break;
default:
break;
Modified: multipath-tools/trunk/libmultipath/print.h
==============================================================================
--- multipath-tools/trunk/libmultipath/print.h (original)
+++ multipath-tools/trunk/libmultipath/print.h Wed Feb 1 23:59:42 2006
@@ -8,7 +8,6 @@
* %t : device mapper path status
* %T : checker path status
* %s : scsi strings
- * %c : claimed
* %p : priority
*
* map format magics :
@@ -17,27 +16,38 @@
* %d : DM device name
* %F : failback countdown
* %C : checker countdown
+ * %Q : queueing policy changer countdown (no_path_retry)
+ * %n : number of active paths
+ * %t : device mapper map status
*/
-#define PRINT_PATH_LONG "%w %i %d %D %p %t%T%c %s"
-#define PRINT_PATH_INDENT " \\_ %i %d %D %t%T%c"
+#define PRINT_PATH_LONG "%w %i %d %D %p %t%T %s"
+#define PRINT_PATH_INDENT " \\_ %i %d %D %t%T"
#define PRINT_PATH_CHECKER "%i %d %D %p %t%T %C"
-#define PRINT_MAP_FAILBACK "%w %d %F"
+#define PRINT_MAP_FAILBACK "%w %d %F %Q %n %t"
#define MAX_LINE_LEN 80
+#define PROGRESS_LEN 10
struct path_layout {
+ int uuid_len;
int hbtl_len;
int dev_len;
int dev_t_len;
+ int prio_len;
};
struct map_layout {
int mapname_len;
int mapdev_len;
+ int failback_progress_len;
+ int queueing_progress_len;
+ int nr_active_len;
};
void get_path_layout (struct path_layout * pl, vector pathvec);
void get_map_layout (struct map_layout * pl, vector mpvec);
+int snprint_path_header (char *, int, char *, struct path_layout *);
+int snprint_map_header (char *, int, char *, struct map_layout *);
int snprint_path (char *, int, char *, struct path *, struct path_layout *);
int snprint_map (char *, int, char *,struct multipath *, struct map_layout *);
Modified: multipath-tools/trunk/libmultipath/propsel.c
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.c (original)
+++ multipath-tools/trunk/libmultipath/propsel.c Wed Feb 1 23:59:42 2006
@@ -5,6 +5,7 @@
#include "config.h"
#include "debug.h"
#include "pgpolicies.h"
+#include "alias.h"
#include "../libcheckers/checkers.h"
@@ -75,30 +76,35 @@
if (conf->pgpolicy_flag > 0) {
mp->pgpolicy = conf->pgpolicy_flag;
- get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+ if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+ return 1;
condlog(3, "pgpolicy = %s (cmd line flag)", pgpolicy_name);
return 0;
}
if (mp->mpe && mp->mpe->pgpolicy > 0) {
mp->pgpolicy = mp->mpe->pgpolicy;
- get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+ if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+ return 1;
condlog(3, "pgpolicy = %s (LUN setting)", pgpolicy_name);
return 0;
}
if (mp->hwe && mp->hwe->pgpolicy > 0) {
mp->pgpolicy = mp->hwe->pgpolicy;
- get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+ if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+ return 1;
condlog(3, "pgpolicy = %s (controler setting)", pgpolicy_name);
return 0;
}
if (conf->default_pgpolicy > 0) {
mp->pgpolicy = conf->default_pgpolicy;
- get_pgpolicy_name(pgpolicy_name, mp->pgpolicy);
+ if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+ return 1;
condlog(3, "pgpolicy = %s (config file default)", pgpolicy_name);
return 0;
}
mp->pgpolicy = FAILOVER;
- get_pgpolicy_name(pgpolicy_name, FAILOVER);
+ if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
+ return 1;
condlog(3, "pgpolicy = %s (internal default)", pgpolicy_name);
return 0;
}
@@ -116,7 +122,7 @@
condlog(3, "selector = %s (controler setting)", mp->selector);
return 0;
}
- mp->selector = conf->default_selector;
+ mp->selector = conf->selector;
condlog(3, "selector = %s (internal default)", mp->selector);
return 0;
}
@@ -126,8 +132,14 @@
{
if (mp->mpe && mp->mpe->alias)
mp->alias = mp->mpe->alias;
- else
- mp->alias = mp->wwid;
+ else {
+ mp->alias = NULL;
+ if (conf->user_friendly_names)
+ mp->alias = get_user_friendly_alias(mp->wwid,
+ conf->bindings_file);
+ if (mp->alias == NULL)
+ mp->alias = mp->wwid;
+ }
return 0;
}
@@ -140,7 +152,7 @@
condlog(3, "features = %s (controler setting)", mp->features);
return 0;
}
- mp->features = conf->default_features;
+ mp->features = conf->features;
condlog(3, "features = %s (internal default)", mp->features);
return 0;
}
@@ -169,8 +181,8 @@
pp->checkfn = get_checker_addr(pp->hwe->checker_index);
return 0;
}
- pp->checkfn = &readsector0;
- get_checker_name(checker_name, READSECTOR0);
+ pp->checkfn = get_checker_addr(conf->default_checker_index);
+ get_checker_name(checker_name, conf->default_checker_index);
condlog(3, "path checker = %s (internal default)", checker_name);
return 0;
}
@@ -201,3 +213,28 @@
return 0;
}
+extern int
+select_no_path_retry(struct multipath *mp)
+{
+ if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ mp->no_path_retry = mp->mpe->no_path_retry;
+ condlog(3, "no_path_retry = %i (multipath setting)",
+ mp->no_path_retry);
+ return 0;
+ }
+ if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ mp->no_path_retry = mp->hwe->no_path_retry;
+ condlog(3, "no_path_retry = %i (controler setting)",
+ mp->no_path_retry);
+ return 0;
+ }
+ if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ mp->no_path_retry = conf->no_path_retry;
+ condlog(3, "no_path_retry = %i (config file default)",
+ mp->no_path_retry);
+ return 0;
+ }
+ mp->no_path_retry = NO_PATH_RETRY_UNDEF;
+ condlog(3, "no_path_retry = NONE (internal default)");
+ return 0;
+}
Modified: multipath-tools/trunk/libmultipath/propsel.h
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.h (original)
+++ multipath-tools/trunk/libmultipath/propsel.h Wed Feb 1 23:59:42 2006
@@ -8,4 +8,4 @@
int select_checkfn(struct path *pp);
int select_getuid (struct path * pp);
int select_getprio (struct path * pp);
-
+int select_no_path_retry(struct multipath *mp);
Modified: multipath-tools/trunk/libmultipath/structs.c
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.c (original)
+++ multipath-tools/trunk/libmultipath/structs.c Wed Feb 1 23:59:42 2006
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <unistd.h>
+#include <libdevmapper.h>
#include "memory.h"
#include "vector.h"
@@ -20,6 +21,7 @@
pp->sg_id.channel = -1;
pp->sg_id.scsi_id = -1;
pp->sg_id.lun = -1;
+ pp->fd = -1;
}
return pp;
}
@@ -33,7 +35,7 @@
if (pp->checker_context)
free(pp->checker_context);
- if (pp->fd > 0)
+ if (pp->fd >= 0)
close(pp->fd);
FREE(pp);
@@ -106,7 +108,7 @@
mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
if (mpp)
- mpp->nextpg = 1;
+ mpp->bestpg = 1;
return mpp;
}
@@ -118,7 +120,7 @@
return;
if (mpp->selector &&
- mpp->selector != conf->default_selector &&
+ mpp->selector != conf->selector &&
(!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
(!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector)))
FREE(mpp->selector);
@@ -129,7 +131,7 @@
FREE(mpp->alias);
if (mpp->features &&
- mpp->features != conf->default_features &&
+ mpp->features != conf->features &&
(!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features)))
FREE(mpp->features);
@@ -138,12 +140,33 @@
(!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler)))
FREE(mpp->hwhandler);
+ if (mpp->dmi)
+ FREE(mpp->dmi);
+
free_pathvec(mpp->paths, free_paths);
free_pgvec(mpp->pg, free_paths);
FREE(mpp);
}
void
+drop_multipath (vector mpvec, char * wwid, int free_paths)
+{
+ int i;
+ struct multipath * mpp;
+
+ if (!mpvec)
+ return;
+
+ vector_foreach_slot (mpvec, mpp, i) {
+ if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
+ free_multipath(mpp, free_paths);
+ vector_del_slot(mpvec, i);
+ return;
+ }
+ }
+}
+
+void
free_multipathvec (vector mpvec, int free_paths)
{
int i;
@@ -186,8 +209,11 @@
int i;
struct multipath * mpp;
+ if (!mpp->dmi)
+ return NULL;
+
vector_foreach_slot (mp, mpp, i)
- if (mpp->minor == minor)
+ if (mpp->dmi->minor == minor)
return mpp;
return NULL;
@@ -207,7 +233,7 @@
}
struct multipath *
-find_mp (vector mp, char * alias)
+find_mp_by_alias (vector mp, char * alias)
{
int i;
int len;
Modified: multipath-tools/trunk/libmultipath/structs.h
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.h (original)
+++ multipath-tools/trunk/libmultipath/structs.h Wed Feb 1 23:59:42 2006
@@ -14,6 +14,10 @@
#define SCSI_PRODUCT_SIZE 17
#define SCSI_REV_SIZE 5
+#define NO_PATH_RETRY_UNDEF 0
+#define NO_PATH_RETRY_FAIL -1
+#define NO_PATH_RETRY_QUEUE -2
+
enum free_path_switch {
KEEP_PATHS,
FREE_PATHS
@@ -87,12 +91,11 @@
unsigned long long size;
unsigned int checkint;
unsigned int tick;
- int state;
int bus;
+ int state;
int dmstate;
int failcount;
int priority;
- int claimed;
int pgindex;
char * getuid;
char * getprio;
@@ -107,19 +110,23 @@
struct multipath {
char wwid[WWID_SIZE];
- int minor;
int pgpolicy;
int nextpg;
+ int bestpg;
int queuedio;
int action;
int pgfailback;
int failback_tick;
int rr_weight;
+ int nr_active; /* current available(= not known as failed) paths */
+ int no_path_retry; /* number of retries after all paths are down */
+ int retry_tick; /* remaining times for retries */
unsigned long long size;
vector paths;
vector pg;
char params[PARAMS_SIZE];
char status[PARAMS_SIZE];
+ struct dm_info * dmi;
/* configlet pointers */
char * alias;
@@ -148,12 +155,13 @@
void free_pathgroup (struct pathgroup * pgp, int free_paths);
void free_pgvec (vector pgvec, int free_paths);
void free_multipath (struct multipath *, int free_paths);
+void drop_multipath (vector mpvec, char * wwid, int free_paths);
void free_multipathvec (vector mpvec, int free_paths);
int store_path (vector pathvec, struct path * pp);
int store_pathgroup (vector pgvec, struct pathgroup * pgp);
-struct multipath * find_mp (vector mp, char * alias);
+struct multipath * find_mp_by_alias (vector mp, char * alias);
struct multipath * find_mp_by_wwid (vector mp, char * wwid);
struct multipath * find_mp_by_minor (vector mp, int minor);
Modified: multipath-tools/trunk/libmultipath/switchgroup.c
==============================================================================
--- multipath-tools/trunk/libmultipath/switchgroup.c (original)
+++ multipath-tools/trunk/libmultipath/switchgroup.c Wed Feb 1 23:59:42 2006
@@ -3,22 +3,31 @@
#include "switchgroup.h"
#include "../libcheckers/path_state.h"
-extern void
+extern int
select_path_group (struct multipath * mpp)
{
int i, j;
int highest = 0;
+ int bestpg = 1;
struct pathgroup * pgp;
struct path * pp;
+
+ if (!mpp->pg)
+ return 1;
vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+
vector_foreach_slot (pgp->paths, pp, j) {
if (pp->state != PATH_DOWN)
pgp->priority += pp->priority;
}
+
if (pgp->priority > highest) {
highest = pgp->priority;
- mpp->nextpg = i + 1;
+ bestpg = i + 1;
}
}
+ return bestpg;
}
Modified: multipath-tools/trunk/libmultipath/switchgroup.h
==============================================================================
--- multipath-tools/trunk/libmultipath/switchgroup.h (original)
+++ multipath-tools/trunk/libmultipath/switchgroup.h Wed Feb 1 23:59:42 2006
@@ -1 +1 @@
-void select_path_group (struct multipath * mpp);
+int select_path_group (struct multipath * mpp);
Modified: multipath-tools/trunk/libmultipath/uevent.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uevent.c (original)
+++ multipath-tools/trunk/libmultipath/uevent.c Wed Feb 1 23:59:42 2006
@@ -58,7 +58,7 @@
sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (sock == -1) {
condlog(0, "error getting socket, exit\n");
- exit(1);
+ return 1;
}
retval = bind(sock, (struct sockaddr *) &snl,
@@ -126,6 +126,8 @@
if (uev_trigger && uev_trigger(uev, trigger_data))
condlog(0, "uevent trigger error");
+
+ FREE(uev);
}
exit:
Modified: multipath-tools/trunk/libmultipath/uxsock.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uxsock.c (original)
+++ multipath-tools/trunk/libmultipath/uxsock.c Wed Feb 1 23:59:42 2006
@@ -8,6 +8,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
+#include <errno.h>
#include "memory.h"
#include "uxsock.h"
@@ -70,14 +71,21 @@
}
/*
- * keep writing until its all sent
+ * keep writing until it's all sent
*/
-int write_all(int fd, const void *buf, size_t len)
+size_t write_all(int fd, const void *buf, size_t len)
{
size_t total = 0;
+
while (len) {
- int n = write(fd, buf, len);
- if (n <= 0) return total;
+ ssize_t n = write(fd, buf, len);
+ if (n < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ return total;
+ }
+ if (!n)
+ return total;
buf = n + (char *)buf;
len -= n;
total += n;
@@ -88,12 +96,19 @@
/*
* keep reading until its all read
*/
-int read_all(int fd, void *buf, size_t len)
+size_t read_all(int fd, void *buf, size_t len)
{
size_t total = 0;
+
while (len) {
- int n = read(fd, buf, len);
- if (n <= 0) return total;
+ ssize_t n = read(fd, buf, len);
+ if (n < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ return total;
+ }
+ if (!n)
+ return total;
buf = n + (char *)buf;
len -= n;
total += n;
Modified: multipath-tools/trunk/libmultipath/uxsock.h
==============================================================================
--- multipath-tools/trunk/libmultipath/uxsock.h (original)
+++ multipath-tools/trunk/libmultipath/uxsock.h Wed Feb 1 23:59:42 2006
@@ -3,4 +3,5 @@
int ux_socket_listen(const char *name);
int send_packet(int fd, const char *buf, size_t len);
int recv_packet(int fd, char **buf, size_t *len);
-
+size_t write_all(int fd, const void *buf, size_t len);
+size_t read_all(int fd, void *buf, size_t len);
Modified: multipath-tools/trunk/libmultipath/vector.c
==============================================================================
--- multipath-tools/trunk/libmultipath/vector.c (original)
+++ multipath-tools/trunk/libmultipath/vector.c Wed Feb 1 23:59:42 2006
@@ -80,7 +80,7 @@
{
int i;
- if (!v->allocated)
+ if (!v->allocated || slot < 0 || slot > VECTOR_SIZE(v))
return;
for (i = slot + 1; i < (v->allocated / VECTOR_DEFAULT_SIZE); i++)
Modified: multipath-tools/trunk/multipath.conf.annotated
==============================================================================
--- multipath-tools/trunk/multipath.conf.annotated (original)
+++ multipath-tools/trunk/multipath.conf.annotated Wed Feb 1 23:59:42 2006
@@ -9,14 +9,6 @@
##
#defaults {
# #
-# # name : multipath_tool
-# # scope : multipathd
-# # desc : the tool in charge of configuring the multipath device maps
-# # default : "/sbin/multipath -v0"
-# #
-# multipath_tool "/sbin/multipath -v0"
-#
-# #
# # name : udev_dir
# # desc : directory where udev creates its device nodes
# # default : /dev
@@ -32,42 +24,51 @@
# polling_interval 10
#
# #
-# # name : default_selector
+# # name : selector
# # scope : multipath
# # desc : the default path selector algorithm to use
# # these algorithms are offered by the kernel multipath target
# # values : "round-robin 0"
# # default : "round-robin 0"
# #
-# default_selector "round-robin 0"
+# selector "round-robin 0"
#
# #
-# # name : default_path_grouping_policy
+# # name : path_grouping_policy
# # scope : multipath
# # desc : the default path grouping policy to apply to unspecified
# # multipaths
# # default : multibus
# #
-# default_path_grouping_policy multibus
+# path_grouping_policy multibus
#
# #
-# # name : default_getuid_callout
+# # name : getuid_callout
# # 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_getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
+# getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
#
# #
-# # name : default_prio_callout
+# # name : prio_callout
# # scope : multipath
# # desc : the default program and args to callout to obtain a path
# # priority value. The ALUA bits in SPC-3 provide an
# # exploitable prio value for example. "none" is a valid value
# # default : (null)
# #
-# #default_prio_callout "/bin/true"
+# #prio_callout "/bin/true"
+#
+# #
+# # name : path_checker
+# # scope : multipath & multipathd
+# # desc : the default method used to determine the paths' state
+# # values : readsector0|tur|emc_clariion|hp_sw|directio
+# # default : readsector0
+# #
+# #path_checker readsector0
#
# #
# # name : rr_min_io
@@ -76,7 +77,7 @@
# # to the next in the same path group
# # default : 1000
# #
-# r_min_io 100
+# rr_min_io 100
#
# #
# # name : rr_weight
@@ -86,7 +87,7 @@
# # values : priorities|uniform
# # default : uniform
# #
-# rr_weight priorities
+# rr_weight priorities
#
# #
# # name : failback
@@ -98,6 +99,31 @@
# # default : immediate
# #
# failback manual
+#
+# #
+# # name : no_path_retry
+# # scope : multipath & multipathd
+# # desc : tell the number of retries until disable queueing, or
+# # "fail" means immediate failure (no queueing),
+# # "queue" means never stop queueing
+# # values : queue|fail|n (>0)
+# # default : (null)
+# #
+# #no_path_retry queue
+#
+# #
+# # name : user_friendly_names
+# # scope : multipath
+# # desc : If set to "yes", using the bindings file
+# # /var/lib/multipath/bindings to assign a persistent and
+# # unique alias to the multipath, in the form of mpath<n>.
+# # If set to "no" use the WWID as the alias. In either case
+# # this be will be overriden by any specific aliases in this
+# # file.
+# # values : yes|no
+# # default : no
+# user_friendly_names no
+#
#}
#
##
@@ -107,7 +133,7 @@
## default : cciss, fd, hd, md, dm, sr, scd, st, ram, raw, loop
##
#blacklist {
-# wwid 26353900f02796769
+# wwid 26353900f02796769
# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
# devnode "^hd[a-z][[0-9]*]"
# devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
@@ -176,6 +202,17 @@
# # default : immediate
# #
# failback manual
+#
+# #
+# # name : no_path_retry
+# # scope : multipath & multipathd
+# # desc : tell the number of retries until disable queueing, or
+# # "fail" means immediate failure (no queueing),
+# # "queue" means never stop queueing
+# # values : queue|fail|n (>0)
+# # default : (null)
+# #
+# #no_path_retry queue
# }
# multipath {
# wwid 1DEC_____321816758474
Modified: multipath-tools/trunk/multipath.conf.synthetic
==============================================================================
--- multipath-tools/trunk/multipath.conf.synthetic (original)
+++ multipath-tools/trunk/multipath.conf.synthetic Wed Feb 1 23:59:42 2006
@@ -3,20 +3,21 @@
## Uncomment the lines relevent to your environment
##
#defaults {
-# multipath_tool "/sbin/multipath -v0"
-# udev_dir /dev
-# polling_interval 10
-# default_selector "round-robin 0"
-# default_path_grouping_policy multibus
-# default_getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
-# default_prio_callout "/bin/true"
-# default_features "0"
+# udev_dir /dev
+# polling_interval 10
+# selector "round-robin 0"
+# path_grouping_policy multibus
+# getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
+# prio_callout /bin/true
+# path_checker readsector0
# rr_min_io 100
# rr_weight priorities
# failback immediate
+# no_path_retry fail
+# user_friendly_name no
#}
#devnode_blacklist {
-# wwid 26353900f02796769
+# wwid 26353900f02796769
# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
# devnode "^hd[a-z][[0-9]*]"
# devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
@@ -30,10 +31,11 @@
# path_selector "round-robin 0"
# failback manual
# rr_weight priorities
+# no_path_retry 5
# }
# multipath {
-# wwid 1DEC_____321816758474
-# alias red
+# wwid 1DEC_____321816758474
+# alias red
# }
#}
#devices {
@@ -44,10 +46,10 @@
# getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
# path_checker readsector0
# path_selector "round-robin 0"
-# features "1 queue_if_no_path"
# hardware_handler "0"
# failback 15
# rr_weight priorities
+# no_path_retry queue
# }
# device {
# vendor "COMPAQ "
Modified: multipath-tools/trunk/multipath/Makefile
==============================================================================
--- multipath-tools/trunk/multipath/Makefile (original)
+++ multipath-tools/trunk/multipath/Makefile Wed Feb 1 23:59:42 2006
@@ -13,7 +13,7 @@
ifeq ($(strip $(BUILD)),klibc)
OBJS += $(libdm) $(libsysfs)
else
- LDFLAGS += -ldevmapper -lsysfs
+ LDFLAGS += -ldevmapper -lsysfs -lm
endif
EXEC = multipath
@@ -26,12 +26,10 @@
glibc: prepare $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(CHECKERSLIB)-$(BUILD).a:
@@ -50,7 +48,6 @@
install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
uninstall:
- rm $(DESTDIR)/etc/dev.d/block/multipath.dev
rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
rm $(DESTDIR)$(bindir)/$(EXEC)
rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
Modified: multipath-tools/trunk/multipath/main.c
==============================================================================
--- multipath-tools/trunk/multipath/main.c (original)
+++ multipath-tools/trunk/multipath/main.c Wed Feb 1 23:59:42 2006
@@ -20,6 +20,8 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <sys/file.h>
+#include <errno.h>
#include <parser.h>
#include <vector.h>
@@ -42,6 +44,7 @@
#include <switchgroup.h>
#include <sysfs/libsysfs.h>
#include <print.h>
+#include <alias.h>
#include "main.h"
#include "pgpolicies.h"
@@ -61,7 +64,6 @@
return NULL;
if (conf->dev_type == DEV_DEVNODE) {
- condlog(3, "limited scope = %s", conf->dev);
basename(conf->dev, buff);
pp = find_path_by_dev(pathvec, buff);
@@ -81,32 +83,24 @@
return NULL;
}
}
-
- refwwid = MALLOC(WWID_SIZE);
-
- if (!refwwid)
- return NULL;
-
- memcpy(refwwid, pp->wwid, WWID_SIZE);
- return refwwid;
+ refwwid = pp->wwid;
+ goto out;
}
if (conf->dev_type == DEV_DEVT) {
- condlog(3, "limited scope = %s", conf->dev);
pp = find_path_by_devt(pathvec, conf->dev);
if (!pp) {
+ if (devt2devname(buff, conf->dev))
+ return NULL;
+
pp = alloc_path();
if (!pp)
return NULL;
- devt2devname(conf->dev, buff);
+ strncpy(pp->dev, buff, FILE_NAME_SIZE);
- if(safe_sprintf(pp->dev, "%s", buff)) {
- fprintf(stderr, "pp->dev too small\n");
- exit(1);
- }
if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
return NULL;
@@ -115,46 +109,44 @@
return NULL;
}
}
-
- refwwid = MALLOC(WWID_SIZE);
-
- if (!refwwid)
- return NULL;
-
- memcpy(refwwid, pp->wwid, WWID_SIZE);
- return refwwid;
+ refwwid = pp->wwid;
+ goto out;
}
if (conf->dev_type == DEV_DEVMAP) {
- condlog(3, "limited scope = %s", conf->dev);
/*
- * may be an alias
+ * may be a binding
*/
- refwwid = get_mpe_wwid(conf->dev);
+ refwwid = get_user_friendly_wwid(conf->dev,
+ conf->bindings_file);
if (refwwid)
return refwwid;
-
+
/*
- * or directly a wwid
+ * or may be an alias
*/
- refwwid = MALLOC(WWID_SIZE);
+ refwwid = get_mpe_wwid(conf->dev);
+ /*
+ * or directly a wwid
+ */
if (!refwwid)
- return NULL;
-
- strncpy(refwwid, conf->dev, WWID_SIZE);
- return refwwid;
+ refwwid = conf->dev;
}
+out:
+ if (refwwid && strlen(refwwid))
+ return STRDUP(refwwid);
+
return NULL;
}
static void
print_path (struct path * pp, char * style)
{
- char buff[MAX_LINE_LEN];
+ char line[MAX_LINE_LEN];
- snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
- printf("%s", buff);
+ snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl);
+ printf("%s", line);
}
static void
@@ -167,10 +159,24 @@
}
static void
-print_all_paths (vector pathvec)
+print_all_paths (vector pathvec, int banner)
{
int i;
struct path * pp;
+ char line[MAX_LINE_LEN];
+
+ if (!VECTOR_SIZE(pathvec)) {
+ if (banner)
+ fprintf(stdout, "===== no paths =====\n");
+ return;
+ }
+
+ if (banner)
+ fprintf(stdout, "===== paths list =====\n");
+
+ get_path_layout(&pl, pathvec);
+ snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl);
+ fprintf(stdout, "%s", line);
vector_foreach_slot (pathvec, pp, i)
print_path(pp, PRINT_PATH_LONG);
@@ -183,7 +189,7 @@
struct path * pp = NULL;
struct pathgroup * pgp = NULL;
- if (mpp->action == ACT_NOTHING || conf->verbosity == 0)
+ if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
return;
if (conf->verbosity > 1) {
@@ -283,7 +289,7 @@
return 0;
vector_foreach_slot (pathvec, pp, i) {
- if (memcmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
+ if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
condlog(3, "skip path %s : out of scope", pp->dev);
free_path(pp);
vector_del_slot(pathvec, i);
@@ -311,7 +317,7 @@
shift = snprintf(p, freechar, "%s %s %i %i",
mp->features, mp->hwhandler,
- VECTOR_SIZE(mp->pg), mp->nextpg);
+ VECTOR_SIZE(mp->pg), mp->bestpg);
if (shift >= freechar) {
fprintf(stderr, "mp->params too small\n");
@@ -362,9 +368,6 @@
static int
setup_map (struct multipath * mpp)
{
- struct path * pp;
- int i;
-
/*
* don't bother if devmap size is unknown
*/
@@ -374,17 +377,6 @@
}
/*
- * don't bother if a constituant path is claimed
- * (not by the device mapper driver)
- */
- vector_foreach_slot (mpp->paths, pp, i) {
- if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
- condlog(3, "%s claimed", pp->dev);
- return 1;
- }
- }
-
- /*
* properties selectors
*/
select_pgpolicy(mpp);
@@ -392,6 +384,7 @@
select_features(mpp);
select_hwhandler(mpp);
select_rr_weight(mpp);
+ select_no_path_retry(mpp);
/*
* apply selected grouping policy to valid paths
@@ -425,7 +418,7 @@
* ponders each path group and determine highest prio pg
* to switch over (default to first)
*/
- select_path_group(mpp);
+ mpp->bestpg = select_path_group(mpp);
/*
* transform the mp->pg vector of vectors of paths
@@ -492,7 +485,7 @@
{
struct multipath * cmpp;
- cmpp = find_mp(curmp, mpp->alias);
+ cmpp = find_mp_by_alias(curmp, mpp->alias);
if (!cmpp) {
cmpp = find_mp_by_wwid(curmp, mpp->wwid);
@@ -503,52 +496,65 @@
dm_flush_map(cmpp->alias, DEFAULT_TARGET);
}
mpp->action = ACT_CREATE;
+ condlog(3, "set ACT_CREATE: map does not exists");
return;
}
+
+ if (!find_mp_by_wwid(curmp, mpp->wwid)) {
+ condlog(2, "remove: %s (wwid changed)", cmpp->alias);
+ dm_flush_map(mpp->alias, NULL);
+ strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
+ drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
+ mpp->action = ACT_CREATE;
+ condlog(3, "set ACT_CREATE: map wwid change");
+ return;
+ }
+
if (pathcount(mpp, PATH_UP) == 0) {
- condlog(3, "no good path");
mpp->action = ACT_NOTHING;
+ condlog(3, "set ACT_NOTHING: no usable path");
return;
}
if (cmpp->size != mpp->size) {
- condlog(3, "size different than current");
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: size change");
return;
}
- if (strncmp(cmpp->features, mpp->features,
- strlen(mpp->features))) {
- condlog(3, "features different than current");
+ if (!mpp->no_path_retry && /* let features be handled by the daemon */
+ strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: features change");
return;
}
if (strncmp(cmpp->hwhandler, mpp->hwhandler,
strlen(mpp->hwhandler))) {
- condlog(3, "hwhandler different than current");
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: hwhandler change");
return;
}
if (strncmp(cmpp->selector, mpp->selector,
strlen(mpp->selector))) {
- condlog(3, "selector different than current");
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: selector change");
return;
}
if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
- condlog(3, "different number of PG");
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: number of path group change");
return;
}
if (pgcmp(mpp, cmpp)) {
- condlog(3, "different path group topology");
mpp->action = ACT_RELOAD;
+ condlog(3, "set ACT_RELOAD: path group topology change");
return;
}
- if (cmpp->nextpg != mpp->nextpg) {
- condlog(3, "nextpg different than current");
+ if (cmpp->nextpg != mpp->bestpg) {
mpp->action = ACT_SWITCHPG;
+ condlog(3, "set ACT_SWITCHPG: next path group change");
return;
}
mpp->action = ACT_NOTHING;
+ condlog(3, "set ACT_NOTHING: map unchanged");
return;
}
@@ -559,7 +565,13 @@
struct pathgroup * pgp;
struct path * pp;
+ if (!mpp->pg)
+ return 0;
+
vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+
vector_foreach_slot (pgp->paths, pp, j) {
if (pp->state != PATH_UP &&
(pgp->status == PGSTATE_DISABLED ||
@@ -567,7 +579,7 @@
continue;
if (pp->dmstate == PSTATE_FAILED) {
- if (dm_reinstate(mpp->alias, pp->dev_t))
+ if (dm_reinstate_path(mpp->alias, pp->dev_t))
condlog(0, "error reinstating %s",
pp->dev);
}
@@ -576,75 +588,139 @@
return 0;
}
+int lock_multipath (struct multipath * mpp, int lock)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ if (!mpp || !mpp->pg)
+ return 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
+ errno == EWOULDBLOCK)
+ return 1;
+ else if (!lock)
+ flock(pp->fd, LOCK_UN);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Return value:
+ * -1: Retry
+ * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
+ * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
+ * 2: Map is already existing.
+ */
static int
domap (struct multipath * mpp)
{
- int op = ACT_NOTHING;
int r = 0;
- print_mp(mpp);
-
/*
* last chance to quit before touching the devmaps
*/
- if (conf->dry_run)
+ if (conf->dry_run) {
+ print_mp(mpp);
return 0;
+ }
switch (mpp->action) {
case ACT_NOTHING:
- return 0;
+ return 2;
case ACT_SWITCHPG:
- dm_switchgroup(mpp->alias, mpp->nextpg);
+ dm_switchgroup(mpp->alias, mpp->bestpg);
/*
* we may have avoided reinstating paths because there where in
* active or disabled PG. Now that the topology has changed,
* retry.
*/
reinstate_paths(mpp);
- return 0;
+ return 2;
case ACT_CREATE:
- op = DM_DEVICE_CREATE;
+ if (lock_multipath(mpp, 1)) {
+ condlog(3, "%s: in use", mpp->alias);
+ return -1;
+ }
+ dm_shut_log();
+
+ if (dm_map_present(mpp->alias))
+ break;
+
+ r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
+ mpp->params, mpp->size, mpp->wwid);
+
+ /*
+ * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
+ * DM_TABLE_LOAD. Failing the second part leaves an
+ * empty map. Clean it up.
+ */
+ if (!r && dm_map_present(mpp->alias)) {
+ condlog(3, "%s: failed to load map "
+ "(a path might be in use)",
+ mpp->alias);
+ dm_flush_map(mpp->alias, NULL);
+ }
+
+ lock_multipath(mpp, 0);
+ dm_restore_log();
break;
case ACT_RELOAD:
- op = DM_DEVICE_RELOAD;
+ r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
+ mpp->params, mpp->size, NULL) &&
+ dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
break;
default:
break;
}
-
- /*
- * device mapper creation or updating
- * here we know we'll have garbage on stderr from
- * libdevmapper. so shut it down temporarily.
- */
- dm_log_init_verbose(0);
+ if (r) {
+ /*
+ * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
+ */
+ dm_switchgroup(mpp->alias, mpp->bestpg);
+ print_mp(mpp);
+ }
- r = dm_addmap(op, mpp->alias, DEFAULT_TARGET, mpp->params, mpp->size);
+ return r;
+}
- if (r == 0)
- dm_simplecmd(DM_DEVICE_REMOVE, mpp->alias);
- else if (op == DM_DEVICE_RELOAD)
- dm_simplecmd(DM_DEVICE_RESUME, mpp->alias);
+static int
+deadmap (struct multipath * mpp)
+{
+ int i, j;
+ struct pathgroup * pgp;
+ struct path * pp;
- /*
- * PG order is random, so we need to set the primary one
- * upon create or reload
- */
- dm_switchgroup(mpp->alias, mpp->nextpg);
+ if (!mpp->pg)
+ return 1;
- dm_log_init_verbose(1);
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
- return r;
+ vector_foreach_slot (pgp->paths, pp, j)
+ if (strlen(pp->dev))
+ return 0; /* alive */
+ }
+
+ return 1; /* dead */
}
static int
coalesce_paths (vector curmp, vector pathvec)
{
+ int r = 1;
int k, i;
char empty_buff[WWID_SIZE];
struct multipath * mpp;
@@ -675,10 +751,10 @@
mpp->mpe = find_mpe(pp1->wwid);
mpp->hwe = pp1->hwe;
+ strcpy(mpp->wwid, pp1->wwid);
select_alias(mpp);
pp1->mpp = mpp;
- strcpy(mpp->wwid, pp1->wwid);
mpp->size = pp1->size;
mpp->paths = vector_alloc();
@@ -713,20 +789,42 @@
if (store_path(mpp->paths, pp2))
return 1;
}
- if (setup_map(mpp)) {
- free_multipath(mpp, KEEP_PATHS);
- continue;
- }
- condlog(3, "action preset to %i", mpp->action);
+ if (setup_map(mpp))
+ goto next;
if (mpp->action == ACT_UNDEF)
select_action(mpp, curmp);
- condlog(3, "action set to %i", mpp->action);
+ r = domap(mpp);
- domap(mpp);
+ if (r < 0)
+ return r;
+
+ if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+ dm_queue_if_no_path(mpp->alias, 0);
+ else
+ dm_queue_if_no_path(mpp->alias, 1);
+ }
+
+next:
+ drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
free_multipath(mpp, KEEP_PATHS);
}
+ /*
+ * Flush maps with only dead paths (ie not in sysfs)
+ * Keep maps with only failed paths
+ */
+ vector_foreach_slot (curmp, mpp, i) {
+ if (!deadmap(mpp))
+ continue;
+
+ if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
+ condlog(2, "remove: %s (dead) failed!",
+ mpp->alias);
+ else
+ condlog(2, "remove: %s (dead)", mpp->alias);
+ }
return 0;
}
@@ -740,15 +838,16 @@
"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
"\t\t\t[device]\n" \
"\n" \
- "\t-v level\tverbosty level\n" \
+ "\t-v level\tverbosity level\n" \
"\t 0\t\t\tno output\n" \
"\t 1\t\t\tprint created devmap names only\n" \
"\t 2\t\t\tdefault verbosity\n" \
"\t 3\t\t\tprint debug information\n" \
+ "\t-b file\t\tbindings file location\n" \
"\t-d\t\tdry run, do not create or update devmaps\n" \
"\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
"\t-ll\t\tshow multipath topology (maximum info)\n" \
- "\t-F\t\tflush a multipath device map\n" \
+ "\t-f\t\tflush a multipath device map\n" \
"\t-F\t\tflush all multipath device maps\n" \
"\t-p policy\tforce all maps to specified policy :\n" \
"\t failover\t\t1 path per priority group\n" \
@@ -772,10 +871,22 @@
struct pathgroup * pgp;
struct path * pp;
+ if (!mpp->pg)
+ return 0;
+
vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+
vector_foreach_slot (pgp->paths, pp, j) {
if (!strlen(pp->dev)) {
- devt2devname(pp->dev, pp->dev_t);
+ if (devt2devname(pp->dev, pp->dev_t)) {
+ /*
+ * path is not in sysfs anymore
+ */
+ pp->state = PATH_DOWN;
+ continue;
+ }
pathinfo(pp, conf->hwtable,
DI_SYSFS | DI_CHECKER | \
DI_SERIAL | DI_PRIO);
@@ -796,29 +907,30 @@
{
int i;
struct multipath * mpp;
- char * wwid;
if (dm_get_maps(curmp, DEFAULT_TARGET))
return 1;
vector_foreach_slot (curmp, mpp, i) {
- wwid = get_mpe_wwid(mpp->alias);
-
- if (wwid) {
- /* out of specified scope */
- if (refwwid && strncmp(wwid, refwwid, WWID_SIZE))
- continue;
- wwid = NULL;
+ /*
+ * discard out of scope maps
+ */
+ if (mpp->wwid && refwwid &&
+ strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
+ condlog(3, "skip map %s: out of scope", mpp->alias);
+ free_multipath(mpp, KEEP_PATHS);
+ vector_del_slot(curmp, i);
+ i--;
+ continue;
}
condlog(3, "params = %s", mpp->params);
condlog(3, "status = %s", mpp->status);
- /* will set mpp->wwid */
disassemble_map(pathvec, mpp->params, mpp);
/*
- * disassemble_map may have added new paths to pathvec.
+ * disassemble_map() can add new paths to pathvec.
* If not in "fast list mode", we need to fetch information
* about them
*/
@@ -826,7 +938,7 @@
update_paths(mpp);
if (conf->list > 1)
- select_path_group(mpp);
+ mpp->bestpg = select_path_group(mpp);
disassemble_status(mpp->status, mpp);
@@ -839,17 +951,122 @@
return 0;
}
-int
-main (int argc, char *argv[])
+
+/*
+ * Return value:
+ * -1: Retry
+ * 0: Success
+ * 1: Failure
+ */
+static int
+configure (void)
{
vector curmp = NULL;
vector pathvec = NULL;
- int i;
+ int r = 1;
int di_flag = 0;
+ char * refwwid = NULL;
+ char * dev = NULL;
+
+ /*
+ * allocate core vectors to store paths and multipaths
+ */
+ curmp = vector_alloc();
+ pathvec = vector_alloc();
+
+ if (!curmp || !pathvec) {
+ condlog(0, "can not allocate memory");
+ goto out;
+ }
+
+ /*
+ * if we have a blacklisted device parameter, exit early
+ */
+ if (conf->dev) {
+ if (!strncmp(conf->dev, "/dev/", 5) &&
+ strlen(conf->dev) > 5)
+ dev = conf->dev + 5;
+ else
+ dev = conf->dev;
+ }
+
+ if (dev && blacklist(conf->blist, dev))
+ goto out;
+
+ condlog(3, "load path identifiers cache");
+ cache_load(pathvec);
+
+ if (conf->verbosity > 2)
+ print_all_paths(pathvec, 1);
+
+ /*
+ * scope limiting must be translated into a wwid
+ * failing the translation is fatal (by policy)
+ */
+ if (conf->dev) {
+ refwwid = get_refwwid(pathvec);
+
+ if (!refwwid) {
+ condlog(3, "scope is nul");
+ goto out;
+ }
+ condlog(3, "scope limited to %s", refwwid);
+ }
+
+ /*
+ * get a path list
+ */
+ if (conf->dev)
+ di_flag = DI_WWID;
+
+ if (conf->list > 1)
+ /* extended path info '-ll' */
+ di_flag |= DI_SYSFS | DI_CHECKER;
+ else if (conf->list)
+ /* minimum path info '-l' */
+ di_flag |= DI_SYSFS;
+ else
+ /* maximum info */
+ di_flag = DI_ALL;
+
+ if (path_discovery(pathvec, conf, di_flag))
+ goto out;
+
+ if (conf->verbosity > 2)
+ print_all_paths(pathvec, 1);
+
+ get_path_layout(&pl, pathvec);
+
+ if (get_dm_mpvec(curmp, pathvec, refwwid))
+ goto out;
+
+ filter_pathvec(pathvec, refwwid);
+
+ if (conf->list)
+ goto out;
+
+ /*
+ * core logic entry point
+ */
+ r = coalesce_paths(curmp, pathvec);
+
+out:
+ if (refwwid)
+ FREE(refwwid);
+
+ free_multipathvec(curmp, KEEP_PATHS);
+ free_pathvec(pathvec, FREE_PATHS);
+
+ return r;
+}
+
+int
+main (int argc, char *argv[])
+{
int arg;
extern char *optarg;
extern int optind;
- char * refwwid = NULL;
+ int i, r;
if (getuid() != 0) {
fprintf(stderr, "need to be root\n");
@@ -866,7 +1083,7 @@
if (load_config(DEFAULT_CONFIGFILE))
exit(1);
- while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -877,14 +1094,17 @@
conf->verbosity = atoi(optarg);
break;
+ case 'b':
+ conf->bindings_file = optarg;
+ break;
case 'd':
conf->dry_run = 1;
break;
case 'f':
- conf->remove = 1;
+ conf->remove = FLUSH_ONE;
break;
case 'F':
- conf->remove = 2;
+ conf->remove = FLUSH_ALL;
break;
case 'l':
conf->list = 1;
@@ -945,83 +1165,15 @@
dm_flush_maps(DEFAULT_TARGET);
goto out;
}
-
- /*
- * allocate core vectors to store paths and multipaths
- */
- curmp = vector_alloc();
- pathvec = vector_alloc();
-
- if (!curmp || !pathvec) {
- condlog(0, "can not allocate memory");
- goto out;
- }
-
- /*
- * if we have a blacklisted device parameter, exit early
- */
- if (conf->dev && blacklist(conf->blist, conf->dev))
- goto out;
+ while ((r = configure()) < 0)
+ condlog(3, "restart multipath configuration process");
- condlog(3, "load path identifiers cache");
- cache_load(pathvec);
-
- if (conf->verbosity > 2) {
- fprintf(stdout, "#\n# all paths in cache :\n#\n");
- print_all_paths(pathvec);
- }
-
- /*
- * get a path list
- */
- if (conf->dev)
- di_flag = DI_WWID;
-
- if (conf->list > 1)
- /* extended path info '-ll' */
- di_flag |= DI_SYSFS | DI_CHECKER;
- else if (conf->list)
- /* minimum path info '-l' */
- di_flag |= DI_SYSFS;
- else
- /* maximum info */
- di_flag = DI_ALL;
-
- if (path_discovery(pathvec, conf, di_flag) || VECTOR_SIZE(pathvec) == 0)
- goto out;
-
- if (conf->verbosity > 2) {
- fprintf(stdout, "#\n# all paths :\n#\n");
- print_all_paths(pathvec);
- }
-
- refwwid = get_refwwid(pathvec);
- get_path_layout(&pl, pathvec);
-
- if (get_dm_mpvec(curmp, pathvec, refwwid))
- goto out;
-
- filter_pathvec(pathvec, refwwid);
-
- if (conf->list)
- goto out;
-
- /*
- * core logic entry point
- */
- coalesce_paths(curmp, pathvec);
-
out:
- if (refwwid)
- FREE(refwwid);
-
- free_multipathvec(curmp, KEEP_PATHS);
- free_pathvec(pathvec, FREE_PATHS);
free_config(conf);
dm_lib_release();
dm_lib_exit();
#ifdef _DEBUG_
dbg_free_final(NULL);
#endif
- exit(0);
+ return r;
}
Modified: multipath-tools/trunk/multipath/main.h
==============================================================================
--- multipath-tools/trunk/multipath/main.h (original)
+++ multipath-tools/trunk/multipath/main.h Wed Feb 1 23:59:42 2006
@@ -43,8 +43,8 @@
*/
#define PROG "multipath"
-#define VERSION_CODE 0x000405
-#define DATE_CODE 0x100605
+#define VERSION_CODE 0x000406
+#define DATE_CODE 0x0b0a05
#define MULTIPATH_VERSION(version) \
(version >> 16) & 0xFF, \
Modified: multipath-tools/trunk/multipath/multipath.rules
==============================================================================
--- multipath-tools/trunk/multipath/multipath.rules (original)
+++ multipath-tools/trunk/multipath/multipath.rules Wed Feb 1 23:59:42 2006
@@ -1 +1,14 @@
-SUBSYSTEM=="block", BUS=="scsi", KERNEL=="sd*[!0-9]", ACTION=="add", RUN+="/etc/udev/scripts/multipath.sh %k"
+#
+# multipath and multipath partitions nodes are created in /dev/mapper/
+# this file should be installed in /etc/udev/rules.d
+#
+
+# take care of devmap partitioning
+ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
+ PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info", \
+ RUN+="/sbin/kpartx -a /dev/mapper/%c"
+
+# insert new paths in multipath topology
+ACTION=="add", SUBSYSTEM=="block", KERNEL!="dm-*", \
+ RUN+="/sbin/multipath -v0 %r/%k"
+
Modified: multipath-tools/trunk/multipathd/Makefile
==============================================================================
--- multipath-tools/trunk/multipathd/Makefile (original)
+++ multipath-tools/trunk/multipathd/Makefile Wed Feb 1 23:59:42 2006
@@ -15,7 +15,7 @@
#
CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
-DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lcurses
+LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses -lm
#
# debuging stuff
@@ -27,7 +27,7 @@
#
# object files
#
-OBJS = main.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
$(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
@@ -43,7 +43,6 @@
$(EXEC): clean $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
- $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(CHECKERSLIB)-glibc.a:
@@ -54,7 +53,7 @@
install:
install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
install -d $(DESTDIR)$(rcdir)
install -d $(DESTDIR)$(mandir)
install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
@@ -65,6 +64,6 @@
rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
clean:
- $(MAKE) -C $(multipathdir) prepare
+ $(MAKE) -C $(multipathdir) prepare DAEMON=1
rm -f core *.o $(EXEC) *.gz
Modified: multipath-tools/trunk/multipathd/cli.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli.c (original)
+++ multipath-tools/trunk/multipathd/cli.c Wed Feb 1 23:59:42 2006
@@ -121,6 +121,10 @@
r += add_key(keys, "del", DEL, 0);
r += add_key(keys, "switch", SWITCH, 0);
r += add_key(keys, "switchgroup", SWITCH, 0);
+ r += add_key(keys, "suspend", SUSPEND, 0);
+ r += add_key(keys, "resume", RESUME, 0);
+ r += add_key(keys, "reinstate", REINSTATE, 0);
+ r += add_key(keys, "fail", FAIL, 0);
r += add_key(keys, "paths", PATHS, 0);
r += add_key(keys, "maps", MAPS, 0);
r += add_key(keys, "path", PATH, 1);
@@ -282,7 +286,6 @@
return NULL;
p = reply;
- p += sprintf(p, "\n");
vector_foreach_slot (handlers, h, i) {
fp = h->fingerprint;
@@ -311,7 +314,7 @@
if (!cmdvec) {
*reply = genhelp_handler();
- *len = strlen(*reply);
+ *len = strlen(*reply) + 1;
return 0;
}
Modified: multipath-tools/trunk/multipathd/cli.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli.h (original)
+++ multipath-tools/trunk/multipathd/cli.h Wed Feb 1 23:59:42 2006
@@ -1,15 +1,38 @@
-#define LIST 1
-#define ADD (1 << 1)
-#define DEL (1 << 2)
-#define SWITCH (1 << 3)
-#define PATHS (1 << 4)
-#define MAPS (1 << 5)
-#define PATH (1 << 6)
-#define MAP (1 << 7)
-#define GROUP (1 << 8)
-#define DUMP (1 << 9)
-#define PATHVEC (1 << 10)
-#define RECONFIGURE (1 << 11)
+enum {
+ __LIST,
+ __ADD,
+ __DEL,
+ __SWITCH,
+ __SUSPEND,
+ __RESUME,
+ __REINSTATE,
+ __FAIL,
+ __PATHS,
+ __MAPS,
+ __PATH,
+ __MAP,
+ __GROUP,
+ __DUMP,
+ __PATHVEC,
+ __RECONFIGURE
+};
+
+#define LIST (1 << __LIST)
+#define ADD (1 << __ADD)
+#define DEL (1 << __DEL)
+#define SWITCH (1 << __SWITCH)
+#define SUSPEND (1 << __SUSPEND)
+#define RESUME (1 << __RESUME)
+#define REINSTATE (1 << __REINSTATE)
+#define FAIL (1 << __FAIL)
+#define PATHS (1 << __PATHS)
+#define MAPS (1 << __MAPS)
+#define PATH (1 << __PATH)
+#define MAP (1 << __MAP)
+#define GROUP (1 << __GROUP)
+#define DUMP (1 << __DUMP)
+#define PATHVEC (1 << __PATHVEC)
+#define RECONFIGURE (1 << __RECONFIGURE)
#define MAX_REPLY_LEN 1000
Modified: multipath-tools/trunk/multipathd/cli_handlers.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.c (original)
+++ multipath-tools/trunk/multipathd/cli_handlers.c Wed Feb 1 23:59:42 2006
@@ -1,6 +1,7 @@
#include <memory.h>
#include <vector.h>
#include <structs.h>
+#include <libdevmapper.h>
#include <devmapper.h>
#include <config.h>
#include <blacklist.h>
@@ -11,23 +12,23 @@
int
cli_list_paths (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
- return show_paths(reply, len, allpaths);
+ return show_paths(reply, len, vecs);
}
int
cli_list_maps (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
- return show_maps(reply, len, allpaths);
+ return show_maps(reply, len, vecs);
}
int
cli_add_path (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
if (blacklist(conf->blist, param)) {
@@ -35,34 +36,34 @@
*len = strlen(*reply) + 1;
return 0;
}
- return uev_add_path(param, allpaths);
+ return uev_add_path(param, vecs);
}
int
cli_del_path (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
- return uev_remove_path(param, allpaths);
+ return uev_remove_path(param, vecs);
}
int
cli_add_map (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
- return uev_add_map(param, allpaths);
+ return uev_add_map(param, vecs);
}
int
cli_del_map (void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
- return uev_remove_map(param, allpaths);
+ return uev_remove_map(param, vecs);
}
int
@@ -77,15 +78,89 @@
int
cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
- return dump_pathvec(reply, len, allpaths);
+ return dump_pathvec(reply, len, vecs);
}
int
cli_reconfigure(void * v, char ** reply, int * len, void * data)
{
- struct paths * allpaths = (struct paths *)data;
+ struct vectors * vecs = (struct vectors *)data;
- return reconfigure(allpaths);
+ return reconfigure(vecs);
+}
+
+int
+cli_suspend(void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+ int r = dm_simplecmd(DM_DEVICE_SUSPEND, param);
+
+ if (!r) /* error */
+ return 1;
+
+ struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ dm_get_info(param, &mpp->dmi);
+ return 0;
+}
+
+int
+cli_resume(void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+ int r = dm_simplecmd(DM_DEVICE_RESUME, param);
+
+ if (!r) /* error */
+ return 1;
+
+ struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ dm_get_info(param, &mpp->dmi);
+ return 0;
+}
+
+int
+cli_reinstate(void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, PATH);
+ struct path * pp;
+
+ pp = find_path_by_dev(vecs->pathvec, param);
+
+ if (!pp)
+ pp = find_path_by_devt(vecs->pathvec, param);
+
+ if (!pp || !pp->mpp || !pp->mpp->alias)
+ return 1;
+
+ return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
+}
+
+int
+cli_fail(void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, PATH);
+ struct path * pp;
+
+ pp = find_path_by_dev(vecs->pathvec, param);
+
+ if (!pp)
+ pp = find_path_by_devt(vecs->pathvec, param);
+
+ if (!pp || !pp->mpp || !pp->mpp->alias)
+ return 1;
+
+ return dm_fail_path(pp->mpp->alias, pp->dev_t);
}
Modified: multipath-tools/trunk/multipathd/cli_handlers.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.h (original)
+++ multipath-tools/trunk/multipathd/cli_handlers.h Wed Feb 1 23:59:42 2006
@@ -7,3 +7,7 @@
int cli_switch_group(void * v, char ** reply, int * len, void * data);
int cli_dump_pathvec(void * v, char ** reply, int * len, void * data);
int cli_reconfigure(void * v, char ** reply, int * len, void * data);
+int cli_suspend(void * v, char ** reply, int * len, void * data);
+int cli_resume(void * v, char ** reply, int * len, void * data);
+int cli_reinstate(void * v, char ** reply, int * len, void * data);
+int cli_fail(void * v, char ** reply, int * len, void * data);
Modified: multipath-tools/trunk/multipathd/main.c
==============================================================================
--- multipath-tools/trunk/multipathd/main.c (original)
+++ multipath-tools/trunk/multipathd/main.c Wed Feb 1 23:59:42 2006
@@ -3,6 +3,9 @@
#include <libdevmapper.h>
#include <wait.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
/*
* libsysfs
@@ -63,9 +66,13 @@
#define unlock(a) \
fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
pthread_mutex_unlock(a)
+#define lock_cleanup_pop(a) \
+ fprintf(stderr, "%s:%s(%i) unlock %p\n", __FILE__, __FUNCTION__, __LINE__, a); \
+ pthread_cleanup_pop(1);
#else
#define lock(a) pthread_mutex_lock(a)
#define unlock(a) pthread_mutex_unlock(a)
+#define lock_cleanup_pop(a) pthread_cleanup_pop(1);
#endif
pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
@@ -79,7 +86,7 @@
pthread_t thread;
int event_nr;
char mapname[WWID_SIZE];
- struct paths *allpaths;
+ struct vectors *vecs;
};
static struct event_thread *
@@ -94,13 +101,43 @@
}
static void
+free_waiter (void * data)
+{
+ struct event_thread * wp = (struct event_thread *)data;
+
+ if (wp->dmt)
+ dm_task_destroy(wp->dmt);
+ FREE(wp);
+}
+
+static void
+stop_waiter_thread (struct multipath * mpp, struct vectors * vecs)
+{
+ struct event_thread * wp = (struct event_thread *)mpp->waiter;
+ pthread_t thread;
+
+ if (!wp) {
+ condlog(3, "%s: no waiter thread", mpp->alias);
+ return;
+ }
+ thread = wp->thread;
+
+ if (!wp) {
+ condlog(3, "%s: thread not started", mpp->alias);
+ return;
+ }
+ condlog(2, "%s: stop event checker thread", wp->mapname);
+ pthread_kill(thread, SIGHUP);
+}
+
+static void
cleanup_lock (void * data)
{
- unlock((pthread_mutex_t *)data);
+ pthread_mutex_unlock((pthread_mutex_t *)data);
}
static void
-set_paths_owner (struct paths * allpaths, struct multipath * mpp)
+adopt_paths (struct vectors * vecs, struct multipath * mpp)
{
int i;
struct path * pp;
@@ -108,7 +145,7 @@
if (!mpp)
return;
- vector_foreach_slot (allpaths->pathvec, pp, i) {
+ vector_foreach_slot (vecs->pathvec, pp, i) {
if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
condlog(4, "%s ownership set", pp->dev_t);
pp->mpp = mpp;
@@ -117,15 +154,31 @@
}
static void
-unset_paths_owner (struct paths * allpaths, struct multipath * mpp)
+orphan_path (struct path * pp)
+{
+ pp->mpp = NULL;
+ pp->checkfn = NULL;
+ pp->dmstate = PSTATE_UNDEF;
+ pp->checker_context = NULL;
+ pp->getuid = NULL;
+ pp->getprio = NULL;
+
+ if (pp->fd >= 0)
+ close(pp->fd);
+
+ pp->fd = -1;
+}
+
+static void
+orphan_paths (struct vectors * vecs, struct multipath * mpp)
{
int i;
struct path * pp;
- vector_foreach_slot (allpaths->pathvec, pp, i) {
+ vector_foreach_slot (vecs->pathvec, pp, i) {
if (pp->mpp == mpp) {
condlog(4, "%s is orphaned", pp->dev_t);
- pp->mpp = NULL;
+ orphan_path(pp);
}
}
}
@@ -193,42 +246,165 @@
static void
set_multipath_wwid (struct multipath * mpp)
{
- char * wwid;
-
- wwid = get_mpe_wwid(mpp->alias);
+ if (mpp->wwid)
+ return;
- if (wwid) {
- strncpy(mpp->wwid, wwid, WWID_SIZE);
- wwid = NULL;
- } else
- strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
+ dm_get_uuid(mpp->alias, mpp->wwid);
}
static int
-setup_multipath (struct paths * allpaths, struct multipath * mpp)
+pathcount (struct multipath *mpp, int state)
+{
+ struct pathgroup *pgp;
+ struct path *pp;
+ int i, j;
+ int count = 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i)
+ vector_foreach_slot (pgp->paths, pp, j)
+ if (pp->state == state)
+ count++;
+ return count;
+}
+
+/*
+ * mpp->no_path_retry:
+ * -2 (QUEUE) : queue_if_no_path enabled, never turned off
+ * -1 (FAIL) : fail_if_no_path
+ * 0 (UNDEF) : nothing
+ * >0 : queue_if_no_path enabled, turned off after polling n times
+ */
+static void
+update_queue_mode_del_path(struct multipath *mpp)
+{
+ if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
+ /*
+ * Enter retry mode.
+ * meaning of +1: retry_tick may be decremented in
+ * checkerloop before starting retry.
+ */
+ mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
+ condlog(1, "%s: Entering recovery mode: max_retries=%d",
+ mpp->alias, mpp->no_path_retry);
+ }
+ condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
+}
+
+static void
+update_queue_mode_add_path(struct multipath *mpp)
+{
+ if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
+ /* come back to normal mode from retry mode */
+ mpp->retry_tick = 0;
+ dm_queue_if_no_path(mpp->alias, 1);
+ condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
+ condlog(1, "%s: Recovered to normal mode", mpp->alias);
+ }
+ condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
+}
+
+static void
+set_no_path_retry(struct multipath *mpp)
+{
+ mpp->retry_tick = 0;
+ mpp->nr_active = pathcount(mpp, PATH_UP);
+ select_no_path_retry(mpp);
+
+ switch (mpp->no_path_retry) {
+ case NO_PATH_RETRY_UNDEF:
+ break;
+ case NO_PATH_RETRY_FAIL:
+ dm_queue_if_no_path(mpp->alias, 0);
+ break;
+ case NO_PATH_RETRY_QUEUE:
+ dm_queue_if_no_path(mpp->alias, 1);
+ break;
+ default:
+ dm_queue_if_no_path(mpp->alias, 1);
+ if (mpp->nr_active == 0) {
+ /* Enter retry mode */
+ mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+ condlog(1, "%s: Entering recovery mode: max_retries=%d",
+ mpp->alias, mpp->no_path_retry);
+ }
+ break;
+ }
+}
+
+static struct hwentry *
+extract_hwe_from_path(struct multipath * mpp)
+{
+ struct path * pp;
+ struct pathgroup * pgp;
+
+ pgp = VECTOR_SLOT(mpp->pg, 0);
+ pp = VECTOR_SLOT(pgp->paths, 0);
+
+ return pp->hwe;
+}
+
+static void
+remove_map (struct multipath * mpp, struct vectors * vecs)
+{
+ int i;
+
+ stop_waiter_thread(mpp, vecs);
+
+ /*
+ * clear references to this map
+ */
+ orphan_paths(vecs, mpp);
+
+ /*
+ * purge the multipath vector
+ */
+ i = find_slot(vecs->mpvec, (void *)mpp);
+ vector_del_slot(vecs->mpvec, i);
+
+ /*
+ * final free
+ */
+ free_multipath(mpp, KEEP_PATHS);
+ mpp = NULL;
+}
+
+static void
+remove_maps (struct vectors * vecs)
{
int i;
+ struct multipath * mpp;
+
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
+ remove_map(mpp, vecs);
+ i--;
+ }
+
+ vector_free(vecs->mpvec);
+ vecs->mpvec = NULL;
+}
+
+static int
+setup_multipath (struct vectors * vecs, struct multipath * mpp)
+{
+ if (dm_get_info(mpp->alias, &mpp->dmi))
+ goto out;
set_multipath_wwid(mpp);
mpp->mpe = find_mpe(mpp->wwid);
condlog(4, "discovered map %s", mpp->alias);
- if (update_multipath_strings(mpp, allpaths->pathvec))
+ if (update_multipath_strings(mpp, vecs->pathvec))
goto out;
- set_paths_owner(allpaths, mpp);
+ adopt_paths(vecs, mpp);
+ mpp->hwe = extract_hwe_from_path(mpp);
select_pgfailback(mpp);
+ set_no_path_retry(mpp);
return 0;
out:
- /*
- * purge the multipath vector
- */
- if ((i = find_slot(allpaths->mpvec, (void *)mpp)) != -1)
- vector_del_slot(allpaths->mpvec, i);
-
- free_multipath(mpp, KEEP_PATHS);
- condlog(0, "failed to setup multipath");
+ condlog(0, "%s: failed to setup multipath", mpp->alias);
+ remove_map(mpp, vecs);
return 1;
}
@@ -250,10 +426,9 @@
vector_foreach_slot (pgp->paths, pp, j)
pathinfo(pp, conf->hwtable, DI_PRIO);
- select_path_group(mpp); /* sets mpp->nextpg */
- pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
+ mpp->bestpg = select_path_group(mpp);
- if (pgp && pgp->status != PGSTATE_ACTIVE)
+ if (mpp->bestpg != mpp->nextpg)
return 1;
return 0;
@@ -262,19 +437,13 @@
static void
switch_pathgroup (struct multipath * mpp)
{
- struct pathgroup * pgp;
-
- pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
-
- if (pgp && pgp->status != PGSTATE_ACTIVE) {
- dm_switchgroup(mpp->alias, mpp->nextpg);
- condlog(2, "%s: switch to path group #%i",
- mpp->alias, mpp->nextpg);
- }
+ dm_switchgroup(mpp->alias, mpp->bestpg);
+ condlog(2, "%s: switch to path group #%i",
+ mpp->alias, mpp->bestpg);
}
static int
-update_multipath (struct paths *allpaths, char *mapname)
+update_multipath (struct vectors *vecs, char *mapname)
{
struct multipath *mpp;
struct pathgroup *pgp;
@@ -282,7 +451,7 @@
int i, j;
int r = 1;
- mpp = find_mp(allpaths->mpvec, mapname);
+ mpp = find_mp_by_alias(vecs->mpvec, mapname);
if (!mpp)
goto out;
@@ -290,7 +459,7 @@
free_pgvec(mpp->pg, KEEP_PATHS);
mpp->pg = NULL;
- if (setup_multipath(allpaths, mpp))
+ if (setup_multipath(vecs, mpp))
goto out; /* mpp freed in setup_multipath */
/*
@@ -304,6 +473,7 @@
if (pp->state != PATH_DOWN) {
condlog(2, "%s: mark as failed", pp->dev_t);
pp->state = PATH_DOWN;
+ update_queue_mode_del_path(mpp);
/*
* if opportune,
@@ -322,16 +492,6 @@
return r;
}
-static void
-free_waiter (void * data)
-{
- struct event_thread * wp = (struct event_thread *)data;
-
- if (wp->dmt)
- dm_task_destroy(wp->dmt);
- FREE(wp);
-}
-
static sigset_t unblock_sighup(void)
{
sigset_t set, old;
@@ -359,22 +519,37 @@
if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
return 1;
- if (!dm_task_set_name(waiter->dmt, waiter->mapname))
+ if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+ dm_task_destroy(waiter->dmt);
return 1;
+ }
if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
- waiter->event_nr))
+ waiter->event_nr)) {
+ dm_task_destroy(waiter->dmt);
return 1;
+ }
dm_task_no_open_count(waiter->dmt);
-
+
+ /* accept wait interruption */
set = unblock_sighup();
- dm_task_run(waiter->dmt);
+
+ /* 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);
- pthread_testcancel();
+ //dm_restore_log();
+
+ if (!r) /* wait interrupted by signal */
+ return -1;
+
dm_task_destroy(waiter->dmt);
waiter->dmt = NULL;
-
waiter->event_nr++;
/*
@@ -395,11 +570,10 @@
* 4) a path reinstate : nothing to do
* 5) a switch group : nothing to do
*/
- pthread_cleanup_push(cleanup_lock, waiter->allpaths->lock);
- lock(waiter->allpaths->lock);
-
- r = update_multipath(waiter->allpaths, waiter->mapname);
- pthread_cleanup_pop(1);
+ pthread_cleanup_push(cleanup_lock, waiter->vecs->lock);
+ lock(waiter->vecs->lock);
+ r = update_multipath(waiter->vecs, waiter->mapname);
+ lock_cleanup_pop(waiter->vecs->lock);
if (r)
return -1; /* stop the thread */
@@ -431,9 +605,7 @@
if (r < 0)
break;
- pthread_testcancel();
sleep(r);
- pthread_testcancel();
}
pthread_cleanup_pop(1);
@@ -441,26 +613,7 @@
}
static int
-stop_waiter_thread (struct multipath * mpp, struct paths * allpaths)
-{
- struct event_thread * wp = (struct event_thread *)mpp->waiter;
- pthread_t thread = wp->thread;
- int r;
-
- if (!wp)
- return 1;
-
- condlog(2, "%s: reap event checker", wp->mapname);
-
- if ((r = pthread_cancel(thread)))
- return r;
-
- pthread_kill(thread, SIGHUP);
- return 0;
-}
-
-static int
-start_waiter_thread (struct multipath * mpp, struct paths * allpaths)
+start_waiter_thread (struct multipath * mpp, struct vectors * vecs)
{
pthread_attr_t attr;
struct event_thread * wp;
@@ -481,7 +634,7 @@
mpp->waiter = (void *)wp;
strncpy(wp->mapname, mpp->alias, WWID_SIZE);
- wp->allpaths = allpaths;
+ wp->vecs = vecs;
if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
condlog(0, "%s: cannot create event checker", wp->mapname);
@@ -498,68 +651,20 @@
return 1;
}
-static void
-remove_map (struct multipath * mpp, struct paths * allpaths)
-{
- int i;
-
- /*
- * stop the DM event waiter thread
- */
- if (stop_waiter_thread(mpp, allpaths)) {
- condlog(0, "%s: error canceling waiter thread", mpp->alias);
- /*
- * warrior mode
- */
- free_waiter(mpp->waiter);
- }
-
- /*
- * clear references to this map
- */
- unset_paths_owner(allpaths, mpp);
-
- /*
- * purge the multipath vector
- */
- i = find_slot(allpaths->mpvec, (void *)mpp);
- vector_del_slot(allpaths->mpvec, i);
-
- /*
- * final free
- */
- free_multipath(mpp, KEEP_PATHS);
- mpp = NULL;
-}
-
-static void
-remove_maps (struct paths * allpaths)
-{
- int i;
- struct multipath * mpp;
-
- vector_foreach_slot (allpaths->mpvec, mpp, i)
- remove_map(mpp, allpaths);
-
- vector_free(allpaths->mpvec);
- allpaths->mpvec = NULL;
-}
-
int
-uev_add_map (char * devname, struct paths * allpaths)
+uev_add_map (char * devname, struct vectors * vecs)
{
- int major, minor, i;
+ int major, minor;
char dev_t[BLK_DEV_SIZE];
char * alias;
struct multipath * mpp;
- if (sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE))
- return 1;
-
- if (sscanf(dev_t, "%d:%d", &major, &minor) != 2)
- return 1;
-
- alias = dm_mapname(major, minor);
+ 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);
if (!alias)
return 1;
@@ -570,7 +675,7 @@
return 0;
}
- mpp = find_mp(allpaths->mpvec, alias);
+ mpp = find_mp_by_alias(vecs->mpvec, alias);
if (mpp) {
/*
@@ -578,7 +683,7 @@
* we missed a remove map event (not sent ?)
*/
condlog(2, "%s: already registered", alias);
- remove_map(mpp, allpaths);
+ remove_map(mpp, vecs);
}
/*
@@ -589,69 +694,62 @@
if (!mpp)
return 1;
- mpp->minor = minor;
mpp->alias = alias;
- if (setup_multipath(allpaths, mpp))
+ if (setup_multipath(vecs, mpp))
return 1; /* mpp freed in setup_multipath */
- if (!vector_alloc_slot(allpaths->mpvec))
+ if (!vector_alloc_slot(vecs->mpvec))
goto out;
- vector_set_slot(allpaths->mpvec, mpp);
- set_paths_owner(allpaths, mpp);
+ vector_set_slot(vecs->mpvec, mpp);
+ adopt_paths(vecs, mpp);
- if (start_waiter_thread(mpp, allpaths))
+ if (start_waiter_thread(mpp, vecs))
goto out;
return 0;
out:
condlog(2, "%s: add devmap failed", mpp->alias);
- /*
- * purge the multipath vector
- */
- if ((i = find_slot(allpaths->mpvec, (void *)mpp)) != -1)
- vector_del_slot(allpaths->mpvec, i);
-
- free_multipath(mpp, KEEP_PATHS);
+ remove_map(mpp, vecs);
return 1;
}
int
-uev_remove_map (char * devname, struct paths * allpaths)
+uev_remove_map (char * devname, struct vectors * vecs)
{
int minor;
struct multipath * mpp;
- if (sscanf(devname, "dm-%d", &minor) != 1)
- return 1;
-
- mpp = find_mp_by_minor(allpaths->mpvec, minor);
+ if (sscanf(devname, "dm-%d", &minor) == 1)
+ mpp = find_mp_by_minor(vecs->mpvec, minor);
+ else
+ mpp = find_mp_by_alias(vecs->mpvec, devname);
if (!mpp) {
condlog(3, "%s: devmap not registered, can't remove",
devname);
- return 1;
+ return 0;
}
condlog(2, "remove %s devmap", mpp->alias);
- remove_map(mpp, allpaths);
+ remove_map(mpp, vecs);
return 0;
}
int
-uev_add_path (char * devname, struct paths * allpaths)
+uev_add_path (char * devname, struct vectors * vecs)
{
struct path * pp;
- pp = find_path_by_dev(allpaths->pathvec, devname);
+ pp = find_path_by_dev(vecs->pathvec, devname);
if (pp) {
condlog(3, "%s: already in pathvec");
return 1;
}
- pp = store_pathinfo(allpaths->pathvec, conf->hwtable,
+ pp = store_pathinfo(vecs->pathvec, conf->hwtable,
devname, DI_SYSFS | DI_WWID);
if (!pp) {
@@ -660,39 +758,45 @@
}
condlog(2, "%s: path checker registered", devname);
- pp->mpp = find_mp_by_wwid(allpaths->mpvec, pp->wwid);
+ pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
- if (pp->mpp)
+ if (pp->mpp) {
condlog(4, "%s: ownership set to %s",
pp->dev_t, pp->mpp->alias);
- else
+ } else {
condlog(4, "%s: orphaned", pp->dev_t);
+ orphan_path(pp);
+ }
return 0;
}
int
-uev_remove_path (char * devname, struct paths * allpaths)
+uev_remove_path (char * devname, struct vectors * vecs)
{
int i;
struct path * pp;
- pp = find_path_by_dev(allpaths->pathvec, devname);
+ pp = find_path_by_dev(vecs->pathvec, devname);
if (!pp) {
condlog(3, "%s: not in pathvec");
return 1;
}
+
+ if (pp->mpp && pp->state == PATH_UP)
+ update_queue_mode_del_path(pp->mpp);
+
condlog(2, "remove %s path checker", devname);
- i = find_slot(allpaths->pathvec, (void *)pp);
- vector_del_slot(allpaths->pathvec, i);
+ i = find_slot(vecs->pathvec, (void *)pp);
+ vector_del_slot(vecs->pathvec, i);
free_path(pp);
return 0;
}
int
-show_paths (char ** r, int * len, struct paths * allpaths)
+show_paths (char ** r, int * len, struct vectors * vecs)
{
int i;
struct path * pp;
@@ -700,16 +804,19 @@
char * reply;
struct path_layout pl;
- get_path_layout(&pl, allpaths->pathvec);
+ get_path_layout(&pl, vecs->pathvec);
reply = MALLOC(MAX_REPLY_LEN);
if (!reply)
return 1;
c = reply;
- c += sprintf(c, "\n");
- vector_foreach_slot(allpaths->pathvec, pp, i)
+ if (VECTOR_SIZE(vecs->pathvec) > 0)
+ c += snprint_path_header(c, reply + MAX_REPLY_LEN - c,
+ PRINT_PATH_CHECKER, &pl);
+
+ vector_foreach_slot(vecs->pathvec, pp, i)
c += snprint_path(c, reply + MAX_REPLY_LEN - c,
PRINT_PATH_CHECKER, pp, &pl);
@@ -719,7 +826,7 @@
}
int
-show_maps (char ** r, int *len, struct paths * allpaths)
+show_maps (char ** r, int *len, struct vectors * vecs)
{
int i;
struct multipath * mpp;
@@ -727,16 +834,18 @@
char * reply;
struct map_layout ml;
- get_map_layout(&ml, allpaths->mpvec);
+ get_map_layout(&ml, vecs->mpvec);
reply = MALLOC(MAX_REPLY_LEN);
if (!reply)
return 1;
c = reply;
- c += sprintf(c, "\n");
+ if (VECTOR_SIZE(vecs->mpvec) > 0)
+ c += snprint_map_header(c, reply + MAX_REPLY_LEN - c,
+ PRINT_MAP_FAILBACK, &ml);
- vector_foreach_slot(allpaths->mpvec, mpp, i)
+ vector_foreach_slot(vecs->mpvec, mpp, i)
c += snprint_map(c, reply + MAX_REPLY_LEN - c,
PRINT_MAP_FAILBACK, mpp, &ml);
@@ -746,14 +855,14 @@
}
int
-dump_pathvec (char ** r, int * len, struct paths * allpaths)
+dump_pathvec (char ** r, int * len, struct vectors * vecs)
{
int i;
struct path * pp;
char * reply;
char * p;
- *len = VECTOR_SIZE(allpaths->pathvec) * sizeof(struct path);
+ *len = VECTOR_SIZE(vecs->pathvec) * sizeof(struct path);
reply = (char *)MALLOC(*len);
*r = reply;
@@ -762,35 +871,35 @@
p = reply;
- vector_foreach_slot (allpaths->pathvec, pp, i) {
+ vector_foreach_slot (vecs->pathvec, pp, i) {
memcpy((void *)p, pp, sizeof(struct path));
p += sizeof(struct path);
}
- return 0;
+ /* return negative to hint caller not to add "ok" to the dump */
+ return -1;
}
static int
-get_dm_mpvec (struct paths * allpaths)
+map_discovery (struct vectors * vecs)
{
int i;
struct multipath * mpp;
- if (dm_get_maps(allpaths->mpvec, "multipath"))
+ if (dm_get_maps(vecs->mpvec, "multipath"))
return 1;
- vector_foreach_slot (allpaths->mpvec, mpp, i) {
- if (setup_multipath(allpaths, mpp))
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
+ if (setup_multipath(vecs, mpp))
return 1;
- mpp->minor = dm_get_minor(mpp->alias);
- start_waiter_thread(mpp, allpaths);
+ start_waiter_thread(mpp, vecs);
}
return 0;
}
int
-reconfigure (struct paths * allpaths)
+reconfigure (struct vectors * vecs)
{
struct config * old = conf;
struct multipath * mpp;
@@ -807,11 +916,13 @@
conf->verbosity = old->verbosity;
free_config(old);
- vector_foreach_slot (allpaths->mpvec, mpp, i) {
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
mpp->mpe = find_mpe(mpp->wwid);
- set_paths_owner(allpaths, mpp);
+ mpp->hwe = extract_hwe_from_path(mpp);
+ adopt_paths(vecs, mpp);
+ set_no_path_retry(mpp);
}
- vector_foreach_slot (allpaths->pathvec, pp, i) {
+ vector_foreach_slot (vecs->pathvec, pp, i) {
select_checkfn(pp);
select_getuid(pp);
select_getprio(pp);
@@ -823,60 +934,76 @@
int
uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
{
- struct paths * allpaths;
+ struct vectors * vecs;
int r;
*reply = NULL;
*len = 0;
- allpaths = (struct paths *)trigger_data;
+ vecs = (struct vectors *)trigger_data;
- pthread_cleanup_push(cleanup_lock, allpaths->lock);
- lock(allpaths->lock);
+ pthread_cleanup_push(cleanup_lock, vecs->lock);
+ lock(vecs->lock);
- r = parse_cmd(str, reply, len, allpaths);
+ r = parse_cmd(str, reply, len, vecs);
- if (r) {
+ if (r > 0) {
*reply = STRDUP("fail\n");
*len = strlen(*reply) + 1;
r = 1;
}
- else if (*len == 0) {
+ else if (!r && *len == 0) {
*reply = STRDUP("ok\n");
*len = strlen(*reply) + 1;
r = 0;
}
+ /* else if (r < 0) leave *reply alone */
- pthread_cleanup_pop(1);
+ lock_cleanup_pop(vecs->lock);
return r;
}
+static int
+uev_discard(char * devpath)
+{
+ char a[10], b[10];
+
+ /*
+ * keep only block devices, discard partitions
+ */
+ if (sscanf(devpath, "/block/%10s", a) != 1 ||
+ sscanf(devpath, "/block/%10[^/]/%10s", a, b) == 2) {
+ condlog(4, "discard event on %s", devpath);
+ return 1;
+ }
+ return 0;
+}
+
int
uev_trigger (struct uevent * uev, void * trigger_data)
{
int r = 0;
char devname[32];
- struct paths * allpaths;
+ struct vectors * vecs;
- allpaths = (struct paths *)trigger_data;
- pthread_cleanup_push(cleanup_lock, allpaths->lock);
- lock(allpaths->lock);
+ vecs = (struct vectors *)trigger_data;
- if (strncmp(uev->devpath, "/block", 6))
+ if (uev_discard(uev->devpath))
goto out;
basename(uev->devpath, devname);
+ lock(vecs->lock);
/*
* device map add/remove event
*/
if (!strncmp(devname, "dm-", 3)) {
if (!strncmp(uev->action, "add", 3)) {
- r = uev_add_map(devname, allpaths);
+ r = uev_add_map(devname, vecs);
goto out;
}
#if 0
if (!strncmp(uev->action, "remove", 6)) {
- r = uev_remove_map(devname, allpaths);
+ r = uev_remove_map(devname, vecs);
goto out;
}
#endif
@@ -890,25 +1017,25 @@
goto out;
if (!strncmp(uev->action, "add", 3)) {
- r = uev_add_path(devname, allpaths);
+ r = uev_add_path(devname, vecs);
goto out;
}
if (!strncmp(uev->action, "remove", 6)) {
- r = uev_remove_path(devname, allpaths);
+ r = uev_remove_path(devname, vecs);
goto out;
}
out:
- FREE(uev);
- pthread_cleanup_pop(1);
+ unlock(vecs->lock);
return r;
}
static void *
ueventloop (void * ap)
{
- uevent_listen(&uev_trigger, ap);
-
+ if (uevent_listen(&uev_trigger, ap))
+ fprintf(stderr, "error starting uevent listener");
+
return NULL;
}
@@ -930,6 +1057,10 @@
add_handler(SWITCH+MAP+GROUP, cli_switch_group);
add_handler(DUMP+PATHVEC, cli_dump_pathvec);
add_handler(RECONFIGURE, cli_reconfigure);
+ add_handler(SUSPEND+MAP, cli_suspend);
+ add_handler(RESUME+MAP, cli_resume);
+ add_handler(REINSTATE+PATH, cli_reinstate);
+ add_handler(FAIL+PATH, cli_fail);
uxsock_listen(&uxsock_trigger, ap);
@@ -962,6 +1093,7 @@
pp->dev_t, pp->mpp->alias);
dm_fail_path(pp->mpp->alias, pp->dev_t);
+ update_queue_mode_del_path(pp->mpp);
}
/*
@@ -970,11 +1102,14 @@
static void
reinstate_path (struct path * pp)
{
- if (pp->mpp) {
- if (dm_reinstate(pp->mpp->alias, pp->dev_t))
- condlog(0, "%s: reinstate failed", pp->dev_t);
- else
- condlog(2, "%s: reinstated", pp->dev_t);
+ if (!pp->mpp)
+ return;
+
+ if (dm_reinstate_path(pp->mpp->alias, pp->dev_t))
+ condlog(0, "%s: reinstate failed", pp->dev_t);
+ else {
+ condlog(2, "%s: reinstated", pp->dev_t);
+ update_queue_mode_add_path(pp->mpp);
}
}
@@ -1002,15 +1137,16 @@
}
static void
-mpvec_garbage_collector (struct paths * allpaths)
+mpvec_garbage_collector (struct vectors * vecs)
{
struct multipath * mpp;
int i;
- vector_foreach_slot (allpaths->mpvec, mpp, i) {
- if (!dm_map_present(mpp->alias)) {
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
+ if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
condlog(2, "%s: remove dead map", mpp->alias);
- remove_map(mpp, allpaths);
+ remove_map(mpp, vecs);
+ i--;
}
}
}
@@ -1034,10 +1170,27 @@
}
}
+static void
+retry_count_tick(vector mpvec)
+{
+ struct multipath *mpp;
+ int i;
+
+ vector_foreach_slot (mpvec, mpp, i) {
+ if (mpp->retry_tick) {
+ condlog(4, "%s: Retrying.. No active path", mpp->alias);
+ if(--mpp->retry_tick == 0) {
+ dm_queue_if_no_path(mpp->alias, 0);
+ condlog(2, "%s: Disable queueing", mpp->alias);
+ }
+ }
+ }
+}
+
static void *
checkerloop (void *ap)
{
- struct paths *allpaths;
+ struct vectors *vecs;
struct path *pp;
int i, count = 0;
int newstate;
@@ -1046,26 +1199,28 @@
mlockall(MCL_CURRENT | MCL_FUTURE);
memset(checker_msg, 0, MAX_CHECKER_MSG_SIZE);
- allpaths = (struct paths *)ap;
+ vecs = (struct vectors *)ap;
condlog(2, "path checkers start up");
+ /*
+ * init the path check interval
+ */
+ vector_foreach_slot (vecs->pathvec, pp, i) {
+ pp->checkint = conf->checkint;
+ }
+
while (1) {
- pthread_cleanup_push(cleanup_lock, allpaths->lock);
- lock(allpaths->lock);
+ pthread_cleanup_push(cleanup_lock, vecs->lock);
+ lock(vecs->lock);
condlog(4, "tick");
- vector_foreach_slot (allpaths->pathvec, pp, i) {
+ vector_foreach_slot (vecs->pathvec, pp, i) {
if (!pp->mpp)
continue;
- if (pp->tick) {
- /*
- * don't check this path yet
- */
- pp->tick--;
- continue;
- }
+ if (pp->tick && --pp->tick)
+ continue; /* don't check this path yet */
/*
* provision a next check soonest,
@@ -1119,14 +1274,14 @@
* need to switch group ?
*/
update_multipath_strings(pp->mpp,
- allpaths->pathvec);
+ vecs->pathvec);
/*
* schedule defered failback
*/
if (pp->mpp->pgfailback > 0)
pp->mpp->failback_tick =
- pp->mpp->pgfailback;
+ pp->mpp->pgfailback + 1;
else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
need_switch_pathgroup(pp->mpp, 1))
switch_pathgroup(pp->mpp);
@@ -1165,64 +1320,65 @@
if (need_switch_pathgroup(pp->mpp, 0)) {
if (pp->mpp->pgfailback > 0)
pp->mpp->failback_tick =
- pp->mpp->pgfailback;
+ pp->mpp->pgfailback + 1;
else if (pp->mpp->pgfailback ==
-FAILBACK_IMMEDIATE)
switch_pathgroup(pp->mpp);
}
}
- defered_failback_tick(allpaths->mpvec);
+ defered_failback_tick(vecs->mpvec);
+ retry_count_tick(vecs->mpvec);
if (count)
count--;
else {
condlog(4, "map garbage collection");
- mpvec_garbage_collector(allpaths);
+ mpvec_garbage_collector(vecs);
count = MAPGCINT;
}
- pthread_cleanup_pop(1);
+ lock_cleanup_pop(vecs->lock);
sleep(1);
}
return NULL;
}
-static struct paths *
+static struct vectors *
init_paths (void)
{
- struct paths * allpaths;
+ struct vectors * vecs;
- allpaths = (struct paths *)MALLOC(sizeof(struct paths));
+ vecs = (struct vectors *)MALLOC(sizeof(struct vectors));
- if (!allpaths)
+ if (!vecs)
return NULL;
- allpaths->lock =
+ vecs->lock =
(pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t));
- if (!allpaths->lock)
+ if (!vecs->lock)
goto out;
- allpaths->pathvec = vector_alloc();
+ vecs->pathvec = vector_alloc();
- if (!allpaths->pathvec)
+ if (!vecs->pathvec)
goto out1;
- allpaths->mpvec = vector_alloc();
+ vecs->mpvec = vector_alloc();
- if (!allpaths->mpvec)
+ if (!vecs->mpvec)
goto out2;
- pthread_mutex_init(allpaths->lock, NULL);
+ pthread_mutex_init(vecs->lock, NULL);
- return allpaths;
+ return vecs;
out2:
- vector_free(allpaths->pathvec);
+ vector_free(vecs->pathvec);
out1:
- FREE(allpaths->lock);
+ FREE(vecs->lock);
out:
- FREE(allpaths);
+ FREE(vecs);
condlog(0, "failed to init paths");
return NULL;
}
@@ -1305,7 +1461,7 @@
{
pthread_t check_thr, uevent_thr, uxlsnr_thr;
pthread_attr_t attr;
- struct paths * allpaths;
+ struct vectors * vecs;
mlockall(MCL_CURRENT | MCL_FUTURE);
@@ -1337,9 +1493,9 @@
signal_init();
setscheduler();
set_oom_adj(-17);
- allpaths = init_paths();
+ vecs = init_paths();
- if (!allpaths)
+ if (!vecs)
exit(1);
if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
@@ -1352,8 +1508,8 @@
* no paths and/or no multipaths are valid scenarii
* vectors maintenance will be driven by events
*/
- path_discovery(allpaths->pathvec, conf, DI_SYSFS | DI_WWID);
- get_dm_mpvec(allpaths);
+ path_discovery(vecs->pathvec, conf, DI_SYSFS | DI_WWID | DI_CHECKER);
+ map_discovery(vecs);
/*
* start threads
@@ -1362,32 +1518,37 @@
pthread_attr_setstacksize(&attr, 64 * 1024);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&check_thr, &attr, checkerloop, allpaths);
- pthread_create(&uevent_thr, &attr, ueventloop, allpaths);
- pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, allpaths);
+ pthread_create(&check_thr, &attr, checkerloop, vecs);
+ pthread_create(&uevent_thr, &attr, ueventloop, vecs);
+ pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, vecs);
pthread_cond_wait(&exit_cond, &exit_mutex);
/*
* exit path
*/
- lock(allpaths->lock);
- remove_maps(allpaths);
- free_pathvec(allpaths->pathvec, FREE_PATHS);
+ lock(vecs->lock);
+ remove_maps(vecs);
+ free_pathvec(vecs->pathvec, FREE_PATHS);
pthread_cancel(check_thr);
pthread_cancel(uevent_thr);
pthread_cancel(uxlsnr_thr);
free_keys(keys);
+ keys = NULL;
free_handlers(handlers);
+ handlers = NULL;
free_polls();
- unlock(allpaths->lock);
- pthread_mutex_destroy(allpaths->lock);
- FREE(allpaths->lock);
- FREE(allpaths);
+ unlock(vecs->lock);
+ pthread_mutex_destroy(vecs->lock);
+ FREE(vecs->lock);
+ vecs->lock = NULL;
+ FREE(vecs);
+ vecs = NULL;
free_config(conf);
+ conf = NULL;
condlog(2, "--------shut down-------");
@@ -1401,6 +1562,53 @@
exit(0);
}
+static int
+daemonize(void)
+{
+ int pid;
+ int in_fd, out_fd;
+
+ if( (pid = fork()) < 0){
+ fprintf(stderr, "Failed first fork : %s\n", strerror(errno));
+ return -1;
+ }
+ else if (pid != 0)
+ return pid;
+
+ setsid();
+
+ if ( (pid = fork()) < 0)
+ fprintf(stderr, "Failed second fork : %s\n", strerror(errno));
+ else if (pid != 0)
+ _exit(0);
+
+ in_fd = open("/dev/null", O_RDONLY);
+ if (in_fd < 0){
+ fprintf(stderr, "cannot open /dev/null for input : %s\n",
+ strerror(errno));
+ _exit(0);
+ }
+ out_fd = open("/dev/console", O_WRONLY);
+ if (out_fd < 0){
+ fprintf(stderr, "cannot open /dev/console for output : %s\n",
+ strerror(errno));
+ _exit(0);
+ }
+
+ close(STDIN_FILENO);
+ dup(in_fd);
+ close(STDOUT_FILENO);
+ dup(out_fd);
+ close(STDERR_FILENO);
+ dup(out_fd);
+
+ close(in_fd);
+ close(out_fd);
+ chdir("/");
+ umask(0);
+ return 0;
+}
+
int
main (int argc, char *argv[])
{
@@ -1449,7 +1657,7 @@
if (!logsink)
err = 0;
else
- err = fork();
+ err = daemonize();
if (err < 0)
/* error */
Modified: multipath-tools/trunk/multipathd/main.h
==============================================================================
--- multipath-tools/trunk/multipathd/main.h (original)
+++ multipath-tools/trunk/multipathd/main.h Wed Feb 1 23:59:42 2006
@@ -6,19 +6,19 @@
#define MAPGCINT 5
#define MAX_CHECKINT CHECKINT << 2
-struct paths {
+struct vectors {
pthread_mutex_t *lock;
vector pathvec;
vector mpvec;
};
-int reconfigure (struct paths *);
-int show_paths (char **, int *, struct paths *);
-int show_maps (char **, int *, struct paths *);
-int dump_pathvec (char **, int *, struct paths * allpaths);
-int uev_add_path (char *, struct paths *);
-int uev_remove_path (char *, struct paths *);
-int uev_add_map (char *, struct paths *);
-int uev_remove_map (char *, struct paths *);
+int reconfigure (struct vectors *);
+int show_paths (char **, int *, struct vectors *);
+int show_maps (char **, int *, struct vectors *);
+int dump_pathvec (char **, int *, struct vectors *);
+int uev_add_path (char *, struct vectors *);
+int uev_remove_path (char *, struct vectors *);
+int uev_add_map (char *, struct vectors *);
+int uev_remove_map (char *, struct vectors *);
#endif /* MAIN_H */
Modified: multipath-tools/trunk/multipathd/uxclnt.c
==============================================================================
--- multipath-tools/trunk/multipathd/uxclnt.c (original)
+++ multipath-tools/trunk/multipathd/uxclnt.c Wed Feb 1 23:59:42 2006
@@ -25,11 +25,17 @@
while ((line = readline("multipathd> "))) {
size_t len;
+ size_t llen = strlen(line);
- if (send_packet(fd, line, strlen(line) + 1) != 0) break;
+ if (!llen) {
+ free(line);
+ continue;
+ }
+
+ if (send_packet(fd, line, llen + 1) != 0) break;
if (recv_packet(fd, &reply, &len) != 0) break;
- printf("%s\n", reply);
+ printf("%s", reply);
if (line && *line)
add_history(line);
@@ -47,7 +53,7 @@
send_packet(fd, inbuf, strlen(inbuf) + 1);
recv_packet(fd, &reply, &len);
- printf("%s\n", reply);
+ printf("%s", reply);
FREE(reply);
}
Modified: multipath-tools/trunk/path_priority/pp_alua/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_alua/Makefile Wed Feb 1 23:59:42 2006
@@ -22,9 +22,6 @@
ifneq ($(shell ls $(TOPDIR)/Makefile.inc 2>/dev/null),)
include $(TOPDIR)/Makefile.inc
-else
-# "out of tree building"
-STRIP = strip --strip-all -R .comment -R .note
endif
CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -DDEBUG=$(DEBUG)
@@ -33,11 +30,9 @@
glibc: $(OBJS)
$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
- $(STRIP) $(EXEC)
klibc: $(OBJS)
$(CC) -static -o $(EXEC) $(OBJS)
- $(STRIP) $(EXEC)
install: $(BUILD) $(EXEC).8.gz
install -d $(DESTDIR)$(bindir)
Modified: multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8 (original)
+++ multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8 Wed Feb 1 23:59:42 2006
@@ -137,7 +137,7 @@
.B Notes:
.IP \(bu 2
Depending on your default configuration not all keywords are required
-.RB "(e.g. if your " default_path_checker " is set to tur you don't have to"
+.RB "(e.g. if your " path_checker " is set to tur you don't have to"
.RB "use the " path_checker " statement in the device section)."
.IP \(bu
.RB "The entries for " vendor " and " product " must be strings that are 8"
Modified: multipath-tools/trunk/path_priority/pp_balance_units/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_balance_units/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_balance_units/Makefile Wed Feb 1 23:59:42 2006
@@ -27,18 +27,16 @@
glibc: prepare $(OBJS)
$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
- $(STRIP) $(EXEC)
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
- $(STRIP) $(EXEC)
$(MULTIPATHLIB)-$(BUILD).a:
make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
install:
install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
uninstall:
rm $(DESTDIR)$(bindir)/$(EXEC)
Modified: multipath-tools/trunk/path_priority/pp_emc/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_emc/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_emc/Makefile Wed Feb 1 23:59:42 2006
@@ -11,14 +11,12 @@
glibc: $(OBJS)
$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
- $(STRIP) $(EXEC)
klibc: $(OBJS)
$(CC) -static -o $(EXEC) $(OBJS)
- $(STRIP) $(EXEC)
install: $(EXEC)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
uninstall:
rm $(DESTDIR)$(bindir)/$(EXEC)
Added: multipath-tools/trunk/path_priority/pp_random/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_random/Makefile Wed Feb 1 23:59:42 2006
@@ -0,0 +1,27 @@
+EXEC = mpath_prio_random
+BUILD = glibc
+OBJS = pp_random.o
+
+TOPDIR = ../..
+include $(TOPDIR)/Makefile.inc
+
+CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
+
+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)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
Added: multipath-tools/trunk/path_priority/pp_random/pp_random.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_random/pp_random.c Wed Feb 1 23:59:42 2006
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+
+int main(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ srand((unsigned int)tv.tv_usec);
+ printf("%i\n", 1+(int) (10.0*rand()/(RAND_MAX+1.0)));
+ return 0;
+}
More information about the pkg-lvm-commits
mailing list