r157 - in multipath-tools/trunk: . getuid kpartx libcheckers
libmultipath multipath multipathd path_priority
path_priority/pp_alua path_priority/pp_balance_units
path_priority/pp_emc
Bastian Blank
waldi at costa.debian.org
Mon Sep 19 12:44:37 UTC 2005
Author: waldi
Date: Mon Sep 19 12:43:52 2005
New Revision: 157
Added:
multipath-tools/trunk/getuid/
multipath-tools/trunk/getuid/usb_id (contents, props changed)
multipath-tools/trunk/libcheckers/directio.c
multipath-tools/trunk/libcheckers/hp_sw.c
multipath-tools/trunk/libmultipath/print.c
multipath-tools/trunk/libmultipath/print.h
multipath-tools/trunk/libmultipath/switchgroup.c
multipath-tools/trunk/libmultipath/switchgroup.h
multipath-tools/trunk/libmultipath/uevent.c
multipath-tools/trunk/libmultipath/uevent.h
multipath-tools/trunk/libmultipath/uxsock.c
multipath-tools/trunk/libmultipath/uxsock.h
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/uxclnt.c
multipath-tools/trunk/multipathd/uxclnt.h
multipath-tools/trunk/multipathd/uxlsnr.c
multipath-tools/trunk/multipathd/uxlsnr.h
multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8
multipath-tools/trunk/path_priority/pp_balance_units/
multipath-tools/trunk/path_priority/pp_balance_units/Makefile
multipath-tools/trunk/path_priority/pp_balance_units/pp_balance_units.c
Removed:
multipath-tools/trunk/.indent.pro
multipath-tools/trunk/kpartx/kpartx.dev
multipath-tools/trunk/multipathd/clone_platform.h
multipath-tools/trunk/multipathd/copy.c
multipath-tools/trunk/multipathd/copy.h
multipath-tools/trunk/path_priority/Makefile
multipath-tools/trunk/path_priority/pp_balance_units.c
Modified:
multipath-tools/trunk/ (props changed)
multipath-tools/trunk/ChangeLog
multipath-tools/trunk/Makefile
multipath-tools/trunk/kpartx/dos.c
multipath-tools/trunk/kpartx/kpartx.c
multipath-tools/trunk/kpartx/lopart.c
multipath-tools/trunk/libcheckers/Makefile
multipath-tools/trunk/libcheckers/checkers.h
multipath-tools/trunk/libcheckers/path_state.h
multipath-tools/trunk/libcheckers/readsector0.c
multipath-tools/trunk/libcheckers/selector.c
multipath-tools/trunk/libmultipath/Makefile
multipath-tools/trunk/libmultipath/blacklist.c
multipath-tools/trunk/libmultipath/blacklist.h
multipath-tools/trunk/libmultipath/cache.c
multipath-tools/trunk/libmultipath/cache.h
multipath-tools/trunk/libmultipath/callout.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/memory.c
multipath-tools/trunk/libmultipath/memory.h
multipath-tools/trunk/libmultipath/pgpolicies.c
multipath-tools/trunk/libmultipath/pgpolicies.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/util.c
multipath-tools/trunk/libmultipath/util.h
multipath-tools/trunk/libmultipath/vector.c
multipath-tools/trunk/libmultipath/vector.h
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.8
multipath-tools/trunk/multipathd/Makefile
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
multipath-tools/trunk/multipathd/main.c
multipath-tools/trunk/multipathd/main.h
multipath-tools/trunk/multipathd/multipathd.init.redhat
multipath-tools/trunk/path_priority/pp_alua/Makefile
multipath-tools/trunk/path_priority/pp_alua/main.c
multipath-tools/trunk/path_priority/pp_alua/rtpg.c
multipath-tools/trunk/path_priority/pp_alua/spc3.h
multipath-tools/trunk/path_priority/pp_emc/Makefile
Log:
Merge /multipath-tools/upstream/current (0.4.5).
Modified: multipath-tools/trunk/ChangeLog
==============================================================================
--- multipath-tools/trunk/ChangeLog (original)
+++ multipath-tools/trunk/ChangeLog Mon Sep 19 12:43:52 2005
@@ -1,4 +1,27 @@
-2005-03-19 multipath-tools-0.4.4
+2005-05-23 multipath-tools-0.4.5
+
+ * [libmultipath] default_prio and prio_callout keyword can be
+ explicitly set to "none". Suggested by Kiyoshi Ueda, NEC
+ * [path_prio] don't exit pp_balance_units with error when
+ find_controler() is not successful. It just means no other
+ path is currently active on this controler.
+ * [path_prio] move balance_units in its own dir
+ * [multipathd] proactively fail_path upon checker up->down
+ transitions. Suggested by Edward Goggin, EMC
+ * [libmultipath] .priority is clearly an int, not an unsigned
+ int. /bin/false is now personna non grata as a prio callout.
+ Kiyoshi Ueda, NEC
+ * [libmultipath] callout.c argv parsing fix. Kiyoshi Ueda,
+ NEC
+ * [multipathd] check return codes in init_paths(), split out
+ init_event().
+ * [libmultipath] add find_slot(vec, addr) to vector lib.
+ * [multipath] remove signal sending
+ * [multipathd] use uevent to do paths list housekeeping for
+ checkers. Remove signal handling.
+ * [libmultipath] add uevent.[ch]
+
+2005-04-23 multipath-tools-0.4.4
* [path_prio] clarify pp_alua licensing. Stefan Bader, IBM.
* [devmap_name] add a target_type filter (suggested by Hannes)
Modified: multipath-tools/trunk/Makefile
==============================================================================
--- multipath-tools/trunk/Makefile (original)
+++ multipath-tools/trunk/Makefile Mon Sep 19 12:43:52 2005
@@ -20,12 +20,9 @@
export KRNLSRC
export KRNLOBJ
-BUILDDIRS = libmultipath libcheckers path_priority \
- devmap_name multipath multipathd kpartx
-ALLDIRS = $(shell find . -type d -maxdepth 1 -mindepth 1)
+BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \;)
VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
-INSTALLDIRS = devmap_name multipath multipathd kpartx path_priority
all: recurse
@@ -36,17 +33,17 @@
done
recurse_clean:
- @for dir in $(ALLDIRS); do\
+ @for dir in $(BUILDDIRS); do\
$(MAKE) -C $$dir clean || exit $?; \
done
recurse_install:
- @for dir in $(INSTALLDIRS); do\
+ @for dir in $(BUILDDIRS); do\
$(MAKE) -C $$dir install || exit $?; \
done
recurse_uninstall:
- @for dir in $(INSTALLDIRS); do\
+ @for dir in $(BUILDDIRS); do\
$(MAKE) -C $$dir uninstall || exit $?; \
done
Added: multipath-tools/trunk/getuid/usb_id
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/getuid/usb_id Mon Sep 19 12:43:52 2005
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# copy in /bin and add this line to a device block in multipath.conf :
+# getuid_callout "/bin/usb_id %n"
+#
+cd /sys/block/$1 && cd $(ls -l device|cut -d">" -f2) && cd ../../../.. && cat serial
Modified: multipath-tools/trunk/kpartx/dos.c
==============================================================================
--- multipath-tools/trunk/kpartx/dos.c (original)
+++ multipath-tools/trunk/kpartx/dos.c Mon Sep 19 12:43:52 2005
@@ -26,7 +26,7 @@
if (++loopct > 100)
return n;
- bp = getblock(fd, here);
+ bp = (unsigned char *)getblock(fd, here);
if (bp == NULL)
return n;
@@ -74,7 +74,7 @@
int i, n=0;
unsigned char *bp;
- bp = getblock(fd, offset);
+ bp = (unsigned char *)getblock(fd, offset);
if (bp == NULL)
return -1;
Modified: multipath-tools/trunk/kpartx/kpartx.c
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.c (original)
+++ multipath-tools/trunk/kpartx/kpartx.c Mon Sep 19 12:43:52 2005
@@ -429,6 +429,9 @@
if (n > 0)
break;
}
+ dm_lib_release();
+ dm_lib_exit();
+
return 0;
}
Modified: multipath-tools/trunk/kpartx/lopart.c
==============================================================================
--- multipath-tools/trunk/kpartx/lopart.c (original)
+++ multipath-tools/trunk/kpartx/lopart.c Mon Sep 19 12:43:52 2005
@@ -26,6 +26,18 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include <sysmacros.h>
+
+#if defined(__hppa__) || defined(__powerpc64__) || defined (__alpha__) \
+ || defined (__x86_64__)
+typedef unsigned long __kernel_old_dev_t;
+#elif defined(__powerpc__) || defined(__ia64__)
+typedef unsigned int __kernel_old_dev_t;
+#else
+typedef unsigned short __kernel_old_dev_t;
+#endif
+
+#define dev_t __kernel_old_dev_t
+
#include <linux/loop.h>
#include "lopart.h"
Modified: multipath-tools/trunk/libcheckers/Makefile
==============================================================================
--- multipath-tools/trunk/libcheckers/Makefile (original)
+++ multipath-tools/trunk/libcheckers/Makefile Mon Sep 19 12:43:52 2005
@@ -6,12 +6,12 @@
include ../Makefile.inc
-OBJS = readsector0.o tur.o selector.o emc_clariion.o
+OBJS = readsector0.o tur.o selector.o directio.o emc_clariion.o hp_sw.o
all: $(BUILD)
prepare:
- rm -f core *.o *.gz
+ @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
klibc: prepare $(OBJS)
ar rs libcheckers-klibc.a *.o
Modified: multipath-tools/trunk/libcheckers/checkers.h
==============================================================================
--- multipath-tools/trunk/libcheckers/checkers.h (original)
+++ multipath-tools/trunk/libcheckers/checkers.h Mon Sep 19 12:43:52 2005
@@ -6,21 +6,25 @@
#define MAX_CHECKER_MSG_SIZE 256
enum checkers {
- CHECKER_RESERVED,
+ CHECKER_UNDEF,
TUR,
READSECTOR0,
- EMC_CLARIION
+ DIRECTIO,
+ EMC_CLARIION,
+ HP_SW
};
#define MSG(a) if (msg != NULL) \
- snprintf(msg, MAX_CHECKER_MSG_SIZE, "%s\n", a);
+ snprintf(msg, MAX_CHECKER_MSG_SIZE, "%s", a);
int get_checker_id (char *);
void *get_checker_addr (int);
int get_checker_name (char *, int);
int emc_clariion (int fd, char * msg, void ** ctxt);
+int directio (int fd, char * msg, void ** ctxt);
int readsector0 (int fd, char * msg, void ** ctxt);
int tur (int fd, char * msg, void ** ctxt);
+int hp_sw (int fd, char * msg, void ** ctxt);
#endif /* _CHECKERS_H */
Added: multipath-tools/trunk/libcheckers/directio.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/directio.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,165 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+
+#include "path_state.h"
+#include "checkers.h"
+
+#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
+#define MSG_DIRECTIO_UP "directio checker reports path is up"
+#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
+
+struct readsector0_checker_context {
+ void * dummy;
+};
+
+static int
+direct_read (int fd, unsigned char * buff, int size)
+{
+ long flags;
+ int reset_flags = 0;
+ int res, retval;
+
+ flags = fcntl(fd,F_GETFL);
+
+ if (flags < 0) {
+ return PATH_UNCHECKED;
+ }
+
+ if (!(flags & O_DIRECT)) {
+ flags |= O_DIRECT;
+ if (fcntl(fd,F_SETFL,flags) < 0) {
+ return PATH_UNCHECKED;
+ }
+ reset_flags = 1;
+ }
+
+ while ( (res = read(fd,buff,size)) < 0 && errno == EINTR );
+ if (res < 0) {
+ if (errno == EINVAL) {
+ /* O_DIRECT is not available */
+ retval = PATH_UNCHECKED;
+ } else if (errno == ENOMEM) {
+ retval = PATH_UP;
+ } else {
+ retval = PATH_DOWN;
+ }
+ } else {
+ retval = PATH_UP;
+ }
+
+ if (reset_flags) {
+ flags &= ~O_DIRECT;
+ /* No point in checking for errors */
+ fcntl(fd,F_SETFL,flags);
+ }
+
+ return retval;
+}
+
+extern int
+directio (int fd, char *msg, void **context)
+{
+ unsigned char *buf, *ptr;
+ struct readsector0_checker_context * ctxt = NULL;
+ unsigned long pgsize, numsect;
+ int ret, blksize;
+
+ pgsize = getpagesize();
+
+ /*
+ * caller passed in a context : use its address
+ */
+ if (context)
+ ctxt = (struct readsector0_checker_context *) (*context);
+
+ /*
+ * passed in context is uninitialized or volatile context :
+ * initialize it
+ */
+ if (!ctxt) {
+ ctxt = malloc(sizeof(struct readsector0_checker_context));
+ memset(ctxt, 0, sizeof(struct readsector0_checker_context));
+
+ if (!ctxt) {
+ MSG("cannot allocate context");
+ return -1;
+ }
+ if (context)
+ *context = ctxt;
+ }
+ if (fd <= 0) {
+ MSG("no usable fd");
+ ret = -1;
+ goto out;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &numsect) < 0) {
+ MSG("cannot get number of sectors, set default");
+ numsect = 0;
+ }
+
+ if (ioctl(fd, BLKBSZGET, &blksize) < 0) {
+ MSG("cannot get blocksize, set default");
+ blksize = 512;
+ }
+
+ if (blksize > 4096) {
+ /*
+ * Sanity check for DASD; BSZGET is broken
+ */
+ blksize = 4096;
+ }
+
+ if (!blksize) {
+ /*
+ * Blocksize is 0, assume we can't write
+ * to this device.
+ */
+ MSG(MSG_DIRECTIO_DOWN);
+ ret = PATH_DOWN;
+ goto out;
+ }
+
+ buf = (unsigned char *)malloc(blksize + pgsize);
+ if (!buf){
+ goto out;
+ }
+ ptr = (unsigned char *)(((unsigned long)buf + pgsize - 1) &
+ (~(pgsize - 1)));
+ ret = direct_read(fd, ptr, blksize);
+
+ switch (ret)
+ {
+ case PATH_UNCHECKED:
+ MSG(MSG_DIRECTIO_UNKNOWN);
+ break;
+ case PATH_DOWN:
+ MSG(MSG_DIRECTIO_DOWN);
+ break;
+ case PATH_UP:
+ MSG(MSG_DIRECTIO_UP);
+ break;
+ default:
+ break;
+ }
+ free(buf);
+
+out:
+ /*
+ * caller told us he doesn't want to keep the context :
+ * free it
+ */
+ if (!context)
+ free(ctxt);
+
+ return ret;
+}
Added: multipath-tools/trunk/libcheckers/hp_sw.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/hp_sw.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "path_state.h"
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define TUR_CMD_LEN 6
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_CMD 0x12
+#define SENSE_BUFF_LEN 32
+#define DEF_TIMEOUT 60000
+#define SCSI_CHECK_CONDITION 0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE 0x08
+#define RECOVERED_ERROR 0x01
+#define MX_ALLOC_LEN 255
+#define HEAVY_CHECK_COUNT 10
+
+#define MSG_HP_SW_UP "hp_sw checker reports path is up"
+#define MSG_HP_SW_DOWN "hp_sw checker reports path is down"
+#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
+
+struct sw_checker_context {
+ int run_count;
+};
+
+static int
+do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
+ void *resp, int mx_resp_len, int noisy)
+{
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
+ { INQUIRY_CMD, 0, 0, 0, 0, 0 };
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (cmddt)
+ inqCmdBlk[1] |= 2;
+ if (evpd)
+ inqCmdBlk[1] |= 1;
+ inqCmdBlk[2] = (unsigned char) pg_op;
+ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+ return 1;
+
+ /* treat SG_ERR here to get rid of sg_err.[ch] */
+ io_hdr.status &= 0x7e;
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status))
+ return 0;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2)
+ sense_key = sense_buffer[1] & 0xf;
+ else
+ sense_key = sense_buffer[2] & 0xf;
+ if(RECOVERED_ERROR == sense_key)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+do_tur (int fd)
+{
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+ struct sg_io_hdr io_hdr;
+ unsigned char sense_buffer[32];
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (turCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = 20000;
+ io_hdr.pack_id = 0;
+
+ if (ioctl(fd, SG_IO, &io_hdr) < 0)
+ return 1;
+
+ if (io_hdr.info & SG_INFO_OK_MASK)
+ return 1;
+
+ return 0;
+}
+
+extern int
+hp_sw (int fd, char *msg, void **context)
+{
+ char buff[MX_ALLOC_LEN];
+ struct sw_checker_context * ctxt = NULL;
+ int ret;
+
+ /*
+ * caller passed in a context : use its address
+ */
+ if (context)
+ ctxt = (struct sw_checker_context *) (*context);
+
+ /*
+ * passed in context is uninitialized or volatile context :
+ * initialize it
+ */
+ if (!ctxt) {
+ ctxt = malloc(sizeof(struct sw_checker_context));
+ memset(ctxt, 0, sizeof(struct sw_checker_context));
+
+ if (!ctxt) {
+ MSG("cannot allocate context");
+ return -1;
+ }
+ if (context)
+ *context = ctxt;
+ }
+ ctxt->run_count++;
+
+ if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
+ ctxt->run_count = 0;
+ /* do stuff */
+ }
+ if (fd <= 0) {
+ MSG("no usable fd");
+ ret = -1;
+ goto out;
+ }
+
+ if (0 != do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ MSG(MSG_HP_SW_DOWN);
+ ret = PATH_DOWN;
+ goto out;
+ }
+
+ if (do_tur(fd)) {
+ MSG(MSG_HP_SW_GHOST);
+ ret = PATH_GHOST;
+ } else {
+ MSG(MSG_HP_SW_UP);
+ ret = PATH_UP;
+ }
+
+out:
+ /*
+ * caller told us he doesn't want to keep the context :
+ * free it
+ */
+ if (!context)
+ free(ctxt);
+
+ return(ret);
+}
Modified: multipath-tools/trunk/libcheckers/path_state.h
==============================================================================
--- multipath-tools/trunk/libcheckers/path_state.h (original)
+++ multipath-tools/trunk/libcheckers/path_state.h Mon Sep 19 12:43:52 2005
@@ -2,3 +2,4 @@
#define PATH_DOWN 1
#define PATH_UP 2
#define PATH_SHAKY 3
+#define PATH_GHOST 4
Modified: multipath-tools/trunk/libcheckers/readsector0.c
==============================================================================
--- multipath-tools/trunk/libcheckers/readsector0.c (original)
+++ multipath-tools/trunk/libcheckers/readsector0.c Mon Sep 19 12:43:52 2005
@@ -85,7 +85,7 @@
extern int
readsector0 (int fd, char *msg, void **context)
{
- char buf[512];
+ unsigned char buf[512];
struct readsector0_checker_context * ctxt = NULL;
int ret;
Modified: multipath-tools/trunk/libcheckers/selector.c
==============================================================================
--- multipath-tools/trunk/libcheckers/selector.c (original)
+++ multipath-tools/trunk/libcheckers/selector.c Mon Sep 19 12:43:52 2005
@@ -10,8 +10,12 @@
return TUR;
if (0 == strncmp(str, "readsector0", 11))
return READSECTOR0;
+ if (0 == strncmp(str, "directio", 8))
+ return DIRECTIO;
if (0 == strncmp(str, "emc_clariion", 12))
return EMC_CLARIION;
+ if (0 == strncmp(str, "hp_sw", 5))
+ return HP_SW;
return -1;
}
@@ -27,9 +31,15 @@
case READSECTOR0:
checker = &readsector0;
break;
+ case DIRECTIO:
+ checker = &directio;
+ break;
case EMC_CLARIION:
checker = &emc_clariion;
break;
+ case HP_SW:
+ checker = &hp_sw;
+ break;
default:
checker = NULL;
break;
@@ -49,9 +59,15 @@
case READSECTOR0:
s = "readsector0";
break;
+ case DIRECTIO:
+ s = "directio";
+ break;
case EMC_CLARIION:
s = "emc_clariion";
break;
+ case HP_SW:
+ s = "hp_sw";
+ break;
default:
s = "undefined";
break;
Modified: multipath-tools/trunk/libmultipath/Makefile
==============================================================================
--- multipath-tools/trunk/libmultipath/Makefile (original)
+++ multipath-tools/trunk/libmultipath/Makefile Mon Sep 19 12:43:52 2005
@@ -9,7 +9,8 @@
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
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
+ pgpolicies.o debug.o regex.o defaults.o uevent.o \
+ switchgroup.o uxsock.o print.o
CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
@@ -20,12 +21,14 @@
all: $(BUILD)
prepare:
- rm -f core *.o *.gz
+ @rm -f debug.o
+ @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
+ @rm -f *-$(BUILD).a
-klibc: prepare $(OBJS)
+klibc: $(OBJS)
ar rs libmultipath-klibc.a *.o
-glibc: prepare $(OBJS)
+glibc: $(OBJS)
ar rs libmultipath-glibc.a *.o
install:
Modified: multipath-tools/trunk/libmultipath/blacklist.c
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.c (original)
+++ multipath-tools/trunk/libmultipath/blacklist.c Mon Sep 19 12:43:52 2005
@@ -10,40 +10,24 @@
static int
store_ble (vector blist, char * str)
{
- struct blentry * ble;
+ regex_t * ble;
if (!str)
return 0;
- ble = (struct blentry *)MALLOC(sizeof(struct blentry));
+ ble = MALLOC(sizeof(regex_t));
if (!ble)
goto out;
- ble->preg = MALLOC(sizeof(regex_t));
-
- if (!ble->preg)
+ if (regcomp(ble, str, REG_EXTENDED|REG_NOSUB))
goto out1;
- ble->str = (char *)MALLOC(strlen(str) + 1);
-
- if (!ble->str)
- goto out2;
-
- strcpy(ble->str, str);
-
- if (regcomp((regex_t *)ble->preg, ble->str, REG_EXTENDED|REG_NOSUB))
- goto out3;
-
if (!vector_alloc_slot(blist))
- goto out3;
+ goto out1;
vector_set_slot(blist, ble);
return 0;
-out3:
- FREE(ble->str);
-out2:
- FREE(ble->preg);
out1:
FREE(ble);
out:
@@ -55,9 +39,9 @@
{
int r = 0;
- r += store_ble(blist, "(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
- r += store_ble(blist, "hd[a-z]");
- r += store_ble(blist, "cciss!c[0-9]d[0-9]*");
+ r += store_ble(blist, "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
+ r += store_ble(blist, "^hd[a-z]");
+ r += store_ble(blist, "^cciss!c[0-9]d[0-9]*");
return r;
}
@@ -66,10 +50,10 @@
blacklist (vector blist, char * dev)
{
int i;
- struct blentry *ble;
+ regex_t * ble;
vector_foreach_slot (blist, ble, i) {
- if (!regexec(ble->preg, dev, 0, NULL, 0)) {
+ if (!regexec(ble, dev, 0, NULL, 0)) {
condlog(3, "%s blacklisted", dev);
return 1;
}
@@ -92,20 +76,15 @@
void
free_blacklist (vector blist)
{
- struct blentry * ble;
+ regex_t * ble;
int i;
if (!blist)
return;
- vector_foreach_slot (blist, ble, i) {
- if (ble->str)
- FREE(ble->str);
-
- if (ble->preg)
- FREE(ble->preg);
+ vector_foreach_slot (blist, ble, i)
+ if (ble)
+ FREE(ble);
- FREE(ble);
- }
vector_free(blist);
}
Modified: multipath-tools/trunk/libmultipath/blacklist.h
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.h (original)
+++ multipath-tools/trunk/libmultipath/blacklist.h Mon Sep 19 12:43:52 2005
@@ -3,11 +3,6 @@
#define BLIST_ENTRY_SIZE 255
-struct blentry {
- char * str;
- void * preg;
-};
-
int setup_default_blist (vector blist);
int blacklist (vector blist, char * dev);
int store_regex (vector blist, char * regex);
Modified: multipath-tools/trunk/libmultipath/cache.c
==============================================================================
--- multipath-tools/trunk/libmultipath/cache.c (original)
+++ multipath-tools/trunk/libmultipath/cache.c Mon Sep 19 12:43:52 2005
@@ -1,62 +1,45 @@
-#include <stdio.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <time.h>
+#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "debug.h"
#include "cache.h"
+#include "uxsock.h"
+#include "defaults.h"
static void
revoke_cache_info(struct path * pp)
{
+ pp->checker_context = NULL;
pp->fd = 0;
-}
-
-static int
-lock_fd (int fd, int flag)
-{
- struct flock fl;
-
- fl.l_type = flag;
- fl.l_whence = 0;
- fl.l_start = 0;
- fl.l_len = 0;
-
- alarm(MAX_WAIT);
-
- if (fcntl(fd, F_SETLKW, &fl) == -1) {
- condlog(0, "can't take a write lease on cache file\n");
- return 1;
- }
- alarm(0);
- return 0;
+ pp->mpp = NULL;
+ pp->getuid = NULL;
+ pp->getprio = NULL;
+ pp->checkfn = NULL;
}
int
cache_load (vector pathvec)
{
+ char *reply;
+ size_t len;
int fd;
- int r = 1;
- off_t record_len;
- struct path record;
struct path * pp;
+ int r = 1;
+ char * p;
- fd = open(CACHE_FILE, O_RDONLY);
+ fd = ux_socket_connect(DEFAULT_SOCKET);
- if (fd < 0)
+ if (fd == -1) {
+ condlog(3, "ux_socket_connect error");
return 1;
+ }
- if (lock_fd(fd, F_RDLCK))
- goto out;
-
- record_len = sizeof(struct path);
+ send_packet(fd, "dump pathvec", 13);
+ recv_packet(fd, &reply, &len);
- while (read(fd, &record, record_len)) {
+ for (p = reply; p < (reply + len); p += sizeof(struct path)) {
pp = alloc_path();
if (!pp)
@@ -67,63 +50,13 @@
goto out;
}
vector_set_slot(pathvec, pp);
- memcpy(pp, &record, record_len);
+ memcpy(pp, (void *)p, sizeof(struct path));
revoke_cache_info(pp);
}
- r = 0;
- lock_fd(fd, F_UNLCK);
-out:
- close(fd);
- return r;
-}
-int
-cache_dump (vector pathvec)
-{
- int i;
- int fd;
- int r = 1;
- off_t record_len;
- struct path * pp;
-
- fd = open(CACHE_TMPFILE, O_RDWR|O_CREAT, 0600);
-
- if (fd < 0)
- return 1;
-
- if (lock_fd(fd, F_WRLCK))
- goto out;
-
- ftruncate(fd, 0);
- record_len = sizeof(struct path);
-
- vector_foreach_slot (pathvec, pp, i) {
- if (write(fd, pp, record_len) < record_len)
- goto out1;
- }
- rename(CACHE_TMPFILE, CACHE_FILE);
r = 0;
-out1:
- lock_fd(fd, F_UNLCK);
out:
+ FREE(reply);
close(fd);
return r;
}
-
-int
-cache_cold (int expire)
-{
- time_t t;
- struct stat s;
-
- if (time(&t) < 0)
- return 1;
-
- if(stat(CACHE_FILE, &s))
- return 1;
-
- if ((t - s.st_mtime) < expire)
- return 0;
-
- return 1;
-}
Modified: multipath-tools/trunk/libmultipath/cache.h
==============================================================================
--- multipath-tools/trunk/libmultipath/cache.h (original)
+++ multipath-tools/trunk/libmultipath/cache.h Mon Sep 19 12:43:52 2005
@@ -1,8 +1 @@
-#define CACHE_FILE "/var/cache/multipath/.multipath.cache"
-#define CACHE_TMPFILE "/var/cache/multipath/.multipath.cache.tmp"
-#define CACHE_EXPIRE 5
-#define MAX_WAIT 5
-
int cache_load (vector pathvec);
-int cache_dump (vector pathvec);
-int cache_cold (int expire);
Modified: multipath-tools/trunk/libmultipath/callout.c
==============================================================================
--- multipath-tools/trunk/libmultipath/callout.c (original)
+++ multipath-tools/trunk/libmultipath/callout.c Mon Sep 19 12:43:52 2005
@@ -29,6 +29,7 @@
int i;
i = 0;
+
if (strchr(path, ' ')) {
strfieldcpy(arg, path);
pos = arg;
@@ -39,11 +40,13 @@
argv[i] = strsep(&pos, "\'");
while (pos[0] == ' ')
pos++;
- } else {
+ } else {
argv[i] = strsep(&pos, " ");
}
i++;
}
+ } else {
+ argv[i++] = path;
}
argv[i] = NULL;
Modified: multipath-tools/trunk/libmultipath/config.c
==============================================================================
--- multipath-tools/trunk/libmultipath/config.c (original)
+++ multipath-tools/trunk/libmultipath/config.c Mon Sep 19 12:43:52 2005
@@ -14,56 +14,6 @@
#include "../libcheckers/checkers.h"
-/*
- * helper function to draw a list of callout binaries found in the config file
- */
-extern int
-push_callout(char * callout)
-{
- int i;
- char * bin;
- char * p;
-
- /*
- * purge command line arguments
- */
- p = callout;
-
- while (*p != ' ' && *p != '\0')
- p++;
-
- if (!conf->binvec)
- conf->binvec = vector_alloc();
-
-
- if (!conf->binvec)
- return 1;
-
- /*
- * if this callout is already stored in binvec, don't store it twice
- */
- vector_foreach_slot (conf->binvec, bin, i)
- if (memcmp(bin, callout, p - callout) == 0)
- return 0;
-
- /*
- * else, store it
- */
- bin = MALLOC((p - callout) + 1);
-
- if (!bin)
- return 1;
-
- strncpy(bin, callout, p - callout);
-
- if (!vector_alloc_slot(conf->binvec))
- return 1;
-
- vector_set_slot(conf->binvec, bin);
-
- return 0;
-}
-
struct hwentry *
find_hwe (vector hwtable, char * vendor, char * product)
{
@@ -89,7 +39,7 @@
return NULL;
vector_foreach_slot (conf->mptable, mpe, i)
- if (mpe->wwid && strcmp(mpe->wwid, wwid) == 0)
+ if (mpe->wwid && !strcmp(mpe->wwid, wwid))
return mpe;
return NULL;
@@ -192,10 +142,22 @@
vector_free(mptable);
}
+struct mpentry *
+alloc_mpe (void)
+{
+ struct mpentry * mpe = (struct mpentry *)
+ MALLOC(sizeof(struct mpentry));
+
+ return mpe;
+}
+
static struct hwentry *
alloc_hwe (void)
{
- return (struct hwentry *)MALLOC(sizeof(struct hwentry));
+ struct hwentry * hwe = (struct hwentry *)
+ MALLOC(sizeof(struct hwentry));
+
+ return hwe;
}
static char *
@@ -245,13 +207,10 @@
if (pgp)
hwe->pgpolicy = pgp;
- if (getuid) {
+ if (getuid)
hwe->getuid = set_param_str(getuid);
- push_callout(getuid);
- } else {
+ else
hwe->getuid = set_default(DEFAULT_GETUID);
- push_callout(DEFAULT_GETUID);
- }
if (!hwe->getuid)
goto out;
@@ -291,21 +250,17 @@
if (pgp)
hwe->pgpolicy = pgp;
- if (getuid) {
+ if (getuid)
hwe->getuid = set_param_str(getuid);
- push_callout(getuid);
- } else {
+ else
hwe->getuid = set_default(DEFAULT_GETUID);
- push_callout(DEFAULT_GETUID);
- }
if (!hwe->getuid)
goto out;
- if (getprio) {
+ if (getprio)
hwe->getprio = set_param_str(getprio);
- push_callout(getprio);
- } else
+ else
hwe->getprio = NULL;
if (hwhandler)
@@ -378,7 +333,6 @@
free_blacklist(conf->blist);
free_mptable(conf->mptable);
free_hwtable(conf->hwtable);
- free_strvec(conf->binvec);
FREE(conf);
}
@@ -386,7 +340,8 @@
int
load_config (char * file)
{
- conf = alloc_config();
+ if (!conf)
+ conf = alloc_config();
if (!conf)
return 1;
@@ -394,8 +349,9 @@
/*
* internal defaults
*/
- conf->verbosity = 2;
- conf->signal = 1; /* 1 == Send a signal to multipathd */
+ if (!conf->verbosity)
+ conf->verbosity = 2;
+
conf->dev_type = DEV_NONE;
conf->minio = 1000;
Modified: multipath-tools/trunk/libmultipath/config.h
==============================================================================
--- multipath-tools/trunk/libmultipath/config.h (original)
+++ multipath-tools/trunk/libmultipath/config.h Mon Sep 19 12:43:52 2005
@@ -16,6 +16,8 @@
int selector_args;
int pgpolicy;
int checker_index;
+ int pgfailback;
+ int rr_weight;
char * vendor;
char * product;
@@ -29,6 +31,8 @@
struct mpentry {
int selector_args;
int pgpolicy;
+ int pgfailback;
+ int rr_weight;
char * wwid;
char * selector;
@@ -40,7 +44,6 @@
int verbosity;
int dry_run;
int list;
- int signal;
int pgpolicy_flag;
int with_sysfs;
int default_selector_args;
@@ -48,6 +51,10 @@
int dev_type;
int minio;
int checkint;
+ int max_checkint;
+ int pgfailback;
+ int remove;
+ int rr_weight;
char * dev;
char * multipath;
@@ -61,17 +68,16 @@
vector mptable;
vector hwtable;
vector blist;
- vector binvec;
};
struct config * conf;
-extern int push_callout(char * callout);
-
struct hwentry * find_hwe (vector hwtable, char * vendor, char * product);
struct mpentry * find_mpe (char * wwid);
char * get_mpe_wwid (char * alias);
+struct mpentry * alloc_mpe (void);
+
void free_hwe (struct hwentry * hwe);
void free_hwtable (vector hwtable);
void free_mpe (struct mpentry * mpe);
Modified: multipath-tools/trunk/libmultipath/debug.c
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.c (original)
+++ multipath-tools/trunk/libmultipath/debug.c Mon Sep 19 12:43:52 2005
@@ -2,23 +2,29 @@
#include <stdlib.h>
#include <stdarg.h>
+#if DAEMON
+#include "../multipathd/log_pthread.h"
+#endif
+
#include "config.h"
-void condlog (int prio, char * fmt, ...)
+void dlog (int sink, int prio, char * fmt, ...)
{
va_list ap;
int thres;
- if (!conf)
- thres = 0;
- else
- thres = conf->verbosity;
-
va_start(ap, fmt);
+ thres = (conf) ? conf->verbosity : 0;
if (prio <= thres) {
- vfprintf(stdout, fmt, ap);
- fprintf(stdout, "\n");
+ if (!sink) {
+ vfprintf(stdout, fmt, ap);
+ fprintf(stdout, "\n");
+ }
+#if DAEMON
+ else
+ log_safe(prio + 3, fmt, ap);
+#endif
}
va_end(ap);
}
Modified: multipath-tools/trunk/libmultipath/debug.h
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.h (original)
+++ multipath-tools/trunk/libmultipath/debug.h Mon Sep 19 12:43:52 2005
@@ -1,8 +1,19 @@
-void condlog (int prio, char * fmt, ...);
+void dlog (int sink, int prio, char * fmt, ...);
#if DAEMON
+
#include <pthread.h>
+#include <stdarg.h>
#include "../multipathd/log_pthread.h"
+
+int logsink;
+
#define condlog(prio, fmt, args...) \
- log_safe(prio + 3, fmt, ##args)
-#endif
+ dlog(logsink, prio, fmt, ##args)
+
+#else /* DAEMON */
+
+#define condlog(prio, fmt, args...) \
+ dlog(0, prio, fmt, ##args)
+
+#endif /* DAEMON */
Modified: multipath-tools/trunk/libmultipath/defaults.h
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.h (original)
+++ multipath-tools/trunk/libmultipath/defaults.h Mon Sep 19 12:43:52 2005
@@ -7,7 +7,7 @@
#define DEFAULT_TARGET "multipath"
#define DEFAULT_PIDFILE "/var/run/multipathd.pid"
-#define DEFAULT_RUNFILE "/var/run/multipath.run"
+#define DEFAULT_SOCKET "/var/run/multipathd.sock"
#define DEFAULT_CONFIGFILE "/etc/multipath.conf"
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 Mon Sep 19 12:43:52 2005
@@ -4,46 +4,60 @@
#include <libdevmapper.h>
#include <ctype.h>
#include <linux/kdev_t.h>
+#include <unistd.h>
#include "vector.h"
#include "structs.h"
#include "debug.h"
#include "memory.h"
+#include "devmapper.h"
+
+#define MAX_WAIT 5
+#define LOOPS_PER_SEC 5
extern int
dm_prereq (char * str, int x, int y, int z)
{
- int r = 1;
+ int r = 2;
struct dm_task *dmt;
struct dm_versions *target;
struct dm_versions *last_target;
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
- return 1;
+ return 3;
dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
+ if (!dm_task_run(dmt)) {
+ condlog(0, "Can not communicate with kernel DM");
goto out;
+ }
target = dm_task_get_versions(dmt);
- /* Fetch targets and print 'em */
do {
last_target = target;
- if (!strncmp(str, target->name, strlen(str)) &&
- /* dummy prereq on multipath version */
- target->version[0] >= x &&
- target->version[1] >= y &&
- target->version[2] >= z
- )
- r = 0;
+ if (!strncmp(str, target->name, strlen(str))) {
+ r--;
+
+ if (target->version[0] >= x &&
+ target->version[1] >= y &&
+ target->version[2] >= z)
+ r--;
+
+ break;
+ }
target = (void *) target + target->next;
} while (last_target != target);
- out:
+ if (r == 2)
+ condlog(0, "DM multipath kernel driver not loaded");
+ else if (r == 1)
+ condlog(0, "DM multipath kernel driver version too old");
+
+out:
dm_task_destroy(dmt);
return r;
}
@@ -70,7 +84,7 @@
extern int
dm_addmap (int task, const char *name, const char *target,
- const char *params, unsigned long size) {
+ const char *params, unsigned long long size) {
int r = 0;
struct dm_task *dmt;
@@ -121,7 +135,7 @@
}
extern int
-dm_get_map(char * name, unsigned long * size, char * outparams)
+dm_get_map(char * name, unsigned long long * size, char * outparams)
{
int r = 1;
struct dm_task *dmt;
@@ -183,6 +197,9 @@
if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
r = 0;
out:
+ if (r)
+ condlog(0, "%s: error getting map status string", name);
+
dm_task_destroy(dmt);
return r;
}
@@ -220,6 +237,35 @@
return r;
}
+static int
+dm_dev_t (char * mapname, char * dev_t, int len)
+{
+ int r = 1;
+ struct dm_task *dmt;
+ struct dm_info info;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ return 0;
+
+ if (!dm_task_set_name(dmt, mapname))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, &info))
+ goto out;
+
+ r = info.open_count;
+ if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
+ goto out;
+
+ r = 0;
+out:
+ dm_task_destroy(dmt);
+ return r;
+}
+
int
dm_get_opencount (char * mapname)
{
@@ -245,6 +291,57 @@
return r;
}
+int
+dm_get_minor (char * mapname)
+{
+ int r = -1;
+ struct dm_task *dmt;
+ struct dm_info info;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ return 0;
+
+ if (!dm_task_set_name(dmt, mapname))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, &info))
+ goto out;
+
+ r = info.minor;
+out:
+ dm_task_destroy(dmt);
+ return r;
+}
+
+extern int
+dm_flush_map (char * mapname, char * type)
+{
+ int r;
+
+ if (!dm_map_present(mapname))
+ return 0;
+
+ if (!dm_type(mapname, type))
+ return 1;
+
+ if (dm_remove_partmaps(mapname))
+ return 1;
+
+ if (dm_get_opencount(mapname))
+ return 1;
+
+ r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
+
+ if (r) {
+ condlog(4, "multipath map %s removed", mapname);
+ return 0;
+ }
+ return 1;
+}
+
extern int
dm_flush_maps (char * type)
{
@@ -268,11 +365,7 @@
goto out;
do {
- if (dm_type(names->name, type) &&
- dm_get_opencount(names->name) == 0 &&
- !dm_simplecmd(DM_DEVICE_REMOVE, names->name))
- r++;
-
+ r += dm_flush_map(names->name, type);
next = names->next;
names = (void *) names + next;
} while (next);
@@ -348,8 +441,8 @@
return r;
}
-int
-dm_switchgroup(char * mapname, int index)
+static int
+dm_groupmsg (char * msg, char * mapname, int index)
{
int r = 0;
struct dm_task *dmt;
@@ -364,8 +457,7 @@
if (!dm_task_set_sector(dmt, 0))
goto out;
- snprintf(str, 24, "switch_group %i\n", index);
- condlog(3, "message %s 0 %s", mapname, str);
+ snprintf(str, 24, "%s_group %i\n", msg, index);
if (!dm_task_set_message(dmt, str))
goto out;
@@ -375,15 +467,37 @@
if (!dm_task_run(dmt))
goto out;
+ 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);
return r;
}
int
+dm_switchgroup(char * mapname, int index)
+{
+ return dm_groupmsg("switch", mapname,index);
+}
+
+int
+dm_enablegroup(char * mapname, int index)
+{
+ return dm_groupmsg("enable", mapname,index);
+}
+
+int
+dm_disablegroup(char * mapname, int index)
+{
+ return dm_groupmsg("disable", mapname,index);
+}
+
+int
dm_get_maps (vector mp, char * type)
{
struct multipath * mpp;
@@ -392,7 +506,7 @@
struct dm_names *names;
unsigned next = 0;
- if (!type)
+ if (!type || !mp)
return 1;
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
@@ -413,8 +527,7 @@
do {
if (dm_type(names->name, type)) {
- mpp = (struct multipath *)
- MALLOC(sizeof(struct multipath));
+ mpp = alloc_multipath();
if (!mpp)
goto out;
@@ -483,3 +596,152 @@
return info.event_nr;
}
+
+char *
+dm_mapname(int major, int minor)
+{
+ char * response;
+ struct dm_task *dmt;
+ int r;
+ int loop = MAX_WAIT * LOOPS_PER_SEC;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+ return NULL;
+
+ if (!dm_task_set_major(dmt, major) ||
+ !dm_task_set_minor(dmt, minor))
+ goto bad;
+
+ dm_task_no_open_count(dmt);
+
+ /*
+ * device map might not be ready when we get here from
+ * uevent trigger
+ */
+ while (--loop) {
+ r = dm_task_run(dmt);
+
+ if (r)
+ break;
+
+ usleep(1000 * 1000 / LOOPS_PER_SEC);
+ }
+
+ if (!r) {
+ condlog(0, "%i:%i: timeout fetching map name", major, minor);
+ goto bad;
+ }
+
+ response = STRDUP((char *)dm_task_get_name(dmt));
+ dm_task_destroy(dmt);
+ return response;
+bad:
+ dm_task_destroy(dmt);
+ condlog(0, "%i:%i: error fetching map name", major, minor);
+ return NULL;
+}
+
+int
+dm_remove_partmaps (char * mapname)
+{
+ struct dm_task *dmt;
+ struct dm_names *names;
+ unsigned next = 0;
+ char params[PARAMS_SIZE];
+ unsigned long long size;
+ char dev_t[32];
+ int r = 1;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ return 1;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!(names = dm_task_get_names(dmt)))
+ goto out;
+
+ if (!names->dev) {
+ r = 0; /* this is perfectly valid */
+ goto out;
+ }
+
+ if (dm_dev_t(mapname, &dev_t[0], 32))
+ goto out;
+
+ do {
+ if (
+ /*
+ * if devmap target is "linear"
+ */
+ dm_type(names->name, "linear") &&
+
+ /*
+ * and the multipath mapname and the part mapname start
+ * the same
+ */
+ !strncmp(names->name, mapname, strlen(mapname)) &&
+
+ /*
+ * and the opencount is 0 for us to allow removal
+ */
+ !dm_get_opencount(names->name) &&
+
+ /*
+ * and we can fetch the map table from the kernel
+ */
+ !dm_get_map(names->name, &size, ¶ms[0]) &&
+
+ /*
+ * and the table maps over the multipath map
+ */
+ strstr(params, dev_t)
+ ) {
+ /*
+ * then it's a kpartx generated partition.
+ * remove it.
+ */
+ condlog(4, "partition map %s removed",
+ names->name);
+ dm_simplecmd(DM_DEVICE_REMOVE, names->name);
+ }
+
+ next = names->next;
+ names = (void *) names + next;
+ } while (next);
+
+ r = 0;
+out:
+ dm_task_destroy (dmt);
+ return r;
+}
+
+#if 0
+int
+dm_rename (char * old, char * new)
+{
+ int r = 1;
+ struct dm_task *dmt;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
+ return 0;
+
+ if (!dm_task_set_name(dmt, old))
+ goto out;
+
+ if (!dm_task_set_newname(dmt, new))
+ goto out;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ r = 0;
+out:
+ dm_task_destroy(dmt);
+ return r;
+}
+#endif
Modified: multipath-tools/trunk/libmultipath/devmapper.h
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.h (original)
+++ multipath-tools/trunk/libmultipath/devmapper.h Mon Sep 19 12:43:52 2005
@@ -1,13 +1,24 @@
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);
+int dm_addmap (int, const char *, const char *, const char *,
+ unsigned long long);
int dm_map_present (char *);
-int dm_get_map(char *, unsigned long *, char *);
+int dm_get_map(char *, unsigned long long *, char *);
int dm_get_status(char *, char *);
int dm_type(char *, char *);
+int dm_flush_map (char *, char *);
int dm_flush_maps (char *);
int dm_fail_path(char * mapname, char * path);
int dm_reinstate(char * mapname, char * path);
int dm_switchgroup(char * mapname, int index);
+int dm_enablegroup(char * mapname, int index);
+int dm_disablegroup(char * mapname, int index);
int dm_get_maps (vector mp, char * type);
int dm_geteventnr (char *name);
+int dm_get_minor (char *name);
+char * dm_mapname(int major, int minor);
+int dm_remove_partmaps (char * mapname);
+
+#if 0
+int dm_rename (char * old, char * new);
+#endif
Modified: multipath-tools/trunk/libmultipath/dict.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.c (original)
+++ multipath-tools/trunk/libmultipath/dict.c Mon Sep 19 12:43:52 2005
@@ -21,7 +21,7 @@
if (!conf->multipath)
return 1;
- return push_callout(conf->multipath);
+ return 0;
}
static int
@@ -31,6 +31,7 @@
buff = VECTOR_SLOT(strvec, 1);
conf->checkint = atoi(buff);
+ conf->max_checkint = conf->checkint << 2;
return 0;
}
@@ -81,7 +82,7 @@
if (!conf->default_getuid)
return 1;
- return push_callout(conf->default_getuid);
+ return 0;
}
static int
@@ -92,7 +93,12 @@
if (!conf->default_getprio)
return 1;
- return push_callout(conf->default_getprio);
+ if (!strncmp(conf->default_getprio, "none", 4)) {
+ FREE(conf->default_getprio);
+ conf->default_getprio = NULL;
+ }
+
+ return 0;
}
static int
@@ -122,6 +128,44 @@
return 0;
}
+static int
+def_weight_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ if (strlen(buff) == 10 &&
+ !strcmp(buff, "priorities"))
+ conf->rr_weight = RR_WEIGHT_PRIO;
+
+ FREE(buff);
+
+ return 0;
+}
+
+static int
+default_failback_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!strncmp(buff, "manual", 6))
+ conf->pgfailback = -FAILBACK_MANUAL;
+ else if (!strncmp(buff, "immediate", 9))
+ conf->pgfailback = -FAILBACK_IMMEDIATE;
+ else
+ conf->pgfailback = atoi(buff);
+
+ FREE(buff);
+
+ return 0;
+}
+
/*
* blacklist block handlers
*/
@@ -245,7 +289,7 @@
if (!hwe->getuid)
return 1;
- return push_callout(hwe->getuid);
+ return 0;
}
static int
@@ -329,7 +373,58 @@
if (!hwe->getprio)
return 1;
- return push_callout(hwe->getprio);
+ if (!strncmp(hwe->getprio, "none", 4)) {
+ FREE(hwe->getprio);
+ hwe->getprio = NULL;
+ }
+
+ return 0;
+}
+
+static int
+hw_failback_handler(vector strvec)
+{
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+ char * buff;
+
+ if (!hwe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!strncmp(buff, "manual", 6))
+ hwe->pgfailback = -FAILBACK_MANUAL;
+ else if (!strncmp(buff, "immediate", 9))
+ hwe->pgfailback = -FAILBACK_IMMEDIATE;
+ else
+ hwe->pgfailback = atoi(buff);
+
+ FREE(buff);
+
+ return 0;
+}
+
+static int
+hw_weight_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 (strlen(buff) == 10 &&
+ !strcmp(buff, "priorities"))
+ hwe->rr_weight = RR_WEIGHT_PRIO;
+
+ FREE(buff);
+
+ return 0;
}
/*
@@ -433,6 +528,52 @@
return 0;
}
+static int
+mp_failback_handler(vector strvec)
+{
+ struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
+ char * buff;
+
+ if (!mpe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!strncmp(buff, "manual", 6))
+ mpe->pgfailback = -FAILBACK_MANUAL;
+ else if (!strncmp(buff, "immediate", 9))
+ mpe->pgfailback = -FAILBACK_IMMEDIATE;
+ else
+ mpe->pgfailback = atoi(buff);
+
+ FREE(buff);
+
+ return 0;
+}
+
+static int
+mp_weight_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 (strlen(buff) == 10 &&
+ !strcmp(buff, "priorities"))
+ mpe->rr_weight = RR_WEIGHT_PRIO;
+
+ FREE(buff);
+
+ return 0;
+}
+
vector
init_keywords(void)
{
@@ -447,7 +588,9 @@
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_root("devnode_blacklist", &blacklist_handler);
install_keyword("devnode", &ble_handler);
@@ -465,6 +608,8 @@
install_keyword("features", &hw_features_handler);
install_keyword("hardware_handler", &hw_handler_handler);
install_keyword("prio_callout", &prio_callout_handler);
+ install_keyword("failback", &hw_failback_handler);
+ install_keyword("rr_weight", &hw_weight_handler);
install_sublevel_end();
install_keyword_root("multipaths", &multipaths_handler);
@@ -474,6 +619,8 @@
install_keyword("alias", &alias_handler);
install_keyword("path_grouping_policy", &mp_pgpolicy_handler);
install_keyword("path_selector", &mp_selector_handler);
+ install_keyword("failback", &mp_failback_handler);
+ install_keyword("rr_weight", &mp_weight_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 Mon Sep 19 12:43:52 2005
@@ -2,6 +2,8 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <errno.h>
#include <sysfs/dlist.h>
#include <sysfs/libsysfs.h>
@@ -21,17 +23,43 @@
#define readattr(a,b) \
sysfs_read_attribute_value(a, b, sizeof(b))
+struct path *
+store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
+{
+ struct path * pp;
+
+ pp = alloc_path();
+
+ if (!pp)
+ return NULL;
+
+ if(safe_sprintf(pp->dev, "%s", devname)) {
+ condlog(0, "pp->dev too small");
+ goto out;
+ }
+ if (pathinfo(pp, hwtable, flag))
+ goto out;
+
+ if (store_path(pathvec, pp))
+ goto out;
+
+ return pp;
+out:
+ free_path(pp);
+ return NULL;
+}
+
int
path_discovery (vector pathvec, struct config * conf, int flag)
{
struct sysfs_directory * sdir;
struct sysfs_directory * devp;
char path[FILE_NAME_SIZE];
- struct path * curpath;
+ struct path * pp;
int r = 1;
if(safe_sprintf(path, "%s/block", sysfs_path)) {
- fprintf(stderr, "path too small\n");
+ condlog(0, "path too small");
exit(1);
}
sdir = sysfs_open_directory(path);
@@ -43,36 +71,30 @@
if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
devp->name)) {
- fprintf(stderr, "path too small\n");
+ condlog(0, "path too small");
exit(1);
}
if (!filepresent(path))
continue;
- curpath = find_path_by_dev(pathvec, devp->name);
-
- if (!curpath) {
- curpath = alloc_path();
-
- if (!curpath)
- goto out;
+ pp = find_path_by_dev(pathvec, devp->name);
- if (store_path(pathvec, curpath)) {
- free_path(curpath);
+ if (!pp) {
+ /*
+ * new path : alloc, store and fetch info
+ * the caller wants
+ */
+ if (!store_pathinfo(pathvec, conf->hwtable,
+ devp->name, flag))
goto out;
- }
- if(safe_sprintf(curpath->dev, "%s", devp->name)) {
- fprintf(stderr, "curpath->dev too small\n");
- exit(1);
- }
- devinfo(curpath, conf->hwtable, DI_ALL);
} else {
/*
- * path already known,
+ * path already known :
* refresh only what the caller wants
*/
- devinfo(curpath, conf->hwtable, flag);
+ if (pathinfo(pp, conf->hwtable, flag))
+ goto out;
}
}
r = 0;
@@ -81,6 +103,26 @@
return r;
}
+#define WAIT_MAX_SECONDS 5
+#define WAIT_LOOP_PER_SECOND 5
+
+static int
+wait_sysfs_attr (char * filename)
+{
+ int loop;
+ struct stat stats;
+
+ loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
+
+ while (--loop) {
+ if (stat(filename, &stats) == 0)
+ return 0;
+
+ usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+ }
+ return 1;
+}
+
#define declare_sysfs_get_str(fname, fmt) \
extern int \
sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
@@ -89,8 +131,12 @@
char attr_buff[SYSFS_PATH_SIZE]; \
int attr_len; \
\
- if(safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
+ if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
+ return 1; \
+\
+ if (wait_sysfs_attr(attr_path)) \
return 1; \
+\
if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
return 1; \
\
@@ -109,50 +155,77 @@
declare_sysfs_get_str(dev, "%s/block/%s/dev");
#define declare_sysfs_get_val(fname, fmt) \
-extern unsigned long \
+extern unsigned long long \
sysfs_get_##fname (char * sysfs_path, char * dev) \
{ \
char attr_path[SYSFS_PATH_SIZE]; \
char attr_buff[SYSFS_PATH_SIZE]; \
+ int r; \
+ unsigned long long val; \
+\
+ if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
+ return 0; \
\
- if(safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
+ if (wait_sysfs_attr(attr_path)) \
return 0; \
+\
if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
return 0; \
\
- return strtoul(attr_buff, NULL, 0); \
+ r = sscanf(attr_buff, "%llu\n", &val); \
+\
+ if (r != 1) \
+ return 0; \
+ else \
+ return (val); \
}
declare_sysfs_get_val(size, "%s/block/%s/size");
+/*
+ * udev might be slow creating node files : wait
+ */
static int
opennode (char * dev, int mode)
{
char devpath[FILE_NAME_SIZE];
int fd;
+ int loop;
if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) {
- fprintf(stderr, "devpath too small\n");
+ condlog(0, "devpath too small");
return -1;
}
- fd = open(devpath, mode);
- if (fd <= 0)
- condlog(0, "open(%s) failed", devpath);
+ loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
- return fd;
+ 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);
+ }
+ condlog(0, "failed to open %s", devpath);
+ return -1;
}
-#if 0
int
-get_claimed(int fd)
+get_claimed(char * devname)
{
- /*
- * FIXME : O_EXCL always fails ?
- */
+ int fd = opennode(devname, O_EXCL);
+
+ if (fd < 0)
+ return 1;
+
+ close(fd);
return 0;
}
-#endif
extern int
devt2devname (char *devname, char *devt)
@@ -165,7 +238,7 @@
int len;
if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
- fprintf(stderr, "block_path too small\n");
+ condlog(0, "block_path too small");
exit(1);
}
sdir = sysfs_open_directory(block_path);
@@ -174,7 +247,7 @@
dlist_for_each_data (sdir->subdirs, devp, struct sysfs_directory) {
if(safe_sprintf(attr_path, "%s/%s/dev",
block_path, devp->name)) {
- fprintf(stderr, "attr_path too small\n");
+ condlog(0, "attr_path too small");
exit(1);
}
sysfs_read_attribute_value(attr_path, attr_value,
@@ -189,7 +262,7 @@
strncmp(attr_value, devt, len) == 0) {
if(safe_sprintf(attr_path, "%s/%s",
block_path, devp->name)) {
- fprintf(stderr, "attr_path too small\n");
+ condlog(0, "attr_path too small");
exit(1);
}
sysfs_get_name_from_path(attr_path, devname,
@@ -267,15 +340,48 @@
len = buff[3];
if (len > 0) {
memcpy(str, buff + 4, len);
- buff[len] = '\0';
+ str[len] = '\0';
}
return 1;
}
return 0;
}
-extern int
-sysfs_devinfo(struct path * curpath)
+static void
+sysfs_get_bus (char * sysfs_path, struct path * curpath)
+{
+ struct sysfs_device *sdev;
+ char attr_path[FILE_NAME_SIZE];
+ char attr_buff[FILE_NAME_SIZE];
+
+ curpath->bus = SYSFS_BUS_UNDEF;
+
+ /*
+ * This is ugly : we should be able to do a simple
+ * get_link("%s/block/%s/device/bus", ...) but it just
+ * won't work
+ */
+ if(safe_sprintf(attr_path, "%s/block/%s/device",
+ sysfs_path, curpath->dev)) {
+ condlog(0, "attr_path too small");
+ return;
+ }
+
+ if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
+ return;
+
+ sdev = sysfs_open_device_path(attr_buff);
+
+ if (!strncmp(sdev->bus, "scsi", 4))
+ curpath->bus = SYSFS_BUS_SCSI;
+ else if (!strncmp(sdev->bus, "ide", 3))
+ curpath->bus = SYSFS_BUS_IDE;
+
+ return;
+}
+
+static int
+scsi_sysfs_pathinfo (struct path * curpath)
{
char attr_path[FILE_NAME_SIZE];
char attr_buff[FILE_NAME_SIZE];
@@ -283,40 +389,34 @@
if (sysfs_get_vendor(sysfs_path, curpath->dev,
curpath->vendor_id, SCSI_VENDOR_SIZE))
return 1;
+
condlog(3, "vendor = %s", curpath->vendor_id);
if (sysfs_get_model(sysfs_path, curpath->dev,
curpath->product_id, SCSI_PRODUCT_SIZE))
return 1;
+
condlog(3, "product = %s", curpath->product_id);
if (sysfs_get_rev(sysfs_path, curpath->dev,
curpath->rev, SCSI_REV_SIZE))
return 1;
- condlog(3, "rev = %s", curpath->rev);
-
- if (sysfs_get_dev(sysfs_path, curpath->dev,
- curpath->dev_t, BLK_DEV_SIZE))
- return 1;
- condlog(3, "dev_t = %s", curpath->dev_t);
-
- curpath->size = sysfs_get_size(sysfs_path, curpath->dev);
- if (curpath->size == 0)
- return 1;
- condlog(3, "size = %lu", curpath->size);
+ condlog(3, "rev = %s", curpath->rev);
/*
* host / bus / target / lun
*/
if(safe_sprintf(attr_path, "%s/block/%s/device",
sysfs_path, curpath->dev)) {
- fprintf(stderr, "attr_path too small\n");
+ condlog(0, "attr_path too small");
return 1;
}
if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
return 1;
+
basename(attr_buff, attr_path);
+
sscanf(attr_path, "%i:%i:%i:%i",
&curpath->sg_id.host_no,
&curpath->sg_id.channel,
@@ -337,7 +437,7 @@
curpath->sg_id.host_no,
curpath->sg_id.channel,
curpath->sg_id.scsi_id)) {
- fprintf(stderr, "attr_path too small\n");
+ condlog(0, "attr_path too small");
return 1;
}
if (0 <= readattr(attr_path, attr_buff) && strlen(attr_buff) > 0)
@@ -349,6 +449,44 @@
}
static int
+common_sysfs_pathinfo (struct path * curpath)
+{
+
+ sysfs_get_bus(sysfs_path, curpath);
+ condlog(3, "bus = %i", curpath->bus);
+
+ if (sysfs_get_dev(sysfs_path, curpath->dev,
+ curpath->dev_t, BLK_DEV_SIZE))
+ return 1;
+
+ condlog(3, "dev_t = %s", curpath->dev_t);
+
+ curpath->size = sysfs_get_size(sysfs_path, curpath->dev);
+
+ if (curpath->size == 0)
+ return 1;
+
+ condlog(3, "size = %llu", curpath->size);
+
+ return 0;
+}
+
+extern int
+sysfs_pathinfo(struct path * curpath)
+{
+ if (common_sysfs_pathinfo(curpath))
+ return 1;
+
+ if (curpath->bus == SYSFS_BUS_UNDEF)
+ return 0;
+ else if (curpath->bus == SYSFS_BUS_SCSI)
+ if (scsi_sysfs_pathinfo(curpath))
+ return 1;
+
+ return 0;
+}
+
+static int
apply_format (char * string, char * cmd, struct path * pp)
{
char * pos;
@@ -427,8 +565,19 @@
return 0;
}
+static int
+scsi_ioctl_pathinfo (struct path * pp, int mask)
+{
+ if (mask & DI_SERIAL) {
+ get_serial(pp->serial, pp->fd);
+ condlog(3, "serial = %s", pp->serial);
+ }
+
+ return 0;
+}
+
extern int
-devinfo (struct path *pp, vector hwtable, int mask)
+pathinfo (struct path *pp, vector hwtable, int mask)
{
char buff[CALLOUT_MAX_SIZE];
char prio[16];
@@ -438,28 +587,25 @@
/*
* fetch info available in sysfs
*/
- if (mask & DI_SYSFS && sysfs_devinfo(pp))
+ if (mask & DI_SYSFS && sysfs_pathinfo(pp))
return 1;
/*
* then those not available through sysfs
*/
+ if (mask & DI_CLAIMED) {
+ pp->claimed = get_claimed(pp->dev);
+ condlog(3, "claimed = %i", pp->claimed);
+ }
if (pp->fd <= 0)
pp->fd = opennode(pp->dev, O_RDONLY);
if (pp->fd <= 0)
return 1;
- if (mask & DI_SERIAL) {
- get_serial(pp->serial, pp->fd);
- condlog(3, "serial = %s", pp->serial);
- }
-#if 0
- if (mask & DI_CLAIMED) {
- pp->claimed = get_claimed(pp->fd);
- condlog(3, "claimed = %i", pp->claimed);
- }
-#endif
+ if (pp->bus == SYSFS_BUS_SCSI)
+ if (scsi_ioctl_pathinfo(pp, mask))
+ return 1;
/* get and store hwe pointer */
pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id);
@@ -467,9 +613,10 @@
/*
* get path state, no message collection, no context
*/
- select_checkfn(pp);
-
if (mask & DI_CHECKER) {
+ if (!pp->checkfn)
+ select_checkfn(pp);
+
pp->state = pp->checkfn(pp->fd, NULL, NULL);
condlog(3, "state = %i", pp->state);
}
@@ -478,9 +625,12 @@
* get path prio
*/
if (mask & DI_PRIO) {
- select_getprio(pp);
+ if (!pp->getprio)
+ select_getprio(pp);
- if (apply_format(pp->getprio, &buff[0], pp)) {
+ if (!pp->getprio) {
+ pp->priority = 1;
+ } else if (apply_format(pp->getprio, &buff[0], pp)) {
condlog(0, "error formatting prio callout command");
pp->priority = -1;
} else if (execute_program(buff, prio, 16)) {
@@ -496,7 +646,8 @@
* get path uid
*/
if (mask & DI_WWID && !strlen(pp->wwid)) {
- select_getuid(pp);
+ if (!pp->getuid)
+ select_getuid(pp);
if (apply_format(pp->getuid, &buff[0], pp)) {
condlog(0, "error formatting uid callout command");
Modified: multipath-tools/trunk/libmultipath/discovery.h
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.h (original)
+++ multipath-tools/trunk/libmultipath/discovery.h Mon Sep 19 12:43:52 2005
@@ -26,18 +26,16 @@
int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len);
int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len);
-unsigned long sysfs_get_size (char * sysfs_path, char * dev);
+unsigned long long sysfs_get_size (char * sysfs_path, char * dev);
int path_discovery (vector pathvec, struct config * conf, int flag);
void basename (char *, char *);
int get_serial (char * buff, int fd);
int do_tur (char *);
int devt2devname (char *, char *);
-int devinfo (struct path *, vector hwtable, int mask);
-
-#if 0
-int get_claimed(int fd);
-#endif
+int pathinfo (struct path *, vector hwtable, int mask);
+struct path * store_pathinfo (vector pathvec, vector hwtable,
+ char * devname, int flag);
/*
* discovery bitmask
Modified: multipath-tools/trunk/libmultipath/dmparser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.c (original)
+++ multipath-tools/trunk/libmultipath/dmparser.c Mon Sep 19 12:43:52 2005
@@ -16,45 +16,6 @@
#define WORD_SIZE 64
static int
-get_word (char * sentence, char ** word)
-{
- char * p;
- int len;
- int skip = 0;
-
- while (*sentence == ' ') {
- sentence++;
- skip++;
- }
- if (*sentence == '\0')
- return 0;
-
- p = sentence;
-
- while (*p != ' ' && *p != '\0')
- p++;
-
- len = (int) (p - sentence);
-
- if (!word)
- return skip + len;
-
- *word = MALLOC(len + 1);
-
- if (!*word) {
- condlog(0, "get_word : oom\n");
- return 0;
- }
- strncpy(*word, sentence, len);
- condlog(4, "*word = %s, len = %i", *word, len);
-
- if (*p == '\0')
- return 0;
-
- return skip + len;
-}
-
-static int
merge_words (char ** dst, char * word, int space)
{
char * p;
@@ -255,11 +216,23 @@
if (store_path(pgp->paths, pp))
goto out;
- pgp->id ^= (long)pp;
-
+ /*
+ * Update wwid for multipaths which are not setup
+ * in the get_dm_mpvec() code path
+ */
if (!strlen(mpp->wwid))
strncpy(mpp->wwid, pp->wwid, WWID_SIZE);
+ /*
+ * Update wwid for paths which may not have been
+ * active at the time the getuid callout was run
+ */
+ else if (!strlen(pp->wwid))
+ strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
+
+ pgp->id ^= (long)pp;
+ pp->pgindex = i + 1;
+
for (k = 0; k < num_paths_args; k++)
p += get_word(p, NULL);
}
@@ -367,7 +340,7 @@
pgp->status = PGSTATE_ENABLED;
break;
default:
- pgp->status = PGSTATE_RESERVED;
+ pgp->status = PGSTATE_UNDEF;
break;
}
FREE(word);
Modified: multipath-tools/trunk/libmultipath/hwtable.c
==============================================================================
--- multipath-tools/trunk/libmultipath/hwtable.c (original)
+++ multipath-tools/trunk/libmultipath/hwtable.c Mon Sep 19 12:43:52 2005
@@ -12,17 +12,18 @@
int r = 0;
r += store_hwe(hw, "3PARdata", "VV", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "HSV110 (C)COMPAQ", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "MSA1000", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "MSA1000 VOLUME", MULTIBUS, DEFAULT_GETUID);
+ r += store_hwe(hw, "COMPAQ", "HSV110 (C)COMPAQ", GROUP_BY_SERIAL, DEFAULT_GETUID);
+ r += store_hwe(hw, "COMPAQ", "MSA1000", GROUP_BY_SERIAL, DEFAULT_GETUID);
+ 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", 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, "FSC", "CentricStor", MULTIBUS, DEFAULT_GETUID);
+ 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);
r += store_hwe(hw, "HITACHI", "DF600", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HP", "HSV110", MULTIBUS, DEFAULT_GETUID);
+ r += store_hwe(hw, "HP", "HSV110", GROUP_BY_SERIAL, DEFAULT_GETUID);
+ r += store_hwe(hw, "HP", "HSV210", MULTIBUS, DEFAULT_GETUID);
r += store_hwe(hw, "HP", "A6189A", MULTIBUS, DEFAULT_GETUID);
r += store_hwe(hw, "HP", "OPEN-", MULTIBUS, DEFAULT_GETUID);
r += store_hwe(hw, "IBM", "ProFibre 4000R", MULTIBUS, DEFAULT_GETUID);
@@ -34,7 +35,8 @@
r += store_hwe(hw, "SUN", "T4", MULTIBUS, DEFAULT_GETUID);
r += store_hwe_ext(hw, "DGC", "*", GROUP_BY_PRIO, DEFAULT_GETUID,
- "/sbin/pp_emc /dev/%n", "1 emc", "0", "emc_clariion");
+ "/sbin/mpath_prio_emc /dev/%n", "1 emc",
+ "1 queue_if_no_path", "emc_clariion");
r += store_hwe_ext(hw, "IBM", "3542", GROUP_BY_SERIAL, DEFAULT_GETUID,
NULL, "0", "0", "tur");
r += store_hwe_ext(hw, "SGI", "TP9400", MULTIBUS, DEFAULT_GETUID,
Modified: multipath-tools/trunk/libmultipath/memory.c
==============================================================================
--- multipath-tools/trunk/libmultipath/memory.c (original)
+++ multipath-tools/trunk/libmultipath/memory.c Mon Sep 19 12:43:52 2005
@@ -133,6 +133,49 @@
return buf;
}
+char *
+dbg_strdup(char *str, char *file, char *function, int line)
+{
+ void *buf;
+ int i = 0;
+ long check;
+ long size;
+
+ size = strlen(str) + 1;
+ buf = zalloc(size + sizeof (long));
+ strcat(buf, str);
+
+ check = 0xa5a5 + size;
+ *(long *) ((char *) buf + size) = check;
+
+ while (i < number_alloc_list) {
+ if (alloc_list[i].type == 0)
+ break;
+ i++;
+ }
+
+ if (i == number_alloc_list)
+ number_alloc_list++;
+
+ assert(number_alloc_list < MAX_ALLOC_LIST);
+
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = size;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].csum = check;
+ alloc_list[i].type = 9;
+
+ if (debug & 1)
+ printf("strdup[%3d:%3d], %p, %4ld at %s, %3d, %s\n",
+ i, number_alloc_list, buf, size, file, line,
+ function);
+
+ n++;
+ return buf;
+}
+
/* Display a buffer into a HEXA formated output */
Modified: multipath-tools/trunk/libmultipath/memory.h
==============================================================================
--- multipath-tools/trunk/libmultipath/memory.h (original)
+++ multipath-tools/trunk/libmultipath/memory.h Mon Sep 19 12:43:52 2005
@@ -51,11 +51,14 @@
(__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
#define REALLOC(b,n) ( dbg_realloc((b), (n), \
(__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+#define STRDUP(n) ( dbg_strdup((n), \
+ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
/* Memory debug prototypes defs */
extern char *dbg_malloc(unsigned long, char *, char *, int);
extern int dbg_free(void *, char *, char *, int);
extern void *dbg_realloc(void *, unsigned long, char *, char *, int);
+extern char *dbg_strdup(char *, char *, char *, int);
extern void dbg_free_final(char *);
#else
@@ -63,6 +66,7 @@
#define MALLOC(n) (zalloc(n))
#define FREE(p) (xfree(p))
#define REALLOC(p,n) (realloc((p),(n)))
+#define STRDUP(n) (strdup(n))
#endif
Modified: multipath-tools/trunk/libmultipath/pgpolicies.c
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.c (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.c Mon Sep 19 12:43:52 2005
@@ -243,7 +243,7 @@
{
struct pathgroup * pgp;
- if (VECTOR_SIZE(pgp->paths) < 0)
+ if (VECTOR_SIZE(mp->paths) < 0)
return 0;
if (!mp->pg)
Modified: multipath-tools/trunk/libmultipath/pgpolicies.h
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.h (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.h Mon Sep 19 12:43:52 2005
@@ -11,7 +11,7 @@
/* Storage controlers capabilities */
enum iopolicies {
- IOPOLICY_RESERVED,
+ IOPOLICY_UNDEF,
FAILOVER,
MULTIBUS,
GROUP_BY_SERIAL,
Added: multipath-tools/trunk/libmultipath/print.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/print.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "vector.h"
+#include "structs.h"
+#include "print.h"
+#include "dmparser.h"
+
+#include "../libcheckers/path_state.h"
+
+#define MAX_FIELD_LEN 64
+
+#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;
+
+ /* reset max col lengths */
+ pl->hbtl_len = 0;
+ pl->dev_len = 0;
+ pl->dev_t_len = 0;
+
+ vector_foreach_slot (pathvec, pp, i) {
+ hbtl_len = snprintf(buff, MAX_FIELD_LEN, "%i:%i:%i:%i",
+ pp->sg_id.host_no,
+ pp->sg_id.channel,
+ pp->sg_id.scsi_id,
+ pp->sg_id.lun);
+ dev_len = strlen(pp->dev);
+ dev_t_len = strlen(pp->dev_t);
+
+ 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);
+ }
+ return;
+}
+
+void
+get_map_layout (struct map_layout * ml, vector mpvec)
+{
+ int i;
+ char buff[MAX_FIELD_LEN];
+ int mapname_len, mapdev_len;
+ struct multipath * mpp;
+
+ /* reset max col lengths */
+ ml->mapname_len = 0;
+ ml->mapdev_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);
+
+ mapdev_len = snprintf(buff, MAX_FIELD_LEN,
+ "dm-%i", mpp->minor);
+ ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len);
+ }
+ return;
+}
+
+#define TAIL (line + len - 1 - c)
+#define PAD(x) while ((int)(c - s) < (x)) *c++ = ' '; s = c
+#define NOPAD s = c
+#define PRINT(var, size, format, args...) \
+ fwd = snprintf(var, size, format, ##args); \
+ c += (fwd >= size) ? size : fwd;
+
+int
+snprint_map (char * line, int len, char * format,
+ struct multipath * mpp, struct map_layout * ml)
+{
+ char * c = line; /* line cursor */
+ char * s = line; /* for padding */
+ char * f = format; /* format string cursor */
+ int i, j;
+ int fwd;
+
+ do {
+ if (!TAIL)
+ break;
+
+ if (*f != '%') {
+ *c++ = *f;
+ NOPAD;
+ continue;
+ }
+ f++;
+ switch (*f) {
+ case 'w':
+ if (mpp->alias) {
+ PRINT(c, TAIL, "%s", mpp->alias);
+ } else {
+ PRINT(c, TAIL, "%s", mpp->wwid);
+ }
+ PAD(ml->mapname_len);
+ break;
+ case 'd':
+ PRINT(c, TAIL, "dm-%i", mpp->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");
+ }
+ while (j-- > 0) {
+ PRINT(c, TAIL, ".");
+ }
+ PRINT(c, TAIL, " %i/%i",
+ mpp->failback_tick, mpp->pgfailback);
+ NOPAD;
+ break;
+ default:
+ break;
+ }
+ } while (*f++);
+
+ line[c - line - 1] = '\n';
+ line[c - line] = '\0';
+
+ return (c - line);
+}
+
+int
+snprint_path (char * line, int len, char * format, struct path * pp,
+ struct path_layout * pl)
+{
+ char * c = line; /* line cursor */
+ char * s = line; /* for padding */
+ char * f = format; /* format string cursor */
+ int i, j;
+ int fwd;
+
+ do {
+ if (!TAIL)
+ break;
+
+ if (*f != '%') {
+ *c++ = *f;
+ NOPAD;
+ continue;
+ }
+ f++;
+ switch (*f) {
+ case 'w':
+ PRINT(c, TAIL, "%s ", pp->wwid);
+ NOPAD;
+ break;
+ case 'i':
+ if (pp->sg_id.host_no < 0) {
+ PRINT(c, TAIL, "#:#:#:# ");
+ } else {
+ PRINT(c, TAIL, "%i:%i:%i:%i",
+ pp->sg_id.host_no,
+ pp->sg_id.channel,
+ pp->sg_id.scsi_id,
+ pp->sg_id.lun);
+ }
+ PAD(pl->hbtl_len);
+ break;
+ case 'd':
+ PRINT(c, TAIL, "%s", pp->dev);
+ PAD(pl->dev_len);
+ break;
+ case 'D':
+ PRINT(c, TAIL, "%s", pp->dev_t);
+ PAD(pl->dev_t_len);
+ break;
+ case 'T':
+ switch (pp->state) {
+ case PATH_UP:
+ PRINT(c, TAIL, "[ready]");
+ break;
+ case PATH_DOWN:
+ PRINT(c, TAIL, "[faulty]");
+ break;
+ case PATH_SHAKY:
+ PRINT(c, TAIL, "[shaky]");
+ break;
+ case PATH_GHOST:
+ PRINT(c, TAIL, "[ghost]");
+ break;
+ default:
+ break;
+ }
+ NOPAD;
+ break;
+ case 't':
+ switch (pp->dmstate) {
+ case PSTATE_ACTIVE:
+ PRINT(c, TAIL, "[active]");
+ break;
+ case PSTATE_FAILED:
+ PRINT(c, TAIL, "[failed]");
+ break;
+ default:
+ break;
+ }
+ NOPAD;
+ break;
+ case 'c':
+ if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
+ PRINT(c, TAIL, "[claimed]");
+ }
+ NOPAD;
+ break;
+ case 's':
+ PRINT(c, TAIL, "%s/%s/%s",
+ pp->vendor_id, pp->product_id, pp->rev);
+ NOPAD;
+ break;
+ 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, ".");
+ }
+ PRINT(c, TAIL, " %i/%i",
+ pp->tick, pp->checkint);
+ NOPAD;
+ break;
+ case 'p':
+ if (pp->priority) {
+ PRINT(c, TAIL, "%i", pp->priority);
+ }
+ NOPAD;
+ break;
+ default:
+ break;
+ }
+ } while (*f++);
+
+ line[c - line - 1] = '\n';
+ line[c - line] = '\0';
+
+ return (c - line);
+}
+
Added: multipath-tools/trunk/libmultipath/print.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/print.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,43 @@
+/*
+ * path format magics :
+ *
+ * %w : multipath uid
+ * %i : scsi tuple
+ * %d : device name
+ * %D : device major:minor
+ * %t : device mapper path status
+ * %T : checker path status
+ * %s : scsi strings
+ * %c : claimed
+ * %p : priority
+ *
+ * map format magics :
+ *
+ * %w : multipath uid
+ * %d : DM device name
+ * %F : failback countdown
+ * %C : checker countdown
+ */
+#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_CHECKER "%i %d %D %p %t%T %C"
+#define PRINT_MAP_FAILBACK "%w %d %F"
+
+#define MAX_LINE_LEN 80
+
+struct path_layout {
+ int hbtl_len;
+ int dev_len;
+ int dev_t_len;
+};
+
+struct map_layout {
+ int mapname_len;
+ int mapdev_len;
+};
+
+
+void get_path_layout (struct path_layout * pl, vector pathvec);
+void get_map_layout (struct map_layout * pl, vector mpvec);
+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 Mon Sep 19 12:43:52 2005
@@ -14,6 +14,58 @@
* stop at first explicit setting found
*/
extern int
+select_rr_weight (struct multipath * mp)
+{
+ if (mp->mpe && mp->mpe->rr_weight) {
+ mp->rr_weight = mp->mpe->rr_weight;
+ condlog(3, "rr_weight = %i (LUN setting)",
+ mp->rr_weight);
+ return 0;
+ }
+ if (mp->hwe && mp->hwe->rr_weight) {
+ mp->rr_weight = mp->hwe->rr_weight;
+ condlog(3, "rr_weight = %i (controler setting)",
+ mp->rr_weight);
+ return 0;
+ }
+ if (conf->rr_weight) {
+ mp->rr_weight = conf->rr_weight;
+ condlog(3, "rr_weight = %i (config file default)",
+ mp->rr_weight);
+ return 0;
+ }
+ mp->rr_weight = RR_WEIGHT_NONE;
+ condlog(3, "rr_weight = %i (internal default)",
+ mp->rr_weight);
+ return 0;
+}
+
+extern int
+select_pgfailback (struct multipath * mp)
+{
+ if (mp->mpe && mp->mpe->pgfailback != FAILBACK_UNDEF) {
+ mp->pgfailback = mp->mpe->pgfailback;
+ condlog(3, "pgfailback = %i (LUN setting)", mp->pgfailback);
+ return 0;
+ }
+ if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
+ mp->pgfailback = mp->hwe->pgfailback;
+ condlog(3, "pgfailback = %i (controler setting)",
+ mp->pgfailback);
+ return 0;
+ }
+ if (conf->pgfailback != FAILBACK_UNDEF) {
+ mp->pgfailback = conf->pgfailback;
+ condlog(3, "pgfailback = %i (config file default)",
+ mp->pgfailback);
+ return 0;
+ }
+ mp->pgfailback = -FAILBACK_MANUAL;
+ condlog(3, "pgfailover = %i (internal default)", mp->pgfailback);
+ return 0;
+}
+
+extern int
select_pgpolicy (struct multipath * mp)
{
struct path * pp;
Modified: multipath-tools/trunk/libmultipath/propsel.h
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.h (original)
+++ multipath-tools/trunk/libmultipath/propsel.h Mon Sep 19 12:43:52 2005
@@ -1,3 +1,5 @@
+int select_rr_weight (struct multipath * mp);
+int select_pgfailback (struct multipath * mp);
int select_pgpolicy (struct multipath * mp);
int select_selector (struct multipath * mp);
int select_alias (struct multipath * mp);
Modified: multipath-tools/trunk/libmultipath/structs.c
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.c (original)
+++ multipath-tools/trunk/libmultipath/structs.c Mon Sep 19 12:43:52 2005
@@ -11,7 +11,17 @@
struct path *
alloc_path (void)
{
- return (struct path *)MALLOC(sizeof(struct path));
+ struct path * pp;
+
+ pp = (struct path *)MALLOC(sizeof(struct path));
+
+ if (pp) {
+ pp->sg_id.host_no = -1;
+ pp->sg_id.channel = -1;
+ pp->sg_id.scsi_id = -1;
+ pp->sg_id.lun = -1;
+ }
+ return pp;
}
void
@@ -21,7 +31,7 @@
return;
if (pp->checker_context)
- FREE(pp->checker_context);
+ free(pp->checker_context);
if (pp->fd > 0)
close(pp->fd);
@@ -91,7 +101,14 @@
struct multipath *
alloc_multipath (void)
{
- return (struct multipath *)MALLOC(sizeof(struct multipath));
+ struct multipath * mpp;
+
+ mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
+
+ if (mpp)
+ mpp->nextpg = 1;
+
+ return mpp;
}
void
@@ -164,6 +181,32 @@
}
struct multipath *
+find_mp_by_minor (vector mp, int minor)
+{
+ int i;
+ struct multipath * mpp;
+
+ vector_foreach_slot (mp, mpp, i)
+ if (mpp->minor == minor)
+ return mpp;
+
+ return NULL;
+}
+
+struct multipath *
+find_mp_by_wwid (vector mp, char * wwid)
+{
+ int i;
+ struct multipath * mpp;
+
+ vector_foreach_slot (mp, mpp, i)
+ if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
+ return mpp;
+
+ return NULL;
+}
+
+struct multipath *
find_mp (vector mp, char * alias)
{
int i;
Modified: multipath-tools/trunk/libmultipath/structs.h
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.h (original)
+++ multipath-tools/trunk/libmultipath/structs.h Mon Sep 19 12:43:52 2005
@@ -14,17 +14,37 @@
#define SCSI_PRODUCT_SIZE 17
#define SCSI_REV_SIZE 5
-#define KEEP_PATHS 0
-#define FREE_PATHS 1
+enum free_path_switch {
+ KEEP_PATHS,
+ FREE_PATHS
+};
+
+enum rr_weight_mode {
+ RR_WEIGHT_UNDEF,
+ RR_WEIGHT_NONE,
+ RR_WEIGHT_PRIO
+};
+
+enum failback_mode {
+ FAILBACK_UNDEF,
+ FAILBACK_MANUAL,
+ FAILBACK_IMMEDIATE
+};
+
+enum sysfs_buses {
+ SYSFS_BUS_UNDEF,
+ SYSFS_BUS_SCSI,
+ SYSFS_BUS_IDE
+};
enum pathstates {
- PSTATE_RESERVED,
+ PSTATE_UNDEF,
PSTATE_FAILED,
PSTATE_ACTIVE
};
enum pgstates {
- PGSTATE_RESERVED,
+ PGSTATE_UNDEF,
PGSTATE_ENABLED,
PGSTATE_DISABLED,
PGSTATE_ACTIVE
@@ -64,12 +84,16 @@
char rev[SCSI_REV_SIZE];
char serial[SERIAL_SIZE];
char tgt_node_name[NODE_NAME_SIZE];
- unsigned long size;
+ unsigned long long size;
+ unsigned int checkint;
+ unsigned int tick;
int state;
+ int bus;
int dmstate;
int failcount;
- unsigned int priority;
+ int priority;
int claimed;
+ int pgindex;
char * getuid;
char * getprio;
int (*checkfn) (int, char *, void **);
@@ -83,11 +107,15 @@
struct multipath {
char wwid[WWID_SIZE];
+ int minor;
int pgpolicy;
int nextpg;
int queuedio;
int action;
- unsigned long size;
+ int pgfailback;
+ int failback_tick;
+ int rr_weight;
+ unsigned long long size;
vector paths;
vector pg;
char params[PARAMS_SIZE];
@@ -100,6 +128,9 @@
char * hwhandler;
struct mpentry * mpe;
struct hwentry * hwe;
+
+ /* daemon store a data blob for DM event waiter threads */
+ void * waiter;
};
struct pathgroup {
@@ -123,6 +154,9 @@
int store_pathgroup (vector pgvec, struct pathgroup * pgp);
struct multipath * find_mp (vector mp, char * alias);
+struct multipath * find_mp_by_wwid (vector mp, char * wwid);
+struct multipath * find_mp_by_minor (vector mp, int minor);
+
struct path * find_path_by_devt (vector pathvec, char * devt);
struct path * find_path_by_dev (vector pathvec, char * dev);
Added: multipath-tools/trunk/libmultipath/switchgroup.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/switchgroup.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,24 @@
+#include "vector.h"
+#include "structs.h"
+#include "switchgroup.h"
+#include "../libcheckers/path_state.h"
+
+extern void
+select_path_group (struct multipath * mpp)
+{
+ int i, j;
+ int highest = 0;
+ struct pathgroup * pgp;
+ struct path * pp;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ 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;
+ }
+ }
+}
Added: multipath-tools/trunk/libmultipath/switchgroup.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/switchgroup.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1 @@
+void select_path_group (struct multipath * mpp);
Added: multipath-tools/trunk/libmultipath/uevent.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/uevent.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,134 @@
+/*
+ * uevent.c - trigger upon netlink uevents from the kernel
+ *
+ * Only kernels from version 2.6.10* on provide the uevent netlink socket.
+ * Until the libc-kernel-headers are updated, you need to compile with:
+ *
+ * gcc -I /lib/modules/`uname -r`/build/include -o uevent_listen uevent_listen.c
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers at vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/user.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+
+#include "memory.h"
+#include "debug.h"
+#include "uevent.h"
+
+struct uevent * alloc_uevent (void)
+{
+ return (struct uevent *)MALLOC(sizeof(struct uevent));
+}
+
+int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data),
+ void * trigger_data)
+{
+ int sock;
+ struct sockaddr_nl snl;
+ int retval;
+
+ memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+ snl.nl_family = AF_NETLINK;
+ snl.nl_pid = getpid();
+ snl.nl_groups = 0xffffffff;
+
+ sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ if (sock == -1) {
+ condlog(0, "error getting socket, exit\n");
+ exit(1);
+ }
+
+ retval = bind(sock, (struct sockaddr *) &snl,
+ sizeof(struct sockaddr_nl));
+ if (retval < 0) {
+ condlog(0, "bind failed, exit\n");
+ goto exit;
+ }
+
+ while (1) {
+ static char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
+ int i;
+ char *pos;
+ size_t bufpos;
+ ssize_t buflen;
+ struct uevent *uev;
+
+ buflen = recv(sock, &buffer, sizeof(buffer), 0);
+ if (buflen < 0) {
+ condlog(0, "error receiving message\n");
+ continue;
+ }
+
+ if ((size_t)buflen > sizeof(buffer)-1)
+ buflen = sizeof(buffer)-1;
+
+ buffer[buflen] = '\0';
+ uev = alloc_uevent();
+
+ if (!uev) {
+ condlog(1, "lost uevent, oom");
+ continue;
+ }
+
+ /* save start of payload */
+ bufpos = strlen(buffer) + 1;
+
+ /* action string */
+ uev->action = buffer;
+ pos = strchr(buffer, '@');
+ if (!pos)
+ continue;
+ pos[0] = '\0';
+
+ /* sysfs path */
+ uev->devpath = &pos[1];
+
+ /* hotplug events have the environment attached - reconstruct envp[] */
+ for (i = 0; (bufpos < (size_t)buflen) && (i < HOTPLUG_NUM_ENVP-1); i++) {
+ int keylen;
+ char *key;
+
+ key = &buffer[bufpos];
+ keylen = strlen(key);
+ uev->envp[i] = key;
+ bufpos += keylen + 1;
+ }
+ uev->envp[i] = NULL;
+
+ condlog(3, "uevent '%s' from '%s'\n", uev->action, uev->devpath);
+
+ /* print payload environment */
+ for (i = 0; uev->envp[i] != NULL; i++)
+ condlog(3, "%s\n", uev->envp[i]);
+
+ if (uev_trigger && uev_trigger(uev, trigger_data))
+ condlog(0, "uevent trigger error");
+ }
+
+exit:
+ close(sock);
+ return 1;
+}
Added: multipath-tools/trunk/libmultipath/uevent.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/uevent.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,17 @@
+/* environment buffer, the kernel's size in lib/kobject_uevent.c should fit in */
+#define HOTPLUG_BUFFER_SIZE 1024
+#define HOTPLUG_NUM_ENVP 32
+#define OBJECT_SIZE 512
+
+#ifndef NETLINK_KOBJECT_UEVENT
+#define NETLINK_KOBJECT_UEVENT 15
+#endif
+
+struct uevent {
+ char *devpath;
+ char *action;
+ char *envp[HOTPLUG_NUM_ENVP];
+};
+
+int uevent_listen(int (*store_uev)(struct uevent *, void * trigger_data),
+ void * trigger_data);
Modified: multipath-tools/trunk/libmultipath/util.c
==============================================================================
--- multipath-tools/trunk/libmultipath/util.c (original)
+++ multipath-tools/trunk/libmultipath/util.c Mon Sep 19 12:43:52 2005
@@ -4,6 +4,9 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "debug.h"
+#include "memory.h"
+
#define PARAMS_SIZE 255
int
@@ -49,3 +52,45 @@
return 0;
}
+int
+get_word (char * sentence, char ** word)
+{
+ char * p;
+ int len;
+ int skip = 0;
+
+ if (word)
+ *word = NULL;
+
+ while (*sentence == ' ') {
+ sentence++;
+ skip++;
+ }
+ if (*sentence == '\0')
+ return 0;
+
+ p = sentence;
+
+ while (*p != ' ' && *p != '\0')
+ p++;
+
+ len = (int) (p - sentence);
+
+ if (!word)
+ return skip + len;
+
+ *word = MALLOC(len + 1);
+
+ if (!*word) {
+ condlog(0, "get_word : oom\n");
+ return 0;
+ }
+ strncpy(*word, sentence, len);
+ condlog(4, "*word = %s, len = %i", *word, len);
+
+ if (*p == '\0')
+ return 0;
+
+ return skip + len;
+}
+
Modified: multipath-tools/trunk/libmultipath/util.h
==============================================================================
--- multipath-tools/trunk/libmultipath/util.h (original)
+++ multipath-tools/trunk/libmultipath/util.h Mon Sep 19 12:43:52 2005
@@ -4,6 +4,8 @@
int strcmp_chomp(char *, char *);
void basename (char * src, char * dst);
int filepresent (char * run);
+int get_word (char * sentence, char ** word);
+
#define safe_sprintf(var, format, args...) \
snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
Added: multipath-tools/trunk/libmultipath/uxsock.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/uxsock.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+
+#include "memory.h"
+#include "uxsock.h"
+
+/*
+ * connect to a unix domain socket
+ */
+int ux_socket_connect(const char *name)
+{
+ int fd;
+ struct sockaddr_un addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ return -1;
+ }
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * create a unix domain socket and start listening on it
+ * return a file descriptor open on the socket
+ */
+int ux_socket_listen(const char *name)
+{
+ int fd;
+ struct sockaddr_un addr;
+
+ /* get rid of any old socket */
+ unlink(name);
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 10) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * keep writing until its all sent
+ */
+int 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;
+ buf = n + (char *)buf;
+ len -= n;
+ total += n;
+ }
+ return total;
+}
+
+/*
+ * keep reading until its all read
+ */
+int 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;
+ buf = n + (char *)buf;
+ len -= n;
+ total += n;
+ }
+ return total;
+}
+
+/*
+ * send a packet in length prefix format
+ */
+int send_packet(int fd, const char *buf, size_t len)
+{
+ if (write_all(fd, &len, sizeof(len)) != sizeof(len)) return -1;
+ if (write_all(fd, buf, len) != len) return -1;
+ return 0;
+}
+
+/*
+ * receive a packet in length prefix format
+ */
+int recv_packet(int fd, char **buf, size_t *len)
+{
+ if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
+ (*buf) = MALLOC(*len);
+ if (read_all(fd, *buf, *len) != *len) {
+ FREE(*buf);
+ return -1;
+ }
+ return 0;
+}
Added: multipath-tools/trunk/libmultipath/uxsock.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/uxsock.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,6 @@
+/* some prototypes */
+int ux_socket_connect(const char *name);
+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);
+
Modified: multipath-tools/trunk/libmultipath/vector.c
==============================================================================
--- multipath-tools/trunk/libmultipath/vector.c (original)
+++ multipath-tools/trunk/libmultipath/vector.c Mon Sep 19 12:43:52 2005
@@ -63,6 +63,18 @@
return v->slot[slot];
}
+int
+find_slot(vector v, void * addr)
+{
+ int i;
+
+ for (i = 0; i < (v->allocated / VECTOR_DEFAULT_SIZE); i++)
+ if (v->slot[i] == addr)
+ return i;
+
+ return -1;
+}
+
void
vector_del_slot(vector v, int slot)
{
@@ -76,12 +88,27 @@
v->allocated -= VECTOR_DEFAULT_SIZE;
- if (!v->allocated)
+ if (!v->allocated) {
+ FREE(v->slot);
v->slot = NULL;
+ }
else
v = REALLOC(v->slot, sizeof (void *) * v->allocated);
}
+void
+vector_repack(vector v)
+{
+ int i;
+
+ if (!v->allocated)
+ return;
+
+ for (i = 0; i < (v->allocated / VECTOR_DEFAULT_SIZE); i++)
+ if (i > 0 && v->slot[i] == NULL)
+ vector_del_slot(v, i--);
+}
+
/* Free memory vector allocation */
void
vector_free(vector v)
@@ -104,8 +131,8 @@
if (!strvec)
return;
- for (i = 0; i < VECTOR_SIZE(strvec); i++)
- if ((str = VECTOR_SLOT(strvec, i)) != NULL)
+ vector_foreach_slot (strvec, str, i)
+ if (str)
FREE(str);
vector_free(strvec);
Modified: multipath-tools/trunk/libmultipath/vector.h
==============================================================================
--- multipath-tools/trunk/libmultipath/vector.h (original)
+++ multipath-tools/trunk/libmultipath/vector.h Mon Sep 19 12:43:52 2005
@@ -46,6 +46,8 @@
extern void vector_set_slot(vector v, void *value);
extern void vector_del_slot(vector v, int slot);
extern void *vector_insert_slot(vector v, int slot, void *value);
+int find_slot(vector v, void * addr);
+extern void vector_repack(vector v);
extern void vector_dump(vector v);
extern void dump_strvec(vector strvec);
Modified: multipath-tools/trunk/multipath.conf.annotated
==============================================================================
--- multipath-tools/trunk/multipath.conf.annotated (original)
+++ multipath-tools/trunk/multipath.conf.annotated Mon Sep 19 12:43:52 2005
@@ -1,342 +1,279 @@
+##
+## This is a template multipath-tools configuration file
+## Uncomment the lines relevent to your environment
+##
#
-# name : defaults
-# desc : multipath-tools default settings
+##
+## name : defaults
+## desc : multipath-tools default settings
+##
+#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"
#
-defaults {
- #
- # name : multipath_tool
- # scope : multipathd
- # desc : the tool in charge of configuring the multipath device maps
- # default : "/sbin/multipath -v 0 -S"
- #
- multipath_tool "/sbin/multipath -v 0 -S"
-
- #
- # name : udev_dir
- # desc : directory where udev creates its device nodes
- # default : /dev
- #
- udev_dir /dev
-
- #
- # name : polling_interval
- # scope : multipathd
- # desc : interval between two path checks in seconds
- # default : 5
- #
- polling_interval 10
-
- #
- # name : default_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"
-
- #
- # name : default_path_grouping_policy
- # scope : multipath
- # desc : the default path grouping policy to apply to unspecified
- # multipaths
- # default : multibus
- #
- default_path_grouping_policy multibus
-
- #
- # name : default_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"
-
- #
- # name : default_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
- # default : /bin/false
- #
- default_prio_callout "/bin/false"
-
- #
- # name : rr_min_io
- # scope : multipath
- # desc : the number of IO to route to a path before switching
- # to the next in the same path group
- # default : 1000
- #
- r_min_io 100
-}
-
-#
-# name : blacklist
-# scope : multipath & multipathd
-# desc : list of device names to discard as not multipath candidates
-# default : cciss, fd, hd, md, dm, sr, scd, st, ram, raw, loop
-#
-blacklist {
- 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]*]"
-}
-
-#
-# name : multipaths
-# scope : multipath & multipathd
-# desc : list of multipaths finest-grained settings
-#
-multipaths {
- #
- # name : multipath
- # scope : multipath & multipathd
- # desc : container for settings that apply to one specific multipath
- #
- multipath {
- #
- # name : wwid
- # scope : multipath & multipathd
- # desc : index of the container
- #
- wwid 3600508b4000156d700012000000b0000
-
- #
- # name : alias
- # scope : multipath
- # desc : symbolic name for the multipath
- #
- alias yellow
-
- #
- # name : path_grouping_policy
- # scope : multipath
- # desc : path grouping policy to apply to this multipath
- # values : failover, multibus, group_by_serial
- # default : failover
- #
- path_grouping_policy multibus
-
- #
- # name : path_checker
- # scope : multipathd
- # desc : path checking alorithm to use to check path state
- # values : readsector0, tur
- # default : readsector0
- #
- # path_checker readsector0
-
- #
- # name : path_selector
- # desc : the path selector algorithm to use for this mpath
- # these algo are offered by the kernel mpath target
- # values : "round-robin 0"
- # default : "round-robin 0"
- #
- path_selector "round-robin 0"
- }
- multipath {
- wwid 1DEC_____321816758474
- alias red
- }
-}
-
-#
-# name : devices
-# scope : multipath & multipathd
-# desc : list of per storage controler settings
-# overrides default settings (device_maps block)
-# overriden by per multipath settings (multipaths block)
-#
-devices {
- #
- # name : device
- # scope : multipath & multipathd
- # desc : settings for this specific storage controler
- #
- device {
- #
- # name : vendor, product
- # scope : multipath & multipathd
- # desc : index for the block
- #
- vendor "COMPAQ "
- product "HSV110 (C)COMPAQ"
-
- #
- # name : path_grouping_policy
- # scope : multipath
- # desc : path grouping policy to apply to multipath hosted
- # by this storage controler
- # values : failover = 1 path per priority group
- # multibus = all valid paths in 1 priority
- # group
- # group_by_serial = 1 priority group per detected
- # serial number
- # default : failover
- #
- path_grouping_policy multibus
-
- #
- # name : getuid_callout
- # scope : multipath
- # desc : the program and args to callout to obtain a unique
- # path identifier. Absolute path required
- # default : /sbin/scsi_id -g -u -s
- #
- getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
-
- #
- # name : prio_callout
- # scope : multipath
- # desc : the program and args to callout to obtain a path
- # weight. Weights are summed for each path group to
- # determine the next PG to use case of failure.
- # default : no callout, all paths equals
- #
- prio_callout "/sbin/pp_balance_units %d"
-
- #
- # name : path_checker
- # scope : multipathd
- # desc : path checking alorithm to use to check path state
- # values : readsector0, tur
- # default : readsector0
- #
- path_checker readsector0
-
- #
- # name : path_selector
- # desc : the path selector algorithm to use for this mpath
- # these algo are offered by the kernel mpath target
- # values : "round-robin 0"
- # default : "round-robin 0"
- #
- path_selector "round-robin 0"
- }
- device {
- vendor "COMPAQ "
- product "MSA1000 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "COMPAQ "
- product "MSA1000 VOLUME "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "DEC "
- product "HSG80 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HP "
- product "HSV100 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "3PARdata"
- product "VV "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "DDN "
- product "SAN DataDirector"
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "FSC "
- product "CentricStor "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF400 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF500 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF600 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "IBM "
- product "ProFibre 4000R "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "IBM "
- product "3542 "
- path_grouping_policy group_by_serial
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9100 "
- vendor "COMPAQ "
- product "MSA1000 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9300 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9400 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9500 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- # all paths active but with a switchover latency
- # LSI controlers
- vendor "STK "
- product "OPENstorage D280"
- path_grouping_policy group_by_serial
- path_checker tur
- }
- device {
- # assymmetric array
- vendor "SUN "
- product "StorEdge 3510 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- # symmetric array
- vendor "SUN "
- product "T4 "
- path_grouping_policy multibus
- path_checker tur
- }
-}
+# #
+# # name : udev_dir
+# # desc : directory where udev creates its device nodes
+# # default : /dev
+# #
+# udev_dir /dev
+#
+# #
+# # name : polling_interval
+# # scope : multipathd
+# # desc : interval between two path checks in seconds
+# # default : 5
+# #
+# polling_interval 10
+#
+# #
+# # name : default_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"
+#
+# #
+# # name : default_path_grouping_policy
+# # scope : multipath
+# # desc : the default path grouping policy to apply to unspecified
+# # multipaths
+# # default : multibus
+# #
+# default_path_grouping_policy multibus
+#
+# #
+# # name : default_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"
+#
+# #
+# # name : default_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"
+#
+# #
+# # name : rr_min_io
+# # scope : multipath
+# # desc : the number of IO to route to a path before switching
+# # to the next in the same path group
+# # default : 1000
+# #
+# r_min_io 100
+#
+# #
+# # name : rr_weight
+# # scope : multipath
+# # desc : if set to priorities the multipath configurator will assign
+# # path weights as "path prio * rr_min_io"
+# # values : priorities|uniform
+# # default : uniform
+# #
+# rr_weight priorities
+#
+# #
+# # name : failback
+# # scope : multipathd
+# # desc : tell the daemon to manage path group failback, or not to.
+# # 0 means immediate failback, values >0 means deffered failback
+# # expressed in seconds.
+# # values : manual|immediate|n > 0
+# # default : immediate
+# #
+# failback manual
+#}
+#
+##
+## name : blacklist
+## scope : multipath & multipathd
+## desc : list of device names to discard as not multipath candidates
+## default : cciss, fd, hd, md, dm, sr, scd, st, ram, raw, loop
+##
+#blacklist {
+# 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]*]"
+#}
+#
+##
+## name : multipaths
+## scope : multipath & multipathd
+## desc : list of multipaths finest-grained settings
+##
+#multipaths {
+# #
+# # name : multipath
+# # scope : multipath & multipathd
+# # desc : container for settings that apply to one specific multipath
+# #
+# multipath {
+# #
+# # name : wwid
+# # scope : multipath & multipathd
+# # desc : index of the container
+# #
+# wwid 3600508b4000156d700012000000b0000
+#
+# #
+# # name : alias
+# # scope : multipath
+# # desc : symbolic name for the multipath
+# #
+# alias yellow
+#
+# #
+# # name : path_grouping_policy
+# # scope : multipath
+# # desc : path grouping policy to apply to this multipath
+# # values : failover, multibus, group_by_serial
+# # default : failover
+# #
+# path_grouping_policy multibus
+#
+# #
+# # name : path_checker
+# # scope : multipathd
+# # desc : path checking alorithm to use to check path state
+# # values : readsector0, tur
+# # default : readsector0
+# #
+# # path_checker readsector0
+#
+# #
+# # name : path_selector
+# # desc : the path selector algorithm to use for this mpath
+# # these algo are offered by the kernel mpath target
+# # values : "round-robin 0"
+# # default : "round-robin 0"
+# #
+# path_selector "round-robin 0"
+#
+# #
+# # name : failback
+# # scope : multipathd
+# # desc : tell the daemon to manage path group failback, or not to.
+# # 0 means immediate failback, values >0 means deffered failback
+# # expressed in seconds.
+# # values : manual|immediate|n > 0
+# # default : immediate
+# #
+# failback manual
+# }
+# multipath {
+# wwid 1DEC_____321816758474
+# alias red
+# rr_weight priorities
+# }
+#}
+#
+##
+## name : devices
+## scope : multipath & multipathd
+## desc : list of per storage controler settings
+## overrides default settings (device_maps block)
+## overriden by per multipath settings (multipaths block)
+##
+#devices {
+# #
+# # name : device
+# # scope : multipath & multipathd
+# # desc : settings for this specific storage controler
+# #
+# device {
+# #
+# # name : vendor, product
+# # scope : multipath & multipathd
+# # desc : index for the block
+# #
+# vendor "COMPAQ "
+# product "HSV110 (C)COMPAQ"
+#
+# #
+# # name : path_grouping_policy
+# # scope : multipath
+# # desc : path grouping policy to apply to multipath hosted
+# # by this storage controler
+# # values : failover = 1 path per priority group
+# # multibus = all valid paths in 1 priority
+# # group
+# # group_by_serial = 1 priority group per detected
+# # serial number
+# # default : failover
+# #
+# path_grouping_policy multibus
+#
+# #
+# # name : getuid_callout
+# # scope : multipath
+# # desc : the program and args to callout to obtain a unique
+# # path identifier. Absolute path required
+# # default : /sbin/scsi_id -g -u -s
+# #
+# getuid_callout "/sbin/scsi_id -g -u -s /block/%n"
+#
+# #
+# # name : prio_callout
+# # scope : multipath
+# # desc : the program and args to callout to obtain a path
+# # weight. Weights are summed for each path group to
+# # determine the next PG to use case of failure.
+# # "none" is a valid value.
+# # default : no callout, all paths equals
+# #
+# prio_callout "/sbin/mpath_prio_balance_units %d"
+#
+# #
+# # name : path_checker
+# # scope : multipathd
+# # desc : path checking alorithm to use to check path state
+# # values : readsector0, tur
+# # default : readsector0
+# #
+# path_checker readsector0
+#
+# #
+# # name : path_selector
+# # desc : the path selector algorithm to use for this mpath
+# # these algo are offered by the kernel mpath target
+# # values : "round-robin 0"
+# # default : "round-robin 0"
+# #
+# path_selector "round-robin 0"
+#
+# #
+# # name : failback
+# # scope : multipathd
+# # desc : tell the daemon to manage path group failback, or not to.
+# # 0 means immediate failback, values >0 means deffered failback
+# # expressed in seconds.
+# # values : manual|immediate|n > 0
+# # default : immediate
+# #
+# failback 30
+# }
+# device {
+# vendor "COMPAQ "
+# product "MSA1000 "
+# path_grouping_policy multibus
+# path_checker tur
+# rr_weight priorities
+# }
+#}
Modified: multipath-tools/trunk/multipath.conf.synthetic
==============================================================================
--- multipath-tools/trunk/multipath.conf.synthetic (original)
+++ multipath-tools/trunk/multipath.conf.synthetic Mon Sep 19 12:43:52 2005
@@ -1,162 +1,57 @@
-defaults {
- multipath_tool "/sbin/multipath -v 0 -S"
- 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/false"
- default_features "0"
- rr_wmin_io 100
-}
-devnode_blacklist {
- 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]*]"
-}
-multipaths {
- multipath {
- wwid 3600508b4000156d700012000000b0000
- alias yellow
- path_grouping_policy multibus
- path_checker readsector0
- path_selector "round-robin 0"
- }
- multipath {
- wwid 1DEC_____321816758474
- alias red
- }
-}
-devices {
- device {
- vendor "COMPAQ "
- product "HSV110 (C)COMPAQ"
- path_grouping_policy multibus
- 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"
- }
- device {
- vendor "COMPAQ "
- product "MSA1000 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "COMPAQ "
- product "MSA1000 VOLUME "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "DEC "
- product "HSG80 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HP "
- product "HSV100 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "3PARdata"
- product "VV "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "IBM "
- product "3542 "
- path_grouping_policy group_by_serial
- path_checker tur
- }
- device {
- vendor "DDN "
- product "SAN DataDirector"
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "FSC "
- product "CentricStor "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF400 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF500 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "HITACHI "
- product "DF600 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "IBM "
- product "ProFibre 4000R "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9100 "
- vendor "COMPAQ "
- product "MSA1000 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9300 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9400 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- vendor "SGI "
- product "TP9500 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- # all paths active but with a switchover latency
- # LSI controlers
- vendor "STK "
- product "OPENstorage D280"
- path_grouping_policy group_by_serial
- path_checker tur
- }
- device {
- # assymmetric array
- vendor "SUN "
- product "StorEdge 3510 "
- path_grouping_policy multibus
- path_checker tur
- }
- device {
- # symmetric array
- vendor "SUN "
- product "T4 "
- path_grouping_policy multibus
- path_checker tur
- }
-}
+##
+## This is a template multipath-tools configuration file
+## 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"
+# rr_min_io 100
+# rr_weight priorities
+# failback immediate
+#}
+#devnode_blacklist {
+# 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]*]"
+#}
+#multipaths {
+# multipath {
+# wwid 3600508b4000156d700012000000b0000
+# alias yellow
+# path_grouping_policy multibus
+# path_checker readsector0
+# path_selector "round-robin 0"
+# failback manual
+# rr_weight priorities
+# }
+# multipath {
+# wwid 1DEC_____321816758474
+# alias red
+# }
+#}
+#devices {
+# device {
+# vendor "COMPAQ "
+# product "HSV110 (C)COMPAQ"
+# path_grouping_policy multibus
+# 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
+# }
+# device {
+# vendor "COMPAQ "
+# product "MSA1000 "
+# path_grouping_policy multibus
+# }
+#}
Modified: multipath-tools/trunk/multipath/Makefile
==============================================================================
--- multipath-tools/trunk/multipath/Makefile (original)
+++ multipath-tools/trunk/multipath/Makefile Mon Sep 19 12:43:52 2005
@@ -21,7 +21,7 @@
all: $(BUILD)
prepare:
- make -C $(multipathdir) clean
+ make -C $(multipathdir) prepare
rm -f core *.o *.gz
glibc: prepare $(OBJS)
@@ -43,7 +43,6 @@
install:
install -d $(DESTDIR)$(bindir)
install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
- install -d $(DESTDIR)/var/cache/multipath/
install -d $(DESTDIR)/etc/dev.d/block/
install -m 755 multipath.dev $(DESTDIR)/etc/dev.d/block/
install -d $(DESTDIR)/etc/udev/rules.d
Modified: multipath-tools/trunk/multipath/main.c
==============================================================================
--- multipath-tools/trunk/multipath/main.c (original)
+++ multipath-tools/trunk/multipath/main.c Mon Sep 19 12:43:52 2005
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <signal.h>
#include <parser.h>
#include <vector.h>
@@ -40,12 +39,17 @@
#include <propsel.h>
#include <discovery.h>
#include <debug.h>
+#include <switchgroup.h>
#include <sysfs/libsysfs.h>
+#include <print.h>
#include "main.h"
#include "pgpolicies.h"
#include "dict.h"
+/* for column aligned output */
+struct path_layout pl;
+
static char *
get_refwwid (vector pathvec)
{
@@ -67,13 +71,15 @@
if (!pp)
return NULL;
+ strncpy(pp->dev, buff, FILE_NAME_SIZE);
+
+ if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+ return NULL;
+
if (store_path(pathvec, pp)) {
free_path(pp);
return NULL;
}
- strncpy(pp->dev, buff, FILE_NAME_SIZE);
- if (devinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
- return NULL;
}
refwwid = MALLOC(WWID_SIZE);
@@ -95,18 +101,19 @@
if (!pp)
return NULL;
- if (store_path(pathvec, pp)) {
- free_path(pp);
- return NULL;
- }
devt2devname(conf->dev, buff);
if(safe_sprintf(pp->dev, "%s", buff)) {
fprintf(stderr, "pp->dev too small\n");
exit(1);
}
- if (devinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+ if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+ return NULL;
+
+ if (store_path(pathvec, pp)) {
+ free_path(pp);
return NULL;
+ }
}
refwwid = MALLOC(WWID_SIZE);
@@ -141,70 +148,20 @@
return NULL;
}
-/*
- * print_path styles
- */
-#define PRINT_PATH_ALL 0
-#define PRINT_PATH_SHORT 1
-
static void
-print_path (struct path * pp, int style)
+print_path (struct path * pp, char * style)
{
- if (style != PRINT_PATH_SHORT && pp->wwid)
- printf ("%s ", pp->wwid);
- else
- printf (" \\_ ");
-
- printf("%i:%i:%i:%i ",
- pp->sg_id.host_no,
- pp->sg_id.channel,
- pp->sg_id.scsi_id,
- pp->sg_id.lun);
-
- if (pp->dev)
- printf("%-4s ", pp->dev);
-
- if (pp->dev_t)
- printf("%-7s ", pp->dev_t);
-
- switch (pp->state) {
- case PATH_UP:
- printf("[ready ]");
- break;
- case PATH_DOWN:
- printf("[faulty]");
- break;
- case PATH_SHAKY:
- printf("[shaky ]");
- break;
- default:
- printf("[undef ]");
- break;
- }
- switch (pp->dmstate) {
- case PSTATE_ACTIVE:
- printf("[active]");
- break;
- case PSTATE_FAILED:
- printf("[failed]");
- break;
- default:
- break;
- }
- if (pp->claimed)
- printf("[claimed]");
-
- if (style != PRINT_PATH_SHORT && pp->product_id)
- printf("[%.16s]", pp->product_id);
+ char buff[MAX_LINE_LEN];
- fprintf(stdout, "\n");
+ snprint_path(&buff[0], MAX_LINE_LEN, style, pp, &pl);
+ printf("%s", buff);
}
static void
print_map (struct multipath * mpp)
{
if (mpp->size && mpp->params)
- printf("0 %lu %s %s\n",
+ printf("0 %llu %s %s\n",
mpp->size, DEFAULT_TARGET, mpp->params);
return;
}
@@ -216,7 +173,7 @@
struct path * pp;
vector_foreach_slot (pathvec, pp, i)
- print_path(pp, PRINT_PATH_ALL);
+ print_path(pp, PRINT_PATH_LONG);
}
static void
@@ -260,14 +217,14 @@
printf("\n");
- if (mpp->size < 2000)
- printf("[size=%lu kB]", mpp->size / 2);
- else if (mpp->size < (2000 * 1024))
- printf("[size=%lu MB]", mpp->size / 2 / 1024);
- else if (mpp->size < (2000 * 1024 * 1024))
- printf("[size=%lu GB]", mpp->size / 2 / 1024 / 1024);
+ if (mpp->size < (1 << 11))
+ printf("[size=%llu kB]", mpp->size >> 1);
+ else if (mpp->size < (1 << 21))
+ printf("[size=%llu MB]", mpp->size >> 11);
+ else if (mpp->size < (1 << 31))
+ printf("[size=%llu GB]", mpp->size >> 21);
else
- printf("[size=%lu TB]", mpp->size / 2 / 1024 / 1024 / 1024);
+ printf("[size=%llu TB]", mpp->size >> 31);
if (mpp->features)
printf("[features=\"%s\"]", mpp->features);
@@ -283,8 +240,17 @@
vector_foreach_slot (mpp->pg, pgp, j) {
printf("\\_ ");
- if (mpp->selector)
+ if (mpp->selector) {
printf("%s ", mpp->selector);
+#if 0
+ /* align to path status info */
+ for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
+ i > strlen(mpp->selector); i--)
+ printf(" ");
+#endif
+ }
+ if (pgp->priority)
+ printf("[prio=%i]", pgp->priority);
switch (pgp->status) {
case PGSTATE_ENABLED:
@@ -299,13 +265,10 @@
default:
break;
}
- if (mpp->nextpg && mpp->nextpg == j + 1)
- printf("[first]");
-
printf("\n");
vector_foreach_slot (pgp->paths, pp, i)
- print_path(pp, PRINT_PATH_SHORT);
+ print_path(pp, PRINT_PATH_INDENT);
}
printf("\n");
}
@@ -338,6 +301,7 @@
{
int i, j;
int shift, freechar;
+ int minio;
char * p;
struct pathgroup * pgp;
struct path * pp;
@@ -368,8 +332,13 @@
freechar -= shift;
vector_foreach_slot (pgp->paths, pp, j) {
+ minio = conf->minio;
+
+ if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
+ minio *= pp->priority;
+
shift = snprintf(p, freechar, " %s %d",
- pp->dev_t, conf->minio);
+ pp->dev_t, minio);
if (shift >= freechar) {
fprintf(stderr, "mp->params too small\n");
return 1;
@@ -394,9 +363,7 @@
setup_map (struct multipath * mpp)
{
struct path * pp;
- struct pathgroup * pgp;
- int i, j;
- int highest = 0;
+ int i;
/*
* don't bother if devmap size is unknown
@@ -408,10 +375,10 @@
/*
* don't bother if a constituant path is claimed
- * FIXME : claimed detection broken, always unclaimed for now
+ * (not by the device mapper driver)
*/
vector_foreach_slot (mpp->paths, pp, i) {
- if (pp->claimed) {
+ if (pp->claimed && pp->dmstate == PSTATE_UNDEF) {
condlog(3, "%s claimed", pp->dev);
return 1;
}
@@ -424,6 +391,7 @@
select_selector(mpp);
select_features(mpp);
select_hwhandler(mpp);
+ select_rr_weight(mpp);
/*
* apply selected grouping policy to valid paths
@@ -455,19 +423,9 @@
/*
* ponders each path group and determine highest prio pg
+ * to switch over (default to first)
*/
- mpp->nextpg = 1;
- vector_foreach_slot (mpp->pg, pgp, i) {
- vector_foreach_slot (pgp->paths, pp, j) {
- pgp->id ^= (long)pp;
- if (pp->state != PATH_DOWN)
- pgp->priority += pp->priority;
- }
- if (pgp->priority > highest) {
- highest = pgp->priority;
- mpp->nextpg = i + 1;
- }
- }
+ select_path_group(mpp);
/*
* transform the mp->pg vector of vectors of paths
@@ -495,41 +453,38 @@
return count;
}
-/*
- * detect if a path is in the map we are about to create but not in the
- * current one (triggers a valid reload)
- * if a path is in the current map but not in the one we are about to create,
- * don't reload : it may come back latter so save the reload burden
- */
+static void
+compute_pgid(struct pathgroup * pgp)
+{
+ struct path * pp;
+ int i;
+
+ vector_foreach_slot (pgp->paths, pp, i)
+ pgp->id ^= (long)pp;
+}
+
static int
-pgcmp2 (struct multipath * mpp, struct multipath * cmpp)
+pgcmp (struct multipath * mpp, struct multipath * cmpp)
{
- int i, j, k, l;
+ int i, j;
struct pathgroup * pgp;
struct pathgroup * cpgp;
- struct path * pp;
- struct path * cpp;
- int found = 0;
+ int r = 0;
vector_foreach_slot (mpp->pg, pgp, i) {
- vector_foreach_slot (pgp->paths, pp, j) {
- vector_foreach_slot (cmpp->pg, cpgp, k) {
- vector_foreach_slot (cpgp->paths, cpp, l) {
- if (pp == cpp) {
- found = 1;
- break;
- }
- }
- if (found)
- break;
+ compute_pgid(pgp);
+
+ vector_foreach_slot (cmpp->pg, cpgp, j) {
+ if (pgp->id == cpgp->id) {
+ r = 0;
+ break;
}
- if (found)
- found = 0;
- else
- return 1;
+ r++;
}
+ if (r)
+ return r;
}
- return 0;
+ return r;
}
static void
@@ -540,6 +495,13 @@
cmpp = find_mp(curmp, mpp->alias);
if (!cmpp) {
+ cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+
+ if (cmpp && !conf->dry_run) {
+ condlog(2, "remove: %s (dup of %s)",
+ cmpp->alias, mpp->alias);
+ dm_flush_map(cmpp->alias, DEFAULT_TARGET);
+ }
mpp->action = ACT_CREATE;
return;
}
@@ -576,7 +538,7 @@
mpp->action = ACT_RELOAD;
return;
}
- if (pgcmp2(mpp, cmpp)) {
+ if (pgcmp(mpp, cmpp)) {
condlog(3, "different path group topology");
mpp->action = ACT_RELOAD;
return;
@@ -625,10 +587,14 @@
/*
* last chance to quit before touching the devmaps
*/
- if (conf->dry_run || mpp->action == ACT_NOTHING)
+ if (conf->dry_run)
+ return 0;
+
+ switch (mpp->action) {
+ case ACT_NOTHING:
return 0;
- if (mpp->action == ACT_SWITCHPG) {
+ case ACT_SWITCHPG:
dm_switchgroup(mpp->alias, mpp->nextpg);
/*
* we may have avoided reinstating paths because there where in
@@ -637,12 +603,18 @@
*/
reinstate_paths(mpp);
return 0;
- }
- if (mpp->action == ACT_CREATE)
+
+ case ACT_CREATE:
op = DM_DEVICE_CREATE;
+ break;
- if (mpp->action == ACT_RELOAD)
+ case ACT_RELOAD:
op = DM_DEVICE_RELOAD;
+ break;
+
+ default:
+ break;
+ }
/*
@@ -759,39 +731,10 @@
}
static void
-signal_daemon (void)
-{
- FILE *file;
- pid_t pid;
- char *buf;
-
- buf = MALLOC(8);
-
- if (!buf)
- return;
-
- file = fopen(DEFAULT_PIDFILE, "r");
-
- if (!file) {
- condlog(1, "cannot signal daemon, pidfile not found");
- FREE(buf);
- return;
- }
-
- buf = fgets(buf, 8, file);
- fclose(file);
-
- pid = (pid_t)atol(buf);
- FREE(buf);
-
- kill(pid, SIGHUP);
-}
-
-static void
usage (char * progname)
{
fprintf (stderr, VERSION_STRING);
- fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l] [-S]\n",
+ fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
progname);
fprintf (stderr,
"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
@@ -803,8 +746,9 @@
"\t 2\t\t\tdefault verbosity\n" \
"\t 3\t\t\tprint debug information\n" \
"\t-d\t\tdry run, do not create or update devmaps\n" \
- "\t-l\t\tlist the current multipath topology\n" \
- "\t-S\t\tinhibit signal sending to multipathd\n"
+ "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
+ "\t-ll\t\tshow multipath topology (maximum info)\n" \
+ "\t-F\t\tflush a multipath device map\n" \
"\t-F\t\tflush all multipath device maps\n" \
"\t-p policy\tforce all maps to specified policy :\n" \
"\t failover\t\t1 path per priority group\n" \
@@ -822,25 +766,33 @@
}
static int
-update_pathvec (vector pathvec)
+update_paths (struct multipath * mpp)
{
- int i;
+ int i, j;
+ struct pathgroup * pgp;
struct path * pp;
- vector_foreach_slot (pathvec, pp, i) {
- if (pp->dev && pp->dev_t && strlen(pp->dev) == 0) {
- devt2devname(pp->dev, pp->dev_t);
- devinfo(pp, conf->hwtable,
- DI_SYSFS | DI_CHECKER | DI_SERIAL | DI_PRIO);
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (!strlen(pp->dev)) {
+ devt2devname(pp->dev, pp->dev_t);
+ pathinfo(pp, conf->hwtable,
+ DI_SYSFS | DI_CHECKER | \
+ DI_SERIAL | DI_PRIO);
+ continue;
+ }
+ if (pp->state == PATH_UNCHECKED)
+ pathinfo(pp, conf->hwtable, DI_CHECKER);
+
+ if (!pp->priority)
+ pathinfo(pp, conf->hwtable, DI_PRIO);
}
- if (pp->checkfn && pp->state == PATH_UNCHECKED)
- pp->state = pp->checkfn(pp->fd, NULL, NULL);
}
return 0;
}
static int
-get_current_mp (vector curmp, vector pathvec, char * refwwid)
+get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
{
int i;
struct multipath * mpp;
@@ -853,18 +805,29 @@
wwid = get_mpe_wwid(mpp->alias);
if (wwid) {
- strncpy(mpp->wwid, wwid, WWID_SIZE);
+ /* out of specified scope */
+ if (refwwid && strncmp(wwid, refwwid, WWID_SIZE))
+ continue;
wwid = NULL;
- } else
- strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
-
- if (refwwid && strncmp(mpp->wwid, refwwid, WWID_SIZE))
- continue;
+ }
condlog(3, "params = %s", mpp->params);
condlog(3, "status = %s", mpp->status);
+
+ /* will set mpp->wwid */
disassemble_map(pathvec, mpp->params, mpp);
- update_pathvec(pathvec);
+
+ /*
+ * disassemble_map may have added new paths to pathvec.
+ * If not in "fast list mode", we need to fetch information
+ * about them
+ */
+ if (conf->list != 1)
+ update_paths(mpp);
+
+ if (conf->list > 1)
+ select_path_group(mpp);
+
disassemble_status(mpp->status, mpp);
if (conf->list)
@@ -882,15 +845,20 @@
vector curmp = NULL;
vector pathvec = NULL;
int i;
+ int di_flag = 0;
int arg;
extern char *optarg;
extern int optind;
char * refwwid = NULL;
- if (dm_prereq(DEFAULT_TARGET, 1, 0, 3)) {
- condlog(0, "device mapper prerequisites not met");
+ if (getuid() != 0) {
+ fprintf(stderr, "need to be root\n");
exit(1);
}
+
+ if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
+ exit(1);
+
if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
condlog(0, "multipath tools need sysfs mounted");
exit(1);
@@ -898,7 +866,7 @@
if (load_config(DEFAULT_CONFIGFILE))
exit(1);
- while ((arg = getopt(argc, argv, ":qdlFSi:M:v:p:")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
break;
@@ -911,25 +879,26 @@
break;
case 'd':
conf->dry_run = 1;
- conf->signal = 0;
+ break;
+ case 'f':
+ conf->remove = 1;
break;
case 'F':
- dm_flush_maps(DEFAULT_TARGET);
- goto out;
+ conf->remove = 2;
break;
case 'l':
conf->list = 1;
conf->dry_run = 1;
- conf->signal = 0;
+
+ if (optarg && !strncmp(optarg, "l", 1))
+ conf->list++;
+
break;
case 'M':
#if _DEBUG_
debug = atoi(optarg);
#endif
break;
- case 'S':
- conf->signal = 0;
- break;
case 'p':
conf->pgpolicy_flag = get_pgpolicy_id(optarg);
if (conf->pgpolicy_flag == -1) {
@@ -964,6 +933,19 @@
}
+ if (conf->remove == FLUSH_ONE) {
+ if (conf->dev_type == DEV_DEVMAP)
+ dm_flush_map(conf->dev, DEFAULT_TARGET);
+ else
+ condlog(0, "must provide a map name to remove");
+
+ goto out;
+ }
+ else if (conf->remove == FLUSH_ALL) {
+ dm_flush_maps(DEFAULT_TARGET);
+ goto out;
+ }
+
/*
* allocate core vectors to store paths and multipaths
*/
@@ -981,15 +963,31 @@
if (conf->dev && blacklist(conf->blist, conf->dev))
goto out;
- if (!cache_cold(CACHE_EXPIRE)) {
- condlog(3, "load path identifiers cache");
- cache_load(pathvec);
+ 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 (path_discovery(pathvec, conf, DI_CHECKER) || VECTOR_SIZE(pathvec) == 0)
+ 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) {
@@ -998,11 +996,11 @@
}
refwwid = get_refwwid(pathvec);
+ get_path_layout(&pl, pathvec);
- if (get_current_mp(curmp, pathvec, refwwid))
+ if (get_dm_mpvec(curmp, pathvec, refwwid))
goto out;
- cache_dump(pathvec);
filter_pathvec(pathvec, refwwid);
if (conf->list)
@@ -1014,18 +1012,14 @@
coalesce_paths(curmp, pathvec);
out:
- /*
- * signal multipathd that new devmaps may have come up
- */
- if (conf->signal)
- signal_daemon();
-
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
Modified: multipath-tools/trunk/multipath/main.h
==============================================================================
--- multipath-tools/trunk/multipath/main.h (original)
+++ multipath-tools/trunk/multipath/main.h Mon Sep 19 12:43:52 2005
@@ -35,13 +35,16 @@
ACT_CREATE
};
+#define FLUSH_ONE 1
+#define FLUSH_ALL 2
+
/*
* Build version
*/
#define PROG "multipath"
-#define VERSION_CODE 0x000404
-#define DATE_CODE 0x100405
+#define VERSION_CODE 0x000405
+#define DATE_CODE 0x100605
#define MULTIPATH_VERSION(version) \
(version >> 16) & 0xFF, \
Modified: multipath-tools/trunk/multipath/multipath.8
==============================================================================
--- multipath-tools/trunk/multipath/multipath.8 (original)
+++ multipath-tools/trunk/multipath/multipath.8 Mon Sep 19 12:43:52 2005
@@ -6,12 +6,9 @@
.RB [\| \-v\ \c
.IR verbosity \|]
.RB [\| \-d \|]
-.RB [\| \-l \|]
-.RB [\| \-i\ \c
-.IR int \|]
+.RB [\| \-l | \-ll | \-f | \-F \|]
.RB [\| \-p\ \c
.BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|]
-.RB [\| -S \|]
.RB [\| device \|]
.SH DESCRIPTION
.B multipath
@@ -36,19 +33,22 @@
dry run, do not create or update devmaps
.TP
.B \-l
-list the current multipath configuration
+show the current multipath topology from information fetched in sysfs and the device mapper
.TP
+.B \-ll
+show the current multipath topology from all available information (sysfs, the device mapper, path checkers ...)
.TP
-.BI \-i " interval"
-multipath target param: polling interval
.TP
.BI \-D " major:minor"
update only the devmap the path pointed by
.I major:minor
is in
.TP
+.B \-f
+flush a multipath device map specified as parameter, if unused
+.TP
.B \-F
-flush all the multipath device maps
+flush all unused multipath device maps
.TP
.BI \-p " policy"
force maps to specified policy:
@@ -70,9 +70,6 @@
1 priority group per target node name. Target node names are fetched in /sys/class/fc_transport/target*/node_name.
.RE
.TP
-.B \-S
-do not send signal to multipathd. -d activate this silently.
-.TP
.BI device
update only the devmap the path pointed by
.I device
Modified: multipath-tools/trunk/multipathd/Makefile
==============================================================================
--- multipath-tools/trunk/multipathd/Makefile (original)
+++ multipath-tools/trunk/multipathd/Makefile Mon Sep 19 12:43:52 2005
@@ -15,14 +15,20 @@
#
CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
-DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs
+LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lcurses
+
+#
+# debuging stuff
+#
+#CFLAGS += -DLCKDBG
+#CFLAGS += -D_DEBUG_
+#CFLAGS += -DLOGDBG
#
# object files
#
-OBJS = main.o copy.o log.o log_pthread.o pidfile.o \
- $(MULTIPATHLIB)-glibc.a \
- $(CHECKERSLIB)-glibc.a \
+OBJS = main.o log.o log_pthread.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
+ $(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
#
@@ -37,7 +43,7 @@
$(EXEC): clean $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
- strip $(EXEC)
+ $(STRIP) $(EXEC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(CHECKERSLIB)-glibc.a:
@@ -59,6 +65,6 @@
rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
clean:
- $(MAKE) -C $(multipathdir) clean
+ $(MAKE) -C $(multipathdir) prepare
rm -f core *.o $(EXEC) *.gz
Added: multipath-tools/trunk/multipathd/cli.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/cli.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,346 @@
+#include <memory.h>
+#include <vector.h>
+#include <util.h>
+
+#include "cli.h"
+
+static struct key *
+alloc_key (void)
+{
+ return (struct key *)MALLOC(sizeof(struct key));
+}
+
+static struct handler *
+alloc_handler (void)
+{
+ return (struct handler *)MALLOC(sizeof(struct handler));
+}
+
+static int
+add_key (vector vec, char * str, int code, int has_param)
+{
+ struct key * kw;
+
+ kw = alloc_key();
+
+ if (!kw)
+ return 1;
+
+ kw->code = code;
+ kw->has_param = has_param;
+ kw->str = STRDUP(str);
+
+ if (!kw->str)
+ goto out;
+
+ if (!vector_alloc_slot(vec))
+ goto out1;
+
+ vector_set_slot(vec, kw);
+
+ return 0;
+
+out1:
+ FREE(kw->str);
+out:
+ FREE(kw);
+ return 1;
+}
+
+int
+add_handler (int fp, int (*fn)(void *, char **, int *, void *))
+{
+ struct handler * h;
+
+ h = alloc_handler();
+
+ if (!h)
+ return 1;
+
+ if (!vector_alloc_slot(handlers)) {
+ FREE(h);
+ return 1;
+ }
+
+ vector_set_slot(handlers, h);
+ h->fingerprint = fp;
+ h->fn = fn;
+
+ return 0;
+}
+
+static void
+free_key (struct key * kw)
+{
+ if (kw->str)
+ FREE(kw->str);
+
+ if (kw->param)
+ FREE(kw->param);
+
+ FREE(kw);
+}
+
+void
+free_keys (vector vec)
+{
+ int i;
+ struct key * kw;
+
+ vector_foreach_slot (vec, kw, i)
+ free_key(kw);
+
+ vector_free(vec);
+}
+
+void
+free_handlers (vector vec)
+{
+ int i;
+ struct handler * h;
+
+ vector_foreach_slot (vec, h, i)
+ FREE(h);
+
+ vector_free(vec);
+}
+
+int
+load_keys (void)
+{
+ int r = 0;
+ keys = vector_alloc();
+
+ if (!keys)
+ return 1;
+
+ r += add_key(keys, "list", LIST, 0);
+ r += add_key(keys, "show", LIST, 0);
+ r += add_key(keys, "add", ADD, 0);
+ r += add_key(keys, "remove", DEL, 0);
+ 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, "paths", PATHS, 0);
+ r += add_key(keys, "maps", MAPS, 0);
+ r += add_key(keys, "path", PATH, 1);
+ r += add_key(keys, "map", MAP, 1);
+ r += add_key(keys, "group", GROUP, 1);
+ r += add_key(keys, "dump", DUMP, 0);
+ r += add_key(keys, "pathvec", PATHVEC, 0);
+ r += add_key(keys, "reconfigure", RECONFIGURE, 0);
+
+ if (r) {
+ free_keys(keys);
+ keys = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct key *
+find_key (char * str)
+{
+ int i;
+ struct key * kw = NULL;
+
+ vector_foreach_slot (keys, kw, i)
+ if (strlen(str) == strlen(kw->str) &&
+ !strcmp(kw->str, str))
+ return kw;
+
+ return NULL;
+}
+
+static struct handler *
+find_handler (int fp)
+{
+ int i;
+ struct handler *h;
+
+ vector_foreach_slot (handlers, h, i)
+ if (h->fingerprint == fp)
+ return h;
+
+ return NULL;
+}
+
+static vector
+get_cmdvec (char * cmd)
+{
+ int fwd = 1;
+ char * p = cmd;
+ char * buff;
+ struct key * kw = NULL;
+ struct key * cmdkw = NULL;
+ vector cmdvec;
+
+ cmdvec = vector_alloc();
+
+ if (!cmdvec)
+ return NULL;
+
+ while (fwd) {
+ fwd = get_word(p, &buff);
+
+ if (!buff)
+ break;
+
+ p += fwd;
+ kw = find_key(buff);
+ FREE(buff);
+
+ if (!kw)
+ goto out; /* synthax error */
+
+ cmdkw = alloc_key();
+
+ if (!cmdkw)
+ goto out;
+
+ if (!vector_alloc_slot(cmdvec)) {
+ FREE(cmdkw);
+ goto out;
+ }
+
+ vector_set_slot(cmdvec, cmdkw);
+ cmdkw->code = kw->code;
+ cmdkw->has_param = kw->has_param;
+
+ if (kw->has_param) {
+ if (*p == '\0')
+ goto out;
+
+ fwd = get_word(p, &buff);
+
+ if (!buff)
+ goto out;
+
+ p += fwd;
+ cmdkw->param = buff;
+ }
+ }
+
+ return cmdvec;
+
+out:
+ free_keys(cmdvec);
+ return NULL;
+}
+
+static int
+fingerprint(vector vec)
+{
+ int i;
+ int fp = 0;
+ struct key * kw;
+
+ vector_foreach_slot(vec, kw, i)
+ fp += kw->code;
+
+ return fp;
+}
+
+int
+alloc_handlers (void)
+{
+ handlers = vector_alloc();
+
+ if (!handlers)
+ return 1;
+
+ return 0;
+}
+
+static int
+genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
+{
+ int i, fwd = 0;
+ struct key * kw;
+
+ vector_foreach_slot (keys, kw, i)
+ if (kw->code == refkw->code && kw != refkw)
+ fwd += sprintf(reply, "|%s", kw->str);
+
+ return fwd;
+}
+
+static char *
+genhelp_handler (void)
+{
+ int i, j;
+ int fp;
+ struct handler * h;
+ struct key * kw;
+ char * reply;
+ char * p;
+
+ reply = MALLOC(MAX_REPLY_LEN);
+
+ if (!reply)
+ return NULL;
+
+ p = reply;
+ p += sprintf(p, "\n");
+
+ vector_foreach_slot (handlers, h, i) {
+ fp = h->fingerprint;
+ vector_foreach_slot (keys, kw, j) {
+ if ((kw->code & fp)) {
+ fp -= kw->code;
+ p += sprintf(p, " %s", kw->str);
+ p += genhelp_sprint_aliases(p, keys, kw);
+
+ if (kw->has_param)
+ p += sprintf(p, " $%s", kw->str);
+ }
+ }
+ p += sprintf(p, "\n");
+ }
+
+ return reply;
+}
+
+int
+parse_cmd (char * cmd, char ** reply, int * len, void * data)
+{
+ int r;
+ struct handler * h;
+ vector cmdvec = get_cmdvec(cmd);
+
+ if (!cmdvec) {
+ *reply = genhelp_handler();
+ *len = strlen(*reply);
+ return 0;
+ }
+
+ h = find_handler(fingerprint(cmdvec));
+
+ if (!h) {
+ *reply = genhelp_handler();
+ *len = strlen(*reply) + 1;
+ return 0;
+ }
+
+ /*
+ * execute handler
+ */
+ r = h->fn(cmdvec, reply, len, data);
+ free_keys(cmdvec);
+
+ return r;
+}
+
+char *
+get_keyparam (vector v, int code)
+{
+ struct key * kw;
+ int i;
+
+ vector_foreach_slot(v, kw, i)
+ if (kw->code == code)
+ return kw->param;
+
+ return NULL;
+}
Added: multipath-tools/trunk/multipathd/cli.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/cli.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,37 @@
+#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)
+
+#define MAX_REPLY_LEN 1000
+
+struct key {
+ char * str;
+ char * param;
+ int code;
+ int has_param;
+};
+
+struct handler {
+ int fingerprint;
+ int (*fn)(void *, char **, int *, void *);
+};
+
+vector keys;
+vector handlers;
+
+int alloc_handlers (void);
+int add_handler (int fp, int (*fn)(void *, char **, int *, void *));
+int parse_cmd (char * cmd, char ** reply, int * len, void *);
+int load_keys (void);
+char * get_keyparam (vector v, int code);
+void free_keys (vector vec);
+void free_handlers (vector vec);
Added: multipath-tools/trunk/multipathd/cli_handlers.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/cli_handlers.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,91 @@
+#include <memory.h>
+#include <vector.h>
+#include <structs.h>
+#include <devmapper.h>
+#include <config.h>
+#include <blacklist.h>
+
+#include "main.h"
+#include "cli.h"
+
+int
+cli_list_paths (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return show_paths(reply, len, allpaths);
+}
+
+int
+cli_list_maps (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return show_maps(reply, len, allpaths);
+}
+
+int
+cli_add_path (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, PATH);
+
+ if (blacklist(conf->blist, param)) {
+ *reply = strdup("blacklisted");
+ *len = strlen(*reply) + 1;
+ return 0;
+ }
+ return uev_add_path(param, allpaths);
+}
+
+int
+cli_del_path (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, PATH);
+
+ return uev_remove_path(param, allpaths);
+}
+
+int
+cli_add_map (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, MAP);
+
+ return uev_add_map(param, allpaths);
+}
+
+int
+cli_del_map (void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+ char * param = get_keyparam(v, MAP);
+
+ return uev_remove_map(param, allpaths);
+}
+
+int
+cli_switch_group(void * v, char ** reply, int * len, void * data)
+{
+ char * mapname = get_keyparam(v, MAP);
+ int groupnum = atoi(get_keyparam(v, GROUP));
+
+ return dm_switchgroup(mapname, groupnum);
+}
+
+int
+cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return dump_pathvec(reply, len, allpaths);
+}
+
+int
+cli_reconfigure(void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return reconfigure(allpaths);
+}
Added: multipath-tools/trunk/multipathd/cli_handlers.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/cli_handlers.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,9 @@
+int cli_list_paths (void * v, char ** reply, int * len, void * data);
+int cli_list_maps (void * v, char ** reply, int * len, void * data);
+int cli_add_path (void * v, char ** reply, int * len, void * data);
+int cli_del_path (void * v, char ** reply, int * len, void * data);
+int cli_add_map (void * v, char ** reply, int * len, void * data);
+int cli_del_map (void * v, char ** reply, int * len, void * data);
+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);
Modified: multipath-tools/trunk/multipathd/log.c
==============================================================================
--- multipath-tools/trunk/multipathd/log.c (original)
+++ multipath-tools/trunk/multipathd/log.c Mon Sep 19 12:43:52 2005
@@ -4,8 +4,12 @@
#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)
{
@@ -30,7 +34,7 @@
static int logarea_init (int size)
{
logdbg(stderr,"enter logarea_init\n");
- la = malloc(sizeof(struct logarea));
+ la = (struct logarea *)MALLOC(sizeof(struct logarea));
if (!la)
return 1;
@@ -38,11 +42,11 @@
if (size < MAX_MSG_SIZE)
size = DEFAULT_AREA_SIZE;
- la->start = malloc(size);
+ la->start = MALLOC(size);
memset(la->start, 0, size);
if (!la->start) {
- free(la);
+ FREE(la);
return 1;
}
@@ -51,11 +55,11 @@
la->head = la->start;
la->tail = la->start;
- la->buff = malloc(MAX_MSG_SIZE + sizeof(struct logmsg));
+ la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
if (!la->buff) {
- free(la->start);
- free(la);
+ FREE(la->start);
+ FREE(la);
return 1;
}
return 0;
@@ -75,9 +79,9 @@
void free_logarea (void)
{
- free(la->start);
- free(la->buff);
- free(la);
+ FREE(la->start);
+ FREE(la->buff);
+ FREE(la);
return;
}
@@ -101,21 +105,23 @@
if (!la->empty) {
fwd = sizeof(struct logmsg) +
strlen((char *)&lastmsg->str) * sizeof(char) + 1;
- la->tail += fwd;
+ la->tail += ALIGN(fwd, sizeof(void *));
}
vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
- len = strlen(buff) * sizeof(char) + 1;
+ len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
+ sizeof(void *));
/* not enough space on tail : rewind */
- if (la->head <= la->tail &&
- (len + sizeof(struct logmsg)) > (la->end - la->tail)) {
+ 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 + sizeof(struct logmsg)) > (la->head - la->tail)) {
+ if (la->head > la->tail && len >= (la->head - la->tail)) {
logdbg(stderr, "enqueue: log area overrun, drop msg\n");
if (!la->empty)
@@ -128,7 +134,7 @@
la->empty = 0;
msg = (struct logmsg *)la->tail;
msg->prio = prio;
- memcpy((void *)&msg->str, buff, len);
+ memcpy((void *)&msg->str, buff, strlen(buff));
lastmsg->next = la->tail;
msg->next = la->head;
@@ -149,7 +155,7 @@
if (la->empty)
return 1;
-
+
int len = strlen((char *)&src->str) * sizeof(char) +
sizeof(struct logmsg) + 1;
Modified: multipath-tools/trunk/multipathd/log.h
==============================================================================
--- multipath-tools/trunk/multipathd/log.h (original)
+++ multipath-tools/trunk/multipathd/log.h Mon Sep 19 12:43:52 2005
@@ -1,7 +1,7 @@
#ifndef LOG_H
#define LOG_H
-#define DEFAULT_AREA_SIZE 4096
+#define DEFAULT_AREA_SIZE 8192
#define MAX_MSG_SIZE 128
#ifndef LOGLEVEL
Modified: multipath-tools/trunk/multipathd/log_pthread.c
==============================================================================
--- multipath-tools/trunk/multipathd/log_pthread.c (original)
+++ multipath-tools/trunk/multipathd/log_pthread.c Mon Sep 19 12:43:52 2005
@@ -4,15 +4,15 @@
#include <pthread.h>
#include <sys/mman.h>
+#include <memory.h>
+
#include "log_pthread.h"
#include "log.h"
-void log_safe (int prio, char * fmt, ...)
+void log_safe (int prio, char * fmt, va_list ap)
{
- va_list ap;
-
pthread_mutex_lock(logq_lock);
- va_start(ap, fmt);
+ //va_start(ap, fmt);
log_enqueue(prio, fmt, ap);
va_end(ap);
pthread_mutex_unlock(logq_lock);
Modified: multipath-tools/trunk/multipathd/log_pthread.h
==============================================================================
--- multipath-tools/trunk/multipathd/log_pthread.h (original)
+++ multipath-tools/trunk/multipathd/log_pthread.h Mon Sep 19 12:43:52 2005
@@ -7,7 +7,7 @@
pthread_mutex_t *logev_lock;
pthread_cond_t *logev_cond;
-void log_safe(int prio, char * fmt, ...);
+void log_safe(int prio, char * fmt, va_list ap);
void log_thread_start(void);
void log_thread_stop(void);
Modified: multipath-tools/trunk/multipathd/main.c
==============================================================================
--- multipath-tools/trunk/multipathd/main.c (original)
+++ multipath-tools/trunk/multipathd/main.c Mon Sep 19 12:43:52 2005
@@ -1,18 +1,7 @@
-#include <string.h>
-#include <pthread.h>
-#include <stdio.h>
#include <unistd.h>
-#include <linux/unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
#include <libdevmapper.h>
-#include <signal.h>
#include <wait.h>
-#include <sched.h>
-#include <errno.h>
-#include <sys/mount.h>
#include <sys/mman.h>
/*
@@ -46,21 +35,25 @@
#include <discovery.h>
#include <debug.h>
#include <propsel.h>
+#include <uevent.h>
+#include <switchgroup.h>
+#include <path_state.h>
+#include <print.h>
#include "main.h"
-#include "copy.h"
-#include "clone_platform.h"
#include "pidfile.h"
+#include "uxlsnr.h"
+#include "uxclnt.h"
+#include "cli.h"
+#include "cli_handlers.h"
#define FILE_NAME_SIZE 256
#define CMDSIZE 160
-#define CALLOUT_DIR "/var/cache/multipathd"
-
#define LOG_MSG(a,b) \
- if (strlen(a)) { \
- log_safe(LOG_WARNING, "%s: %s", b, a); \
- memset(a, 0, MAX_CHECKER_MSG_SIZE); \
+ if (strlen(b)) { \
+ condlog(a, "%s: %s", pp->dev_t, b); \
+ memset(b, 0, MAX_CHECKER_MSG_SIZE); \
}
#ifdef LCKDBG
@@ -75,229 +68,312 @@
#define unlock(a) pthread_mutex_unlock(a)
#endif
-/*
- * global vars
- */
-int pending_event = 0;
-int from_sighup;
-pthread_mutex_t *event_lock;
-pthread_cond_t *event;
+pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* structs
*/
-struct paths {
- pthread_mutex_t *lock;
- vector pathvec;
-};
-
struct event_thread {
- pthread_t *thread;
- pthread_mutex_t *waiter_lock;
- int lease;
+ struct dm_task *dmt;
+ pthread_t thread;
int event_nr;
char mapname[WWID_SIZE];
struct paths *allpaths;
};
-/*
- * helpers functions
- */
+static struct event_thread *
+alloc_waiter (void)
+{
+
+ struct event_thread * wp;
+
+ wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+
+ return wp;
+}
+
static void
-strvec_free (vector vec)
+cleanup_lock (void * data)
+{
+ unlock((pthread_mutex_t *)data);
+}
+
+static void
+set_paths_owner (struct paths * allpaths, struct multipath * mpp)
{
int i;
- char * str;
+ struct path * pp;
- vector_foreach_slot (vec, str, i)
- if (str)
- FREE(str);
+ if (!mpp)
+ return;
- vector_free(vec);
+ vector_foreach_slot (allpaths->pathvec, pp, i) {
+ if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
+ condlog(4, "%s ownership set", pp->dev_t);
+ pp->mpp = mpp;
+ }
+ }
+}
+
+static void
+unset_paths_owner (struct paths * allpaths, struct multipath * mpp)
+{
+ int i;
+ struct path * pp;
+
+ vector_foreach_slot (allpaths->pathvec, pp, i) {
+ if (pp->mpp == mpp) {
+ condlog(4, "%s is orphaned", pp->dev_t);
+ pp->mpp = NULL;
+ }
+ }
}
static int
-exit_daemon (int status)
+update_multipath_table (struct multipath *mpp, vector pathvec)
{
- if (status != 0)
- fprintf(stderr, "bad exit status. see daemon.log\n");
+ if (!mpp)
+ return 1;
- log_safe(LOG_INFO, "umount ramfs");
- umount(CALLOUT_DIR);
+ if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
+ return 1;
- log_safe(LOG_INFO, "unlink pidfile");
- unlink(DEFAULT_PIDFILE);
+ if (disassemble_map(pathvec, mpp->params, mpp))
+ return 1;
- log_safe(LOG_NOTICE, "--------shut down-------");
- log_thread_stop();
- exit(status);
+ return 0;
}
-static void *
-get_devmaps (void)
+static int
+update_multipath_status (struct multipath *mpp)
{
- char *devmap;
- struct dm_task *dmt;
- struct dm_names *names = NULL;
- unsigned next = 0;
- void *nexttgt;
- vector devmaps;
-
- devmaps = vector_alloc();
+ if (!mpp)
+ return 1;
- if (!devmaps)
- return NULL;
+ if(dm_get_status(mpp->alias, mpp->status))
+ return 1;
- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
- goto out;
+ if (disassemble_status(mpp->status, mpp))
+ return 1;
- dm_task_no_open_count(dmt);
+ return 0;
+}
- if (!dm_task_run(dmt))
- goto out1;
+static int
+update_multipath_strings (struct multipath *mpp, vector pathvec)
+{
+ if (mpp->selector) {
+ FREE(mpp->selector);
+ mpp->selector = NULL;
+ }
- if (!(names = dm_task_get_names(dmt)))
- goto out1;
+ if (mpp->features) {
+ FREE(mpp->features);
+ mpp->features = NULL;
+ }
- if (!names->dev) {
- log_safe(LOG_WARNING, "no devmap found");
- goto out1;
+ if (mpp->hwhandler) {
+ FREE(mpp->hwhandler);
+ mpp->hwhandler = NULL;
}
- do {
- names = (void *) names + next;
- nexttgt = NULL;
- /*
- * keep only multipath maps
- */
- log_safe(LOG_DEBUG, "devmap %s", names->name);
-
- if (!dm_type(names->name, "multipath")) {
- log_safe(LOG_DEBUG,
- " skip non multipath target");
- goto out2;
- }
+ free_pgvec(mpp->pg, KEEP_PATHS);
+ mpp->pg = NULL;
- /*
- * new map
- */
- devmap = MALLOC(WWID_SIZE);
+ if (update_multipath_table(mpp, pathvec))
+ return 1;
- if (!devmap)
- goto out2;
+ if (update_multipath_status(mpp))
+ return 1;
- strcpy(devmap, names->name);
-
- if (!vector_alloc_slot(devmaps)) {
- free(devmap);
- goto out2;
- }
- vector_set_slot(devmaps, devmap);
-out2:
- next = names->next;
- } while (next);
+ return 0;
+}
- dm_task_destroy(dmt);
- return devmaps;
-out1:
- dm_task_destroy(dmt);
-out:
- strvec_free(devmaps);
- return NULL;
+static void
+set_multipath_wwid (struct multipath * mpp)
+{
+ char * wwid;
+
+ wwid = get_mpe_wwid(mpp->alias);
+
+ if (wwid) {
+ strncpy(mpp->wwid, wwid, WWID_SIZE);
+ wwid = NULL;
+ } else
+ strncpy(mpp->wwid, mpp->alias, WWID_SIZE);
}
static int
-updatepaths (struct paths *allpaths, char *sysfs_path)
+setup_multipath (struct paths * allpaths, struct multipath * mpp)
{
- lock(allpaths->lock);
- path_discovery(allpaths->pathvec, conf, 0);
- unlock(allpaths->lock);
+ int i;
+
+ set_multipath_wwid(mpp);
+ mpp->mpe = find_mpe(mpp->wwid);
+ condlog(4, "discovered map %s", mpp->alias);
+
+ if (update_multipath_strings(mpp, allpaths->pathvec))
+ goto out;
+
+ set_paths_owner(allpaths, mpp);
+ select_pgfailback(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");
+ return 1;
}
static int
-mark_failed_path (struct paths *allpaths, char *mapname)
+need_switch_pathgroup (struct multipath * mpp, int refresh)
{
- struct multipath *mpp;
- struct pathgroup *pgp;
- struct path *pp;
- struct path *app;
+ struct pathgroup * pgp;
+ struct path * pp;
int i, j;
- int r = 1;
- if (!dm_map_present(mapname))
+ if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
return 0;
- mpp = alloc_multipath();
+ /*
+ * Refresh path priority values
+ */
+ if (refresh)
+ vector_foreach_slot (mpp->pg, pgp, i)
+ vector_foreach_slot (pgp->paths, pp, j)
+ pathinfo(pp, conf->hwtable, DI_PRIO);
- if (!mpp)
+ select_path_group(mpp); /* sets mpp->nextpg */
+ pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
+
+ if (pgp && pgp->status != PGSTATE_ACTIVE)
return 1;
- if (dm_get_map(mapname, &mpp->size, (char *)mpp->params))
- goto out;
+ return 0;
+}
- if (dm_get_status(mapname, mpp->status))
- goto out;
+static void
+switch_pathgroup (struct multipath * mpp)
+{
+ struct pathgroup * pgp;
- lock(allpaths->lock);
- r = disassemble_map(allpaths->pathvec, mpp->params, mpp);
- unlock(allpaths->lock);
+ pgp = VECTOR_SLOT(mpp->pg, mpp->nextpg - 1);
- if (r)
- goto out;
+ if (pgp && pgp->status != PGSTATE_ACTIVE) {
+ dm_switchgroup(mpp->alias, mpp->nextpg);
+ condlog(2, "%s: switch to path group #%i",
+ mpp->alias, mpp->nextpg);
+ }
+}
- r = disassemble_status(mpp->status, mpp);
+static int
+update_multipath (struct paths *allpaths, char *mapname)
+{
+ struct multipath *mpp;
+ struct pathgroup *pgp;
+ struct path *pp;
+ int i, j;
+ int r = 1;
- if (r)
+ mpp = find_mp(allpaths->mpvec, mapname);
+
+ if (!mpp)
goto out;
- r = 0; /* can't fail from here on */
- lock(allpaths->lock);
+ free_pgvec(mpp->pg, KEEP_PATHS);
+ mpp->pg = NULL;
+
+ if (setup_multipath(allpaths, mpp))
+ goto out; /* mpp freed in setup_multipath */
+ /*
+ * compare checkers states with DM states
+ */
vector_foreach_slot (mpp->pg, pgp, i) {
vector_foreach_slot (pgp->paths, pp, j) {
if (pp->dmstate != PSTATE_FAILED)
continue;
- app = find_path_by_devt(allpaths->pathvec, pp->dev_t);
+ if (pp->state != PATH_DOWN) {
+ condlog(2, "%s: mark as failed", pp->dev_t);
+ pp->state = PATH_DOWN;
- if (app && app->state != PATH_DOWN) {
- log_safe(LOG_NOTICE, "mark %s as failed",
- pp->dev_t);
- app->state = PATH_DOWN;
+ /*
+ * if opportune,
+ * schedule the next check earlier
+ */
+ if (pp->tick > conf->checkint)
+ pp->tick = conf->checkint;
}
}
}
- unlock(allpaths->lock);
+ r = 0;
out:
- free_multipath(mpp, KEEP_PATHS);
+ if (r)
+ condlog(0, "failed to update multipath");
return r;
}
-static void *
-waiteventloop (struct event_thread * waiter, char * cmd)
+static void
+free_waiter (void * data)
{
- //char buff[1];
- struct dm_task *dmt;
+ 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;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGHUP);
+ pthread_sigmask(SIG_UNBLOCK, &set, &old);
+ return old;
+}
+
+/*
+ * returns the reschedule delay
+ * negative means *stop*
+ */
+static int
+waiteventloop (struct event_thread * waiter)
+{
+ sigset_t set;
int event_nr;
+ int r;
if (!waiter->event_nr)
waiter->event_nr = dm_geteventnr(waiter->mapname);
- if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
- return 0;
+ if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
+ return 1;
- if (!dm_task_set_name(dmt, waiter->mapname))
- goto out;
+ if (!dm_task_set_name(waiter->dmt, waiter->mapname))
+ return 1;
- if (waiter->event_nr && !dm_task_set_event_nr(dmt, waiter->event_nr))
- goto out;
+ if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
+ waiter->event_nr))
+ return 1;
- dm_task_no_open_count(dmt);
+ dm_task_no_open_count(waiter->dmt);
- dm_task_run(dmt);
+ set = unblock_sighup();
+ dm_task_run(waiter->dmt);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+ pthread_testcancel();
+ dm_task_destroy(waiter->dmt);
+ waiter->dmt = NULL;
waiter->event_nr++;
@@ -305,269 +381,657 @@
* upon event ...
*/
while (1) {
- log_safe(LOG_DEBUG, "%s", cmd);
- log_safe(LOG_NOTICE, "devmap event (%i) on %s",
- waiter->event_nr, waiter->mapname);
+ condlog(3, "%s: devmap event #%i",
+ waiter->mapname, waiter->event_nr);
- mark_failed_path(waiter->allpaths, waiter->mapname);
- //execute_program(cmd, buff, 1);
+ /*
+ * event might be :
+ *
+ * 1) a table reload, which means our mpp structure is
+ * obsolete : refresh it through update_multipath()
+ * 2) a path failed by DM : mark as such through
+ * update_multipath()
+ * 3) map has gone away : stop the thread.
+ * 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);
+
+ if (r)
+ return -1; /* stop the thread */
event_nr = dm_geteventnr(waiter->mapname);
if (waiter->event_nr == event_nr)
- break;
+ return 1; /* upon problem reschedule 1s later */
waiter->event_nr = event_nr;
}
-
-out:
- dm_task_destroy(dmt);
-
- /*
- * tell waiterloop we have an event
- */
- lock(event_lock);
- pending_event++;
- pthread_cond_signal(event);
- unlock(event_lock);
-
- return NULL;
+ return -1; /* never reach there */
}
static void *
waitevent (void * et)
{
+ int r;
struct event_thread *waiter;
- char cmd[CMDSIZE];
mlockall(MCL_CURRENT | MCL_FUTURE);
waiter = (struct event_thread *)et;
- lock(waiter->waiter_lock);
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ pthread_cleanup_push(free_waiter, et);
+
+ while (1) {
+ r = waiteventloop(waiter);
- if (safe_snprintf(cmd, CMDSIZE, "%s %s",
- conf->multipath, waiter->mapname)) {
- log_safe(LOG_ERR, "command too long, abord reconfigure");
+ if (r < 0)
+ break;
+
+ pthread_testcancel();
+ sleep(r);
+ pthread_testcancel();
+ }
+
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+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)
+{
+ pthread_attr_t attr;
+ struct event_thread * wp;
+
+ if (!mpp)
+ return 0;
+
+ if (pthread_attr_init(&attr))
+ goto out;
+
+ pthread_attr_setstacksize(&attr, 32 * 1024);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ wp = alloc_waiter();
+
+ if (!wp)
goto out;
+
+ mpp->waiter = (void *)wp;
+ strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+ wp->allpaths = allpaths;
+
+ if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
+ condlog(0, "%s: cannot create event checker", wp->mapname);
+ goto out1;
}
- while (1)
- waiteventloop(waiter, cmd);
+ condlog(2, "%s: event checker started", wp->mapname);
+ return 0;
+out1:
+ free_waiter(wp);
+ mpp->waiter = NULL;
out:
+ condlog(0, "failed to start waiter thread");
+ 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);
+ }
+
/*
- * release waiter_lock so that waiterloop knows we are gone
+ * clear references to this map
*/
- unlock(waiter->waiter_lock);
- pthread_exit(waiter->thread);
+ unset_paths_owner(allpaths, mpp);
- return NULL;
+ /*
+ * 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 *
-alloc_waiter (void)
+static void
+remove_maps (struct paths * allpaths)
{
+ int i;
+ struct multipath * mpp;
- struct event_thread * wp;
+ vector_foreach_slot (allpaths->mpvec, mpp, i)
+ remove_map(mpp, allpaths);
- wp = MALLOC(sizeof(struct event_thread));
+ vector_free(allpaths->mpvec);
+ allpaths->mpvec = NULL;
+}
- if (!wp)
- return NULL;
+int
+uev_add_map (char * devname, struct paths * allpaths)
+{
+ int major, minor, i;
+ char dev_t[BLK_DEV_SIZE];
+ char * alias;
+ struct multipath * mpp;
- wp->thread = MALLOC(sizeof(pthread_t));
+ if (sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE))
+ return 1;
- if (!wp->thread)
- goto out;
+ if (sscanf(dev_t, "%d:%d", &major, &minor) != 2)
+ return 1;
+
+ alias = dm_mapname(major, minor);
- wp->waiter_lock = (pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t));
+ if (!alias)
+ return 1;
+
+ if (!dm_type(alias, DEFAULT_TARGET)) {
+ condlog(4, "%s: not a multipath map", alias);
+ FREE(alias);
+ return 0;
+ }
- if (!wp->waiter_lock)
- goto out1;
+ mpp = find_mp(allpaths->mpvec, alias);
- pthread_mutex_init(wp->waiter_lock, NULL);
- return wp;
+ if (mpp) {
+ /*
+ * this should not happen,
+ * we missed a remove map event (not sent ?)
+ */
+ condlog(2, "%s: already registered", alias);
+ remove_map(mpp, allpaths);
+ }
+
+ /*
+ * now we can allocate
+ */
+ mpp = alloc_multipath();
+
+ if (!mpp)
+ return 1;
+
+ mpp->minor = minor;
+ mpp->alias = alias;
+
+ if (setup_multipath(allpaths, mpp))
+ return 1; /* mpp freed in setup_multipath */
+
+ if (!vector_alloc_slot(allpaths->mpvec))
+ goto out;
+
+ vector_set_slot(allpaths->mpvec, mpp);
+ set_paths_owner(allpaths, mpp);
+
+ if (start_waiter_thread(mpp, allpaths))
+ 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);
+ return 1;
+}
+
+int
+uev_remove_map (char * devname, struct paths * allpaths)
+{
+ int minor;
+ struct multipath * mpp;
+
+ if (sscanf(devname, "dm-%d", &minor) != 1)
+ return 1;
+
+ mpp = find_mp_by_minor(allpaths->mpvec, minor);
+
+ if (!mpp) {
+ condlog(3, "%s: devmap not registered, can't remove",
+ devname);
+ return 1;
+ }
+
+ condlog(2, "remove %s devmap", mpp->alias);
+ remove_map(mpp, allpaths);
+
+ return 0;
+}
+
+int
+uev_add_path (char * devname, struct paths * allpaths)
+{
+ struct path * pp;
+
+ pp = find_path_by_dev(allpaths->pathvec, devname);
+
+ if (pp) {
+ condlog(3, "%s: already in pathvec");
+ return 1;
+ }
+ pp = store_pathinfo(allpaths->pathvec, conf->hwtable,
+ devname, DI_SYSFS | DI_WWID);
+
+ if (!pp) {
+ condlog(0, "%s: failed to store path info", devname);
+ return 1;
+ }
+
+ condlog(2, "%s: path checker registered", devname);
+ pp->mpp = find_mp_by_wwid(allpaths->mpvec, pp->wwid);
+
+ if (pp->mpp)
+ condlog(4, "%s: ownership set to %s",
+ pp->dev_t, pp->mpp->alias);
+ else
+ condlog(4, "%s: orphaned", pp->dev_t);
+
+ return 0;
+}
+
+int
+uev_remove_path (char * devname, struct paths * allpaths)
+{
+ int i;
+ struct path * pp;
+
+ pp = find_path_by_dev(allpaths->pathvec, devname);
+
+ if (!pp) {
+ condlog(3, "%s: not in pathvec");
+ return 1;
+ }
+ condlog(2, "remove %s path checker", devname);
+ i = find_slot(allpaths->pathvec, (void *)pp);
+ vector_del_slot(allpaths->pathvec, i);
+ free_path(pp);
+
+ return 0;
+}
+
+int
+show_paths (char ** r, int * len, struct paths * allpaths)
+{
+ int i;
+ struct path * pp;
+ char * c;
+ char * reply;
+ struct path_layout pl;
+
+ get_path_layout(&pl, allpaths->pathvec);
+ reply = MALLOC(MAX_REPLY_LEN);
+
+ if (!reply)
+ return 1;
+
+ c = reply;
+ c += sprintf(c, "\n");
+
+ vector_foreach_slot(allpaths->pathvec, pp, i)
+ c += snprint_path(c, reply + MAX_REPLY_LEN - c,
+ PRINT_PATH_CHECKER, pp, &pl);
+
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+show_maps (char ** r, int *len, struct paths * allpaths)
+{
+ int i;
+ struct multipath * mpp;
+ char * c;
+ char * reply;
+ struct map_layout ml;
+
+ get_map_layout(&ml, allpaths->mpvec);
+ reply = MALLOC(MAX_REPLY_LEN);
+
+ if (!reply)
+ return 1;
+
+ c = reply;
+ c += sprintf(c, "\n");
+
+ vector_foreach_slot(allpaths->mpvec, mpp, i)
+ c += snprint_map(c, reply + MAX_REPLY_LEN - c,
+ PRINT_MAP_FAILBACK, mpp, &ml);
+
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+dump_pathvec (char ** r, int * len, struct paths * allpaths)
+{
+ int i;
+ struct path * pp;
+ char * reply;
+ char * p;
+
+ *len = VECTOR_SIZE(allpaths->pathvec) * sizeof(struct path);
+ reply = (char *)MALLOC(*len);
+ *r = reply;
+
+ if (!reply)
+ return 1;
+
+ p = reply;
+
+ vector_foreach_slot (allpaths->pathvec, pp, i) {
+ memcpy((void *)p, pp, sizeof(struct path));
+ p += sizeof(struct path);
+ }
+
+ return 0;
+}
+
+static int
+get_dm_mpvec (struct paths * allpaths)
+{
+ int i;
+ struct multipath * mpp;
+
+ if (dm_get_maps(allpaths->mpvec, "multipath"))
+ return 1;
+
+ vector_foreach_slot (allpaths->mpvec, mpp, i) {
+ if (setup_multipath(allpaths, mpp))
+ return 1;
+ mpp->minor = dm_get_minor(mpp->alias);
+ start_waiter_thread(mpp, allpaths);
+ }
+
+ return 0;
+}
+
+int
+reconfigure (struct paths * allpaths)
+{
+ struct config * old = conf;
+ struct multipath * mpp;
+ struct path * pp;
+ int i;
+
+ conf = NULL;
+
+ if (load_config(DEFAULT_CONFIGFILE)) {
+ conf = old;
+ condlog(2, "reconfigure failed, continue with old config");
+ return 1;
+ }
+ conf->verbosity = old->verbosity;
+ free_config(old);
+
+ vector_foreach_slot (allpaths->mpvec, mpp, i) {
+ mpp->mpe = find_mpe(mpp->wwid);
+ set_paths_owner(allpaths, mpp);
+ }
+ vector_foreach_slot (allpaths->pathvec, pp, i) {
+ select_checkfn(pp);
+ select_getuid(pp);
+ select_getprio(pp);
+ }
+ condlog(2, "reconfigured");
+ return 0;
+}
+
+int
+uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
+{
+ struct paths * allpaths;
+ int r;
+
+ *reply = NULL;
+ *len = 0;
+ allpaths = (struct paths *)trigger_data;
+
+ pthread_cleanup_push(cleanup_lock, allpaths->lock);
+ lock(allpaths->lock);
+
+ r = parse_cmd(str, reply, len, allpaths);
+
+ if (r) {
+ *reply = STRDUP("fail\n");
+ *len = strlen(*reply) + 1;
+ r = 1;
+ }
+ else if (*len == 0) {
+ *reply = STRDUP("ok\n");
+ *len = strlen(*reply) + 1;
+ r = 0;
+ }
+
+ pthread_cleanup_pop(1);
+ return r;
+}
+
+int
+uev_trigger (struct uevent * uev, void * trigger_data)
+{
+ int r = 0;
+ char devname[32];
+ struct paths * allpaths;
+
+ allpaths = (struct paths *)trigger_data;
+ pthread_cleanup_push(cleanup_lock, allpaths->lock);
+ lock(allpaths->lock);
+
+ if (strncmp(uev->devpath, "/block", 6))
+ goto out;
+
+ basename(uev->devpath, devname);
+
+ /*
+ * device map add/remove event
+ */
+ if (!strncmp(devname, "dm-", 3)) {
+ if (!strncmp(uev->action, "add", 3)) {
+ r = uev_add_map(devname, allpaths);
+ goto out;
+ }
+#if 0
+ if (!strncmp(uev->action, "remove", 6)) {
+ r = uev_remove_map(devname, allpaths);
+ goto out;
+ }
+#endif
+ goto out;
+ }
+
+ /*
+ * path add/remove event
+ */
+ if (blacklist(conf->blist, devname))
+ goto out;
+
+ if (!strncmp(uev->action, "add", 3)) {
+ r = uev_add_path(devname, allpaths);
+ goto out;
+ }
+ if (!strncmp(uev->action, "remove", 6)) {
+ r = uev_remove_path(devname, allpaths);
+ goto out;
+ }
-out1:
- free(wp->thread);
out:
- free(wp);
- return NULL;
+ FREE(uev);
+ pthread_cleanup_pop(1);
+ return r;
}
-static void
-free_waiter (struct event_thread * wp)
+static void *
+ueventloop (void * ap)
{
- pthread_mutex_destroy(wp->waiter_lock);
- free(wp->thread);
- free(wp);
+ uevent_listen(&uev_trigger, ap);
+
+ return NULL;
}
static void *
-waiterloop (void *ap)
+uxlsnrloop (void * ap)
{
- struct paths *allpaths;
- vector devmaps = NULL;
- char *devmap;
- vector waiters;
- struct event_thread *wp;
- pthread_attr_t attr;
- int r;
- char buff[1];
- int i, j;
-
- mlockall(MCL_CURRENT | MCL_FUTURE);
- log_safe(LOG_NOTICE, "start DM events thread");
-
- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
- log_safe(LOG_ERR, "can not find sysfs mount point");
+ if (load_keys())
return NULL;
- }
-
- /*
- * inits
- */
- allpaths = (struct paths *)ap;
- waiters = vector_alloc();
-
- if (!waiters)
+
+ if (alloc_handlers())
return NULL;
- if (pthread_attr_init(&attr))
- return NULL;
+ add_handler(LIST+PATHS, cli_list_paths);
+ add_handler(LIST+MAPS, cli_list_maps);
+ add_handler(ADD+PATH, cli_add_path);
+ add_handler(DEL+PATH, cli_del_path);
+ add_handler(ADD+MAP, cli_add_map);
+ add_handler(DEL+MAP, cli_del_map);
+ add_handler(SWITCH+MAP+GROUP, cli_switch_group);
+ add_handler(DUMP+PATHVEC, cli_dump_pathvec);
+ add_handler(RECONFIGURE, cli_reconfigure);
- pthread_attr_setstacksize(&attr, 32 * 1024);
+ uxsock_listen(&uxsock_trigger, ap);
- log_safe(LOG_NOTICE, "initial reconfigure multipath maps");
- execute_program(conf->multipath, buff, 1);
+ return NULL;
+}
- while (1) {
- /*
- * revoke the leases
- */
- vector_foreach_slot (waiters, wp, i)
- wp->lease = 0;
+static int
+exit_daemon (int status)
+{
+ if (status != 0)
+ fprintf(stderr, "bad exit status. see daemon.log\n");
- /*
- * update devmap list
- */
- log_safe(LOG_INFO, "refresh devmaps list");
+ condlog(3, "unlink pidfile");
+ unlink(DEFAULT_PIDFILE);
- if (devmaps)
- free_strvec(devmaps);
+ lock(&exit_mutex);
+ pthread_cond_signal(&exit_cond);
+ unlock(&exit_mutex);
- while ((devmaps = get_devmaps()) == NULL) {
- /*
- * we're not allowed to fail here
- */
- log_safe(LOG_ERR, "can't get devmaps ... retry");
- sleep(5);
- }
+ return status;
+}
- /*
- * update paths list
- */
- log_safe(LOG_INFO, "refresh paths list");
+static void
+fail_path (struct path * pp)
+{
+ if (!pp->mpp)
+ return;
- while(updatepaths(allpaths, sysfs_path)) {
- log_safe(LOG_ERR, "can't update path list ... retry");
- sleep(5);
- }
+ condlog(2, "checker failed path %s in map %s",
+ pp->dev_t, pp->mpp->alias);
- /*
- * start waiters on all devmaps
- */
- log_safe(LOG_INFO, "start up event loops");
+ dm_fail_path(pp->mpp->alias, pp->dev_t);
+}
- vector_foreach_slot (devmaps, devmap, i) {
- /*
- * find out if devmap already has
- * a running waiter thread
- */
- vector_foreach_slot (waiters, wp, j)
- if (!strcmp(wp->mapname, devmap))
- break;
-
- /*
- * no event_thread struct : init it
- */
- if (j == VECTOR_SIZE(waiters)) {
- wp = alloc_waiter();
+/*
+ * caller must have locked the path list before calling that function
+ */
+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 (!wp)
- continue;
+static void
+enable_group(struct path * pp)
+{
+ struct pathgroup * pgp;
- strncpy(wp->mapname, devmap, WWID_SIZE);
- wp->allpaths = allpaths;
+ /*
+ * if path is added through uev_add_path, pgindex can be unset.
+ * next update_strings() will set it, upon map reload event.
+ *
+ * we can safely return here, because upon map reload, all
+ * PG will be enabled.
+ */
+ if (!pp->pgindex)
+ return;
- if (!vector_alloc_slot(waiters)) {
- free_waiter(wp);
- continue;
- }
- vector_set_slot(waiters, wp);
- }
-
- /*
- * event_thread struct found
- */
- else if (j < VECTOR_SIZE(waiters)) {
- r = pthread_mutex_trylock(wp->waiter_lock);
+ pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1);
+
+ if (pgp->status == PGSTATE_DISABLED) {
+ condlog(2, "%s: enable group #%i", pp->mpp->alias, pp->pgindex);
+ dm_enablegroup(pp->mpp->alias, pp->pgindex);
+ }
+}
- /*
- * thread already running : next devmap
- */
- if (r) {
- log_safe(LOG_DEBUG,
- "event checker running : %s",
- wp->mapname);
+static void
+mpvec_garbage_collector (struct paths * allpaths)
+{
+ struct multipath * mpp;
+ int i;
- /*
- * renew the lease
- */
- wp->lease = 1;
- continue;
- }
- pthread_mutex_unlock(wp->waiter_lock);
- }
-
- if (pthread_create(wp->thread, &attr, waitevent, wp)) {
- log_safe(LOG_ERR,
- "cannot create event checker : %s",
- wp->mapname);
- free_waiter(wp);
- vector_del_slot(waiters, j);
- continue;
- }
- wp->lease = 1;
- log_safe(LOG_NOTICE, "event checker started : %s",
- wp->mapname);
- }
- vector_foreach_slot (waiters, wp, i) {
- if (wp->lease == 0) {
- log_safe(LOG_NOTICE, "reap event checker : %s",
- wp->mapname);
-
- pthread_cancel(*wp->thread);
- free_waiter(wp);
- vector_del_slot(waiters, i);
- i--;
- }
+ vector_foreach_slot (allpaths->mpvec, mpp, i) {
+ if (!dm_map_present(mpp->alias)) {
+ condlog(2, "%s: remove dead map", mpp->alias);
+ remove_map(mpp, allpaths);
}
- /*
- * wait event condition
- */
- lock(event_lock);
+ }
+}
- if (pending_event > 0)
- pending_event--;
+static void
+defered_failback_tick (vector mpvec)
+{
+ struct multipath * mpp;
+ int i;
- log_safe(LOG_INFO, "%i pending event(s)", pending_event);
- if(pending_event == 0)
- pthread_cond_wait(event, event_lock);
+ vector_foreach_slot (mpvec, mpp, i) {
+ /*
+ * defered failback getting sooner
+ */
+ if (mpp->pgfailback > 0 && mpp->failback_tick > 0) {
+ mpp->failback_tick--;
- unlock(event_lock);
+ if (!mpp->failback_tick && need_switch_pathgroup(mpp, 1))
+ switch_pathgroup(mpp);
+ }
}
- return NULL;
}
static void *
@@ -575,10 +1039,8 @@
{
struct paths *allpaths;
struct path *pp;
- int i;
+ int i, count = 0;
int newstate;
- char buff[1];
- char cmd[CMDSIZE];
char checker_msg[MAX_CHECKER_MSG_SIZE];
mlockall(MCL_CURRENT | MCL_FUTURE);
@@ -586,21 +1048,38 @@
memset(checker_msg, 0, MAX_CHECKER_MSG_SIZE);
allpaths = (struct paths *)ap;
- log_safe(LOG_NOTICE, "path checkers start up");
+ condlog(2, "path checkers start up");
while (1) {
+ pthread_cleanup_push(cleanup_lock, allpaths->lock);
lock(allpaths->lock);
- log_safe(LOG_DEBUG, "checking paths");
+ condlog(4, "tick");
vector_foreach_slot (allpaths->pathvec, pp, i) {
+ if (!pp->mpp)
+ continue;
+
+ if (pp->tick) {
+ /*
+ * don't check this path yet
+ */
+ pp->tick--;
+ continue;
+ }
+
+ /*
+ * provision a next check soonest,
+ * in case we exit abnormaly from here
+ */
+ pp->tick = conf->checkint;
+
if (!pp->checkfn) {
- devinfo(pp, conf->hwtable, DI_SYSFS);
+ pathinfo(pp, conf->hwtable, DI_SYSFS);
select_checkfn(pp);
}
if (!pp->checkfn) {
- log_safe(LOG_ERR, "%s: checkfn is void",
- pp->dev);
+ condlog(0, "%s: checkfn is void", pp->dev);
continue;
}
newstate = pp->checkfn(pp->fd, checker_msg,
@@ -608,166 +1087,145 @@
if (newstate != pp->state) {
pp->state = newstate;
- LOG_MSG(checker_msg, pp->dev_t);
+ LOG_MSG(1, checker_msg);
/*
- * don't trigger map reconfiguration for
- * path going down. It will be handled
- * in due time by DM event waiters
+ * upon state change, reset the checkint
+ * to the shortest delay
*/
+ pp->checkint = conf->checkint;
+
if (newstate == PATH_DOWN ||
- newstate == PATH_SHAKY)
+ newstate == PATH_SHAKY) {
+ /*
+ * proactively fail path in the DM
+ */
+ fail_path(pp);
+
+ /*
+ * cancel scheduled failback
+ */
+ pp->mpp->failback_tick = 0;
+
continue;
+ }
/*
- * reconfigure map now
+ * reinstate this path
*/
- if (safe_snprintf(cmd, CMDSIZE, "%s %s",
- conf->multipath, pp->dev_t)) {
- log_safe(LOG_ERR, "command too long,"
- " abord reconfigure");
- } else {
- log_safe(LOG_DEBUG, "%s", cmd);
- log_safe(LOG_INFO,
- "reconfigure %s multipath",
- pp->dev_t);
- execute_program(cmd, buff, 1);
- }
+ reinstate_path(pp);
+
+ /*
+ * need to switch group ?
+ */
+ update_multipath_strings(pp->mpp,
+ allpaths->pathvec);
+
+ /*
+ * schedule defered failback
+ */
+ if (pp->mpp->pgfailback > 0)
+ pp->mpp->failback_tick =
+ pp->mpp->pgfailback;
+ else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
+ need_switch_pathgroup(pp->mpp, 1))
+ switch_pathgroup(pp->mpp);
/*
- * tell waiterloop we have an event
+ * if at least one path is up in a group, and
+ * the group is disabled, re-enable it
+ */
+ if (newstate == PATH_UP)
+ enable_group(pp);
+ }
+ else if (newstate == PATH_UP || newstate == PATH_GHOST) {
+ LOG_MSG(4, checker_msg);
+ /*
+ * double the next check delay.
+ * max at conf->max_checkint
*/
- lock (event_lock);
- pending_event++;
- pthread_cond_signal(event);
- unlock (event_lock);
+ if (pp->checkint < (conf->max_checkint / 2))
+ pp->checkint = 2 * pp->checkint;
+ else
+ pp->checkint = conf->max_checkint;
+
+ pp->tick = pp->checkint;
+ condlog(4, "%s: delay next check %is",
+ pp->dev_t, pp->tick);
+
}
pp->state = newstate;
+
+ /*
+ * path prio refreshing
+ */
+ condlog(4, "path prio refresh");
+ pathinfo(pp, conf->hwtable, DI_PRIO);
+
+ if (need_switch_pathgroup(pp->mpp, 0)) {
+ if (pp->mpp->pgfailback > 0)
+ pp->mpp->failback_tick =
+ pp->mpp->pgfailback;
+ else if (pp->mpp->pgfailback ==
+ -FAILBACK_IMMEDIATE)
+ switch_pathgroup(pp->mpp);
+ }
+ }
+ defered_failback_tick(allpaths->mpvec);
+
+ if (count)
+ count--;
+ else {
+ condlog(4, "map garbage collection");
+ mpvec_garbage_collector(allpaths);
+ count = MAPGCINT;
}
- unlock(allpaths->lock);
- sleep(conf->checkint);
+
+ pthread_cleanup_pop(1);
+ sleep(1);
}
return NULL;
}
static struct paths *
-initpaths (void)
+init_paths (void)
{
- struct paths *allpaths;
+ struct paths * allpaths;
+
+ allpaths = (struct paths *)MALLOC(sizeof(struct paths));
+
+ if (!allpaths)
+ return NULL;
- allpaths = MALLOC (sizeof (struct paths));
allpaths->lock =
- (pthread_mutex_t *) MALLOC (sizeof (pthread_mutex_t));
- allpaths->pathvec = vector_alloc();
- pthread_mutex_init (allpaths->lock, NULL);
+ (pthread_mutex_t *)MALLOC(sizeof(pthread_mutex_t));
- event = (pthread_cond_t *) MALLOC (sizeof (pthread_cond_t));
- pthread_cond_init (event, NULL);
- event_lock = (pthread_mutex_t *) MALLOC (sizeof (pthread_mutex_t));
- pthread_mutex_init (event_lock, NULL);
-
- return (allpaths);
-}
+ if (!allpaths->lock)
+ goto out;
-/*
- * this logic is all about keeping callouts working in case of
- * system disk outage (think system over SAN)
- * this needs the clone syscall, so don't bother if not present
- * (Debian Woody)
- */
-#ifdef CLONE_NEWNS
-static int
-prepare_namespace(void)
-{
- mode_t mode = S_IRWXU;
- struct stat *buf;
- char ramfs_args[64];
- int i;
- int fd;
- char * bin;
- size_t size = 10;
- struct stat statbuf;
-
- buf = MALLOC(sizeof(struct stat));
+ allpaths->pathvec = vector_alloc();
- /*
- * create a temp mount point for ramfs
- */
- if (stat(CALLOUT_DIR, buf) < 0) {
- if (mkdir(CALLOUT_DIR, mode) < 0) {
- log_safe(LOG_ERR, "cannot create " CALLOUT_DIR);
- return -1;
- }
- log_safe(LOG_DEBUG, "created " CALLOUT_DIR);
- }
+ if (!allpaths->pathvec)
+ goto out1;
+
+ allpaths->mpvec = vector_alloc();
- /*
- * compute the optimal ramdisk size
- */
- vector_foreach_slot (conf->binvec, bin,i) {
- if ((fd = open(bin, O_RDONLY)) < 0) {
- log_safe(LOG_ERR, "cannot open %s", bin);
- return -1;
- }
- if (fstat(fd, &statbuf) < 0) {
- log_safe(LOG_ERR, "cannot stat %s", bin);
- return -1;
- }
- size += statbuf.st_size;
- close(fd);
- }
- log_safe(LOG_INFO, "ramfs maxsize is %u", (unsigned int) size);
+ if (!allpaths->mpvec)
+ goto out2;
- /*
- * mount the ramfs
- */
- if (safe_sprintf(ramfs_args, "maxsize=%u", (unsigned int) size)) {
- fprintf(stderr, "ramfs_args too small\n");
- return -1;
- }
- if (mount(NULL, CALLOUT_DIR, "ramfs", MS_SYNCHRONOUS, ramfs_args) < 0) {
- log_safe(LOG_ERR, "cannot mount ramfs on " CALLOUT_DIR);
- return -1;
- }
- log_safe(LOG_DEBUG, "mount ramfs on " CALLOUT_DIR);
-
- /*
- * populate the ramfs with callout binaries
- */
- vector_foreach_slot (conf->binvec, bin,i) {
- if (copytodir(bin, CALLOUT_DIR) < 0) {
- log_safe(LOG_ERR, "cannot copy %s in ramfs", bin);
- exit_daemon(1);
- }
- log_safe(LOG_DEBUG, "cp %s in ramfs", bin);
- }
- strvec_free(conf->binvec);
+ pthread_mutex_init(allpaths->lock, NULL);
- /*
- * bind the ramfs to :
- * /sbin : default home of multipath ...
- * /bin : default home of scsi_id ...
- * /tmp : home of scsi_id temp files
- */
- if (mount(CALLOUT_DIR, "/sbin", NULL, MS_BIND, NULL) < 0) {
- log_safe(LOG_ERR, "cannot bind ramfs on /sbin");
- return -1;
- }
- log_safe(LOG_DEBUG, "bind ramfs on /sbin");
- if (mount(CALLOUT_DIR, "/bin", NULL, MS_BIND, NULL) < 0) {
- log_safe(LOG_ERR, "cannot bind ramfs on /bin");
- return -1;
- }
- log_safe(LOG_DEBUG, "bind ramfs on /bin");
- if (mount(CALLOUT_DIR, "/tmp", NULL, MS_BIND, NULL) < 0) {
- log_safe(LOG_ERR, "cannot bind ramfs on /tmp");
- return -1;
- }
- log_safe(LOG_DEBUG, "bind ramfs on /tmp");
+ return allpaths;
- return 0;
+out2:
+ vector_free(allpaths->pathvec);
+out1:
+ FREE(allpaths->lock);
+out:
+ FREE(allpaths);
+ condlog(0, "failed to init paths");
+ return NULL;
}
-#endif
static void *
signal_set(int signo, void (*func) (int))
@@ -791,24 +1249,11 @@
static void
sighup (int sig)
{
- log_safe(LOG_NOTICE, "SIGHUP received from multipath or operator");
+ condlog(3, "SIGHUP received");
#ifdef _DEBUG_
- dbg_free_final(NULL);
+ dbg_free_final(NULL);
#endif
-
- /*
- * signal updatepaths() that we come from SIGHUP
- */
- from_sighup = 1;
-
- /*
- * ask for allpaths refresh
- */
- lock(event_lock);
- pending_event++;
- pthread_cond_signal(event);
- unlock(event_lock);
}
static void
@@ -837,7 +1282,7 @@
res = sched_setscheduler (0, SCHED_RR, &sched_param);
if (res == -1)
- log_safe(LOG_WARNING, "Could not set SCHED_RR at priority 99");
+ condlog(LOG_WARNING, "Could not set SCHED_RR at priority 99");
return;
}
@@ -858,85 +1303,102 @@
static int
child (void * param)
{
- pthread_t wait_thr, check_thr;
+ pthread_t check_thr, uevent_thr, uxlsnr_thr;
pthread_attr_t attr;
- struct paths *allpaths;
+ struct paths * allpaths;
mlockall(MCL_CURRENT | MCL_FUTURE);
- log_thread_start();
- log_safe(LOG_NOTICE, "--------start up--------");
+ if (logsink)
+ log_thread_start();
- if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
- log_thread_stop();
+ condlog(2, "--------start up--------");
+ condlog(2, "read " DEFAULT_CONFIGFILE);
+
+ if (load_config(DEFAULT_CONFIGFILE))
exit(1);
- }
- signal_init();
- setscheduler();
- set_oom_adj(-17);
- allpaths = initpaths();
-
- conf->checkint = CHECKINT;
setlogmask(LOG_UPTO(conf->verbosity + 3));
- condlog(2, "read " DEFAULT_CONFIGFILE);
- init_data(DEFAULT_CONFIGFILE, init_keywords);
-
/*
* fill the voids left in the config file
*/
- if (conf->binvec == NULL) {
- conf->binvec = vector_alloc();
- push_callout("/sbin/scsi_id");
- }
- if (conf->multipath == NULL) {
- conf->multipath = MULTIPATH;
- push_callout(conf->multipath);
- }
- if (conf->hwtable == NULL) {
- conf->hwtable = vector_alloc();
- setup_default_hwtable(conf->hwtable);
+ if (!conf->checkint) {
+ conf->checkint = CHECKINT;
+ conf->max_checkint = MAX_CHECKINT;
}
- if (conf->blist == NULL) {
- conf->blist = vector_alloc();
- setup_default_blist(conf->blist);
- }
- if (conf->default_selector == NULL)
- conf->default_selector = set_default(DEFAULT_SELECTOR);
-
- if (conf->udev_dir == NULL)
- conf->udev_dir = set_default(DEFAULT_UDEVDIR);
- 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 (pidfile_create(DEFAULT_PIDFILE, getpid())) {
+ if (logsink)
+ log_thread_stop();
- if (conf->default_hwhandler == NULL)
- conf->default_hwhandler = set_default(DEFAULT_HWHANDLER);
+ exit(1);
+ }
+ signal_init();
+ setscheduler();
+ set_oom_adj(-17);
+ allpaths = init_paths();
+ if (!allpaths)
+ exit(1);
-#ifdef CLONE_NEWNS
- if (prepare_namespace() < 0) {
- log_safe(LOG_ERR, "cannot prepare namespace");
- exit_daemon(1);
+ if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
+ condlog(0, "can not find sysfs mount point");
+ exit(1);
}
-#endif
+
+ /*
+ * fetch paths and multipaths lists
+ * 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);
/*
* start threads
*/
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 64 * 1024);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&wait_thr, &attr, waiterloop, allpaths);
pthread_create(&check_thr, &attr, checkerloop, allpaths);
- pthread_join(wait_thr, NULL);
- pthread_join(check_thr, NULL);
+ pthread_create(&uevent_thr, &attr, ueventloop, allpaths);
+ pthread_create(&uxlsnr_thr, &attr, uxlsnrloop, allpaths);
- return 0;
+ pthread_cond_wait(&exit_cond, &exit_mutex);
+
+ /*
+ * exit path
+ */
+ lock(allpaths->lock);
+ remove_maps(allpaths);
+ free_pathvec(allpaths->pathvec, FREE_PATHS);
+
+ pthread_cancel(check_thr);
+ pthread_cancel(uevent_thr);
+ pthread_cancel(uxlsnr_thr);
+
+ free_keys(keys);
+ free_handlers(handlers);
+ free_polls();
+
+ unlock(allpaths->lock);
+ pthread_mutex_destroy(allpaths->lock);
+ FREE(allpaths->lock);
+ FREE(allpaths);
+ free_config(conf);
+
+ condlog(2, "--------shut down-------");
+
+ if (logsink)
+ log_thread_stop();
+
+#ifdef _DEBUG_
+ dbg_free_final(NULL);
+#endif
+
+ exit(0);
}
int
@@ -946,10 +1408,11 @@
extern int optind;
int arg;
int err;
- void * child_stack;
+ logsink = 1;
+
if (getuid() != 0) {
- fprintf(stderr, "need to be root, exit");
+ fprintf(stderr, "need to be root\n");
exit(1);
}
@@ -957,20 +1420,17 @@
chdir("/");
umask(umask(077) | 022);
- child_stack = (void *)malloc(CHILD_STACK_SIZE);
-
- if (!child_stack)
- exit(1);
-
conf = alloc_config();
if (!conf)
exit(1);
- conf->verbosity = 2;
-
- while ((arg = getopt(argc, argv, ":qdlFSi:v:p:")) != EOF ) {
+ while ((arg = getopt(argc, argv, ":dv:k::")) != EOF ) {
switch(arg) {
+ case 'd':
+ logsink = 0;
+ //debug=1; /* ### comment me out ### */
+ break;
case 'v':
if (sizeof(optarg) > sizeof(char *) ||
!isdigit(optarg[0]))
@@ -978,33 +1438,26 @@
conf->verbosity = atoi(optarg);
break;
+ case 'k':
+ uxclnt(optarg);
+ exit(0);
default:
;
}
}
-#ifdef CLONE_NEWNS /* recent systems have clone() */
-
-# if defined(__hppa__) || defined(__powerpc64__)
- err = clone(child, child_stack, CLONE_NEWNS, NULL);
-# elif defined(__ia64__)
- err = clone2(child, child_stack,
- CHILD_STACK_SIZE, CLONE_NEWNS, NULL,
- NULL, NULL, NULL);
-# else
- err = clone(child, child_stack + CHILD_STACK_SIZE, CLONE_NEWNS, NULL);
-# endif
- if (err < 0)
- exit (1);
-
- exit(0);
-#else /* older system fallback to fork() */
- err = fork();
+ if (!logsink)
+ err = 0;
+ else
+ err = fork();
if (err < 0)
- exit (1);
-
- return (child(child_stack));
-#endif
-
+ /* error */
+ exit(1);
+ else if (err > 0)
+ /* parent dies */
+ exit(0);
+ else
+ /* child lives */
+ return (child(NULL));
}
Modified: multipath-tools/trunk/multipathd/main.h
==============================================================================
--- multipath-tools/trunk/multipathd/main.h (original)
+++ multipath-tools/trunk/multipathd/main.h Mon Sep 19 12:43:52 2005
@@ -1,8 +1,24 @@
-#ifndef HWTABLE_H
-#define HWTABLE_H
+#ifndef MAIN_H
+#define MAIN_H
#define DAEMON 1
#define CHECKINT 5
-#define MULTIPATH "/sbin/multipath -v0 -S"
+#define MAPGCINT 5
+#define MAX_CHECKINT CHECKINT << 2
-#endif
+struct paths {
+ 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 *);
+
+#endif /* MAIN_H */
Modified: multipath-tools/trunk/multipathd/multipathd.init.redhat
==============================================================================
--- multipath-tools/trunk/multipathd/multipathd.init.redhat (original)
+++ multipath-tools/trunk/multipathd/multipathd.init.redhat Mon Sep 19 12:43:52 2005
@@ -5,7 +5,7 @@
#
# Starts the multipath daemon
#
-# chkconfig: 2345 13 87
+# chkconfig: - 13 87
# description: Manage device-mapper multipath devices
# processname: multipathd
Added: multipath-tools/trunk/multipathd/uxclnt.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/uxclnt.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include <uxsock.h>
+#include <memory.h>
+#include <defaults.h>
+
+/*
+ * process the client
+ */
+static void process(int fd)
+{
+ char *line;
+ char *reply;
+
+ while ((line = readline("multipathd> "))) {
+ size_t len;
+
+ if (send_packet(fd, line, strlen(line) + 1) != 0) break;
+ if (recv_packet(fd, &reply, &len) != 0) break;
+
+ printf("%s\n", reply);
+
+ if (line && *line)
+ add_history(line);
+
+ free(line);
+ FREE(reply);
+ }
+}
+
+static void process_req(int fd, char * inbuf)
+{
+ char *reply;
+ size_t len;
+
+ send_packet(fd, inbuf, strlen(inbuf) + 1);
+ recv_packet(fd, &reply, &len);
+
+ printf("%s\n", reply);
+ FREE(reply);
+}
+
+/*
+ * entry point
+ */
+int uxclnt(char * inbuf)
+{
+ int fd;
+
+ fd = ux_socket_connect(DEFAULT_SOCKET);
+ if (fd == -1) {
+ perror("ux_socket_connect");
+ exit(1);
+ }
+
+ if (inbuf)
+ process_req(fd, inbuf);
+ else
+ process(fd);
+
+ return 0;
+}
Added: multipath-tools/trunk/multipathd/uxclnt.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/uxclnt.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1 @@
+int uxclnt(char * inbuf);
Added: multipath-tools/trunk/multipathd/uxlsnr.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/uxlsnr.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,164 @@
+/*
+ * A simple domain socket listener
+ * Original author : tridge at samba.org, January 2002
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+
+#include <memory.h>
+#include <debug.h>
+#include <vector.h>
+#include <structs.h>
+#include <uxsock.h>
+#include <defaults.h>
+
+#include "uxlsnr.h"
+
+#define SLEEP_TIME 5000
+
+struct client {
+ int fd;
+ struct client *next, *prev;
+};
+
+static struct client *clients;
+static unsigned num_clients;
+
+/*
+ * handle a new client joining
+ */
+static void new_client(int ux_sock)
+{
+ struct client *c;
+ struct sockaddr addr;
+ socklen_t len = sizeof(addr);
+ int fd;
+
+ fd = accept(ux_sock, &addr, &len);
+
+ if (fd == -1)
+ return;
+
+ /* put it in our linked list */
+ c = (struct client *)MALLOC(sizeof(*c));
+ memset(c, 0, sizeof(*c));
+ c->fd = fd;
+ c->next = clients;
+ if (c->next) c->next->prev = c;
+ clients = c;
+ num_clients++;
+}
+
+/*
+ * kill off a dead client
+ */
+static void dead_client(struct client *c)
+{
+ close(c->fd);
+ if (c->prev) c->prev->next = c->next;
+ if (c->next) c->next->prev = c->prev;
+ if (c == clients) clients = c->next;
+ FREE(c);
+ num_clients--;
+}
+
+void free_polls (void)
+{
+ FREE(polls);
+}
+
+/*
+ * entry point
+ */
+void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
+ void * trigger_data)
+{
+ int ux_sock;
+ size_t len;
+ int rlen;
+ char *inbuf;
+ char *reply;
+
+ ux_sock = ux_socket_listen(DEFAULT_SOCKET);
+
+ if (ux_sock == -1) {
+ condlog(0, "ux_socket_listen error");
+ exit(1);
+ }
+
+ polls = (struct pollfd *)MALLOC(0);
+
+ while (1) {
+ struct client *c;
+ int i, poll_count;
+
+ /* setup for a poll */
+ polls = REALLOC(polls, (1+num_clients) * sizeof(*polls));
+ polls[0].fd = ux_sock;
+ polls[0].events = POLLIN;
+
+ /* setup the clients */
+ for (i=1, c = clients; c; i++, c = c->next) {
+ polls[i].fd = c->fd;
+ polls[i].events = POLLIN;
+ }
+
+ /* most of our life is spent in this call */
+ poll_count = poll(polls, i, SLEEP_TIME);
+
+ if (poll_count == -1) {
+ if (errno == EINTR)
+ continue;
+
+ /* something went badly wrong! */
+ condlog(0, "poll");
+ exit(1);
+ }
+
+ if (poll_count == 0)
+ continue;
+
+ /* see if a client wants to speak to us */
+ for (i=1, c = clients; c; i++) {
+ struct client *next = c->next;
+
+ if (polls[i].revents & POLLIN) {
+ if (recv_packet(c->fd, &inbuf, &len) != 0) {
+ dead_client(c);
+ } else {
+ inbuf[len - 1] = 0;
+ condlog(4, "Got request [%s]", inbuf);
+ uxsock_trigger(inbuf, &reply, &rlen,
+ trigger_data);
+
+ if (reply) {
+ if (send_packet(c->fd, reply,
+ rlen) != 0) {
+ dead_client(c);
+ }
+ FREE(reply);
+ reply = NULL;
+ }
+ FREE(inbuf);
+ }
+ }
+ c = next;
+ }
+
+ /* see if we got a new client */
+ if (polls[0].revents & POLLIN) {
+ new_client(ux_sock);
+ }
+ }
+
+ return NULL;
+}
Added: multipath-tools/trunk/multipathd/uxlsnr.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/multipathd/uxlsnr.h Mon Sep 19 12:43:52 2005
@@ -0,0 +1,7 @@
+struct pollfd *polls;
+
+void free_polls(void);
+void * uxsock_listen(int (*uxsock_trigger)
+ (char *, char **, int *, void *),
+ void * trigger_data);
+
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 Mon Sep 19 12:43:52 2005
@@ -12,7 +12,7 @@
#
# This file is released under the GPL.
#==============================================================================
-EXEC = pp_alua
+EXEC = mpath_prio_alua
BUILD = glibc
DEBUG = 0
DEBUG_DUMPHEX = 0
@@ -39,17 +39,23 @@
$(CC) -static -o $(EXEC) $(OBJS)
$(STRIP) $(EXEC)
-install: $(EXEC)
+install: $(BUILD) $(EXEC).8.gz
install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+ install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
uninstall:
rm $(DESTDIR)$(bindir)/$(EXEC)
+ rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
+
clean:
- rm -f *.o $(EXEC)
+ rm -f *.o *.gz $(EXEC)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
+$(EXEC).8.gz: $(EXEC).8
+ $(GZIP) $< >$@
+
main.o: main.c rtpg.h spc3.h
rtpg.o: rtpg.c rtpg.h spc3.h
Modified: multipath-tools/trunk/path_priority/pp_alua/main.c
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/main.c (original)
+++ multipath-tools/trunk/path_priority/pp_alua/main.c Mon Sep 19 12:43:52 2005
@@ -12,13 +12,18 @@
*
* This file is released under the GPL.
*/
+#include <linux/kdev_t.h>
+
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
#include "rtpg.h"
@@ -30,7 +35,7 @@
#define ALUA_PRIO_GETAAS_FAILED 5
#define ALUA_PRIO_MAJOR 0
-#define ALUA_PRIO_MINOR 4
+#define ALUA_PRIO_MINOR 6
#define PRINT_ERROR(f, a...) \
if (verbose) \
@@ -59,11 +64,23 @@
basename(command));
printf("Options are:\n");
+ printf("\t-d <device directory>\n");
+ printf("\t\tSets the directory prefix for relative path names and");
+ printf(" created\n\t\tpath names. (default = \"/dev\")\n");
+
+ printf("\t-h\n");
+ printf("\t\tPrint this help.\n");
+
printf("\t-v\n");
printf("\t\tTurn on verbose output.\n");
printf("\t-V\n");
printf("\t\tPrints the version number and exits.\n");
+
+ printf("\nDevice may be an absolute or relative path to a device ");
+ printf("node or a major and\nminor number seperated by a colon (:).");
+ printf(" In this case a temporary device node\nwill be created in ");
+ printf("the device directory.\n");
}
void
@@ -168,13 +185,20 @@
int
main (int argc, char **argv)
{
- char * s_opts = "hvV";
+ char devicepath[PATH_MAX];
+ char * devicedir;
+ char * s_opts = "d:hvV";
+ char * pos;
int fd;
int rc;
int c;
+ devicedir = "/dev";
while ((c = getopt(argc, argv, s_opts)) >= 0) {
switch(c) {
+ case 'd':
+ devicedir = optarg;
+ break;
case 'h':
print_help(argv[0]);
return ALUA_PRIO_SUCCESS;
@@ -200,8 +224,32 @@
rc = ALUA_PRIO_SUCCESS;
for(c = optind; c < argc && !rc; c++) {
- fd = open_block_device(argv[c]);
+ if (argv[c][0] == '/') {
+ pos = NULL;
+ sprintf(devicepath, "%s", argv[c]);
+ } else if ((pos = index(argv[c], ':')) == NULL) {
+ sprintf(devicepath, "%s/%s", devicedir, argv[c]);
+ } else {
+ int major;
+ int minor;
+
+ major = atoi(argv[c]);
+ minor = atoi(++pos);
+ sprintf(devicepath, "%s/tmpdev-%u:%u-%u",
+ devicedir, major, minor, getpid()
+ );
+ mknod(
+ devicepath,
+ S_IFBLK|S_IRUSR|S_IWUSR,
+ MKDEV(major, minor)
+ );
+
+ }
+
+ fd = open_block_device(devicepath);
if (fd < 0) {
+ if (pos != NULL)
+ unlink(devicepath);
return -fd;
}
rc = get_alua_info(fd);
@@ -223,6 +271,10 @@
rc = ALUA_PRIO_SUCCESS;
}
close_block_device(fd);
+
+ /* The path was created before. */
+ if (pos != NULL)
+ unlink(devicepath);
}
return -rc;
Added: multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_alua/mpath_prio_alua.8 Mon Sep 19 12:43:52 2005
@@ -0,0 +1,162 @@
+.TH MPATH_PRIO_ALUA 8 "7. June 2005" "multipath-tools" \
+"Linux Administrator's Manual"
+.SH NAME
+mpath_prio_alua \- Path priority tool based on Asymmetric LUn Access
+.SH SYNOPSIS
+.B mpath_prio_alua
+.RB [\| \-d\ \c
+.IR directory \|]
+.RB [\| \-h \|]
+.RB [\| \-v \|]
+.RB [\| \-V \|]
+.IR device " \|[ " device " \|[ " ... " \|]\|]"
+.SH DESCRIPTION
+.B mpath_prio_alua
+is used as a priority callout for the multipath command. It returns a number
+that is used by multipath to group devices with the same priority together.
+.SH OPTIONS
+.TP
+.BI \-d " directory"
+target directory for devices given as relative device names or devices given
+as
+.IR major : minor \c
+ number.
+Default is "/dev".
+.TP
+.B \-h
+displays the command line help.
+.TP
+.B \-v
+turns on verbose output. This shows all results in human readable format.
+This includes information about the port group the device is in and its
+current state.
+.TP
+.B \-V
+shows the version number and exits.
+.TP
+.BI device
+specifies the device to query (the device must be a SCSI device that supports
+the \*[lq]Report Target Port Groups\*[rq] command).
+One of the following three formats may be used:
+.RS
+.IP \(bu 2
+The full path name that starts with '/' (e.g. /dev/sda).
+.IP \(bu
+The device name only. This will prefix the directory name given by the
+\-d option (e.g. sda).
+.IP \(bu
+The major and minor number of the device separated by ':'. This will
+create a temporary device node in the device directory (e.g. 8:0). The
+temporary name will be
+.RB \*[lq] tmpdev-<major>:<minor>-<pid> \*[rq].
+.SH "RETURN VALUE"
+The mpath_prio_alua command returns the following values:
+.IP \fB0
+on success. In this case the priority for the device is printed to
+stdout. The priority value is:
+.RS
+.IP \fB50\fP
+for devices that are in the active, optimized group
+.IP \fB10
+for devices that are in an active but non-optimized group
+.IP \fB1
+for devices that are in the standby group
+.IP \fB0
+for all other groups
+.RE
+.IP ""
+The reason for the widely spaced priority values is the way multipath handles
+them. It will multiply the number of paths in a group with the priority value
+and select the group with the highest result. Thus, if there are six paths in
+the active, non-optimized group and only one in the active, optimized one,
+the non-optimized group would be used.
+.IP \fB1
+Indicates an error parsing the command line.
+.IP \fB2
+The given devices could not be opened for reading.
+.IP \fB3
+The device does not support target port groups.
+.IP \fB4
+The inquiry command did not return a target port group for the given device.
+.IP \fB5
+The report target port group command failed or did not return a target
+port group that was obtained from the inquiry command.
+.SH "EXAMPLES"
+This example queries a device directly and returns the priority string:
+.P
+.RS
+.B #> mpath_prio_alua /dev/sda
+.br
+50
+.RE
+.P
+Now the major and minor number is used to specify the device and verbose
+output is selected:
+.P
+.RS
+.B #> mpath_prio_alua -v 8:0
+.br
+Target port groups are implicitly supported.
+.br
+Reported target port group is 0 [active/optimized]
+.br
+50
+.RE
+.P
+The following example shows the entries in the devices section of the
+.RI "multipath-tool configuration file (" /etc/multipath.conf )
+to support an IBM DS6000 storage system:
+.P
+.RS
+.PD 0
+device {
+.RS
+.TP 22
+.B vendor
+"IBM "
+.TP
+.B product
+"1750500 "
+.TP
+.B path_grouping_policy
+group_by_prio
+.TP
+.B prio_callout
+"/sbin/mpath_prio_alua -d/tmp %d"
+.TP
+.B features
+"1 queue_if_no_path"
+.TP
+.B path_checker
+tur
+.RE
+}
+.PD
+.RE
+.TP
+.B Notes:
+.IP \(bu 2
+Depending on your default configuration not all keywords are required
+.RB "(e.g. if your " default_path_checker " is set to tur you don't have to"
+.RB "use the " path_checker " statement in the device section)."
+.IP \(bu
+.RB "The entries for " vendor " and " product " must be strings that are 8"
+.RB "characters long (for " vendor ") and 16 characters long (for " product ")."
+The strings have to be padded with blanks if necessary.
+.IP \(bu
+If you are working with hotpluggable devices whose device nodes are created
+by udev you should use the %d flag in the
+.BR prio_callout " statement."
+This is because a short time elapses between the devices being available
+and udev creating the device nodes.
+.IP \(bu
+If under certain circumstances your storage subsystem temporarily reports
+.RB "failures on all paths, you should use the " features " statement showed"
+in the example.
+This will configure the multipath volume to requeue I/O until a path becomes
+available again, instead of reporting failures in that case.
+.SH "SEE ALSO"
+.BR multipath (8),
+.SH AUTHORS
+.B mpath_prio_alua
+was developed by Jan Kunigk and adapted by Stefan Bader <shbader at de.ibm.com>
Modified: multipath-tools/trunk/path_priority/pp_alua/rtpg.c
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/rtpg.c (original)
+++ multipath-tools/trunk/path_priority/pp_alua/rtpg.c Mon Sep 19 12:43:52 2005
@@ -123,7 +123,7 @@
memset(&cmd, 0, sizeof(cmd));
cmd.op = OPERATION_CODE_INQUIRY;
if (evpd) {
- cmd.evpd = 1;
+ inquiry_command_set_evpd(&cmd);
cmd.page = codepage;
}
set_uint16(cmd.length, resplen);
@@ -166,7 +166,7 @@
rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
if (!rc) {
- rc = inq.tpgs;
+ rc = inquiry_data_get_tpgs(&inq);
}
return rc;
@@ -189,7 +189,7 @@
if ((((char *) dscr) - ((char *) vpd83)) > sizeof(buf))
break;
- if (dscr->id_type == IDTYPE_TARGET_PORT_GROUP) {
+ if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
struct vpd83_tpg_dscr * p;
if (rc != -RTPG_NO_TPG_IDENTIFIER) {
@@ -221,7 +221,7 @@
memset(&cmd, 0, sizeof(cmd));
cmd.op = OPERATION_CODE_RTPG;
- cmd.service_action = SERVICE_ACTION_RTPG;
+ rtpg_command_set_service_action(&cmd);
set_uint32(cmd.length, resplen);
PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
@@ -270,7 +270,7 @@
"group.\n");
} else {
PRINT_DEBUG("pref=%i\n", dscr->pref);
- rc = dscr->aas;
+ rc = rtpg_tpg_dscr_get_aas(dscr);
}
}
}
Modified: multipath-tools/trunk/path_priority/pp_alua/spc3.h
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/spc3.h (original)
+++ multipath-tools/trunk/path_priority/pp_alua/spc3.h Mon Sep 19 12:43:52 2005
@@ -57,14 +57,20 @@
struct inquiry_command {
unsigned char op;
- unsigned char reserved1 : 6;
- unsigned char obsolete1 : 1;
- unsigned char evpd : 1;
+ unsigned char b1; /* xxxxxx.. = reserved */
+ /* ......x. = obsolete */
+ /* .......x = evpd */
unsigned char page;
unsigned char length[2];
unsigned char control;
} __attribute__((packed));
+static inline void
+inquiry_command_set_evpd(struct inquiry_command *ic)
+{
+ ic->b1 |= 1;
+}
+
/*-----------------------------------------------------------------------------
* Data returned by the standard inquiry command.
*-----------------------------------------------------------------------------
@@ -109,64 +115,58 @@
#define TPGS_BOTH 0x3
struct inquiry_data {
- unsigned char peripheral_qualifier : 3;
- unsigned char peripheral_device_type : 5;
- /* Removable Medium Bit (1 == removable) */
- unsigned char rmb : 1;
- unsigned char reserved1 : 7;
+ unsigned char b0; /* xxx..... = peripheral_qualifier */
+ /* ...xxxxx = peripheral_device_type */
+ unsigned char b1; /* x....... = removable medium */
+ /* .xxxxxxx = reserverd */
unsigned char version;
- unsigned char obsolete1 : 2;
- /* Normal ACA Supported */
- unsigned char norm_aca : 1;
- /* Hierarchical LUN assignment support */
- unsigned char hi_sup : 1;
- /* If 2 then response data is as defined in SPC-3. */
- unsigned char response_data_format : 4;
+ unsigned char b3; /* xx...... = obsolete */
+ /* ..x..... = normal aca supported */
+ /* ...x.... = hirarchichal lun supp. */
+ /* ....xxxx = response format */
+ /* 2 is spc-3 format */
unsigned char length;
- /* Storage Controller Component Supported. */
- unsigned char sccs : 1;
- /* Access Controls Cordinator. */
- unsigned char acc : 1;
- /* Target Port Group Support */
- unsigned char tpgs : 2;
- /* Third Party Copy support. */
- unsigned char tpc : 1;
- unsigned char reserved2 : 2;
- /* PROTECTion information supported. */
- unsigned char protect : 1;
- /* Basic task management model supported (CmdQue must be 0). */
- unsigned char bque : 1;
- /* ENClosure SERVices supported. */
- unsigned char encserv : 1;
- unsigned char vs1 : 1;
- /* MULTIPort support. */
- unsigned char multip : 1;
- /* Medium CHaNGeR. */
- unsigned char mchngr : 1;
- unsigned char obsolete2 : 2;
- unsigned char addr16 : 1;
- unsigned char obsolete3 : 2;
- unsigned char wbus16 : 1;
- unsigned char sync : 1;
- /* LINKed commands supported. */
- unsigned char link : 1;
- unsigned char obsolete4 : 1;
- unsigned char cmdque : 1;
- unsigned char vs2 : 1;
+ unsigned char b5; /* x....... = storage controller */
+ /* component supported */
+ /* .x...... = access controls coord. */
+ /* ..xx.... = target port group supp.*/
+ /* ....x... = third party copy supp. */
+ /* .....xx. = reserved */
+ /* .......x = protection info supp. */
+ unsigned char b6; /* x....... = bque */
+ /* .x...... = enclosure services sup.*/
+ /* ..x..... = vs1 */
+ /* ...x.... = multiport support */
+ /* ....x... = medium changer */
+ /* .....xx. = obsolete */
+ /* .......x = add16 */
+ unsigned char b7; /* xx...... = obsolete */
+ /* ..x..... = wbus16 */
+ /* ...x.... = sync */
+ /* ....x... = linked commands supp. */
+ /* .....x.. = obsolete */
+ /* ......x. = command queue support */
+ /* .......x = vs2 */
unsigned char vendor_identification[8];
unsigned char product_identification[8];
unsigned char product_revision[4];
unsigned char vendor_specific[20];
- unsigned char reserved3 : 4;
- unsigned char clocking : 2;
- unsigned char qas : 1;
- unsigned char ius : 1;
+ unsigned char b48; /* xxxx.... = reserved */
+ /* ....xx.. = clocking */
+ /* ......x. = qas */
+ /* .......x = ius */
unsigned char reserved4;
unsigned char version_descriptor[8][2];
unsigned char reserved5[22];
unsigned char vendor_parameters[0];
} __attribute__((packed));
+static inline int
+inquiry_data_get_tpgs(struct inquiry_data *id)
+{
+ return (id->b5 >> 4) & 3;
+}
+
/*-----------------------------------------------------------------------------
* Inquiry data returned when requesting vital product data page 0x83.
*-----------------------------------------------------------------------------
@@ -195,23 +195,28 @@
} __attribute__((packed));
struct vpd83_dscr {
- unsigned char protocol_id : 4;
- unsigned char codeset : 4;
- /* Set if the protocol_id field is valid. */
- unsigned char piv : 1;
- unsigned char reserved1 : 1;
- unsigned char association : 2;
- unsigned char id_type : 4;
+ unsigned char b0; /* xxxx.... = protocol id */
+ /* ....xxxx = codeset */
+ unsigned char b1; /* x....... = protocol id valid */
+ /* .x...... = reserved */
+ /* ..xx.... = association */
+ /* ....xxxx = id type */
unsigned char reserved2;
- unsigned char length; /* size-4 */
+ unsigned char length; /* size-4 */
unsigned char data[0];
} __attribute__((packed));
+static inline int
+vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
+{
+ return ((d->b1 & 7) == type);
+}
+
struct vpd83_data {
- unsigned char peripheral_qualifier : 3;
- unsigned char peripheral_device_type : 5;
- unsigned char page_code; /* 0x83 */
- unsigned char length[2]; /* size-4 */
+ unsigned char b0; /* xxx..... = peripheral_qualifier */
+ /* ...xxxxx = peripheral_device_type */
+ unsigned char page_code; /* 0x83 */
+ unsigned char length[2]; /* size-4 */
struct vpd83_dscr data[0];
} __attribute__((packed));
@@ -243,15 +248,21 @@
#define SERVICE_ACTION_RTPG 0x0a
struct rtpg_command {
- unsigned char op; /* 0xa3 */
- unsigned char reserved1 : 3;
- unsigned char service_action : 5; /* 0x0a */
+ unsigned char op; /* 0xa3 */
+ unsigned char b1; /* xxx..... = reserved */
+ /* ...xxxxx = service action (0x0a) */
unsigned char reserved2[4];
unsigned char length[4];
unsigned char reserved3;
unsigned char control;
} __attribute__((packed));
+static inline void
+rtpg_command_set_service_action(struct rtpg_command *cmd)
+{
+ cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
+}
+
struct rtpg_tp_dscr {
unsigned char obsolete1[2];
/* The Relative Target Port Identifier of a target port. */
@@ -269,14 +280,14 @@
#define TPG_STATUS_IMPLICIT_CHANGE 0x2
struct rtpg_tpg_dscr {
- unsigned char pref : 1;
- unsigned char reserved1 : 3;
- unsigned char aas : 4;
- unsigned char reserved2 : 4;
- unsigned char u_sup : 1;
- unsigned char s_sup : 1;
- unsigned char an_sup : 1;
- unsigned char ao_sup : 1;
+ unsigned char b0; /* x....... = pref(ered) port */
+ /* .xxx.... = reserved */
+ /* ....xxxx = asymetric access state */
+ unsigned char b1; /* xxxx.... = reserved */
+ /* ....x... = unavailable support */
+ /* .....x.. = standby support */
+ /* ......x. = non-optimized support */
+ /* .......x = optimized support */
unsigned char tpg[2];
unsigned char reserved3;
unsigned char status;
@@ -285,6 +296,12 @@
struct rtpg_tp_dscr data[0];
} __attribute__((packed));
+static inline int
+rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
+{
+ return (d->b0 & 0x0f);
+}
+
struct rtpg_data {
unsigned char length[4]; /* size-4 */
struct rtpg_tpg_dscr data[0];
Added: multipath-tools/trunk/path_priority/pp_balance_units/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_balance_units/Makefile Mon Sep 19 12:43:52 2005
@@ -0,0 +1,47 @@
+# Makefile
+#
+# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui at free.fr>
+#
+BUILD = glibc
+DEBUG = 0
+
+TOPDIR = ../..
+include $(TOPDIR)/Makefile.inc
+
+ifeq ($(strip $(BUILD)),klibc)
+ CFLAGS = -I/usr/include -DDEBUG=$(DEBUG)
+ OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
+else
+ CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
+ -I$(multipathdir) -DDEBUG=$(DEBUG)
+ LDFLAGS = -ldevmapper
+ OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
+endif
+
+EXEC = pp_balance_units
+
+all: $(BUILD)
+
+prepare:
+ rm -f core *.o *.gz
+
+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)/
+
+uninstall:
+ rm $(DESTDIR)$(bindir)/$(EXEC)
+
+clean:
+ rm -f core *.o $(EXEC) *.gz
Added: multipath-tools/trunk/path_priority/pp_balance_units/pp_balance_units.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_balance_units/pp_balance_units.c Mon Sep 19 12:43:52 2005
@@ -0,0 +1,474 @@
+/*
+ * Christophe Varoqui (2004)
+ * This code is GPLv2, see license file
+ *
+ * This path prioritizer aims to balance logical units over all
+ * controlers available. The logic is :
+ *
+ * - list all paths in all primary path groups
+ * - for each path, get the controler's serial
+ * - compute the number of active paths attached to each controler
+ * - compute the max number of paths attached to the same controler
+ * - if sums are already balanced or if the path passed as parameter is
+ * attached to controler with less active paths, then return
+ * (max_path_attached_to_one_controler - number_of_paths_on_this_controler)
+ * - else, or if anything goes wrong, return 1 as a default prio
+ *
+ */
+#define __user
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libdevmapper.h>
+#include <vector.h>
+#include <memory.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <scsi/sg.h>
+
+#define SERIAL_SIZE 255
+#define WORD_SIZE 255
+#define PARAMS_SIZE 255
+#define FILE_NAME_SIZE 255
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_CMD 0x12
+#define SENSE_BUFF_LEN 32
+#define DEF_TIMEOUT 60000
+#define RECOVERED_ERROR 0x01
+#define MX_ALLOC_LEN 255
+#define SCSI_CHECK_CONDITION 0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE 0x08
+
+#if DEBUG
+#define debug(format, arg...) fprintf(stderr, format "\n", ##arg)
+#else
+#define debug(format, arg...) do {} while(0)
+#endif
+
+#define safe_sprintf(var, format, args...) \
+ snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
+#define safe_snprintf(var, size, format, args...) \
+ snprintf(var, size, format, ##args) >= size
+
+struct path {
+ char dev_t[WORD_SIZE];
+ char serial[SERIAL_SIZE];
+};
+
+struct controler {
+ char serial[SERIAL_SIZE];
+ int path_count;
+};
+
+static int
+exit_tool (int ret)
+{
+ printf("1\n");
+ exit(ret);
+}
+
+static int
+opennode (char * devt, int mode)
+{
+ char devpath[FILE_NAME_SIZE];
+ unsigned int major;
+ unsigned int minor;
+ int fd;
+
+ sscanf(devt, "%u:%u", &major, &minor);
+ memset(devpath, 0, FILE_NAME_SIZE);
+
+ if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
+ major, minor)) {
+ fprintf(stderr, "devpath too small\n");
+ return -1;
+ }
+ unlink (devpath);
+ mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor));
+ fd = open(devpath, mode);
+
+ if (fd < 0)
+ unlink(devpath);
+
+ return fd;
+
+}
+
+static void
+closenode (char * devt, int fd)
+{
+ char devpath[FILE_NAME_SIZE];
+ unsigned int major;
+ unsigned int minor;
+
+ if (fd >= 0)
+ close(fd);
+
+ sscanf(devt, "%u:%u", &major, &minor);
+ if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
+ major, minor)) {
+ fprintf(stderr, "devpath too small\n");
+ return;
+ }
+ unlink(devpath);
+}
+
+static int
+do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
+ void *resp, int mx_resp_len, int noisy)
+{
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
+ { INQUIRY_CMD, 0, 0, 0, 0, 0 };
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (cmddt)
+ inqCmdBlk[1] |= 2;
+ if (evpd)
+ inqCmdBlk[1] |= 1;
+ inqCmdBlk[2] = (unsigned char) pg_op;
+ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+ return -1;
+
+ /* treat SG_ERR here to get rid of sg_err.[ch] */
+ io_hdr.status &= 0x7e;
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status))
+ return 0;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2)
+ sense_key = sense_buffer[1] & 0xf;
+ else
+ sense_key = sense_buffer[2] & 0xf;
+ if(RECOVERED_ERROR == sense_key)
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+get_serial (char * str, char * devt)
+{
+ int fd;
+ int len;
+ char buff[MX_ALLOC_LEN + 1];
+
+ fd = opennode(devt, O_RDONLY);
+
+ if (fd < 0)
+ return 0;
+
+ if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ len = buff[3];
+ if (len > 0) {
+ memcpy(str, buff + 4, len);
+ buff[len] = '\0';
+ }
+ close(fd);
+ return 1;
+ }
+
+ closenode(devt, fd);
+ return 0;
+}
+
+static void *
+get_params (void)
+{
+ struct dm_task *dmt, *dmt1;
+ struct dm_names *names = NULL;
+ unsigned next = 0;
+ void *nexttgt;
+ uint64_t start, length;
+ char *target_type = NULL;
+ char *params;
+ char *pp;
+ vector paramsvec = NULL;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ return NULL;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!(names = dm_task_get_names(dmt)))
+ goto out;
+
+ if (!names->dev) {
+ debug("no devmap found");
+ goto out;
+ }
+ do {
+ /*
+ * keep only multipath maps
+ */
+ names = (void *) names + next;
+ nexttgt = NULL;
+ debug("devmap %s :", names->name);
+
+ if (!(dmt1 = dm_task_create(DM_DEVICE_TABLE)))
+ goto out;
+
+ if (!dm_task_set_name(dmt1, names->name))
+ goto out1;
+
+ if (!dm_task_run(dmt1))
+ goto out1;
+
+ do {
+ nexttgt = dm_get_next_target(dmt1, nexttgt,
+ &start,
+ &length,
+ &target_type,
+ ¶ms);
+ debug("\\_ %lu %lu %s", (unsigned long) start,
+ (unsigned long) length,
+ target_type);
+
+ if (!target_type) {
+ debug("unknown target type");
+ goto out1;
+ }
+
+ if (!strncmp(target_type, "multipath", 9)) {
+ if (!paramsvec)
+ paramsvec = vector_alloc();
+
+ pp = malloc(PARAMS_SIZE);
+ strncpy(pp, params, PARAMS_SIZE);
+ vector_alloc_slot(paramsvec);
+ vector_set_slot(paramsvec, pp);
+ } else
+ debug("skip non multipath target");
+ } while (nexttgt);
+out1:
+ dm_task_destroy(dmt1);
+ next = names->next;
+ } while (next);
+out:
+ dm_task_destroy(dmt);
+ return paramsvec;
+}
+
+static int
+get_word (char *sentence, char *word)
+{
+ char *p;
+ int skip = 0;
+
+ while (*sentence == ' ') {
+ sentence++;
+ skip++;
+ }
+ p = sentence;
+
+ while (*p != ' ' && *p != '\0')
+ p++;
+
+ skip += (p - sentence);
+
+ if (p - sentence > WORD_SIZE) {
+ fprintf(stderr, "word too small\n");
+ exit_tool(1);
+ }
+ strncpy(word, sentence, WORD_SIZE);
+ word += p - sentence;
+ *word = '\0';
+
+ if (*p == '\0')
+ return 0;
+
+ return skip;
+}
+
+static int
+is_path (char * word)
+{
+ char *p;
+
+ if (!word)
+ return 0;
+
+ p = word;
+
+ while (*p != '\0') {
+ if (*p == ':')
+ return 1;
+ p++;
+ }
+ return 0;
+}
+
+static int
+get_paths (vector pathvec)
+{
+ vector paramsvec = NULL;
+ char * str;
+ struct path * pp;
+ int i;
+ enum where {BEFOREPG, INPG, AFTERPG};
+ int pos = BEFOREPG;
+
+ if (!pathvec)
+ return 1;
+
+ if (!(paramsvec = get_params()))
+ exit_tool(0);
+
+ vector_foreach_slot (paramsvec, str, i) {
+ debug("params %s", str);
+ while (pos != AFTERPG) {
+ pp = zalloc(sizeof(struct path));
+ str += get_word(str, pp->dev_t);
+
+ if (!is_path(pp->dev_t)) {
+ debug("skip \"%s\"", pp->dev_t);
+ free(pp);
+
+ if (pos == INPG)
+ pos = AFTERPG;
+
+ continue;
+ }
+ if (pos == BEFOREPG)
+ pos = INPG;
+
+ get_serial(pp->serial, pp->dev_t);
+ vector_alloc_slot(pathvec);
+ vector_set_slot(pathvec, pp);
+ debug("store %s [%s]",
+ pp->dev_t, pp->serial);
+ }
+ pos = BEFOREPG;
+ }
+ return 0;
+}
+
+static void *
+find_controler (vector controlers, char * serial)
+{
+ int i;
+ struct controler * cp;
+
+ if (!controlers)
+ return NULL;
+
+ vector_foreach_slot (controlers, cp, i)
+ if (!strncmp(cp->serial, serial, SERIAL_SIZE))
+ return cp;
+ return NULL;
+}
+
+static void
+get_controlers (vector controlers, vector pathvec)
+{
+ int i;
+ struct path * pp;
+ struct controler * cp;
+
+ if (!controlers)
+ return;
+
+ vector_foreach_slot (pathvec, pp, i) {
+ if (!pp || !strlen(pp->serial))
+ continue;
+
+ cp = find_controler(controlers, pp->serial);
+
+ if (!cp) {
+ cp = zalloc(sizeof(struct controler));
+ vector_alloc_slot(controlers);
+ vector_set_slot(controlers, cp);
+ strncpy(cp->serial, pp->serial, SERIAL_SIZE);
+ }
+ cp->path_count++;
+ }
+}
+
+static int
+get_max_path_count (vector controlers)
+{
+ int i;
+ int max = 0;
+ struct controler * cp;
+
+ if (!controlers)
+ return 0;
+
+ vector_foreach_slot (controlers, cp, i) {
+ debug("controler %s : %i paths", cp->serial, cp->path_count);
+ if(cp->path_count > max)
+ max = cp->path_count;
+ }
+ debug("max_path_count = %i", max);
+ return max;
+}
+
+int
+main (int argc, char **argv)
+{
+ vector pathvec = NULL;
+ vector controlers = NULL;
+ struct path * ref_path = NULL;
+ struct controler * cp = NULL;
+ int max_path_count = 0;
+
+ ref_path = zalloc(sizeof(struct path));
+
+ if (!ref_path)
+ exit_tool(1);
+
+ if (argc != 2)
+ exit_tool(1);
+
+ if (optind<argc)
+ strncpy(ref_path->dev_t, argv[optind], WORD_SIZE);
+
+ get_serial(ref_path->serial, ref_path->dev_t);
+
+ if (!ref_path->serial || !strlen(ref_path->serial))
+ exit_tool(0);
+
+ pathvec = vector_alloc();
+ controlers = vector_alloc();
+
+ get_paths(pathvec);
+ get_controlers(controlers, pathvec);
+ max_path_count = get_max_path_count(controlers);
+ cp = find_controler(controlers, ref_path->serial);
+
+ if (!cp) {
+ debug("no other active path on serial %s\n",
+ ref_path->serial);
+ exit_tool(0);
+ }
+
+ printf("%i\n", max_path_count - cp->path_count + 1);
+
+ return(0);
+}
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 Mon Sep 19 12:43:52 2005
@@ -1,4 +1,4 @@
-EXEC = pp_emc
+EXEC = mpath_prio_emc
BUILD = glibc
OBJS = pp_emc.o
More information about the pkg-lvm-commits
mailing list