forked from pool/multipath-tools
3097 lines
83 KiB
Plaintext
3097 lines
83 KiB
Plaintext
Makefile.inc | 1 -
|
|
devmap_name/Makefile | 5 +-
|
|
kpartx/Makefile | 10 +-
|
|
kpartx/devmapper.c | 29 ++
|
|
kpartx/devmapper.h | 1 +
|
|
kpartx/dos.c | 7 +-
|
|
kpartx/kpartx.c | 125 ++++++++--
|
|
kpartx/kpartx.h | 3 +
|
|
kpartx/kpartx_id | 110 ++++++++
|
|
libcheckers/Makefile | 4 +-
|
|
libmultipath/Makefile | 6 +-
|
|
libmultipath/config.h | 1 +
|
|
libmultipath/configure.c | 4 +-
|
|
libmultipath/discovery.c | 422 ++++++++++++-------------------
|
|
libmultipath/discovery.h | 7 +-
|
|
libmultipath/list.h | 289 +++++++++++++++++++++
|
|
libmultipath/print.c | 47 ++--
|
|
libmultipath/structs.h | 15 +-
|
|
libmultipath/structs_vec.c | 7 +-
|
|
libmultipath/sysfs.c | 405 +++++++++++++++++++++++++++++
|
|
libmultipath/sysfs.h | 20 ++
|
|
libmultipath/uevent.c | 99 +++++---
|
|
libmultipath/util.c | 52 ++++
|
|
libmultipath/util.h | 4 +-
|
|
multipath/Makefile | 10 +-
|
|
multipath/main.c | 11 +-
|
|
multipath/multipath.init.suse | 104 ++++++++
|
|
multipathd/71-multipath.rules | 27 ++
|
|
multipathd/Makefile | 7 +-
|
|
multipathd/cli_handlers.c | 17 ++-
|
|
multipathd/main.c | 92 +++----
|
|
multipathd/main.h | 2 +-
|
|
multipathd/multipathd.init.suse | 155 +++++++++++
|
|
path_priority/pp_alua/Makefile | 3 +-
|
|
path_priority/pp_balance_units/Makefile | 6 +-
|
|
path_priority/pp_emc/Makefile | 2 +-
|
|
path_priority/pp_hds_modular/Makefile | 2 +-
|
|
path_priority/pp_netapp/Makefile | 2 +-
|
|
path_priority/pp_random/Makefile | 2 +-
|
|
path_priority/pp_tpc/Makefile | 2 +-
|
|
40 files changed, 1685 insertions(+), 432 deletions(-)
|
|
|
|
diff --git a/Makefile.inc b/Makefile.inc
|
|
index fe6cbdf..786565c 100644
|
|
--- a/Makefile.inc
|
|
+++ b/Makefile.inc
|
|
@@ -17,7 +17,6 @@ ifeq ($(strip $(BUILD)),klibc)
|
|
CC = klcc
|
|
klibcdir = /usr/lib/klibc
|
|
libdm = $(klibcdir)/lib/libdevmapper.a
|
|
- libsysfs = $(klibcdir)/lib/libsysfs.a
|
|
endif
|
|
|
|
prefix =
|
|
diff --git a/devmap_name/Makefile b/devmap_name/Makefile
|
|
index 8b0c678..57051d9 100644
|
|
--- a/devmap_name/Makefile
|
|
+++ b/devmap_name/Makefile
|
|
@@ -18,7 +18,7 @@ EXEC = devmap_name
|
|
all: $(BUILD)
|
|
|
|
prepare:
|
|
- rm -f core *.o *.gz
|
|
+ rm -f core *.o
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
@@ -34,7 +34,6 @@ install: $(EXEC) $(EXEC).8
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
- rm -f core *.o $(EXEC) *.gz
|
|
+ rm -f core *.o $(EXEC)
|
|
diff --git a/kpartx/Makefile b/kpartx/Makefile
|
|
index 522a6a0..9832467 100644
|
|
--- a/kpartx/Makefile
|
|
+++ b/kpartx/Makefile
|
|
@@ -23,7 +23,7 @@ EXEC = kpartx
|
|
all: $(BUILD)
|
|
|
|
prepare:
|
|
- rm -f core *.o *.gz
|
|
+ rm -f core *.o
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
@@ -34,15 +34,15 @@ klibc: prepare $(OBJS)
|
|
$(MULTIPATHLIB)-$(BUILD).a:
|
|
make -C $(multipathdir) BUILD=$(BUILD)
|
|
|
|
-install: $(EXEC) $(EXEC).8
|
|
+install: $(EXEC) kpartx_id $(EXEC).8
|
|
install -d $(DESTDIR)$(bindir)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
+ install -m 755 kpartx_id $(DESTDIR)$(bindir)
|
|
install -d $(DESTDIR)$(mandir)
|
|
install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
|
|
uninstall:
|
|
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
|
|
|
|
clean:
|
|
- rm -f core *.o $(EXEC) *.gz
|
|
+ rm -f core *.o $(EXEC)
|
|
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
|
|
index 4b228ed..e5da022 100644
|
|
--- a/kpartx/devmapper.c
|
|
+++ b/kpartx/devmapper.c
|
|
@@ -219,3 +219,32 @@ out:
|
|
dm_task_destroy(dmt);
|
|
return uuid;
|
|
}
|
|
+
|
|
+int
|
|
+dm_devn (char * mapname, int *major, int *minor)
|
|
+{
|
|
+ int r = 1;
|
|
+ struct dm_task *dmt;
|
|
+ struct dm_info info;
|
|
+
|
|
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
|
+ return 0;
|
|
+
|
|
+ if (!dm_task_set_name(dmt, mapname))
|
|
+ goto out;
|
|
+
|
|
+ if (!dm_task_run(dmt))
|
|
+ goto out;
|
|
+
|
|
+ if (!dm_task_get_info(dmt, &info))
|
|
+ goto out;
|
|
+
|
|
+ *major = info.major;
|
|
+ *minor = info.minor;
|
|
+
|
|
+ r = 0;
|
|
+out:
|
|
+ dm_task_destroy(dmt);
|
|
+ return r;
|
|
+}
|
|
+
|
|
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
|
|
index e20e456..ccdbead 100644
|
|
--- a/kpartx/devmapper.h
|
|
+++ b/kpartx/devmapper.h
|
|
@@ -6,3 +6,4 @@ int dm_map_present (char *);
|
|
char * dm_mapname(int major, int minor);
|
|
dev_t dm_get_first_dep(char *devname);
|
|
char * dm_mapuuid(int major, int minor);
|
|
+int dm_devn (char * mapname, int *major, int *minor);
|
|
diff --git a/kpartx/dos.c b/kpartx/dos.c
|
|
index a707423..1691105 100644
|
|
--- a/kpartx/dos.c
|
|
+++ b/kpartx/dos.c
|
|
@@ -16,7 +16,7 @@ is_extended(int type) {
|
|
}
|
|
|
|
static int
|
|
-read_extended_partition(int fd, struct partition *ep,
|
|
+read_extended_partition(int fd, struct partition *ep, int en,
|
|
struct slice *sp, int ns)
|
|
{
|
|
struct partition p;
|
|
@@ -53,6 +53,7 @@ read_extended_partition(int fd, struct p
|
|
if (n < ns) {
|
|
sp[n].start = here + le32_to_cpu(p.start_sect);
|
|
sp[n].size = le32_to_cpu(p.nr_sects);
|
|
+ sp[n].container = en + 1;
|
|
n++;
|
|
} else {
|
|
fprintf(stderr,
|
|
@@ -97,9 +98,7 @@ read_dos_pt(int fd, struct slice all, st
|
|
break;
|
|
}
|
|
if (is_extended(p.sys_type)) {
|
|
- n += read_extended_partition(fd, &p, sp+n, ns-n);
|
|
- /* hide the extended partition itself */
|
|
- sp[i].size = 0;
|
|
+ n += read_extended_partition(fd, &p, i, sp+n, ns-n);
|
|
}
|
|
}
|
|
return n;
|
|
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
|
index b406b95..c48a59c 100644
|
|
--- a/kpartx/kpartx.c
|
|
+++ b/kpartx/kpartx.c
|
|
@@ -182,7 +182,7 @@ get_hotplug_device(void)
|
|
|
|
int
|
|
main(int argc, char **argv){
|
|
- int fd, i, j, k, n, op, off, arg;
|
|
+ int fd, i, j, k, m, n, op, off, arg, c, d;
|
|
struct slice all;
|
|
struct pt *ptp;
|
|
enum action what = LIST;
|
|
@@ -353,30 +353,47 @@ main(int argc, char **argv){
|
|
else
|
|
continue;
|
|
|
|
- /*
|
|
- * test for overlap, as in the case of an extended partition
|
|
- * zero their size to avoid mapping
|
|
- */
|
|
- for (j=0; j<n; j++) {
|
|
- for (k=j+1; k<n; k++) {
|
|
- if (slices[k].start > slices[j].start &&
|
|
- slices[k].start < slices[j].start +
|
|
- slices[j].size)
|
|
- slices[j].size = 0;
|
|
- }
|
|
- }
|
|
-
|
|
switch(what) {
|
|
case LIST:
|
|
- for (j = 0; j < n; j++) {
|
|
+ for (j = 0, c = 0, m = 0; j < n; j++) {
|
|
if (slices[j].size == 0)
|
|
continue;
|
|
+ if (slices[j].container > 0) {
|
|
+ c++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ slices[j].minor = m++;
|
|
|
|
printf("%s%s%d : 0 %lu %s %lu\n",
|
|
mapname, delim, j+1,
|
|
(unsigned long) slices[j].size, device,
|
|
(unsigned long) slices[j].start);
|
|
}
|
|
+ /* Loop to resolve contained slices */
|
|
+ d = c;
|
|
+ while (c) {
|
|
+ for (j = 0; j < n; j++) {
|
|
+ if (slices[j].size == 0)
|
|
+ continue;
|
|
+ if (slices[j].minor > 0)
|
|
+ continue;
|
|
+ if (slices[j].container == 0)
|
|
+ continue;
|
|
+ slices[j].minor = m++;
|
|
+
|
|
+ printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n",
|
|
+ mapname, delim, j+1,
|
|
+ (unsigned long) slices[j].size,
|
|
+ slices[j].minor,
|
|
+ (unsigned long) slices[j].start);
|
|
+ c--;
|
|
+ }
|
|
+ /* Terminate loop if nothing more to resolve */
|
|
+ if (d == c)
|
|
+ break;
|
|
+ }
|
|
+
|
|
break;
|
|
|
|
case DELETE:
|
|
@@ -410,10 +427,16 @@ main(int argc, char **argv){
|
|
break;
|
|
|
|
case ADD:
|
|
- for (j=0; j<n; j++) {
|
|
+ for (j=0, c = 0; j<n; j++) {
|
|
if (slices[j].size == 0)
|
|
continue;
|
|
|
|
+ /* Skip all contained slices */
|
|
+ if (slices[j].container > 0) {
|
|
+ c++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (safe_sprintf(partname, "%s%s%d",
|
|
mapname, delim, j+1)) {
|
|
fprintf(stderr, "partname too small\n");
|
|
@@ -437,10 +460,74 @@ main(int argc, char **argv){
|
|
dm_simplecmd(DM_DEVICE_RESUME,
|
|
partname);
|
|
|
|
+ dm_devn(partname, &slices[j].major,
|
|
+ &slices[j].minor);
|
|
+
|
|
if (verbose)
|
|
- printf("add map %s : 0 %lu %s %s\n",
|
|
- partname, slices[j].size,
|
|
- DM_TARGET, params);
|
|
+ printf("add map %s (%d:%d): 0 %lu %s %s\n",
|
|
+ partname, slices[j].major,
|
|
+ slices[j].minor, slices[j].size,
|
|
+ DM_TARGET, params);
|
|
+ }
|
|
+ /* Loop to resolve contained slices */
|
|
+ d = c;
|
|
+ while (c) {
|
|
+ for (j = 0; j < n; j++) {
|
|
+ int k = slices[j].container - 1;
|
|
+
|
|
+ if (slices[j].size == 0)
|
|
+ continue;
|
|
+
|
|
+ /* Skip all existing slices */
|
|
+ if (slices[j].minor > 0)
|
|
+ continue;
|
|
+
|
|
+ /* Skip all simple slices */
|
|
+ if (k < 0)
|
|
+ continue;
|
|
+
|
|
+ /* Check container slice */
|
|
+ if (slices[k].size == 0)
|
|
+ fprintf(stderr, "Invalid slice %d\n",
|
|
+ k);
|
|
+
|
|
+ if (safe_sprintf(partname, "%s%s%d",
|
|
+ mapname, delim, j+1)) {
|
|
+ fprintf(stderr, "partname too small\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ strip_slash(partname);
|
|
+
|
|
+ if (safe_sprintf(params, "%d:%d %lu",
|
|
+ slices[k].major,
|
|
+ slices[k].minor,
|
|
+ (unsigned long)slices[j].start)) {
|
|
+ fprintf(stderr, "params too small\n");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ op = (dm_map_present(partname) ?
|
|
+ DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
|
|
+
|
|
+ dm_addmap(op, partname, DM_TARGET, params,
|
|
+ slices[j].size, uuid, j+1);
|
|
+
|
|
+ if (op == DM_DEVICE_RELOAD)
|
|
+ dm_simplecmd(DM_DEVICE_RESUME,
|
|
+ partname);
|
|
+
|
|
+ dm_devn(partname, &slices[j].major,
|
|
+ &slices[j].minor);
|
|
+
|
|
+ if (verbose)
|
|
+ printf("add map %s : 0 %lu %s %s\n",
|
|
+ partname, slices[j].size,
|
|
+ DM_TARGET, params);
|
|
+ c--;
|
|
+ }
|
|
+ /* Terminate loop */
|
|
+ if (d == c)
|
|
+ break;
|
|
}
|
|
break;
|
|
|
|
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
|
|
index 6a715de..b49c543 100644
|
|
--- a/kpartx/kpartx.h
|
|
+++ b/kpartx/kpartx.h
|
|
@@ -22,6 +22,9 @@
|
|
struct slice {
|
|
unsigned long start;
|
|
unsigned long size;
|
|
+ int container;
|
|
+ int major;
|
|
+ int minor;
|
|
};
|
|
|
|
typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns);
|
|
diff --git a/kpartx/kpartx_id b/kpartx/kpartx_id
|
|
new file mode 100644
|
|
index 0000000..c599e5d
|
|
--- /dev/null
|
|
+++ b/kpartx/kpartx_id
|
|
@@ -0,0 +1,110 @@
|
|
+#!/bin/bash
|
|
+#
|
|
+# kpartx_id
|
|
+#
|
|
+# Generates ID information for device-mapper tables.
|
|
+#
|
|
+# Copyright (C) 2006 SUSE Linux Products GmbH
|
|
+# Author:
|
|
+# Hannes Reinecke <hare@suse.de>
|
|
+#
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify it
|
|
+# under the terms of the GNU General Public License as published by the
|
|
+# Free Software Foundation version 2 of the License.
|
|
+#
|
|
+# This script generates ID information used to generate persistent symlinks.
|
|
+# It relies on the UUID strings generated by the various programs; the name
|
|
+# of the tables are of no consequence.
|
|
+#
|
|
+# Please note that dmraid does not provide the UUIDs (yet); a patch has been
|
|
+# sent upstream but has not been accepted yet.
|
|
+#
|
|
+
|
|
+DMSETUP=/sbin/dmsetup
|
|
+
|
|
+MAJOR=$1
|
|
+MINOR=$2
|
|
+
|
|
+if [ -z "$MAJOR" -o -z "$MINOR" ]; then
|
|
+ echo "usage: $0 major minor"
|
|
+ exit 1;
|
|
+fi
|
|
+
|
|
+# Device-mapper not installed; not an error
|
|
+if [ ! -x $DMSETUP ] ; then
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+# Get the table info
|
|
+tblinfo=$($DMSETUP info -c --noheadings -o name,uuid -j $MAJOR -m $MINOR)
|
|
+if [ $? -ne 0 ] || [ -z "$tblinfo" ]; then
|
|
+ exit $?
|
|
+fi
|
|
+
|
|
+set -- $(IFS=":"; echo $tblinfo)
|
|
+tblname=$1
|
|
+tbluuid=$2
|
|
+
|
|
+if [ -z "$tbluuid" ] ; then
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+# Table UUIDs are always '<type>-<uuid>'.
|
|
+dmuuid=${tbluuid#*-}
|
|
+dmtbl=${tbluuid%%-*}
|
|
+dmpart=${dmtbl#part}
|
|
+# kpartx types are 'part<num>'
|
|
+if [ "$dmpart" == "$dmtbl" ] ; then
|
|
+ dmpart=
|
|
+else
|
|
+ dmtbl=part
|
|
+fi
|
|
+
|
|
+# Set the name of the table. We're only interested in dmraid,
|
|
+# multipath, and kpartx tables; everything else is ignored.
|
|
+if [ "$dmtbl" == "part" ] ; then
|
|
+ # The name of the kpartx table is the name of the parent table
|
|
+ dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid)
|
|
+ # We need the dependencies of the parent table to figure out
|
|
+ # the type if the parent is a multipath table
|
|
+ case "$dmparent" in
|
|
+ mpath-*)
|
|
+ dmdeps=$($DMSETUP deps -u $dmuuid)
|
|
+ ;;
|
|
+ esac
|
|
+elif [ "$dmtbl" == "mpath" ] ; then
|
|
+ dmname=$tblname
|
|
+ # We need the dependencies of the table to figure out the type
|
|
+ dmdeps=$($DMSETUP deps -u $tbluuid)
|
|
+elif [ "$dmtbl" == "dmraid" ] ; then
|
|
+ dmname=$tblname
|
|
+fi
|
|
+
|
|
+if [ -z "$dmname" ] ; then
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+echo "ID_DM_TABLE=$dmtbl"
|
|
+echo "ID_DM_NAME=$dmname"
|
|
+[ -n "$dmpart" ] && echo "ID_DM_PART=$dmpart"
|
|
+
|
|
+# Figure out the type of the map. For non-multipath maps it's
|
|
+# always 'raid'.
|
|
+if [ -n "$dmdeps" ] ; then
|
|
+ case "$dmdeps" in
|
|
+ *\(94,*)
|
|
+ echo "ID_DM_TYPE=dasd"
|
|
+ ;;
|
|
+ *\(9*)
|
|
+ echo "ID_DM_TYPE=raid"
|
|
+ ;;
|
|
+ *)
|
|
+ echo "ID_DM_TYPE=scsi"
|
|
+ ;;
|
|
+ esac
|
|
+else
|
|
+ echo "ID_DM_TYPE=raid"
|
|
+fi
|
|
+
|
|
+exit 0
|
|
diff --git a/libcheckers/Makefile b/libcheckers/Makefile
|
|
index 6340a68..bdd423f 100644
|
|
--- a/libcheckers/Makefile
|
|
+++ b/libcheckers/Makefile
|
|
@@ -11,7 +11,7 @@ OBJS = libsg.o checkers.o readsector0.o
|
|
all: $(BUILD)
|
|
|
|
prepare:
|
|
- @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
|
|
+ @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o
|
|
|
|
klibc: prepare $(OBJS)
|
|
ar rs libcheckers-klibc.a *.o
|
|
@@ -24,4 +24,4 @@ install:
|
|
uninstall:
|
|
|
|
clean:
|
|
- rm -f core *.a *.o *.gz
|
|
+ rm -f core *.a *.o
|
|
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
|
|
index ef561a8..a6ad89b 100644
|
|
--- a/libmultipath/Makefile
|
|
+++ b/libmultipath/Makefile
|
|
@@ -13,7 +13,7 @@ OBJS = memory.o parser.o vector.o devmap
|
|
structs.o discovery.o propsel.o dict.o \
|
|
pgpolicies.o debug.o regex.o defaults.o uevent.o \
|
|
switchgroup.o uxsock.o print.o alias.o log_pthread.o \
|
|
- log.o configure.o structs_vec.o
|
|
+ log.o configure.o structs_vec.o sysfs.o
|
|
|
|
PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
|
|
|
|
@@ -34,7 +34,7 @@ endif
|
|
all: $(BUILD)
|
|
|
|
prepare: $(CLEAN)
|
|
- @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
|
|
+ @file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o
|
|
@rm -f *-$(BUILD).a
|
|
|
|
klibc: $(OBJS)
|
|
@@ -48,4 +48,4 @@ install:
|
|
uninstall:
|
|
|
|
clean:
|
|
- rm -f core *.a *.o *.gz
|
|
+ rm -f core *.a *.o
|
|
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
|
index 7caa11d..a25b3ad 100644
|
|
--- a/libmultipath/config.h
|
|
+++ b/libmultipath/config.h
|
|
@@ -66,6 +66,7 @@ struct config {
|
|
int pg_timeout;
|
|
|
|
char * dev;
|
|
+ char * sysfs_dir;
|
|
char * udev_dir;
|
|
char * selector;
|
|
char * getuid;
|
|
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
|
index a5bad4c..3cd6041 100644
|
|
--- a/libmultipath/configure.c
|
|
+++ b/libmultipath/configure.c
|
|
@@ -325,8 +325,10 @@ domap (struct multipath * mpp)
|
|
return DOMAP_RETRY;
|
|
}
|
|
|
|
- if (dm_map_present(mpp->alias))
|
|
+ if (dm_map_present(mpp->alias)) {
|
|
+ condlog(3, "%s: map already present", mpp->alias);
|
|
break;
|
|
+ }
|
|
|
|
r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
|
|
mpp->params, mpp->size, mpp->wwid);
|
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
|
index a196583..52e0621 100644
|
|
--- a/libmultipath/discovery.c
|
|
+++ b/libmultipath/discovery.c
|
|
@@ -8,9 +8,8 @@
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
+#include <dirent.h>
|
|
#include <errno.h>
|
|
-#include <sysfs/dlist.h>
|
|
-#include <sysfs/libsysfs.h>
|
|
|
|
#include <checkers.h>
|
|
|
|
@@ -24,6 +23,7 @@
|
|
#include "debug.h"
|
|
#include "propsel.h"
|
|
#include "sg_include.h"
|
|
+#include "sysfs.h"
|
|
#include "discovery.h"
|
|
|
|
struct path *
|
|
@@ -87,127 +87,117 @@ path_discover (vector pathvec, struct co
|
|
int
|
|
path_discovery (vector pathvec, struct config * conf, int flag)
|
|
{
|
|
- struct dlist * ls;
|
|
- struct sysfs_class * class;
|
|
- struct sysfs_class_device * dev;
|
|
- int r = 1;
|
|
-
|
|
- if (!(class = sysfs_open_class("block")))
|
|
+ DIR *blkdir;
|
|
+ struct dirent *blkdev;
|
|
+ struct stat statbuf;
|
|
+ char devpath[PATH_MAX];
|
|
+ char *devptr;
|
|
+ int r = 0;
|
|
+
|
|
+ if (!(blkdir = opendir("/sys/block")))
|
|
return 1;
|
|
|
|
- if (!(ls = sysfs_get_class_devices(class)))
|
|
- goto out;
|
|
+ strcpy(devpath,"/sys/block");
|
|
+ while ((blkdev = readdir(blkdir)) != NULL) {
|
|
+ if ((strcmp(blkdev->d_name,".") == 0) ||
|
|
+ (strcmp(blkdev->d_name,"..") == 0))
|
|
+ continue;
|
|
|
|
- r = 0;
|
|
+ devptr = devpath + 10;
|
|
+ *devptr = '\0';
|
|
+ strcat(devptr,"/");
|
|
+ strcat(devptr,blkdev->d_name);
|
|
+ if (stat(devpath, &statbuf) < 0)
|
|
+ continue;
|
|
|
|
- dlist_for_each_data(ls, dev, struct sysfs_class_device)
|
|
- r += path_discover(pathvec, conf, dev->name, flag);
|
|
+ if (S_ISDIR(statbuf.st_mode) == 0)
|
|
+ continue;
|
|
|
|
-out:
|
|
- sysfs_close_class(class);
|
|
- return r;
|
|
-}
|
|
+ condlog(4, "Discover device %s", devpath);
|
|
|
|
-/*
|
|
- * the daemon can race udev upon path add,
|
|
- * not multipath(8), ran by udev
|
|
- */
|
|
-#if DAEMON
|
|
-#define WAIT_MAX_SECONDS 60
|
|
-#define WAIT_LOOP_PER_SECOND 5
|
|
-
|
|
-static int
|
|
-wait_for_file (char * filename)
|
|
-{
|
|
- int loop;
|
|
- struct stat stats;
|
|
-
|
|
- loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
|
|
-
|
|
- while (--loop) {
|
|
- if (stat(filename, &stats) == 0)
|
|
- return 0;
|
|
-
|
|
- if (errno != ENOENT)
|
|
- return 1;
|
|
-
|
|
- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
|
|
+ r += path_discover(pathvec, conf, blkdev->d_name, flag);
|
|
}
|
|
- return 1;
|
|
-}
|
|
-#else
|
|
-static int
|
|
-wait_for_file (char * filename)
|
|
-{
|
|
- return 0;
|
|
+ closedir(blkdir);
|
|
+ condlog(4, "Discovery status %d", r);
|
|
+ return r;
|
|
}
|
|
-#endif
|
|
|
|
-#define declare_sysfs_get_str(fname, fmt) \
|
|
+#define declare_sysfs_get_str(fname) \
|
|
extern int \
|
|
-sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
|
|
+sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
|
|
{ \
|
|
- struct sysfs_attribute * attr; \
|
|
- char attr_path[SYSFS_PATH_SIZE]; \
|
|
+ char *attr; \
|
|
\
|
|
- if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
|
|
+ attr = sysfs_attr_get_value(dev->devpath, #fname); \
|
|
+ if (!attr) \
|
|
return 1; \
|
|
\
|
|
- if (wait_for_file(attr_path)) \
|
|
- return 1; \
|
|
-\
|
|
- if (!(attr = sysfs_open_attribute(attr_path))) \
|
|
- return 1; \
|
|
-\
|
|
- if (0 > sysfs_read_attribute(attr)) \
|
|
- goto out; \
|
|
-\
|
|
- if (attr->len < 2 || attr->len - 1 > len) \
|
|
- goto out; \
|
|
-\
|
|
- strncpy(buff, attr->value, attr->len - 1); \
|
|
- strchop(buff); \
|
|
- sysfs_close_attribute(attr); \
|
|
+ if (strlcpy(buff, attr, len) != strlen(attr)) \
|
|
+ return 2; \
|
|
return 0; \
|
|
-out: \
|
|
- sysfs_close_attribute(attr); \
|
|
- return 1; \
|
|
}
|
|
|
|
-declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
|
|
-declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
|
|
-declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
|
|
-declare_sysfs_get_str(model, "%s/block/%s/device/model");
|
|
-declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
|
|
-declare_sysfs_get_str(dev, "%s/block/%s/dev");
|
|
+declare_sysfs_get_str(devtype);
|
|
+declare_sysfs_get_str(cutype);
|
|
+declare_sysfs_get_str(vendor);
|
|
+declare_sysfs_get_str(model);
|
|
+declare_sysfs_get_str(rev);
|
|
|
|
int
|
|
-sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
|
|
+sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len)
|
|
{
|
|
- struct sysfs_attribute * attr;
|
|
- char attr_path[SYSFS_PATH_SIZE];
|
|
- int r;
|
|
+ char *attr;
|
|
|
|
- if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
|
|
+ attr = sysfs_attr_get_value(dev->devpath, "dev");
|
|
+ if (!attr) {
|
|
+ condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel);
|
|
return 1;
|
|
+ }
|
|
+ if (strlcpy(buff, attr, len) != strlen(attr)) {
|
|
+ condlog(3, "%s: overflow in 'dev' attribute", dev->kernel);
|
|
+ return 2;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
|
|
- attr = sysfs_open_attribute(attr_path);
|
|
+int
|
|
+sysfs_get_size (struct sysfs_device * dev, unsigned long long * size)
|
|
+{
|
|
+ char *attr;
|
|
+ int r;
|
|
|
|
+ attr = sysfs_attr_get_value(dev->devpath, "size");
|
|
if (!attr)
|
|
return 1;
|
|
|
|
- if (0 > sysfs_read_attribute(attr))
|
|
- goto out;
|
|
-
|
|
- r = sscanf(attr->value, "%llu\n", size);
|
|
- sysfs_close_attribute(attr);
|
|
+ r = sscanf(attr, "%llu\n", size);
|
|
|
|
if (r != 1)
|
|
return 1;
|
|
|
|
return 0;
|
|
-out:
|
|
- sysfs_close_attribute(attr);
|
|
+}
|
|
+
|
|
+int
|
|
+sysfs_get_fc_nodename (struct sysfs_device * dev, char * node,
|
|
+ unsigned int host, unsigned int channel,
|
|
+ unsigned int target)
|
|
+{
|
|
+ char attr_path[SYSFS_PATH_SIZE], *attr;
|
|
+
|
|
+ if (safe_sprintf(attr_path,
|
|
+ "/class/fc_transport/target%i:%i:%i",
|
|
+ host, channel, target)) {
|
|
+ condlog(0, "attr_path too small");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ attr = sysfs_attr_get_value(attr_path, "node_name");
|
|
+ if (attr) {
|
|
+ strlcpy(node, attr, strlen(attr));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
return 1;
|
|
}
|
|
|
|
@@ -224,68 +214,52 @@ opennode (char * dev, int mode)
|
|
return -1;
|
|
}
|
|
|
|
- if (wait_for_file(devpath)) {
|
|
- condlog(3, "failed to open %s", devpath);
|
|
- return -1;
|
|
- }
|
|
-
|
|
return open(devpath, mode);
|
|
}
|
|
|
|
extern int
|
|
devt2devname (char *devname, char *devt)
|
|
{
|
|
- struct dlist * ls;
|
|
- char attr_path[FILE_NAME_SIZE];
|
|
+ FILE *fd;
|
|
+ unsigned int tmpmaj, tmpmin, major, minor;
|
|
+ char dev[FILE_NAME_SIZE];
|
|
char block_path[FILE_NAME_SIZE];
|
|
- struct sysfs_attribute * attr = NULL;
|
|
- struct sysfs_class * class;
|
|
- struct sysfs_class_device * dev;
|
|
+ struct stat statbuf;
|
|
|
|
- if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
|
|
- condlog(0, "block_path too small");
|
|
+ if (sscanf(devt, "%u:%u", &major, &minor) != 2) {
|
|
+ condlog(0, "Invalid device number %s", devt);
|
|
return 1;
|
|
}
|
|
- if (!(class = sysfs_open_class("block")))
|
|
- return 1;
|
|
|
|
- if (!(ls = sysfs_get_class_devices(class)))
|
|
- goto err;
|
|
+ if ((fd = fopen("/proc/partitions", "r")) < 0) {
|
|
+ condlog(0, "Cannot open /proc/partitions");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ while (!feof(fd)) {
|
|
+ if (fscanf(fd," %u %u %*d %s",&tmpmaj, &tmpmin, dev) != 3)
|
|
+ continue;
|
|
|
|
- dlist_for_each_data(ls, dev, struct sysfs_class_device) {
|
|
- if(safe_sprintf(attr_path, "%s/%s/dev",
|
|
- block_path, dev->name)) {
|
|
- condlog(0, "attr_path too small");
|
|
- goto err;
|
|
- }
|
|
- if (!(attr = sysfs_open_attribute(attr_path)))
|
|
- goto err;
|
|
-
|
|
- if (sysfs_read_attribute(attr))
|
|
- goto err1;
|
|
-
|
|
- /* discard newline */
|
|
- if (attr->len > 1) attr->len--;
|
|
-
|
|
- if (strlen(devt) == attr->len &&
|
|
- strncmp(attr->value, devt, attr->len) == 0) {
|
|
- if(safe_sprintf(attr_path, "%s/%s",
|
|
- block_path, dev->name)) {
|
|
- condlog(0, "attr_path too small");
|
|
- goto err1;
|
|
- }
|
|
- sysfs_get_name_from_path(attr_path, devname,
|
|
- FILE_NAME_SIZE);
|
|
- sysfs_close_attribute(attr);
|
|
- sysfs_close_class(class);
|
|
- return 0;
|
|
+ if ((major == tmpmaj) && (minor == tmpmin)) {
|
|
+ sprintf(block_path, "/sys/block/%s", dev);
|
|
+ break;
|
|
}
|
|
}
|
|
-err1:
|
|
- sysfs_close_attribute(attr);
|
|
-err:
|
|
- sysfs_close_class(class);
|
|
- return 1;
|
|
+ fclose(fd);
|
|
+
|
|
+ if (strncpy(block_path,"/sys/block", 10))
|
|
+ return 1;
|
|
+
|
|
+ if (stat(block_path, &statbuf) < 0) {
|
|
+ condlog(0, "No sysfs entry for %s\n", block_path);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (S_ISDIR(statbuf.st_mode) == 0) {
|
|
+ condlog(0, "sysfs entry %s is not a directory\n", block_path);
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
|
|
static int
|
|
@@ -363,79 +337,21 @@ get_serial (char * str, int maxlen, int
|
|
}
|
|
|
|
static int
|
|
-sysfs_get_bus (char * sysfs_path, struct path * pp)
|
|
-{
|
|
- struct sysfs_device *sdev;
|
|
- char attr_path[FILE_NAME_SIZE];
|
|
- char attr_buff[FILE_NAME_SIZE];
|
|
-
|
|
- pp->bus = SYSFS_BUS_UNDEF;
|
|
-
|
|
- /*
|
|
- * This is ugly : we should be able to do a simple
|
|
- * get_link("%s/block/%s/device/bus", ...) but it just
|
|
- * won't work
|
|
- */
|
|
- if(safe_sprintf(attr_path, "%s/block/%s/device",
|
|
- sysfs_path, pp->dev)) {
|
|
- condlog(0, "attr_path too small");
|
|
- return 1;
|
|
- }
|
|
-
|
|
- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
|
|
- return 1;
|
|
-
|
|
-#if DAEMON
|
|
- int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
|
|
-
|
|
- while (loop--) {
|
|
- sdev = sysfs_open_device_path(attr_buff);
|
|
-
|
|
- if (strlen(sdev->bus))
|
|
- break;
|
|
-
|
|
- sysfs_close_device(sdev);
|
|
- usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
|
|
- }
|
|
-#else
|
|
- sdev = sysfs_open_device_path(attr_buff);
|
|
-#endif
|
|
-
|
|
- if (!strncmp(sdev->bus, "scsi", 4))
|
|
- pp->bus = SYSFS_BUS_SCSI;
|
|
- else if (!strncmp(sdev->bus, "ide", 3))
|
|
- pp->bus = SYSFS_BUS_IDE;
|
|
- else if (!strncmp(sdev->bus, "ccw", 3))
|
|
- pp->bus = SYSFS_BUS_CCW;
|
|
- else
|
|
- return 1;
|
|
-
|
|
- sysfs_close_device(sdev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int
|
|
-scsi_sysfs_pathinfo (struct path * pp)
|
|
+scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
|
|
{
|
|
char attr_path[FILE_NAME_SIZE];
|
|
- char attr_buff[FILE_NAME_SIZE];
|
|
- struct sysfs_attribute * attr;
|
|
|
|
- if (sysfs_get_vendor(sysfs_path, pp->dev,
|
|
- pp->vendor_id, SCSI_VENDOR_SIZE))
|
|
+ if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
|
|
return 1;
|
|
|
|
condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
|
|
|
|
- if (sysfs_get_model(sysfs_path, pp->dev,
|
|
- pp->product_id, SCSI_PRODUCT_SIZE))
|
|
+ if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
|
|
return 1;
|
|
|
|
condlog(3, "%s: product = %s", pp->dev, pp->product_id);
|
|
|
|
- if (sysfs_get_rev(sysfs_path, pp->dev,
|
|
- pp->rev, SCSI_REV_SIZE))
|
|
+ if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
|
|
return 1;
|
|
|
|
condlog(3, "%s: rev = %s", pp->dev, pp->rev);
|
|
@@ -448,15 +364,7 @@ scsi_sysfs_pathinfo (struct path * pp)
|
|
/*
|
|
* host / bus / target / lun
|
|
*/
|
|
- if(safe_sprintf(attr_path, "%s/block/%s/device",
|
|
- sysfs_path, pp->dev)) {
|
|
- condlog(0, "attr_path too small");
|
|
- return 1;
|
|
- }
|
|
- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
|
|
- return 1;
|
|
-
|
|
- basename(attr_buff, attr_path);
|
|
+ basename(parent->devpath, attr_path);
|
|
|
|
sscanf(attr_path, "%i:%i:%i:%i",
|
|
&pp->sg_id.host_no,
|
|
@@ -473,35 +381,19 @@ scsi_sysfs_pathinfo (struct path * pp)
|
|
/*
|
|
* target node name
|
|
*/
|
|
- if(safe_sprintf(attr_path,
|
|
- "%s/class/fc_transport/target%i:%i:%i/node_name",
|
|
- sysfs_path,
|
|
- pp->sg_id.host_no,
|
|
- pp->sg_id.channel,
|
|
- pp->sg_id.scsi_id)) {
|
|
- condlog(0, "attr_path too small");
|
|
- return 1;
|
|
+ if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name,
|
|
+ pp->sg_id.host_no,
|
|
+ pp->sg_id.channel,
|
|
+ pp->sg_id.scsi_id)) {
|
|
+ condlog(3, "%s: tgt_node_name = %s",
|
|
+ pp->dev, pp->tgt_node_name);
|
|
}
|
|
- if (!(attr = sysfs_open_attribute(attr_path)))
|
|
- return 0;
|
|
-
|
|
- if (sysfs_read_attribute(attr))
|
|
- goto err;
|
|
-
|
|
- if (attr->len > 0)
|
|
- strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
|
|
-
|
|
- condlog(3, "%s: tgt_node_name = %s",
|
|
- pp->dev, pp->tgt_node_name);
|
|
|
|
return 0;
|
|
-err:
|
|
- sysfs_close_attribute(attr);
|
|
- return 1;
|
|
}
|
|
|
|
static int
|
|
-ccw_sysfs_pathinfo (struct path * pp)
|
|
+ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
|
|
{
|
|
char attr_path[FILE_NAME_SIZE];
|
|
char attr_buff[FILE_NAME_SIZE];
|
|
@@ -510,8 +402,7 @@ ccw_sysfs_pathinfo (struct path * pp)
|
|
|
|
condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
|
|
|
|
- if (sysfs_get_devtype(sysfs_path, pp->dev,
|
|
- attr_buff, FILE_NAME_SIZE))
|
|
+ if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
|
|
return 1;
|
|
|
|
if (!strncmp(attr_buff, "3370", 4)) {
|
|
@@ -531,16 +422,8 @@ ccw_sysfs_pathinfo (struct path * pp)
|
|
|
|
/*
|
|
* host / bus / target / lun
|
|
- */
|
|
- if(safe_sprintf(attr_path, "%s/block/%s/device",
|
|
- sysfs_path, pp->dev)) {
|
|
- condlog(0, "attr_path too small");
|
|
- return 1;
|
|
- }
|
|
- if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
|
|
- return 1;
|
|
-
|
|
- basename(attr_buff, attr_path);
|
|
+ */
|
|
+ basename(parent->devpath, attr_path);
|
|
pp->sg_id.lun = 0;
|
|
sscanf(attr_path, "%i.%i.%x",
|
|
&pp->sg_id.host_no,
|
|
@@ -557,20 +440,20 @@ ccw_sysfs_pathinfo (struct path * pp)
|
|
}
|
|
|
|
static int
|
|
-common_sysfs_pathinfo (struct path * pp)
|
|
+common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
|
|
{
|
|
- if (sysfs_get_bus(sysfs_path, pp))
|
|
- return 1;
|
|
-
|
|
- condlog(3, "%s: bus = %i", pp->dev, pp->bus);
|
|
+ char *attr;
|
|
|
|
- if (sysfs_get_dev(sysfs_path, pp->dev,
|
|
- pp->dev_t, BLK_DEV_SIZE))
|
|
+ attr = sysfs_attr_get_value(dev->devpath, "dev");
|
|
+ if (!attr) {
|
|
+ condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
|
|
return 1;
|
|
+ }
|
|
+ strlcpy(pp->dev_t, attr, BLK_DEV_SIZE);
|
|
|
|
condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
|
|
|
|
- if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
|
|
+ if (sysfs_get_size(dev, &pp->size))
|
|
return 1;
|
|
|
|
condlog(3, "%s: size = %llu", pp->dev, pp->size);
|
|
@@ -578,19 +461,46 @@ common_sysfs_pathinfo (struct path * pp)
|
|
return 0;
|
|
}
|
|
|
|
+struct sysfs_device *sysfs_device_from_path(struct path *pp)
|
|
+{
|
|
+ char sysdev[FILE_NAME_SIZE];
|
|
+
|
|
+ strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
|
|
+ strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
|
|
+
|
|
+ return sysfs_device_get(sysdev);
|
|
+}
|
|
+
|
|
extern int
|
|
sysfs_pathinfo(struct path * pp)
|
|
{
|
|
- if (common_sysfs_pathinfo(pp))
|
|
+ struct sysfs_device *parent;
|
|
+
|
|
+ pp->sysdev = sysfs_device_from_path(pp);
|
|
+ if (!pp->sysdev) {
|
|
+ condlog(1, "%s: failed to get sysfs information", pp->dev);
|
|
return 1;
|
|
+ }
|
|
+
|
|
+ parent = sysfs_device_get_parent(pp->sysdev);
|
|
+
|
|
+ if (common_sysfs_pathinfo(pp, pp->sysdev))
|
|
+ return 1;
|
|
+
|
|
+ condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
|
|
+
|
|
+ if (!strncmp(parent->subsystem, "scsi",4))
|
|
+ pp->bus = SYSFS_BUS_SCSI;
|
|
+ if (!strncmp(parent->subsystem, "ccw",3))
|
|
+ pp->bus = SYSFS_BUS_CCW;
|
|
|
|
if (pp->bus == SYSFS_BUS_UNDEF)
|
|
return 0;
|
|
else if (pp->bus == SYSFS_BUS_SCSI) {
|
|
- if (scsi_sysfs_pathinfo(pp))
|
|
+ if (scsi_sysfs_pathinfo(pp, parent))
|
|
return 1;
|
|
} else if (pp->bus == SYSFS_BUS_CCW) {
|
|
- if (ccw_sysfs_pathinfo(pp))
|
|
+ if (ccw_sysfs_pathinfo(pp, parent))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
|
|
index ab62a59..c7cf7e8 100644
|
|
--- a/libmultipath/discovery.h
|
|
+++ b/libmultipath/discovery.h
|
|
@@ -24,12 +24,7 @@
|
|
#define SCSI_COMMAND_TERMINATED 0x22
|
|
#define SG_ERR_DRIVER_SENSE 0x08
|
|
|
|
-int sysfs_get_vendor (char * sysfs_path, char * dev, char * buff, int len);
|
|
-int sysfs_get_model (char * sysfs_path, char * dev, char * buff, int len);
|
|
-int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len);
|
|
-int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len);
|
|
-
|
|
-int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *);
|
|
+int sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len);
|
|
int path_discovery (vector pathvec, struct config * conf, int flag);
|
|
|
|
void basename (char *, char *);
|
|
diff --git a/libmultipath/list.h b/libmultipath/list.h
|
|
new file mode 100644
|
|
index 0000000..8626630
|
|
--- /dev/null
|
|
+++ b/libmultipath/list.h
|
|
@@ -0,0 +1,289 @@
|
|
+/*
|
|
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
|
|
+ *
|
|
+ * Licensed under the GPL v2 as per the whole kernel source tree.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _LIST_H
|
|
+#define _LIST_H
|
|
+
|
|
+/**
|
|
+ * container_of - cast a member of a structure out to the containing structure
|
|
+ *
|
|
+ * @ptr: the pointer to the member.
|
|
+ * @type: the type of the container struct this is embedded in.
|
|
+ * @member: the name of the member within the struct.
|
|
+ *
|
|
+ */
|
|
+#define container_of(ptr, type, member) ({ \
|
|
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
|
+ (type *)( (char *)__mptr - offsetof(type,member) );})
|
|
+
|
|
+/*
|
|
+ * These are non-NULL pointers that will result in page faults
|
|
+ * under normal circumstances, used to verify that nobody uses
|
|
+ * non-initialized list entries.
|
|
+ */
|
|
+#define LIST_POISON1 ((void *) 0x00100100)
|
|
+#define LIST_POISON2 ((void *) 0x00200200)
|
|
+
|
|
+/*
|
|
+ * Simple doubly linked list implementation.
|
|
+ *
|
|
+ * Some of the internal functions ("__xxx") are useful when
|
|
+ * manipulating whole lists rather than single entries, as
|
|
+ * sometimes we already know the next/prev entries and we can
|
|
+ * generate better code by using them directly rather than
|
|
+ * using the generic single-entry routines.
|
|
+ */
|
|
+
|
|
+struct list_head {
|
|
+ struct list_head *next, *prev;
|
|
+};
|
|
+
|
|
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
|
+
|
|
+#define LIST_HEAD(name) \
|
|
+ struct list_head name = LIST_HEAD_INIT(name)
|
|
+
|
|
+#define INIT_LIST_HEAD(ptr) do { \
|
|
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
|
+} while (0)
|
|
+
|
|
+/*
|
|
+ * Insert a new entry between two known consecutive entries.
|
|
+ *
|
|
+ * This is only for internal list manipulation where we know
|
|
+ * the prev/next entries already!
|
|
+ */
|
|
+static inline void __list_add(struct list_head *new,
|
|
+ struct list_head *prev,
|
|
+ struct list_head *next)
|
|
+{
|
|
+ next->prev = new;
|
|
+ new->next = next;
|
|
+ new->prev = prev;
|
|
+ prev->next = new;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_add - add a new entry
|
|
+ * @new: new entry to be added
|
|
+ * @head: list head to add it after
|
|
+ *
|
|
+ * Insert a new entry after the specified head.
|
|
+ * This is good for implementing stacks.
|
|
+ */
|
|
+static inline void list_add(struct list_head *new, struct list_head *head)
|
|
+{
|
|
+ __list_add(new, head, head->next);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_add_tail - add a new entry
|
|
+ * @new: new entry to be added
|
|
+ * @head: list head to add it before
|
|
+ *
|
|
+ * Insert a new entry before the specified head.
|
|
+ * This is useful for implementing queues.
|
|
+ */
|
|
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|
+{
|
|
+ __list_add(new, head->prev, head);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Delete a list entry by making the prev/next entries
|
|
+ * point to each other.
|
|
+ *
|
|
+ * This is only for internal list manipulation where we know
|
|
+ * the prev/next entries already!
|
|
+ */
|
|
+static inline void __list_del(struct list_head * prev, struct list_head * next)
|
|
+{
|
|
+ next->prev = prev;
|
|
+ prev->next = next;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_del - deletes entry from list.
|
|
+ * @entry: the element to delete from the list.
|
|
+ * Note: list_empty on entry does not return true after this, the entry is
|
|
+ * in an undefined state.
|
|
+ */
|
|
+static inline void list_del(struct list_head *entry)
|
|
+{
|
|
+ __list_del(entry->prev, entry->next);
|
|
+ entry->next = LIST_POISON1;
|
|
+ entry->prev = LIST_POISON2;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_del_init - deletes entry from list and reinitialize it.
|
|
+ * @entry: the element to delete from the list.
|
|
+ */
|
|
+static inline void list_del_init(struct list_head *entry)
|
|
+{
|
|
+ __list_del(entry->prev, entry->next);
|
|
+ INIT_LIST_HEAD(entry);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_move - delete from one list and add as another's head
|
|
+ * @list: the entry to move
|
|
+ * @head: the head that will precede our entry
|
|
+ */
|
|
+static inline void list_move(struct list_head *list, struct list_head *head)
|
|
+{
|
|
+ __list_del(list->prev, list->next);
|
|
+ list_add(list, head);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_move_tail - delete from one list and add as another's tail
|
|
+ * @list: the entry to move
|
|
+ * @head: the head that will follow our entry
|
|
+ */
|
|
+static inline void list_move_tail(struct list_head *list,
|
|
+ struct list_head *head)
|
|
+{
|
|
+ __list_del(list->prev, list->next);
|
|
+ list_add_tail(list, head);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_empty - tests whether a list is empty
|
|
+ * @head: the list to test.
|
|
+ */
|
|
+static inline int list_empty(struct list_head *head)
|
|
+{
|
|
+ return head->next == head;
|
|
+}
|
|
+
|
|
+static inline void __list_splice(struct list_head *list,
|
|
+ struct list_head *head)
|
|
+{
|
|
+ struct list_head *first = list->next;
|
|
+ struct list_head *last = list->prev;
|
|
+ struct list_head *at = head->next;
|
|
+
|
|
+ first->prev = head;
|
|
+ head->next = first;
|
|
+
|
|
+ last->next = at;
|
|
+ at->prev = last;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_splice - join two lists
|
|
+ * @list: the new list to add.
|
|
+ * @head: the place to add it in the first list.
|
|
+ */
|
|
+static inline void list_splice(struct list_head *list, struct list_head *head)
|
|
+{
|
|
+ if (!list_empty(list))
|
|
+ __list_splice(list, head);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_splice_init - join two lists and reinitialise the emptied list.
|
|
+ * @list: the new list to add.
|
|
+ * @head: the place to add it in the first list.
|
|
+ *
|
|
+ * The list at @list is reinitialised
|
|
+ */
|
|
+static inline void list_splice_init(struct list_head *list,
|
|
+ struct list_head *head)
|
|
+{
|
|
+ if (!list_empty(list)) {
|
|
+ __list_splice(list, head);
|
|
+ INIT_LIST_HEAD(list);
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * list_entry - get the struct for this entry
|
|
+ * @ptr: the &struct list_head pointer.
|
|
+ * @type: the type of the struct this is embedded in.
|
|
+ * @member: the name of the list_struct within the struct.
|
|
+ */
|
|
+#define list_entry(ptr, type, member) \
|
|
+ container_of(ptr, type, member)
|
|
+
|
|
+/**
|
|
+ * list_for_each - iterate over a list
|
|
+ * @pos: the &struct list_head to use as a loop counter.
|
|
+ * @head: the head for your list.
|
|
+ */
|
|
+#define list_for_each(pos, head) \
|
|
+ for (pos = (head)->next; pos != (head); \
|
|
+ pos = pos->next)
|
|
+
|
|
+/**
|
|
+ * __list_for_each - iterate over a list
|
|
+ * @pos: the &struct list_head to use as a loop counter.
|
|
+ * @head: the head for your list.
|
|
+ *
|
|
+ * This variant differs from list_for_each() in that it's the
|
|
+ * simplest possible list iteration code.
|
|
+ * Use this for code that knows the list to be very short (empty
|
|
+ * or 1 entry) most of the time.
|
|
+ */
|
|
+#define __list_for_each(pos, head) \
|
|
+ for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
+
|
|
+/**
|
|
+ * list_for_each_prev - iterate over a list backwards
|
|
+ * @pos: the &struct list_head to use as a loop counter.
|
|
+ * @head: the head for your list.
|
|
+ */
|
|
+#define list_for_each_prev(pos, head) \
|
|
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
|
+
|
|
+/**
|
|
+ * list_for_each_safe - iterate over a list safe against removal of list entry
|
|
+ * @pos: the &struct list_head to use as a loop counter.
|
|
+ * @n: another &struct list_head to use as temporary storage
|
|
+ * @head: the head for your list.
|
|
+ */
|
|
+#define list_for_each_safe(pos, n, head) \
|
|
+ for (pos = (head)->next, n = pos->next; pos != (head); \
|
|
+ pos = n, n = pos->next)
|
|
+
|
|
+/**
|
|
+ * list_for_each_entry - iterate over list of given type
|
|
+ * @pos: the type * to use as a loop counter.
|
|
+ * @head: the head for your list.
|
|
+ * @member: the name of the list_struct within the struct.
|
|
+ */
|
|
+#define list_for_each_entry(pos, head, member) \
|
|
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
|
|
+ &pos->member != (head); \
|
|
+ pos = list_entry(pos->member.next, typeof(*pos), member))
|
|
+
|
|
+/**
|
|
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
|
|
+ * @pos: the type * to use as a loop counter.
|
|
+ * @head: the head for your list.
|
|
+ * @member: the name of the list_struct within the struct.
|
|
+ */
|
|
+#define list_for_each_entry_reverse(pos, head, member) \
|
|
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
|
+ &pos->member != (head); \
|
|
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
|
|
+
|
|
+/**
|
|
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
+ * @pos: the type * to use as a loop counter.
|
|
+ * @n: another type * to use as temporary storage
|
|
+ * @head: the head for your list.
|
|
+ * @member: the name of the list_struct within the struct.
|
|
+ */
|
|
+#define list_for_each_entry_safe(pos, n, head, member) \
|
|
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
|
|
+ n = list_entry(pos->member.next, typeof(*pos), member); \
|
|
+ &pos->member != (head); \
|
|
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
|
+
|
|
+#endif /* _LIST_H */
|
|
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
|
index dc8af48..1d80e48 100644
|
|
--- a/libmultipath/print.c
|
|
+++ b/libmultipath/print.c
|
|
@@ -5,8 +5,8 @@
|
|
#include <string.h>
|
|
#include <libdevmapper.h>
|
|
#include <stdarg.h>
|
|
-#include <sysfs/dlist.h>
|
|
-#include <sysfs/libsysfs.h>
|
|
+#include <sys/stat.h>
|
|
+#include <dirent.h>
|
|
|
|
#include <checkers.h>
|
|
|
|
@@ -1096,35 +1096,46 @@ snprint_blacklist_except (char * buff, i
|
|
extern int
|
|
snprint_devices (char * buff, int len, struct vectors *vecs)
|
|
{
|
|
- struct dlist * ls;
|
|
- struct sysfs_class * class;
|
|
- struct sysfs_class_device * dev;
|
|
+ DIR *blkdir;
|
|
+ struct dirent *blkdev;
|
|
+ struct stat statbuf;
|
|
+ char devpath[PATH_MAX];
|
|
+ char *devptr;
|
|
int threshold = MAX_LINE_LEN;
|
|
int fwd = 0;
|
|
int r;
|
|
|
|
struct path * pp;
|
|
|
|
- if (!(class = sysfs_open_class("block")))
|
|
- return 0;
|
|
-
|
|
- if (!(ls = sysfs_get_class_devices(class))) {
|
|
- sysfs_close_class(class);
|
|
- return 0;
|
|
- }
|
|
+ if (!(blkdir = opendir("/sys/block")))
|
|
+ return 1;
|
|
|
|
if ((len - fwd - threshold) <= 0)
|
|
return len;
|
|
fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
|
|
|
|
- dlist_for_each_data(ls, dev, struct sysfs_class_device) {
|
|
+ strcpy(devpath,"/sys/block");
|
|
+ devptr = devpath + 10;
|
|
+ while ((blkdev = readdir(blkdir)) != NULL) {
|
|
+ if ((strcmp(blkdev->d_name,".") == 0) ||
|
|
+ (strcmp(blkdev->d_name,"..") == 0))
|
|
+ continue;
|
|
+
|
|
+ strcat(devptr,blkdev->d_name);
|
|
+ if (stat(devptr, &statbuf) < 0)
|
|
+ continue;
|
|
+
|
|
+ if (S_ISDIR(statbuf.st_mode) == 0)
|
|
+ continue;
|
|
+
|
|
if ((len - fwd - threshold) <= 0)
|
|
return len;
|
|
- fwd += snprintf(buff + fwd, len - fwd, " %s", dev->name);
|
|
- pp = find_path_by_dev(vecs->pathvec, dev->name);
|
|
+
|
|
+ fwd += snprintf(buff + fwd, len - fwd, " %s", devpath);
|
|
+ pp = find_path_by_dev(vecs->pathvec, devpath);
|
|
if (!pp) {
|
|
r = filter_devnode(conf->blist_devnode,
|
|
- conf->elist_devnode, dev->name);
|
|
+ conf->elist_devnode, devpath);
|
|
if (r > 0)
|
|
fwd += snprintf(buff + fwd, len - fwd,
|
|
" (blacklisted)");
|
|
@@ -1133,8 +1144,8 @@ snprint_devices (char * buff, int len, s
|
|
" (whitelisted)");
|
|
}
|
|
fwd += snprintf(buff + fwd, len - fwd, "\n");
|
|
- }
|
|
- sysfs_close_class(class);
|
|
+ }
|
|
+ closedir(blkdir);
|
|
|
|
if (fwd > len)
|
|
return len;
|
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
|
index 46dcdee..75322aa 100644
|
|
--- a/libmultipath/structs.h
|
|
+++ b/libmultipath/structs.h
|
|
@@ -9,6 +9,9 @@
|
|
#define FILE_NAME_SIZE 256
|
|
#define CALLOUT_MAX_SIZE 128
|
|
#define BLK_DEV_SIZE 33
|
|
+#define PATH_SIZE 512
|
|
+#define NAME_SIZE 128
|
|
+
|
|
|
|
#define SCSI_VENDOR_SIZE 9
|
|
#define SCSI_PRODUCT_SIZE 17
|
|
@@ -86,9 +89,19 @@ struct scsi_dev {
|
|
int host_no;
|
|
};
|
|
|
|
+struct sysfs_device {
|
|
+ struct sysfs_device *parent; /* parent device */
|
|
+ char devpath[PATH_SIZE];
|
|
+ char subsystem[NAME_SIZE]; /* $class, $bus, drivers, module */
|
|
+ char kernel[NAME_SIZE]; /* device instance name */
|
|
+ char kernel_number[NAME_SIZE];
|
|
+ char driver[NAME_SIZE]; /* device driver name */
|
|
+};
|
|
+
|
|
struct path {
|
|
char dev[FILE_NAME_SIZE];
|
|
char dev_t[BLK_DEV_SIZE];
|
|
+ struct sysfs_device *sysdev;
|
|
struct scsi_idlun scsi_id;
|
|
struct sg_id sg_id;
|
|
char wwid[WWID_SIZE];
|
|
@@ -200,6 +213,6 @@ struct path * first_path (struct multipa
|
|
int pathcountgr (struct pathgroup *, int);
|
|
int pathcount (struct multipath *, int);
|
|
|
|
-char sysfs_path[FILE_NAME_SIZE];
|
|
+extern char sysfs_path[PATH_SIZE];
|
|
|
|
#endif /* _STRUCTS_H */
|
|
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
|
index a4a996a..1cc6028 100644
|
|
--- a/libmultipath/structs_vec.c
|
|
+++ b/libmultipath/structs_vec.c
|
|
@@ -13,6 +13,7 @@
|
|
#include "dmparser.h"
|
|
#include "config.h"
|
|
#include "propsel.h"
|
|
+#include "sysfs.h"
|
|
#include "discovery.h"
|
|
#include "waiter.h"
|
|
|
|
@@ -373,10 +374,10 @@ verify_paths(struct multipath * mpp, str
|
|
/*
|
|
* see if path is in sysfs
|
|
*/
|
|
- if (!pp->dev || sysfs_get_dev(sysfs_path,
|
|
- pp->dev, pp->dev_t, BLK_DEV_SIZE)) {
|
|
+ if (!pp->sysdev || sysfs_get_dev(pp->sysdev,
|
|
+ pp->dev_t, BLK_DEV_SIZE)) {
|
|
condlog(0, "%s: failed to access path %s", mpp->alias,
|
|
- pp->dev ? pp->dev : pp->dev_t);
|
|
+ pp->sysdev ? pp->sysdev->devpath : pp->dev_t);
|
|
count++;
|
|
vector_del_slot(mpp->paths, i);
|
|
i--;
|
|
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
|
|
new file mode 100644
|
|
index 0000000..e24aa34
|
|
--- /dev/null
|
|
+++ b/libmultipath/sysfs.c
|
|
@@ -0,0 +1,405 @@
|
|
+/*
|
|
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@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.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
+ *
|
|
+ */
|
|
+
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <stddef.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
+#include <ctype.h>
|
|
+#include <errno.h>
|
|
+#include <sys/stat.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "checkers.h"
|
|
+#include "vector.h"
|
|
+#include "structs.h"
|
|
+#include "sysfs.h"
|
|
+#include "list.h"
|
|
+#include "util.h"
|
|
+
|
|
+char sysfs_path[PATH_SIZE];
|
|
+
|
|
+/* attribute value cache */
|
|
+static LIST_HEAD(attr_list);
|
|
+struct sysfs_attr {
|
|
+ struct list_head node;
|
|
+ char path[PATH_SIZE];
|
|
+ char *value; /* points to value_local if value is cached */
|
|
+ char value_local[NAME_SIZE];
|
|
+};
|
|
+
|
|
+int sysfs_init(char *path, size_t len)
|
|
+{
|
|
+ if (path) {
|
|
+ strlcpy(sysfs_path, path, len);
|
|
+ remove_trailing_chars(sysfs_path, '/');
|
|
+ } else
|
|
+ strlcpy(sysfs_path, "/sys", len);
|
|
+ dbg("sysfs_path='%s'", sysfs_path);
|
|
+
|
|
+ INIT_LIST_HEAD(&attr_list);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void sysfs_cleanup(void)
|
|
+{
|
|
+ struct sysfs_attr *attr_loop;
|
|
+ struct sysfs_attr *attr_temp;
|
|
+
|
|
+ list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
|
|
+ list_del(&attr_loop->node);
|
|
+ free(attr_loop);
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
|
|
+ const char *subsystem, const char *driver)
|
|
+{
|
|
+ char *pos;
|
|
+
|
|
+ strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
|
|
+ if (subsystem != NULL)
|
|
+ strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
|
|
+ if (driver != NULL)
|
|
+ strlcpy(dev->driver, driver, sizeof(dev->driver));
|
|
+
|
|
+ /* set kernel name */
|
|
+ pos = strrchr(dev->devpath, '/');
|
|
+ if (pos == NULL)
|
|
+ return;
|
|
+ strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
|
|
+ dbg("kernel='%s'", dev->kernel);
|
|
+
|
|
+ /* some devices have '!' in their name, change that to '/' */
|
|
+ pos = dev->kernel;
|
|
+ while (pos[0] != '\0') {
|
|
+ if (pos[0] == '!')
|
|
+ pos[0] = '/';
|
|
+ pos++;
|
|
+ }
|
|
+
|
|
+ /* get kernel number */
|
|
+ pos = &dev->kernel[strlen(dev->kernel)];
|
|
+ while (isdigit(pos[-1]))
|
|
+ pos--;
|
|
+ strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
|
|
+ dbg("kernel_number='%s'", dev->kernel_number);
|
|
+}
|
|
+
|
|
+int sysfs_resolve_link(char *devpath, size_t size)
|
|
+{
|
|
+ char link_path[PATH_SIZE];
|
|
+ char link_target[PATH_SIZE];
|
|
+ int len;
|
|
+ int i;
|
|
+ int back;
|
|
+
|
|
+ strlcpy(link_path, sysfs_path, sizeof(link_path));
|
|
+ strlcat(link_path, devpath, sizeof(link_path));
|
|
+ len = readlink(link_path, link_target, sizeof(link_target));
|
|
+ if (len <= 0)
|
|
+ return -1;
|
|
+ link_target[len] = '\0';
|
|
+ dbg("path link '%s' points to '%s'", devpath, link_target);
|
|
+
|
|
+ for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
|
|
+ ;
|
|
+ dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back);
|
|
+ for (i = 0; i <= back; i++) {
|
|
+ char *pos = strrchr(devpath, '/');
|
|
+
|
|
+ if (pos == NULL)
|
|
+ return -1;
|
|
+ pos[0] = '\0';
|
|
+ }
|
|
+ dbg("after moving back '%s'", devpath);
|
|
+ strlcat(devpath, "/", size);
|
|
+ strlcat(devpath, &link_target[back * 3], size);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
+{
|
|
+ char path[PATH_SIZE];
|
|
+ char devpath_real[PATH_SIZE];
|
|
+ struct sysfs_device *dev;
|
|
+ struct stat statbuf;
|
|
+ char link_path[PATH_SIZE];
|
|
+ char link_target[PATH_SIZE];
|
|
+ int len;
|
|
+ char *pos;
|
|
+
|
|
+ dbg("open '%s'", devpath);
|
|
+ strlcpy(devpath_real, devpath, sizeof(devpath_real));
|
|
+ remove_trailing_chars(devpath_real, '/');
|
|
+
|
|
+ /* if we got a link, resolve it to the real device */
|
|
+ strlcpy(path, sysfs_path, sizeof(path));
|
|
+ strlcat(path, devpath_real, sizeof(path));
|
|
+ if (lstat(path, &statbuf) != 0) {
|
|
+ dbg("stat '%s' failed: %s", path, strerror(errno));
|
|
+ return NULL;
|
|
+ }
|
|
+ if (S_ISLNK(statbuf.st_mode)) {
|
|
+ if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
|
|
+ return NULL;
|
|
+
|
|
+ }
|
|
+
|
|
+ /* it is a new device */
|
|
+ dbg("new device '%s'", devpath_real);
|
|
+ dev = malloc(sizeof(struct sysfs_device));
|
|
+ if (dev == NULL)
|
|
+ return NULL;
|
|
+ memset(dev, 0x00, sizeof(struct sysfs_device));
|
|
+
|
|
+ sysfs_device_set_values(dev, devpath_real, NULL, NULL);
|
|
+
|
|
+ /* get subsystem name */
|
|
+ strlcpy(link_path, sysfs_path, sizeof(link_path));
|
|
+ strlcat(link_path, dev->devpath, sizeof(link_path));
|
|
+ strlcat(link_path, "/subsystem", sizeof(link_path));
|
|
+ len = readlink(link_path, link_target, sizeof(link_target));
|
|
+ if (len > 0) {
|
|
+ /* get subsystem from "subsystem" link */
|
|
+ link_target[len] = '\0';
|
|
+ dbg("subsystem link '%s' points to '%s'", link_path, link_target);
|
|
+ pos = strrchr(link_target, '/');
|
|
+ if (pos != NULL)
|
|
+ strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
|
|
+ } else if (strncmp(dev->devpath, "/class/", 7) == 0) {
|
|
+ /* get subsystem from class dir */
|
|
+ strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem));
|
|
+ pos = strchr(dev->subsystem, '/');
|
|
+ if (pos != NULL)
|
|
+ pos[0] = '\0';
|
|
+ else
|
|
+ dev->subsystem[0] = '\0';
|
|
+ } else if (strncmp(dev->devpath, "/block/", 7) == 0) {
|
|
+ strlcpy(dev->subsystem, "block", sizeof(dev->subsystem));
|
|
+ } else if (strncmp(dev->devpath, "/devices/", 9) == 0) {
|
|
+ /* get subsystem from "bus" link */
|
|
+ strlcpy(link_path, sysfs_path, sizeof(link_path));
|
|
+ strlcat(link_path, dev->devpath, sizeof(link_path));
|
|
+ strlcat(link_path, "/bus", sizeof(link_path));
|
|
+ len = readlink(link_path, link_target, sizeof(link_target));
|
|
+ if (len > 0) {
|
|
+ link_target[len] = '\0';
|
|
+ dbg("bus link '%s' points to '%s'", link_path, link_target);
|
|
+ pos = strrchr(link_target, '/');
|
|
+ if (pos != NULL)
|
|
+ strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
|
|
+ }
|
|
+ } else if (strstr(dev->devpath, "/drivers/") != NULL) {
|
|
+ strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
|
|
+ } else if (strncmp(dev->devpath, "/module/", 8) == 0) {
|
|
+ strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
|
|
+ }
|
|
+
|
|
+ /* get driver name */
|
|
+ strlcpy(link_path, sysfs_path, sizeof(link_path));
|
|
+ strlcat(link_path, dev->devpath, sizeof(link_path));
|
|
+ strlcat(link_path, "/driver", sizeof(link_path));
|
|
+ len = readlink(link_path, link_target, sizeof(link_target));
|
|
+ if (len > 0) {
|
|
+ link_target[len] = '\0';
|
|
+ dbg("driver link '%s' points to '%s'", link_path, link_target);
|
|
+ pos = strrchr(link_target, '/');
|
|
+ if (pos != NULL)
|
|
+ strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
|
|
+ }
|
|
+
|
|
+ return dev;
|
|
+}
|
|
+
|
|
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
|
+{
|
|
+ char parent_devpath[PATH_SIZE];
|
|
+ char *pos;
|
|
+
|
|
+ dbg("open '%s'", dev->devpath);
|
|
+
|
|
+ /* look if we already know the parent */
|
|
+ if (dev->parent != NULL)
|
|
+ return dev->parent;
|
|
+
|
|
+ /* requesting a parent is only valid for devices */
|
|
+ if ((strncmp(dev->devpath, "/devices/", 9) != 0) &&
|
|
+ (strncmp(dev->devpath, "/subsystem/", 11) != 0) &&
|
|
+ (strncmp(dev->devpath, "/class/", 7) != 0) &&
|
|
+ (strncmp(dev->devpath, "/block/", 7) != 0))
|
|
+ return NULL;
|
|
+
|
|
+ strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
|
|
+ dbg("'%s'", parent_devpath);
|
|
+
|
|
+ /* strip last element */
|
|
+ pos = strrchr(parent_devpath, '/');
|
|
+ if (pos == NULL || pos == parent_devpath)
|
|
+ return NULL;
|
|
+ pos[0] = '\0';
|
|
+
|
|
+ /* are we at the top level of /devices */
|
|
+ if (strcmp(parent_devpath, "/devices") == 0) {
|
|
+ dbg("/devices top level");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* at the subsystems top level we want to follow the old-style "device" link */
|
|
+ if (strncmp(parent_devpath, "/subsystem", 10) == 0) {
|
|
+ pos = strrchr(parent_devpath, '/');
|
|
+ if (pos == &parent_devpath[10] || pos == parent_devpath || strcmp(pos, "/devices") == 0) {
|
|
+ dbg("/subsystem top level, look for device link");
|
|
+ goto device_link;
|
|
+ }
|
|
+ }
|
|
+ if (strncmp(parent_devpath, "/class", 6) == 0) {
|
|
+ pos = strrchr(parent_devpath, '/');
|
|
+ if (pos == &parent_devpath[6] || pos == parent_devpath) {
|
|
+ dbg("/class top level, look for device link");
|
|
+ goto device_link;
|
|
+ }
|
|
+ }
|
|
+ if (strcmp(parent_devpath, "/block") == 0) {
|
|
+ dbg("/block top level, look for device link");
|
|
+ goto device_link;
|
|
+ }
|
|
+
|
|
+ /* get parent and remember it */
|
|
+ dev->parent = sysfs_device_get(parent_devpath);
|
|
+ return dev->parent;
|
|
+
|
|
+device_link:
|
|
+ strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
|
|
+ strlcat(parent_devpath, "/device", sizeof(parent_devpath));
|
|
+ if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
|
|
+ return NULL;
|
|
+
|
|
+ /* get parent and remember it */
|
|
+ dev->parent = sysfs_device_get(parent_devpath);
|
|
+ return dev->parent;
|
|
+}
|
|
+
|
|
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem)
|
|
+{
|
|
+ struct sysfs_device *dev_parent;
|
|
+
|
|
+ dev_parent = sysfs_device_get_parent(dev);
|
|
+ while (dev_parent != NULL) {
|
|
+ if (strcmp(dev_parent->subsystem, subsystem) == 0)
|
|
+ return dev_parent;
|
|
+ dev_parent = sysfs_device_get_parent(dev_parent);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
+{
|
|
+ char path_full[PATH_SIZE];
|
|
+ const char *path;
|
|
+ char value[NAME_SIZE];
|
|
+ struct sysfs_attr *attr_loop;
|
|
+ struct sysfs_attr *attr;
|
|
+ struct stat statbuf;
|
|
+ int fd;
|
|
+ ssize_t size;
|
|
+ size_t sysfs_len;
|
|
+
|
|
+ dbg("open '%s'/'%s'", devpath, attr_name);
|
|
+ sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
|
|
+ path = &path_full[sysfs_len];
|
|
+ strlcat(path_full, devpath, sizeof(path_full));
|
|
+ strlcat(path_full, "/", sizeof(path_full));
|
|
+ strlcat(path_full, attr_name, sizeof(path_full));
|
|
+
|
|
+ /* look for attribute in cache */
|
|
+ list_for_each_entry(attr_loop, &attr_list, node) {
|
|
+ if (strcmp(attr_loop->path, path) == 0) {
|
|
+ dbg("found in cache '%s'", attr_loop->path);
|
|
+ return attr_loop->value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* store attribute in cache (also negatives are kept in cache) */
|
|
+ dbg("new uncached attribute '%s'", path_full);
|
|
+ attr = malloc(sizeof(struct sysfs_attr));
|
|
+ if (attr == NULL)
|
|
+ return NULL;
|
|
+ memset(attr, 0x00, sizeof(struct sysfs_attr));
|
|
+ strlcpy(attr->path, path, sizeof(attr->path));
|
|
+ dbg("add to cache '%s'", path_full);
|
|
+ list_add(&attr->node, &attr_list);
|
|
+
|
|
+ if (lstat(path_full, &statbuf) != 0) {
|
|
+ dbg("stat '%s' failed: %s", path_full, strerror(errno));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (S_ISLNK(statbuf.st_mode)) {
|
|
+ /* links return the last element of the target path */
|
|
+ char link_target[PATH_SIZE];
|
|
+ int len;
|
|
+ const char *pos;
|
|
+
|
|
+ len = readlink(path_full, link_target, sizeof(link_target));
|
|
+ if (len > 0) {
|
|
+ link_target[len] = '\0';
|
|
+ pos = strrchr(link_target, '/');
|
|
+ if (pos != NULL) {
|
|
+ dbg("cache '%s' with link value '%s'", path_full, value);
|
|
+ strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
|
|
+ attr->value = attr->value_local;
|
|
+ }
|
|
+ }
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* skip directories */
|
|
+ if (S_ISDIR(statbuf.st_mode))
|
|
+ goto out;
|
|
+
|
|
+ /* skip non-readable files */
|
|
+ if ((statbuf.st_mode & S_IRUSR) == 0)
|
|
+ goto out;
|
|
+
|
|
+ /* read attribute value */
|
|
+ fd = open(path_full, O_RDONLY);
|
|
+ if (fd < 0) {
|
|
+ dbg("attribute '%s' does not exist", path_full);
|
|
+ goto out;
|
|
+ }
|
|
+ size = read(fd, value, sizeof(value));
|
|
+ close(fd);
|
|
+ if (size < 0)
|
|
+ goto out;
|
|
+ if (size == sizeof(value))
|
|
+ goto out;
|
|
+
|
|
+ /* got a valid value, store and return it */
|
|
+ value[size] = '\0';
|
|
+ remove_trailing_chars(value, '\n');
|
|
+ dbg("cache '%s' with attribute value '%s'", path_full, value);
|
|
+ strlcpy(attr->value_local, value, sizeof(attr->value_local));
|
|
+ attr->value = attr->value_local;
|
|
+
|
|
+out:
|
|
+ return attr->value;
|
|
+}
|
|
diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h
|
|
new file mode 100644
|
|
index 0000000..4ac30db
|
|
--- /dev/null
|
|
+++ b/libmultipath/sysfs.h
|
|
@@ -0,0 +1,20 @@
|
|
+/*
|
|
+ * sysfs.h
|
|
+ */
|
|
+
|
|
+#ifndef _LIBMULTIPATH_SYSFS_H
|
|
+#define _LIBMULTIPATH_SYSFS_H
|
|
+
|
|
+#define dbg(format, arg...) do {} while (0)
|
|
+
|
|
+int sysfs_init(char *path, size_t len);
|
|
+void sysfs_cleanup(void);
|
|
+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
|
|
+ const char *subsystem, const char *driver);
|
|
+struct sysfs_device *sysfs_device_get(const char *devpath);
|
|
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev);
|
|
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem);
|
|
+char *sysfs_attr_get_value(const char *devpath, const char *attr_name);
|
|
+int sysfs_resolve_link(char *path, size_t size);
|
|
+
|
|
+#endif
|
|
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
|
|
index 6482698..a4028d8 100644
|
|
--- a/libmultipath/uevent.c
|
|
+++ b/libmultipath/uevent.c
|
|
@@ -26,12 +26,14 @@
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
+#include <stddef.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/user.h>
|
|
-#include <asm/types.h>
|
|
+#include <sys/un.h>
|
|
+#include <linux/types.h>
|
|
#include <linux/netlink.h>
|
|
#include <pthread.h>
|
|
#include <sys/mman.h>
|
|
@@ -105,6 +107,8 @@ int uevent_listen(int (*uev_trigger)(str
|
|
{
|
|
int sock;
|
|
struct sockaddr_nl snl;
|
|
+ struct sockaddr_un sun;
|
|
+ socklen_t addrlen;
|
|
int retval;
|
|
int rcvbufsz = 128*1024;
|
|
int rcvsz = 0;
|
|
@@ -131,43 +135,72 @@ int uevent_listen(int (*uev_trigger)(str
|
|
pthread_attr_setstacksize(&attr, 64 * 1024);
|
|
pthread_create(&uevq_thr, &attr, uevq_thread, NULL);
|
|
|
|
- memset(&snl, 0x00, sizeof(struct sockaddr_nl));
|
|
- snl.nl_family = AF_NETLINK;
|
|
- snl.nl_pid = getpid();
|
|
- snl.nl_groups = 0xffffffff;
|
|
-
|
|
- sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
|
- if (sock == -1) {
|
|
- condlog(0, "error getting socket, exit");
|
|
- return 1;
|
|
- }
|
|
-
|
|
/*
|
|
- * try to avoid dropping uevents, even so, this is not a guarantee,
|
|
- * but it does help to change the netlink uevent socket's
|
|
- * receive buffer threshold from the default value of 106,496 to
|
|
- * the maximum value of 262,142.
|
|
+ * First check whether we have a udev socket
|
|
*/
|
|
- retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
|
|
- sizeof(rcvbufsz));
|
|
+ memset(&sun, 0x00, sizeof(struct sockaddr_un));
|
|
+ sun.sun_family = AF_LOCAL;
|
|
+ strcpy(&sun.sun_path[1], "/org/kernel/dm/multipath_event");
|
|
+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path+1) + 1;
|
|
+
|
|
+ sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
|
+ if (sock >= 0) {
|
|
+ const int feature_on = 1;
|
|
+
|
|
+ condlog(3, "reading events from udev socket.");
|
|
+
|
|
+ /* the bind takes care of ensuring only one copy running */
|
|
+ retval = bind(sock, (struct sockaddr *) &sun, addrlen);
|
|
+ if (retval < 0) {
|
|
+ condlog(0, "bind failed, exit");
|
|
+ goto exit;
|
|
+ }
|
|
|
|
- if (retval < 0) {
|
|
- condlog(0, "error setting receive buffer size for socket, exit");
|
|
- exit(1);
|
|
- }
|
|
- retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
|
|
+ /* enable receiving of the sender credentials */
|
|
+ setsockopt(sock, SOL_SOCKET, SO_PASSCRED,
|
|
+ &feature_on, sizeof(feature_on));
|
|
+
|
|
+ } else {
|
|
+ /* Fallback to read kernel netlink events */
|
|
+ memset(&snl, 0x00, sizeof(struct sockaddr_nl));
|
|
+ snl.nl_family = AF_NETLINK;
|
|
+ snl.nl_pid = getpid();
|
|
+ snl.nl_groups = 0xffffffff;
|
|
+
|
|
+ sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
|
+ if (sock == -1) {
|
|
+ condlog(0, "error getting socket, exit");
|
|
+ return 1;
|
|
+ }
|
|
|
|
- if (retval < 0) {
|
|
- condlog(0, "error setting receive buffer size for socket, exit");
|
|
- exit(1);
|
|
- }
|
|
- condlog(3, "receive buffer size for socket is %u.", rcvsz);
|
|
+ condlog(3, "reading events from kernel.");
|
|
|
|
- retval = bind(sock, (struct sockaddr *) &snl,
|
|
- sizeof(struct sockaddr_nl));
|
|
- if (retval < 0) {
|
|
- condlog(0, "bind failed, exit");
|
|
- goto exit;
|
|
+ /*
|
|
+ * try to avoid dropping uevents, even so, this is not a guarantee,
|
|
+ * but it does help to change the netlink uevent socket's
|
|
+ * receive buffer threshold from the default value of 106,496 to
|
|
+ * the maximum value of 262,142.
|
|
+ */
|
|
+ retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
|
|
+ sizeof(rcvbufsz));
|
|
+
|
|
+ if (retval < 0) {
|
|
+ condlog(0, "error setting receive buffer size for socket, exit");
|
|
+ exit(1);
|
|
+ }
|
|
+ retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
|
|
+ if (retval < 0) {
|
|
+ condlog(0, "error setting receive buffer size for socket, exit");
|
|
+ exit(1);
|
|
+ }
|
|
+ condlog(3, "receive buffer size for socket is %u.", rcvsz);
|
|
+
|
|
+ retval = bind(sock, (struct sockaddr *) &snl,
|
|
+ sizeof(struct sockaddr_nl));
|
|
+ if (retval < 0) {
|
|
+ condlog(0, "bind failed, exit");
|
|
+ goto exit;
|
|
+ }
|
|
}
|
|
|
|
while (1) {
|
|
diff --git a/libmultipath/util.c b/libmultipath/util.c
|
|
index 911ec55..eaf2266 100644
|
|
--- a/libmultipath/util.c
|
|
+++ b/libmultipath/util.c
|
|
@@ -103,3 +103,55 @@ get_word (char * sentence, char ** word)
|
|
return skip + len;
|
|
}
|
|
|
|
+size_t strlcpy(char *dst, const char *src, size_t size)
|
|
+{
|
|
+ size_t bytes = 0;
|
|
+ char *q = dst;
|
|
+ const char *p = src;
|
|
+ char ch;
|
|
+
|
|
+ while ((ch = *p++)) {
|
|
+ if (bytes+1 < size)
|
|
+ *q++ = ch;
|
|
+ bytes++;
|
|
+ }
|
|
+
|
|
+ /* If size == 0 there is no space for a final null... */
|
|
+ if (size)
|
|
+ *q = '\0';
|
|
+ return bytes;
|
|
+}
|
|
+
|
|
+size_t strlcat(char *dst, const char *src, size_t size)
|
|
+{
|
|
+ size_t bytes = 0;
|
|
+ char *q = dst;
|
|
+ const char *p = src;
|
|
+ char ch;
|
|
+
|
|
+ while (bytes < size && *q) {
|
|
+ q++;
|
|
+ bytes++;
|
|
+ }
|
|
+ if (bytes == size)
|
|
+ return (bytes + strlen(src));
|
|
+
|
|
+ while ((ch = *p++)) {
|
|
+ if (bytes+1 < size)
|
|
+ *q++ = ch;
|
|
+ bytes++;
|
|
+ }
|
|
+
|
|
+ *q = '\0';
|
|
+ return bytes;
|
|
+}
|
|
+
|
|
+void remove_trailing_chars(char *path, char c)
|
|
+{
|
|
+ size_t len;
|
|
+
|
|
+ len = strlen(path);
|
|
+ while (len > 0 && path[len-1] == c)
|
|
+ path[--len] = '\0';
|
|
+}
|
|
+
|
|
diff --git a/libmultipath/util.h b/libmultipath/util.h
|
|
index e86bae2..d0df8aa 100644
|
|
--- a/libmultipath/util.h
|
|
+++ b/libmultipath/util.h
|
|
@@ -6,7 +6,9 @@ void strchop(char *);
|
|
void basename (char * src, char * dst);
|
|
int filepresent (char * run);
|
|
int get_word (char * sentence, char ** word);
|
|
-
|
|
+size_t strlcpy(char *dst, const char *src, size_t size);
|
|
+size_t strlcat(char *dst, const char *src, size_t size);
|
|
+void remove_trailing_chars(char *path, char c);
|
|
|
|
#define safe_sprintf(var, format, args...) \
|
|
snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
|
|
diff --git a/multipath/Makefile b/multipath/Makefile
|
|
index 947d481..a31afe2 100644
|
|
--- a/multipath/Makefile
|
|
+++ b/multipath/Makefile
|
|
@@ -12,7 +12,7 @@ CFLAGS += -I$(multipathdir) -I$(checkers
|
|
ifeq ($(strip $(BUILD)),klibc)
|
|
OBJS += $(libdm) $(libsysfs)
|
|
else
|
|
- LDFLAGS += -ldevmapper -lsysfs
|
|
+ LDFLAGS += -ldevmapper
|
|
endif
|
|
|
|
EXEC = multipath
|
|
@@ -21,7 +21,7 @@ all: $(BUILD)
|
|
|
|
prepare:
|
|
make -C $(multipathdir) prepare
|
|
- rm -f core *.o *.gz
|
|
+ rm -f core *.o
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
|
|
@@ -37,17 +37,17 @@ $(MULTIPATHLIB)-$(BUILD).a:
|
|
|
|
install:
|
|
install -d $(DESTDIR)$(bindir)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
install -d $(DESTDIR)/etc/udev/rules.d
|
|
install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
|
|
install -d $(DESTDIR)$(mandir)
|
|
install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
+ install -d $(DESTDIR)$(man5dir)
|
|
install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
- rm -f core *.o $(EXEC) *.gz
|
|
+ rm -f core *.o $(EXEC)
|
|
diff --git a/multipath/main.c b/multipath/main.c
|
|
index c3d0dac..e2d7f41 100644
|
|
--- a/multipath/main.c
|
|
+++ b/multipath/main.c
|
|
@@ -25,7 +25,6 @@
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
-#include <sysfs/libsysfs.h>
|
|
|
|
#include <checkers.h>
|
|
#include <vector.h>
|
|
@@ -37,6 +36,7 @@
|
|
#include <structs.h>
|
|
#include <structs_vec.h>
|
|
#include <dmparser.h>
|
|
+#include <sysfs.h>
|
|
#include <config.h>
|
|
#include <blacklist.h>
|
|
#include <discovery.h>
|
|
@@ -373,13 +373,13 @@ main (int argc, char *argv[])
|
|
if (dm_prereq(DEFAULT_TARGET))
|
|
exit(1);
|
|
|
|
- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
|
|
- condlog(0, "multipath tools need sysfs mounted");
|
|
- exit(1);
|
|
- }
|
|
if (load_config(DEFAULT_CONFIGFILE))
|
|
exit(1);
|
|
|
|
+ if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
|
|
+ condlog(0, "multipath tools need sysfs mounted");
|
|
+ exit(1);
|
|
+ }
|
|
while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:t")) != EOF ) {
|
|
switch(arg) {
|
|
case 1: printf("optarg : %s\n",optarg);
|
|
@@ -472,6 +472,7 @@ main (int argc, char *argv[])
|
|
condlog(3, "restart multipath configuration process");
|
|
|
|
out:
|
|
+ sysfs_cleanup();
|
|
free_config(conf);
|
|
dm_lib_release();
|
|
dm_lib_exit();
|
|
diff --git a/multipath/multipath.init.suse b/multipath/multipath.init.suse
|
|
new file mode 100755
|
|
index 0000000..34a128c
|
|
--- /dev/null
|
|
+++ b/multipath/multipath.init.suse
|
|
@@ -0,0 +1,104 @@
|
|
+#! /bin/sh
|
|
+# Copyright (c) 2005 SuSE GmbH Nuernberg, Germany.
|
|
+#
|
|
+# Author: Hannes Reinecke <feedback@suse.de>
|
|
+#
|
|
+# init.d/boot.multipath
|
|
+#
|
|
+### BEGIN INIT INFO
|
|
+# Provides: boot.multipath
|
|
+# Required-Start: boot.device-mapper boot.udev
|
|
+# Required-Stop:
|
|
+# Default-Start: B
|
|
+# Default-Stop:
|
|
+# Description: Create multipath device targets
|
|
+### END INIT INFO
|
|
+
|
|
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
|
+PROGRAM=/sbin/multipath
|
|
+
|
|
+# Set the maximum number of open files
|
|
+MAX_OPEN_FDS=4096
|
|
+
|
|
+test -x $PROGRAM || exit 5
|
|
+
|
|
+# Shell functions sourced from /etc/rc.status:
|
|
+# rc_check check and set local and overall rc status
|
|
+# rc_status check and set local and overall rc status
|
|
+# rc_status -v ditto but be verbose in local rc status
|
|
+# rc_status -v -r ditto and clear the local rc status
|
|
+# rc_failed set local and overall rc status to failed
|
|
+# rc_reset clear local rc status (overall remains)
|
|
+# rc_exit exit appropriate to overall rc status
|
|
+. /etc/rc.status
|
|
+
|
|
+# First reset status of this service
|
|
+rc_reset
|
|
+
|
|
+# Return values acc. to LSB for all commands but status:
|
|
+# 0 - success
|
|
+# 1 - misc error
|
|
+# 2 - invalid or excess args
|
|
+# 3 - unimplemented feature (e.g. reload)
|
|
+# 4 - insufficient privilege
|
|
+# 5 - program not installed
|
|
+# 6 - program not configured
|
|
+# 7 - program is not running
|
|
+#
|
|
+# Note that starting an already running service, stopping
|
|
+# or restarting a not-running service as well as the restart
|
|
+# with force-reload (in case signalling is not supported) are
|
|
+# considered a success.
|
|
+
|
|
+case "$1" in
|
|
+ start)
|
|
+ echo -n "Creating multipath targets"
|
|
+ # Check whether multipath daemon is already running
|
|
+ if /sbin/multipathd -k"list paths" > /dev/null 2>&1 ; then
|
|
+ echo -n " (multipathd running)"
|
|
+ rc_status -v
|
|
+ rc_exit
|
|
+ fi
|
|
+
|
|
+ # Load prerequisite module
|
|
+ modprobe dm-multipath
|
|
+
|
|
+ # Be a chicken and flush all existing maps
|
|
+ $PROGRAM -F
|
|
+
|
|
+ # Clear /dev/disk/by-name/ prior to start-up; multipath will
|
|
+ # recreate them.
|
|
+ rm -f /dev/disk/by-name/* 2>&1 >/dev/null
|
|
+
|
|
+ # Set the maximum number of open files
|
|
+ if [ -n "$MAX_OPEN_FDS" ] ; then
|
|
+ ulimit -n $MAX_OPEN_FDS
|
|
+ fi
|
|
+
|
|
+ # Start the program directly as checkproc doesn't work here
|
|
+ $PROGRAM -v 0
|
|
+
|
|
+ # Create all partitions which might have been missing
|
|
+ /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -p -part"
|
|
+
|
|
+ # Remember status and be verbose
|
|
+ rc_status -v
|
|
+ sleep 1
|
|
+ ;;
|
|
+ stop)
|
|
+ # Remove all partition mappings
|
|
+ if dmsetup ls | grep -q -- -part; then
|
|
+ /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -d -p -part"
|
|
+ fi
|
|
+
|
|
+ # And remove the multipath mappings themselves
|
|
+ for map in $(/sbin/dmsetup ls --target multipath | cut -f 1); do
|
|
+ /sbin/dmsetup remove $map
|
|
+ done
|
|
+ ;;
|
|
+ *)
|
|
+ echo "Usage: $0 {start|stop}"
|
|
+ exit 1
|
|
+ ;;
|
|
+esac
|
|
+rc_exit
|
|
diff --git a/multipathd/71-multipath.rules b/multipathd/71-multipath.rules
|
|
new file mode 100644
|
|
index 0000000..756ebe7
|
|
--- /dev/null
|
|
+++ b/multipathd/71-multipath.rules
|
|
@@ -0,0 +1,27 @@
|
|
+#
|
|
+# persistent links for device-mapper devices
|
|
+# only hardware-backed device-mapper devices (ie multipath, dmraid,
|
|
+# and kpartx) have meaningful persistent device names
|
|
+#
|
|
+
|
|
+KERNEL!="dm-*", GOTO="multipath_end"
|
|
+ACTION=="add|remove", GOTO="multipath_end"
|
|
+
|
|
+ACTION=="change", IMPORT{program}=="/sbin/kpartx_id %M %m"
|
|
+
|
|
+# Create persistent links for tables
|
|
+ACTION=="change", ENV{ID_DM_TABLE}=="mpath|dmraid", ENV{ID_DM_TYPE}=="?*", \
|
|
+ SYMLINK+="disk/by-id/$env{ID_DM_TYPE}-$env{ID_DM_NAME}"
|
|
+
|
|
+# Create dm tables for partitions
|
|
+ACTION=="change", ENV{ID_DM_TABLE}=="mpath|dmraid", \
|
|
+ RUN+="/sbin/kpartx -a -p _part /dev/mapper/$env{ID_DM_NAME}"
|
|
+
|
|
+# Create persistent links for partitions
|
|
+ACTION=="change", ENV{ID_DM_TABLE}=="part", ENV{ID_DM_TYPE}=="?*", \
|
|
+ SYMLINK+="disk/by-id/$env{ID_DM_TYPE}-$env{ID_DM_NAME}-part$env{ID_DM_PART}"
|
|
+
|
|
+# socket for uevents
|
|
+RUN+="socket:/org/kernel/dm/multipath_event"
|
|
+LABEL="multipath_end"
|
|
+
|
|
diff --git a/multipathd/Makefile b/multipathd/Makefile
|
|
index da351dc..bbab8da 100644
|
|
--- a/multipathd/Makefile
|
|
+++ b/multipathd/Makefile
|
|
@@ -7,7 +7,7 @@ include ../Makefile.inc
|
|
# basic flags setting
|
|
#
|
|
CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
|
|
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses
|
|
+LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses
|
|
|
|
#
|
|
# debuging stuff
|
|
@@ -44,7 +44,7 @@ $(MULTIPATHLIB)-glibc.a:
|
|
|
|
install:
|
|
install -d $(DESTDIR)$(bindir)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)
|
|
install -d $(DESTDIR)$(rcdir)
|
|
install -d $(DESTDIR)$(mandir)
|
|
install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
|
|
@@ -52,9 +52,8 @@ install:
|
|
uninstall:
|
|
rm -f $(DESTDIR)$(bindir)/$(EXEC)
|
|
rm -f $(DESTDIR)$(rcdir)/$(EXEC)
|
|
- rm -f $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
$(MAKE) -C $(multipathdir) prepare DAEMON=1
|
|
- rm -f core *.o $(EXEC) *.gz
|
|
+ rm -f core *.o $(EXEC)
|
|
|
|
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
|
|
index 4938e84..7bae02a 100644
|
|
--- a/multipathd/cli_handlers.c
|
|
+++ b/multipathd/cli_handlers.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <blacklist.h>
|
|
#include <debug.h>
|
|
#include <print.h>
|
|
+#include <sysfs.h>
|
|
|
|
#include "main.h"
|
|
#include "cli.h"
|
|
@@ -312,6 +313,9 @@ cli_add_map (void * v, char ** reply, in
|
|
{
|
|
struct vectors * vecs = (struct vectors *)data;
|
|
char * param = get_keyparam(v, MAP);
|
|
+ int minor;
|
|
+ char dev_path[PATH_SIZE];
|
|
+ struct sysfs_device *sysdev;
|
|
|
|
condlog(2, "%s: add map (operator)", param);
|
|
|
|
@@ -321,7 +325,18 @@ cli_add_map (void * v, char ** reply, in
|
|
condlog(2, "%s: map blacklisted", param);
|
|
return 0;
|
|
}
|
|
- return ev_add_map(param, vecs);
|
|
+ minor = dm_get_minor(param);
|
|
+ if (minor < 0) {
|
|
+ condlog(2, "%s: not a device mapper table", param);
|
|
+ return 0;
|
|
+ }
|
|
+ sprintf(dev_path,"/block/dm-%d", minor);
|
|
+ sysdev = sysfs_device_get(dev_path);
|
|
+ if (!sysdev) {
|
|
+ condlog(2, "%s: not found in sysfs", param);
|
|
+ return 0;
|
|
+ }
|
|
+ return ev_add_map(sysdev, vecs);
|
|
}
|
|
|
|
int
|
|
diff --git a/multipathd/main.c b/multipathd/main.c
|
|
index 94b0b95..a173da3 100644
|
|
--- a/multipathd/main.c
|
|
+++ b/multipathd/main.c
|
|
@@ -14,12 +14,6 @@
|
|
#include <errno.h>
|
|
|
|
/*
|
|
- * libsysfs
|
|
- */
|
|
-#include <sysfs/libsysfs.h>
|
|
-#include <sysfs/dlist.h>
|
|
-
|
|
-/*
|
|
* libcheckers
|
|
*/
|
|
#include <checkers.h>
|
|
@@ -40,6 +34,7 @@
|
|
#include <structs_vec.h>
|
|
#include <dmparser.h>
|
|
#include <devmapper.h>
|
|
+#include <sysfs.h>
|
|
#include <dict.h>
|
|
#include <discovery.h>
|
|
#include <debug.h>
|
|
@@ -208,31 +203,29 @@ flush_map(struct multipath * mpp, struct
|
|
}
|
|
|
|
static int
|
|
-uev_add_map (char * devname, struct vectors * vecs)
|
|
+uev_add_map (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
- condlog(2, "%s: add map (uevent)", devname);
|
|
- return ev_add_map(devname, vecs);
|
|
+ condlog(2, "%s: add map (uevent)", dev->kernel);
|
|
+ return ev_add_map(dev, vecs);
|
|
}
|
|
|
|
int
|
|
-ev_add_map (char * devname, struct vectors * vecs)
|
|
+ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
- int major, minor;
|
|
- char dev_t[BLK_DEV_SIZE];
|
|
char * alias;
|
|
+ char *dev_t;
|
|
+ int major, minor;
|
|
char * refwwid;
|
|
struct multipath * mpp;
|
|
int map_present;
|
|
int r = 1;
|
|
|
|
- /* libsysfs seems to forget to terminate the string... */
|
|
- memset(dev_t, 0, BLK_DEV_SIZE);
|
|
- if (sscanf(devname, "dm-%d", &minor) == 1 &&
|
|
- !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
|
|
- sscanf(dev_t, "%d:%d", &major, &minor) == 2)
|
|
- alias = dm_mapname(major, minor);
|
|
- else
|
|
- alias = STRDUP(devname);
|
|
+ dev_t = sysfs_attr_get_value(dev->devpath, "dev");
|
|
+
|
|
+ if (!dev_t || sscanf(dev_t, "%d:%d", &major, &minor) != 2)
|
|
+ return 1;
|
|
+
|
|
+ alias = dm_mapname(major, minor);
|
|
|
|
if (!alias)
|
|
return 1;
|
|
@@ -241,7 +234,6 @@ ev_add_map (char * devname, struct vecto
|
|
|
|
if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
|
|
condlog(4, "%s: not a multipath map", alias);
|
|
- FREE(alias);
|
|
return 0;
|
|
}
|
|
|
|
@@ -254,8 +246,7 @@ ev_add_map (char * devname, struct vecto
|
|
* of uev_add_path
|
|
*/
|
|
condlog(0, "%s: devmap already registered",
|
|
- devname);
|
|
- FREE(alias);
|
|
+ dev->kernel);
|
|
return 0;
|
|
}
|
|
|
|
@@ -265,10 +256,10 @@ ev_add_map (char * devname, struct vecto
|
|
if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
|
|
start_waiter_thread))) {
|
|
sync_map_state(mpp);
|
|
- condlog(3, "%s: devmap %s added", alias, devname);
|
|
+ condlog(3, "%s: devmap %s added", alias, dev->kernel);
|
|
return 0;
|
|
}
|
|
- refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec);
|
|
+ refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec);
|
|
|
|
if (refwwid) {
|
|
r = coalesce_paths(vecs, NULL, refwwid);
|
|
@@ -276,20 +267,19 @@ ev_add_map (char * devname, struct vecto
|
|
}
|
|
|
|
if (!r)
|
|
- condlog(3, "%s: devmap %s added", alias, devname);
|
|
+ condlog(3, "%s: devmap %s added", alias, dev->kernel);
|
|
else
|
|
- condlog(0, "%s: uev_add_map %s failed", alias, devname);
|
|
+ condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel);
|
|
|
|
FREE(refwwid);
|
|
- FREE(alias);
|
|
return r;
|
|
}
|
|
|
|
static int
|
|
-uev_remove_map (char * devname, struct vectors * vecs)
|
|
+uev_remove_map (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
- condlog(2, "%s: remove map (uevent)", devname);
|
|
- return ev_remove_map(devname, vecs);
|
|
+ condlog(2, "%s: remove map (uevent)", dev->kernel);
|
|
+ return ev_remove_map(dev->kernel, vecs);
|
|
}
|
|
|
|
int
|
|
@@ -310,13 +300,13 @@ ev_remove_map (char * devname, struct ve
|
|
}
|
|
|
|
static int
|
|
-uev_umount_map (char * devname, struct vectors * vecs)
|
|
+uev_umount_map (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
struct multipath * mpp;
|
|
|
|
- condlog(2, "%s: umount map (uevent)", devname);
|
|
+ condlog(2, "%s: umount map (uevent)", dev->kernel);
|
|
|
|
- mpp = find_mp_by_str(vecs->mpvec, devname);
|
|
+ mpp = find_mp_by_str(vecs->mpvec, dev->kernel);
|
|
|
|
if (!mpp)
|
|
return 0;
|
|
@@ -331,10 +321,10 @@ uev_umount_map (char * devname, struct v
|
|
}
|
|
|
|
static int
|
|
-uev_add_path (char * devname, struct vectors * vecs)
|
|
+uev_add_path (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
- condlog(2, "%s: add path (uevent)", devname);
|
|
- return (ev_add_path(devname, vecs) != 1)? 0 : 1;
|
|
+ condlog(2, "%s: add path (uevent)", dev->kernel);
|
|
+ return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1;
|
|
}
|
|
|
|
|
|
@@ -450,10 +440,10 @@ out:
|
|
}
|
|
|
|
static int
|
|
-uev_remove_path (char * devname, struct vectors * vecs)
|
|
+uev_remove_path (struct sysfs_device * dev, struct vectors * vecs)
|
|
{
|
|
- condlog(2, "%s: remove path (uevent)", devname);
|
|
- return ev_remove_path(devname, vecs);
|
|
+ condlog(2, "%s: remove path (uevent)", dev->kernel);
|
|
+ return ev_remove_path(dev->kernel, vecs);
|
|
}
|
|
|
|
int
|
|
@@ -636,7 +626,7 @@ int
|
|
uev_trigger (struct uevent * uev, void * trigger_data)
|
|
{
|
|
int r = 0;
|
|
- char devname[32];
|
|
+ struct sysfs_device *sysdev;
|
|
struct vectors * vecs;
|
|
|
|
vecs = (struct vectors *)trigger_data;
|
|
@@ -644,7 +634,7 @@ uev_trigger (struct uevent * uev, void *
|
|
if (uev_discard(uev->devpath))
|
|
return 0;
|
|
|
|
- basename(uev->devpath, devname);
|
|
+ sysdev = sysfs_device_get(uev->devpath);
|
|
lock(vecs->lock);
|
|
|
|
/*
|
|
@@ -652,17 +642,17 @@ uev_trigger (struct uevent * uev, void *
|
|
* Add events are ignored here as the tables
|
|
* are not fully initialised then.
|
|
*/
|
|
- if (!strncmp(devname, "dm-", 3)) {
|
|
+ if (!strncmp(sysdev->kernel, "dm-", 3)) {
|
|
if (!strncmp(uev->action, "change", 6)) {
|
|
- r = uev_add_map(devname, vecs);
|
|
+ r = uev_add_map(sysdev, vecs);
|
|
goto out;
|
|
}
|
|
if (!strncmp(uev->action, "remove", 6)) {
|
|
- r = uev_remove_map(devname, vecs);
|
|
+ r = uev_remove_map(sysdev, vecs);
|
|
goto out;
|
|
}
|
|
if (!strncmp(uev->action, "umount", 6)) {
|
|
- r = uev_umount_map(devname, vecs);
|
|
+ r = uev_umount_map(sysdev, vecs);
|
|
goto out;
|
|
}
|
|
goto out;
|
|
@@ -672,15 +662,15 @@ uev_trigger (struct uevent * uev, void *
|
|
* path add/remove event
|
|
*/
|
|
if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
|
|
- devname) > 0)
|
|
+ sysdev->kernel) > 0)
|
|
goto out;
|
|
|
|
if (!strncmp(uev->action, "add", 3)) {
|
|
- r = uev_add_path(devname, vecs);
|
|
+ r = uev_add_path(sysdev, vecs);
|
|
goto out;
|
|
}
|
|
if (!strncmp(uev->action, "remove", 6)) {
|
|
- r = uev_remove_path(devname, vecs);
|
|
+ r = uev_remove_path(sysdev, vecs);
|
|
goto out;
|
|
}
|
|
|
|
@@ -1278,7 +1268,7 @@ child (void * param)
|
|
if (!vecs)
|
|
exit(1);
|
|
|
|
- if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
|
|
+ if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
|
|
condlog(0, "can not find sysfs mount point");
|
|
exit(1);
|
|
}
|
|
@@ -1315,6 +1305,8 @@ child (void * param)
|
|
pthread_cancel(uevent_thr);
|
|
pthread_cancel(uxlsnr_thr);
|
|
|
|
+ sysfs_cleanup();
|
|
+
|
|
free_keys(keys);
|
|
keys = NULL;
|
|
free_handlers(handlers);
|
|
diff --git a/multipathd/main.h b/multipathd/main.h
|
|
index d0cce3a..1a6dc55 100644
|
|
--- a/multipathd/main.h
|
|
+++ b/multipathd/main.h
|
|
@@ -7,7 +7,7 @@
|
|
int reconfigure (struct vectors *);
|
|
int ev_add_path (char *, struct vectors *);
|
|
int ev_remove_path (char *, struct vectors *);
|
|
-int ev_add_map (char *, struct vectors *);
|
|
+int ev_add_map (struct sysfs_device *, struct vectors *);
|
|
int ev_remove_map (char *, struct vectors *);
|
|
|
|
#endif /* MAIN_H */
|
|
diff --git a/multipathd/multipathd.init.suse b/multipathd/multipathd.init.suse
|
|
new file mode 100755
|
|
index 0000000..a297956
|
|
--- /dev/null
|
|
+++ b/multipathd/multipathd.init.suse
|
|
@@ -0,0 +1,155 @@
|
|
+#! /bin/sh
|
|
+# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany.
|
|
+#
|
|
+# Author: Thorsten Kukuk <feedback@suse.de>
|
|
+#
|
|
+# init.d/routed
|
|
+#
|
|
+# and symbolic its link
|
|
+#
|
|
+# /usr/sbin/rcrouted
|
|
+#
|
|
+### BEGIN INIT INFO
|
|
+# Provides: multipathd
|
|
+# Required-Start: $syslog
|
|
+# Required-Stop:
|
|
+# Default-Start: 3 5
|
|
+# Default-Stop: 0 1 2 4 6
|
|
+# Description: Starts multipath daemon
|
|
+### END INIT INFO
|
|
+
|
|
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
|
+DAEMON=/sbin/multipathd
|
|
+PIDFILE=/var/run/multipathd.pid
|
|
+
|
|
+# Set the maximum number of open files
|
|
+MAX_OPEN_FDS=4096
|
|
+
|
|
+test -x $DAEMON || exit 5
|
|
+
|
|
+# Shell functions sourced from /etc/rc.status:
|
|
+# rc_check check and set local and overall rc status
|
|
+# rc_status check and set local and overall rc status
|
|
+# rc_status -v ditto but be verbose in local rc status
|
|
+# rc_status -v -r ditto and clear the local rc status
|
|
+# rc_failed set local and overall rc status to failed
|
|
+# rc_reset clear local rc status (overall remains)
|
|
+# rc_exit exit appropriate to overall rc status
|
|
+. /etc/rc.status
|
|
+
|
|
+# First reset status of this service
|
|
+rc_reset
|
|
+
|
|
+# Return values acc. to LSB for all commands but status:
|
|
+# 0 - success
|
|
+# 1 - misc error
|
|
+# 2 - invalid or excess args
|
|
+# 3 - unimplemented feature (e.g. reload)
|
|
+# 4 - insufficient privilege
|
|
+# 5 - program not installed
|
|
+# 6 - program not configured
|
|
+# 7 - program is not running
|
|
+#
|
|
+# Note that starting an already running service, stopping
|
|
+# or restarting a not-running service as well as the restart
|
|
+# with force-reload (in case signalling is not supported) are
|
|
+# considered a success.
|
|
+
|
|
+case "$1" in
|
|
+ start)
|
|
+ echo -n "Starting multipathd"
|
|
+
|
|
+ modprobe dm-multipath
|
|
+
|
|
+ # Set the maximum number of open files
|
|
+ if [ -n "$MAX_OPEN_FDS" ] ; then
|
|
+ ulimit -n $MAX_OPEN_FDS
|
|
+ fi
|
|
+
|
|
+ if [ -f $PIDFILE ]; then
|
|
+ PID="$(cat $PIDFILE)"
|
|
+ PROCNAME="$(ps -o cmd --no-headers $PID)"
|
|
+ fi
|
|
+
|
|
+ if [ "$PROCNAME" != "$DAEMON" ]; then
|
|
+ $DAEMON
|
|
+ fi
|
|
+
|
|
+ # Remember status and be verbose
|
|
+ rc_status -v
|
|
+ sleep 1
|
|
+ ;;
|
|
+ stop)
|
|
+ echo -n "Shutting down multipathd"
|
|
+ # Because of the way how multipathd sets up its own namespace
|
|
+ # and chroots to it, killproc cannot be used with this process.
|
|
+ # So implement a cruder version:
|
|
+ if [ -f $PIDFILE ]; then
|
|
+ PID="$(cat $PIDFILE)"
|
|
+ PROCNAME="$(ps -o cmd --no-headers $PID)"
|
|
+ fi
|
|
+
|
|
+ if [ "$PROCNAME" == "$DAEMON" ]; then
|
|
+ kill -TERM $PID
|
|
+ fi
|
|
+
|
|
+ # Remember status and be verbose
|
|
+ rc_status -v
|
|
+ ;;
|
|
+ try-restart)
|
|
+ ## Stop the service and if this succeeds (i.e. the
|
|
+ ## service was running before), start it again.
|
|
+ $0 status >/dev/null && $0 restart
|
|
+
|
|
+ # Remember status and be quiet
|
|
+ rc_status
|
|
+ ;;
|
|
+ restart|force-reload)
|
|
+ ## Stop the service and regardless of whether it was
|
|
+ ## running or not, start it again.
|
|
+ $0 stop
|
|
+ $0 start
|
|
+
|
|
+ # Remember status and be quiet
|
|
+ rc_status
|
|
+ ;;
|
|
+ reload)
|
|
+ ## Like force-reload, but if daemon does not support
|
|
+ ## signalling, do nothing (!)
|
|
+
|
|
+ # If it does not support reload:
|
|
+ exit 3
|
|
+ ;;
|
|
+ status)
|
|
+ echo -n "Checking for multipathd: "
|
|
+
|
|
+ # Status has a slightly different for the status command:
|
|
+ # 0 - service running
|
|
+ # 1 - service dead, but /var/run/ pid file exists
|
|
+ # 2 - service dead, but /var/lock/ lock file exists
|
|
+ # 3 - service not running
|
|
+
|
|
+ if [ -f $PIDFILE ]; then
|
|
+ PID="$(cat $PIDFILE)"
|
|
+ PROCNAME="$(ps -o cmd --no-headers $PID)"
|
|
+ if [ "$PROCNAME" == "$DAEMON" ]; then
|
|
+ (exit 0)
|
|
+ else
|
|
+ (exit 1)
|
|
+ fi
|
|
+ else
|
|
+ (exit 3)
|
|
+ fi
|
|
+
|
|
+ rc_status -v
|
|
+ ;;
|
|
+ probe)
|
|
+ ## Optional: Probe for the necessity of a reload,
|
|
+ ## give out the argument which is required for a reload.
|
|
+ ;;
|
|
+ *)
|
|
+ echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
|
|
+ exit 1
|
|
+ ;;
|
|
+esac
|
|
+rc_exit
|
|
diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile
|
|
index 6c58529..ce78455 100644
|
|
--- a/path_priority/pp_alua/Makefile
|
|
+++ b/path_priority/pp_alua/Makefile
|
|
@@ -41,10 +41,9 @@ install: $(EXEC) $(EXEC).8
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
- rm $(DESTDIR)$(mandir)/$(EXEC).8
|
|
|
|
clean:
|
|
- rm -f *.o *.gz $(EXEC)
|
|
+ rm -f *.o $(EXEC)
|
|
|
|
main.o: main.c rtpg.h spc3.h
|
|
|
|
diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile
|
|
index bed7fb0..b0fee28 100644
|
|
--- a/path_priority/pp_balance_units/Makefile
|
|
+++ b/path_priority/pp_balance_units/Makefile
|
|
@@ -22,7 +22,7 @@ EXEC = mpath_prio_balance_units
|
|
all: $(BUILD)
|
|
|
|
prepare:
|
|
- rm -f core *.o *.gz
|
|
+ rm -f core *.o
|
|
|
|
glibc: prepare $(OBJS)
|
|
$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
|
|
@@ -35,10 +35,10 @@ $(MULTIPATHLIB)-$(BUILD).a:
|
|
|
|
install:
|
|
install -d $(DESTDIR)$(bindir)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
clean:
|
|
- rm -f core *.o $(EXEC) *.gz
|
|
+ rm -f core *.o $(EXEC)
|
|
diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile
|
|
index 651bdcd..8c6e922 100644
|
|
--- a/path_priority/pp_emc/Makefile
|
|
+++ b/path_priority/pp_emc/Makefile
|
|
@@ -14,7 +14,7 @@ klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
install: $(EXEC)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile
|
|
index a0249a5..1c276e6 100644
|
|
--- a/path_priority/pp_hds_modular/Makefile
|
|
+++ b/path_priority/pp_hds_modular/Makefile
|
|
@@ -14,7 +14,7 @@ klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
install: $(EXEC)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
diff --git a/path_priority/pp_netapp/Makefile b/path_priority/pp_netapp/Makefile
|
|
index 9e7d3a3..2d571b0 100644
|
|
--- a/path_priority/pp_netapp/Makefile
|
|
+++ b/path_priority/pp_netapp/Makefile
|
|
@@ -14,7 +14,7 @@ klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
install: $(EXEC)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile
|
|
index 85f42a2..ca7974e 100644
|
|
--- a/path_priority/pp_random/Makefile
|
|
+++ b/path_priority/pp_random/Makefile
|
|
@@ -14,7 +14,7 @@ klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
install: $(EXEC)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|
|
diff --git a/path_priority/pp_tpc/Makefile b/path_priority/pp_tpc/Makefile
|
|
index 86841dd..624f76d 100644
|
|
--- a/path_priority/pp_tpc/Makefile
|
|
+++ b/path_priority/pp_tpc/Makefile
|
|
@@ -14,7 +14,7 @@ klibc: $(OBJS)
|
|
$(CC) -static -o $(EXEC) $(OBJS)
|
|
|
|
install: $(EXEC)
|
|
- install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
+ install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
|
|
|
|
uninstall:
|
|
rm $(DESTDIR)$(bindir)/$(EXEC)
|