├── .gitignore ├── COPYING ├── LICENSES ├── GPL-2.0 ├── GPL-3.0 ├── LGPL-2.0 └── LGPL-2.1 ├── Makefile ├── Makefile.inc ├── README.alua ├── README.md ├── kpartx ├── Makefile ├── bsd.c ├── byteorder.h ├── crc32.c ├── crc32.h ├── dasd.c ├── dasd.h ├── del-part-nodes.rules ├── devmapper.c ├── devmapper.h ├── dm-parts.rules ├── dos.c ├── dos.h ├── efi.h ├── gpt.c ├── gpt.h ├── kpartx.8 ├── kpartx.c ├── kpartx.h ├── kpartx.rules ├── kpartx_id ├── lopart.c ├── lopart.h ├── mac.c ├── mac.h ├── ps3.c ├── solaris.c ├── sun.c ├── test-kpartx ├── unixware.c ├── xstrncpy.c └── xstrncpy.h ├── libdmmp ├── DEV_NOTES ├── Makefile ├── docs │ ├── doc-preclean.pl │ ├── kernel-doc │ ├── libdmmp.h.3 │ └── split-man.pl ├── libdmmp.c ├── libdmmp.pc.in ├── libdmmp │ └── libdmmp.h ├── libdmmp_misc.c ├── libdmmp_mp.c ├── libdmmp_path.c ├── libdmmp_pg.c ├── libdmmp_private.h └── test │ ├── Makefile │ ├── libdmmp_speed_test.c │ └── libdmmp_test.c ├── libmpathcmd ├── Makefile ├── mpath_cmd.c └── mpath_cmd.h ├── libmpathpersist ├── Makefile ├── mpath_persist.c ├── mpath_persist.h ├── mpath_persistent_reserve_in.3 ├── mpath_persistent_reserve_out.3 ├── mpath_pr_ioctl.c ├── mpath_pr_ioctl.h ├── mpath_updatepr.c └── mpathpr.h ├── libmultipath ├── Makefile ├── alias.c ├── alias.h ├── blacklist.c ├── blacklist.h ├── byteorder.h ├── callout.c ├── callout.h ├── checkers.c ├── checkers.h ├── checkers │ ├── Makefile │ ├── cciss.h │ ├── cciss_tur.c │ ├── directio.c │ ├── directio.h │ ├── emc_clariion.c │ ├── emc_clariion.h │ ├── hp_sw.c │ ├── hp_sw.h │ ├── rdac.c │ ├── rdac.h │ ├── readsector0.c │ ├── readsector0.h │ ├── tur.c │ └── tur.h ├── config.c ├── config.h ├── configure.c ├── configure.h ├── debug.c ├── debug.h ├── defaults.c ├── defaults.h ├── devmapper.c ├── devmapper.h ├── dict.c ├── dict.h ├── discovery.c ├── discovery.h ├── dm-generic.c ├── dm-generic.h ├── dmparser.c ├── dmparser.h ├── file.c ├── file.h ├── foreign.c ├── foreign.h ├── foreign │ ├── Makefile │ └── nvme.c ├── generic.c ├── generic.h ├── hwtable.c ├── hwtable.h ├── io_err_stat.c ├── io_err_stat.h ├── libsg.c ├── libsg.h ├── list.h ├── lock.c ├── lock.h ├── log.c ├── log.h ├── log_pthread.c ├── log_pthread.h ├── memory.c ├── memory.h ├── nvme-lib.c ├── nvme-lib.h ├── nvme │ ├── argconfig.h │ ├── json.h │ ├── linux │ │ ├── nvme.h │ │ └── nvme_ioctl.h │ ├── nvme-ioctl.c │ ├── nvme-ioctl.h │ ├── nvme.h │ └── plugin.h ├── parser.c ├── parser.h ├── pgpolicies.c ├── pgpolicies.h ├── print.c ├── print.h ├── prio.c ├── prio.h ├── prioritizers │ ├── Makefile │ ├── alua.c │ ├── alua.h │ ├── alua_rtpg.c │ ├── alua_rtpg.h │ ├── alua_spc3.h │ ├── ana.c │ ├── const.c │ ├── datacore.c │ ├── emc.c │ ├── hds.c │ ├── hp_sw.c │ ├── iet.c │ ├── ontap.c │ ├── path_latency.c │ ├── random.c │ ├── rdac.c │ ├── sysfs.c │ ├── weightedpath.c │ └── weightedpath.h ├── prkey.c ├── prkey.h ├── propsel.c ├── propsel.h ├── sg_include.h ├── structs.c ├── structs.h ├── structs_vec.c ├── structs_vec.h ├── switchgroup.c ├── switchgroup.h ├── sysfs.c ├── sysfs.h ├── time-util.c ├── time-util.h ├── uevent.c ├── uevent.h ├── unaligned.h ├── util.c ├── util.h ├── uxsock.c ├── uxsock.h ├── valid.c ├── valid.h ├── vector.c ├── vector.h ├── version.h ├── wwids.c └── wwids.h ├── mpathpersist ├── Makefile ├── main.c ├── main.h └── mpathpersist.8 ├── multipath ├── 11-dm-mpath.rules ├── Makefile ├── main.c ├── multipath.8 ├── multipath.conf.5 └── multipath.rules ├── multipathd ├── Makefile ├── cli.c ├── cli.h ├── cli_handlers.c ├── cli_handlers.h ├── dmevents.c ├── dmevents.h ├── main.c ├── main.h ├── multipathd.8 ├── multipathd.service ├── multipathd.socket ├── pidfile.c ├── pidfile.h ├── uxclnt.c ├── uxclnt.h ├── uxlsnr.c ├── uxlsnr.h ├── waiter.c └── waiter.h ├── tests ├── Makefile ├── README.md ├── alias.c ├── blacklist.c ├── devt.c ├── directio.c ├── dmevents.c ├── globals.c ├── hwtable.c ├── parser.c ├── pgpolicy.c ├── test-lib.c ├── test-lib.h ├── test-log.c ├── test-log.h ├── uevent.c ├── unaligned.c ├── util.c ├── valid.c └── vpd.c └── third-party └── valgrind ├── drd.h └── valgrind.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .dotest 3 | *~ 4 | *.so 5 | *.so.0 6 | *.a 7 | *.gz 8 | *.d 9 | kpartx/kpartx 10 | multipath/multipath 11 | multipathd/multipathd 12 | mpathpersist/mpathpersist 13 | .nfs* 14 | *.swp 15 | *.patch 16 | *.rej 17 | *.orig 18 | libdmmp/docs/man/*.3.gz 19 | libdmmp/*.so.* 20 | libdmmp/test/libdmmp_test 21 | libdmmp/test/libdmmp_speed_test 22 | tests/*-test 23 | tests/*.out 24 | libmultipath/nvme-ioctl.c 25 | libmultipath/nvme-ioctl.h 26 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | LICENSES/LGPL-2.0 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | 5 | BUILDDIRS := \ 6 | libmpathcmd \ 7 | libmultipath \ 8 | libmultipath/prioritizers \ 9 | libmultipath/checkers \ 10 | libmultipath/foreign \ 11 | libmpathpersist \ 12 | multipath \ 13 | multipathd \ 14 | mpathpersist \ 15 | kpartx 16 | 17 | ifneq ($(ENABLE_LIBDMMP),0) 18 | BUILDDIRS += \ 19 | libdmmp 20 | endif 21 | 22 | BUILDDIRS.clean := $(BUILDDIRS:=.clean) tests.clean 23 | 24 | .PHONY: $(BUILDDIRS) $(BUILDDIRS:=.uninstall) $(BUILDDIRS:=.install) $(BUILDDIRS.clean) 25 | 26 | all: $(BUILDDIRS) 27 | 28 | $(BUILDDIRS): 29 | $(MAKE) -C $@ 30 | 31 | libmultipath libdmmp: libmpathcmd 32 | libmpathpersist multipath multipathd: libmultipath 33 | mpathpersist multipathd: libmpathpersist 34 | 35 | libmultipath/checkers.install \ 36 | libmultipath/prioritizers.install \ 37 | libmultipath/foreign.install: libmultipath.install 38 | 39 | $(BUILDDIRS.clean): 40 | $(MAKE) -C ${@:.clean=} clean 41 | 42 | $(BUILDDIRS:=.install): 43 | $(MAKE) -C ${@:.install=} install 44 | 45 | $(BUILDDIRS:=.uninstall): 46 | $(MAKE) -C ${@:.uninstall=} uninstall 47 | 48 | clean: $(BUILDDIRS.clean) 49 | install: $(BUILDDIRS:=.install) 50 | uninstall: $(BUILDDIRS:=.uninstall) 51 | 52 | test: all 53 | $(MAKE) -C tests 54 | 55 | valgrind-test: all 56 | $(MAKE) -C tests valgrind 57 | 58 | .PHONY: TAGS 59 | TAGS: 60 | etags -a libmultipath/*.c 61 | etags -a libmultipath/*.h 62 | etags -a multipathd/*.c 63 | etags -a multipathd/*.h 64 | -------------------------------------------------------------------------------- /README.alua: -------------------------------------------------------------------------------- 1 | This is a rough guide, consult your storage device manufacturer documentation. 2 | 3 | ALUA is supported in some devices, but usually it's disabled by default. 4 | To enable ALUA, the following options should be changed: 5 | 6 | - EMC CLARiiON/VNX: 7 | "Failover Mode" should be changed to "4". 8 | 9 | - HPE 3PAR: 10 | "Host:" should be changed to "Generic-ALUA Persona 2 (UARepLun, SESLun, ALUA)". 11 | 12 | - Promise VTrak/Vess: 13 | "LUN Affinity" and "ALUA" should be changed to "Enable", "Redundancy Type" 14 | must be "Active-Active". 15 | 16 | - LSI/Engenio/NetApp RDAC class, as NetApp SANtricity E/EF Series and OEM arrays: 17 | "Select operating system:" should be changed to "Linux DM-MP (Kernel 3.10 or later)". 18 | 19 | - NetApp ONTAP: 20 | To check ALUA state: "igroup show -v ", and to enable ALUA: 21 | "igroup set alua yes". 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | multipath-tools for Linux 2 | ************************* 3 | 4 | https://github.com/opensvc/multipath-tools 5 | 6 | This package provides the following binaries to drive the Device Mapper multipathing driver: 7 | 8 | * multipath - Device mapper target autoconfig. 9 | * multipathd - Multipath daemon. 10 | * mpathpersist - Manages SCSI persistent reservations on dm multipath devices. 11 | * kpartx - Create device maps from partition tables. 12 | 13 | 14 | Releases 15 | ======== 16 | 17 | To get a specific X.Y.Z release, use one of the following method: 18 | 19 | 20 | Git 21 | --- 22 | 23 | git clone https://github.com/opensvc/multipath-tools.git 24 | cd multipath-tools 25 | git tag 26 | git archive --format=tar.gz --prefix=multipath-tools-X.Y.Z/ X.Y.Z > ../multipath-tools-X.Y.Z.tar.gz 27 | 28 | 29 | Direct download 30 | --------------- 31 | 32 | wget "https://github.com/opensvc/multipath-tools/archive/X.Y.Z.tar.gz" -O multipath-tools-X.Y.Z.tar.gz 33 | 34 | 35 | Browser 36 | ------- 37 | 38 | Go to: https://github.com/opensvc/multipath-tools/tags 39 | Select a release-tag and then click on "zip" or "tar.gz". 40 | 41 | 42 | Source code 43 | =========== 44 | 45 | To get latest devel code: 46 | 47 | git clone https://github.com/opensvc/multipath-tools.git 48 | 49 | Github page: https://github.com/opensvc/multipath-tools 50 | 51 | 52 | Add storage devices 53 | =================== 54 | 55 | Follow the instructions in the `libmultipath/hwtable.c` header. 56 | 57 | 58 | Mailing list 59 | ============ 60 | 61 | (subscribers-only) 62 | To subscribe and archives: https://www.redhat.com/mailman/listinfo/dm-devel 63 | Searchable: https://marc.info/?l=dm-devel 64 | 65 | 66 | Changelog 67 | ========= 68 | 69 | pre-0.4.5: https://web.archive.org/web/20070309224034/http://christophe.varoqui.free.fr/wiki/wakka.php?wiki=ChangeLog 70 | post-0.4.5: https://github.com/opensvc/multipath-tools/commits/master 71 | 72 | 73 | Maintainer 74 | ========== 75 | 76 | Christophe Varoqui 77 | Device-mapper development mailing list 78 | 79 | 80 | Licence 81 | ======= 82 | 83 | The multipath-tools source code is covered by several different licences. 84 | Refer to the individual source files for details. 85 | Source files which do not specify a licence are shipped under LGPL-2.0 86 | (see `LICENSES/LGPL-2.0`). 87 | 88 | -------------------------------------------------------------------------------- /kpartx/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | CFLAGS += $(BIN_CFLAGS) -I. -I$(multipathdir) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 7 | LDFLAGS += $(BIN_LDFLAGS) 8 | 9 | LIBDEPS += -ldevmapper 10 | 11 | ifneq ($(call check_func,dm_task_set_cookie,/usr/include/libdevmapper.h),0) 12 | CFLAGS += -DLIBDM_API_COOKIE 13 | endif 14 | 15 | OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \ 16 | gpt.o mac.o ps3.o crc32.o lopart.o xstrncpy.o devmapper.o 17 | 18 | EXEC = kpartx 19 | 20 | all: $(EXEC) 21 | 22 | $(EXEC): $(OBJS) 23 | $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS) 24 | $(GZIP) $(EXEC).8 > $(EXEC).8.gz 25 | 26 | install: $(EXEC) $(EXEC).8 27 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 28 | $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) 29 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir) 30 | $(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir) 31 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)/rules.d 32 | $(INSTALL_PROGRAM) -m 644 dm-parts.rules $(DESTDIR)$(libudevdir)/rules.d/11-dm-parts.rules 33 | $(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules 34 | $(INSTALL_PROGRAM) -m 644 del-part-nodes.rules $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules 35 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir) 36 | $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir) 37 | 38 | uninstall: 39 | $(RM) $(DESTDIR)$(bindir)/$(EXEC) 40 | $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz 41 | $(RM) $(DESTDIR)$(libudevdir)/kpartx_id 42 | $(RM) $(DESTDIR)$(libudevdir)/rules.d/11-dm-parts.rules 43 | $(RM) $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules 44 | $(RM) $(DESTDIR)$(libudevdir)/rules.d/67-kpartx-compat.rules 45 | $(RM) $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules 46 | 47 | clean: dep_clean 48 | $(RM) core *.o $(EXEC) *.gz 49 | 50 | include $(wildcard $(OBJS:.o=.d)) 51 | 52 | dep_clean: 53 | $(RM) $(OBJS:.o=.d) 54 | -------------------------------------------------------------------------------- /kpartx/byteorder.h: -------------------------------------------------------------------------------- 1 | #ifndef BYTEORDER_H_INCLUDED 2 | #define BYTEORDER_H_INCLUDED 3 | 4 | #ifdef __linux__ 5 | # include 6 | # include 7 | #else 8 | # error unsupported 9 | #endif 10 | 11 | #if BYTE_ORDER == LITTLE_ENDIAN 12 | # define le16_to_cpu(x) (x) 13 | # define be16_to_cpu(x) bswap_16(x) 14 | # define le32_to_cpu(x) (x) 15 | # define le64_to_cpu(x) (x) 16 | # define be32_to_cpu(x) bswap_32(x) 17 | # define be64_to_cpu(x) bswap_64(x) 18 | #elif BYTE_ORDER == BIG_ENDIAN 19 | # define le16_to_cpu(x) bswap_16(x) 20 | # define be16_to_cpu(x) (x) 21 | # define le32_to_cpu(x) bswap_32(x) 22 | # define le64_to_cpu(x) bswap_64(x) 23 | # define be32_to_cpu(x) (x) 24 | # define be64_to_cpu(x) (x) 25 | #else 26 | # error unsupported 27 | #endif 28 | 29 | #endif /* BYTEORDER_H_INCLUDED */ 30 | -------------------------------------------------------------------------------- /kpartx/crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * crc32.h 3 | */ 4 | #ifndef _CRC32_H 5 | #define _CRC32_H 6 | 7 | #include 8 | #include 9 | 10 | extern int init_crc32(void); 11 | extern void cleanup_crc32(void); 12 | extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len); 13 | extern uint32_t crc32_be(uint32_t crc, unsigned char const *p, size_t len); 14 | 15 | #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length) 16 | #define ether_crc_le(length, data) crc32_le(~0, data, length) 17 | #define ether_crc(length, data) crc32_be(~0, data, length) 18 | 19 | #endif /* _CRC32_H */ 20 | -------------------------------------------------------------------------------- /kpartx/del-part-nodes.rules: -------------------------------------------------------------------------------- 1 | # These rules can delete partitions devnodes for slave devices 2 | # for certain aggregate devices such as multipath. 3 | # This is desirable to avoid confusion and keep the number 4 | # of device nodes and symlinks within limits. 5 | # 6 | # This is done only once on the first "add" or "change" event for 7 | # any given device. 8 | # 9 | # To suppress this, use the kernel parameter "dont_del_part_nodes", 10 | # or create an udev rule file that sets ENV{DONT_DEL_PART_NODES}="1". 11 | 12 | SUBSYSTEM!="block", GOTO="end_del_part_nodes" 13 | KERNEL!="sd*|dasd*", GOTO="end_del_part_nodes" 14 | ACTION!="add|change", GOTO="end_del_part_nodes" 15 | ENV{DEVTYPE}=="partition", GOTO="end_del_part_nodes" 16 | 17 | IMPORT{cmdline}="dont_del_part_nodes" 18 | ENV{dont_del_part_nodes}=="1", GOTO="end_del_part_nodes" 19 | ENV{DONT_DEL_PART_NODES}=="1", GOTO="end_del_part_nodes" 20 | 21 | # dm-multipath 22 | ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="del_part_nodes" 23 | 24 | # Other aggregate device types can be added here. 25 | 26 | GOTO="end_del_part_nodes" 27 | 28 | LABEL="del_part_nodes" 29 | IMPORT{db}="DM_DEL_PART_NODES" 30 | ENV{DM_DEL_PART_NODES}!="1", ENV{DM_DEL_PART_NODES}="1", \ 31 | RUN+="/usr/sbin/partx -d --nr 1-1024 $env{DEVNAME}" 32 | 33 | LABEL="end_del_part_nodes" 34 | -------------------------------------------------------------------------------- /kpartx/devmapper.h: -------------------------------------------------------------------------------- 1 | #ifndef _KPARTX_DEVMAPPER_H 2 | #define _KPARTX_DEVMAPPER_H 3 | 4 | #ifdef DM_SUBSYSTEM_UDEV_FLAG0 5 | #define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0 6 | #else 7 | #define MPATH_UDEV_RELOAD_FLAG 0 8 | #endif 9 | 10 | extern int udev_sync; 11 | 12 | int dm_prereq (char *, uint32_t, uint32_t, uint32_t); 13 | int dm_simplecmd (int, const char *, int, uint16_t); 14 | int dm_addmap (int, const char *, const char *, const char *, uint64_t, 15 | int, const char *, int, mode_t, uid_t, gid_t); 16 | char * dm_mapname(int major, int minor); 17 | dev_t dm_get_first_dep(char *devname); 18 | char * dm_mapuuid(const char *mapname); 19 | int dm_devn (const char * mapname, unsigned int *major, unsigned int *minor); 20 | int dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose); 21 | int dm_find_part(const char *parent, const char *delim, int part, 22 | const char *parent_uuid, 23 | char *name, size_t namesiz, char **part_uuid, int verbose); 24 | 25 | /* 26 | * UUID format for partitions created on non-DM devices 27 | * ${UUID_PREFIX}devnode_${MAJOR}:${MINOR}_${NONDM_UUID_SUFFIX}" 28 | * where ${UUID_PREFIX} is "part${PARTNO}-" (see devmapper.c). 29 | * 30 | * The suffix should be sufficiently unique to avoid incidental conflicts; 31 | * the value below is a base64-encoded random number. 32 | * The UUID format shouldn't be changed between kpartx releases. 33 | */ 34 | #define NONDM_UUID_PREFIX "devnode" 35 | #define NONDM_UUID_SUFFIX "Wh5pYvM" 36 | char *nondm_create_uuid(dev_t devt); 37 | int nondm_parse_uuid(const char *uuid, 38 | unsigned int *major, unsigned int *minor); 39 | #endif /* _KPARTX_DEVMAPPER_H */ 40 | -------------------------------------------------------------------------------- /kpartx/dm-parts.rules: -------------------------------------------------------------------------------- 1 | # Rules for partitions created by kpartx 2 | 3 | KERNEL!="dm-*", GOTO="dm_parts_end" 4 | ACTION!="add|change", GOTO="dm_parts_end" 5 | ENV{DM_UUID}!="part[0-9]*", GOTO="dm_parts_end" 6 | 7 | # We must take care that symlinks don't get lost, 8 | # even if blkid fails in 13-dm-disk.rules later. 9 | # 10 | # Fixme: we have currently no way to avoid calling blkid on 11 | # partitions of broken mpath maps such as DM_NOSCAN. 12 | # But when partition devices appear, kpartx has likely read 13 | # the partition table shortly before, so odds are not bad 14 | # that blkid will also succeed. 15 | 16 | IMPORT{db}="ID_FS_USAGE" 17 | IMPORT{db}="ID_FS_UUID_ENC" 18 | IMPORT{db}="ID_FS_LABEL_ENC" 19 | IMPORT{db}="ID_PART_ENTRY_NAME" 20 | IMPORT{db}="ID_PART_ENTRY_UUID" 21 | IMPORT{db}="ID_PART_ENTRY_SCHEME" 22 | 23 | # Maps should take precedence over their members. 24 | ENV{DM_UDEV_LOW_PRIORITY_FLAG}!="1", OPTIONS+="link_priority=50" 25 | 26 | # Set some additional symlinks that typically exist for mpath 27 | # path members, too, and should be overridden. 28 | # 29 | # kpartx_id is very robust, it works for suspended maps and maps 30 | # with 0 dependencies. It sets DM_TYPE, DM_PART, DM_WWN 31 | IMPORT{program}=="kpartx_id %M %m $env{DM_UUID}" 32 | 33 | # DM_TYPE only has a reasonable value for partitions on multipath. 34 | ENV{DM_UUID}=="*-mpath-*", ENV{DM_TYPE}=="?*", ENV{DM_SERIAL}=="?*" \ 35 | SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_SERIAL}-part$env{DM_PART}" 36 | ENV{DM_WWN}=="?*", ENV{DM_PART}=="?*", \ 37 | SYMLINK+="disk/by-id/wwn-$env{DM_WWN}-part$env{DM_PART}" 38 | 39 | LABEL="dm_parts_end" 40 | -------------------------------------------------------------------------------- /kpartx/dos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Source: copy of util-linux' partx dos.c 3 | * 4 | * Copyrights of the original file apply 5 | * Copyright (c) 2005 Bastian Blank 6 | */ 7 | #include "kpartx.h" 8 | #include "byteorder.h" 9 | #include 10 | #include 11 | #include "dos.h" 12 | 13 | static int 14 | is_extended(int type) { 15 | return (type == 5 || type == 0xf || type == 0x85); 16 | } 17 | 18 | static int 19 | read_extended_partition(int fd, struct partition *ep, int en, 20 | struct slice *sp, int ns) 21 | { 22 | struct partition p; 23 | unsigned long start, here, next; 24 | unsigned char *bp; 25 | int loopct = 0; 26 | int moretodo = 1; 27 | int i, n=0; 28 | 29 | int sector_size_mul = get_sector_size(fd)/512; 30 | 31 | next = start = sector_size_mul * le32_to_cpu(ep->start_sect); 32 | 33 | while (moretodo) { 34 | here = next; 35 | moretodo = 0; 36 | if (++loopct > 100) 37 | return n; 38 | 39 | bp = (unsigned char *)getblock(fd, here); 40 | if (bp == NULL) 41 | return n; 42 | 43 | if (bp[510] != 0x55 || bp[511] != 0xaa) 44 | return n; 45 | 46 | for (i=0; i<2; i++) { 47 | memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); 48 | if (is_extended(p.sys_type)) { 49 | if (p.start_sect && p.nr_sects && !moretodo) { 50 | next = start + sector_size_mul * le32_to_cpu(p.start_sect); 51 | moretodo = 1; 52 | } 53 | continue; 54 | } 55 | if (n < ns) { 56 | sp[n].start = here + sector_size_mul * le32_to_cpu(p.start_sect); 57 | sp[n].size = sector_size_mul * le32_to_cpu(p.nr_sects); 58 | sp[n].container = en + 1; 59 | n++; 60 | } else { 61 | fprintf(stderr, 62 | "dos_extd_partition: too many slices\n"); 63 | return n; 64 | } 65 | loopct = 0; 66 | } 67 | } 68 | return n; 69 | } 70 | 71 | static int 72 | is_gpt(int type) { 73 | return (type == 0xEE); 74 | } 75 | 76 | int 77 | read_dos_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 78 | struct partition p; 79 | unsigned long offset = all.start; 80 | unsigned int i, n=4; 81 | unsigned char *bp; 82 | uint64_t sector_size_mul = get_sector_size(fd)/512; 83 | 84 | bp = (unsigned char *)getblock(fd, offset); 85 | if (bp == NULL) 86 | return -1; 87 | 88 | if (bp[510] != 0x55 || bp[511] != 0xaa) 89 | return -1; 90 | 91 | for (i=0; i<4; i++) { 92 | memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p)); 93 | if (is_gpt(p.sys_type)) 94 | return 0; 95 | if (i < ns) { 96 | sp[i].start = sector_size_mul * le32_to_cpu(p.start_sect); 97 | sp[i].size = sector_size_mul * le32_to_cpu(p.nr_sects); 98 | } else { 99 | fprintf(stderr, 100 | "dos_partition: too many slices\n"); 101 | break; 102 | } 103 | if (is_extended(p.sys_type)) { 104 | /* extended partitions only get one or 105 | two sectors mapped for LILO to install, 106 | whichever is needed to have 1kb of space */ 107 | if (sector_size_mul == 1) 108 | sp[i].size = 2; 109 | else sp[i].size = sector_size_mul; 110 | n += read_extended_partition(fd, &p, i, sp+n, ns-n); 111 | } 112 | } 113 | return n; 114 | } 115 | -------------------------------------------------------------------------------- /kpartx/dos.h: -------------------------------------------------------------------------------- 1 | #ifndef DOS_H_INCLUDED 2 | #define DOS_H_INCLUDED 3 | 4 | struct partition { 5 | unsigned char boot_ind; /* 0x80 - active */ 6 | unsigned char bh, bs, bc; 7 | unsigned char sys_type; 8 | unsigned char eh, es, ec; 9 | unsigned int start_sect; 10 | unsigned int nr_sects; 11 | } __attribute__((packed)); 12 | 13 | #endif /* DOS_H_INCLUDED */ 14 | -------------------------------------------------------------------------------- /kpartx/efi.h: -------------------------------------------------------------------------------- 1 | /* 2 | efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars 3 | 4 | Copyright (C) 2001 Dell Computer Corporation 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef EFI_H 21 | #define EFI_H 22 | 23 | /* 24 | * Extensible Firmware Interface 25 | * Based on 'Extensible Firmware Interface Specification' 26 | * version 1.02, 12 December, 2000 27 | */ 28 | #include 29 | #include 30 | 31 | typedef struct { 32 | uint8_t b[16]; 33 | } efi_guid_t; 34 | 35 | #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ 36 | ((efi_guid_t) \ 37 | {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ 38 | (b) & 0xff, ((b) >> 8) & 0xff, \ 39 | (c) & 0xff, ((c) >> 8) & 0xff, \ 40 | (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) 41 | 42 | 43 | /****************************************************** 44 | * GUIDs 45 | ******************************************************/ 46 | #define NULL_GUID \ 47 | EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) 48 | 49 | static inline int 50 | efi_guidcmp(efi_guid_t left, efi_guid_t right) 51 | { 52 | return memcmp(&left, &right, sizeof (efi_guid_t)); 53 | } 54 | 55 | typedef uint16_t efi_char16_t; /* UNICODE character */ 56 | 57 | #endif /* EFI_H */ 58 | -------------------------------------------------------------------------------- /kpartx/gpt.h: -------------------------------------------------------------------------------- 1 | /* 2 | gpt.[ch] 3 | 4 | Copyright (C) 2000-2001 Dell Computer Corporation 5 | 6 | EFI GUID Partition Table handling 7 | Per Intel EFI Specification v1.02 8 | http://developer.intel.com/technology/efi/efi.htm 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | */ 23 | 24 | #ifndef _GPT_H 25 | #define _GPT_H 26 | 27 | 28 | #include 29 | #include "kpartx.h" 30 | #include "dos.h" 31 | #include "efi.h" 32 | 33 | #define EFI_PMBR_OSTYPE_EFI 0xEF 34 | #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE 35 | #define MSDOS_MBR_SIGNATURE 0xaa55 36 | #define GPT_BLOCK_SIZE 512 37 | 38 | #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL 39 | #define GPT_HEADER_REVISION_V1_02 0x00010200 40 | #define GPT_HEADER_REVISION_V1_00 0x00010000 41 | #define GPT_HEADER_REVISION_V0_99 0x00009900 42 | #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 43 | 44 | typedef struct _gpt_header { 45 | uint64_t signature; 46 | uint32_t revision; 47 | uint32_t header_size; 48 | uint32_t header_crc32; 49 | uint32_t reserved1; 50 | uint64_t my_lba; 51 | uint64_t alternate_lba; 52 | uint64_t first_usable_lba; 53 | uint64_t last_usable_lba; 54 | efi_guid_t disk_guid; 55 | uint64_t partition_entry_lba; 56 | uint32_t num_partition_entries; 57 | uint32_t sizeof_partition_entry; 58 | uint32_t partition_entry_array_crc32; 59 | uint8_t reserved2[GPT_BLOCK_SIZE - 92]; 60 | } __attribute__ ((packed)) gpt_header; 61 | 62 | typedef struct _gpt_entry_attributes { 63 | uint64_t required_to_function:1; 64 | uint64_t reserved:47; 65 | uint64_t type_guid_specific:16; 66 | } __attribute__ ((packed)) gpt_entry_attributes; 67 | 68 | typedef struct _gpt_entry { 69 | efi_guid_t partition_type_guid; 70 | efi_guid_t unique_partition_guid; 71 | uint64_t starting_lba; 72 | uint64_t ending_lba; 73 | gpt_entry_attributes attributes; 74 | efi_char16_t partition_name[72 / sizeof(efi_char16_t)]; 75 | } __attribute__ ((packed)) gpt_entry; 76 | 77 | 78 | /* 79 | These values are only defaults. The actual on-disk structures 80 | may define different sizes, so use those unless creating a new GPT disk! 81 | */ 82 | 83 | #define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384 84 | /* 85 | Number of actual partition entries should be calculated 86 | as: 87 | */ 88 | #define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \ 89 | (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \ 90 | sizeof(gpt_entry)) 91 | 92 | 93 | /* Protected Master Boot Record & Legacy MBR share same structure */ 94 | /* Needs to be packed because the u16s force misalignment. */ 95 | 96 | typedef struct _legacy_mbr { 97 | uint8_t bootcode[440]; 98 | uint32_t unique_mbr_signature; 99 | uint16_t unknown; 100 | struct partition partition[4]; 101 | uint16_t signature; 102 | } __attribute__ ((packed)) legacy_mbr; 103 | 104 | 105 | #define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1 106 | 107 | /* Functions */ 108 | int read_gpt_pt (int fd, struct slice all, struct slice *sp, unsigned int ns); 109 | 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /kpartx/kpartx.8: -------------------------------------------------------------------------------- 1 | .\" ---------------------------------------------------------------------------- 2 | .\" Update the date below if you make any significant change. 3 | .\" Make sure there are no errors with: 4 | .\" groff -z -wall -b -e -t kpartx/kpartx.8 5 | .\" 6 | .\" ---------------------------------------------------------------------------- 7 | . 8 | .TH KPARTX 8 2016-10-28 "Linux" 9 | . 10 | . 11 | .\" ---------------------------------------------------------------------------- 12 | .SH NAME 13 | .\" ---------------------------------------------------------------------------- 14 | . 15 | kpartx \- Create device maps from partition tables. 16 | . 17 | . 18 | .\" ---------------------------------------------------------------------------- 19 | .SH SYNOPSIS 20 | .\" ---------------------------------------------------------------------------- 21 | . 22 | .B kpartx 23 | .RB [\| \-a | \-d | \-u | \-l \|] 24 | .RB [\| \-r \|] 25 | .RB [\| \-p \|] 26 | .RB [\| \-f \|] 27 | .RB [\| \-g \|] 28 | .RB [\| \-s | \-n \|] 29 | .RB [\| \-v \|] 30 | .B wholedisk 31 | . 32 | . 33 | .\" ---------------------------------------------------------------------------- 34 | .SH DESCRIPTION 35 | .\" ---------------------------------------------------------------------------- 36 | . 37 | This tool, derived from util-linux' partx, reads partition tables on specified 38 | device and create device maps over partitions segments detected. It is called 39 | from hotplug upon device maps creation and deletion. 40 | . 41 | . 42 | .\" ---------------------------------------------------------------------------- 43 | .SH OPTIONS 44 | .\" ---------------------------------------------------------------------------- 45 | . 46 | .TP 47 | .B \-a 48 | Add partition mappings. 49 | . 50 | .TP 51 | .B \-d 52 | Delete partition mappings. 53 | . 54 | .TP 55 | .B \-u 56 | Update partition mappings. 57 | . 58 | .TP 59 | .B \-l 60 | List partition mappings that would be added \-a. 61 | . 62 | .TP 63 | .B \-r 64 | Read-only partition mappings. 65 | . 66 | .TP 67 | .B \-p 68 | Set device name-partition number delimiter. 69 | . 70 | .TP 71 | .B \-f 72 | Force creation of mappings; overrides 'no_partitions' feature. 73 | . 74 | .TP 75 | .B \-g 76 | Force GUID partition table (GPT). 77 | . 78 | .TP 79 | .B \-s 80 | Sync mode (Default). Don't return until the partitions are created. 81 | . 82 | .TP 83 | .B \-n 84 | Nosync mode. Return before the partitions are created. 85 | . 86 | .TP 87 | .B \-v 88 | Operate verbosely. 89 | . 90 | . 91 | .\" ---------------------------------------------------------------------------- 92 | .SH EXAMPLE 93 | .\" ---------------------------------------------------------------------------- 94 | . 95 | To mount all the partitions in a raw disk image: 96 | .IP 97 | kpartx \-av disk.img 98 | .PP 99 | This will output lines such as: 100 | .IP 101 | add map loop1p1 (254:4): 0 409597 linear 7:1 3 102 | .PP 103 | The \fIloop1p1\fR is the name of a device file under \fI/dev/mapper\fR which you 104 | can use to access the partition, for example to fsck it: 105 | .IP 106 | fsck /dev/mapper/loop1p1 107 | .PP 108 | When you're done, you need to remove the devices: 109 | .IP 110 | kpartx \-d disk.img 111 | . 112 | . 113 | .\" ---------------------------------------------------------------------------- 114 | .SH "SEE ALSO" 115 | .\" ---------------------------------------------------------------------------- 116 | . 117 | .BR multipath (8) 118 | .BR multipathd (8) 119 | .BR hotplug (8) 120 | . 121 | . 122 | .\" ---------------------------------------------------------------------------- 123 | .SH AUTHORS 124 | .\" ---------------------------------------------------------------------------- 125 | . 126 | This man page was assembled By Patrick Caulfield for the Debian project. 127 | .PP 128 | \fImultipath-tools\fR was developed by Christophe Varoqui 129 | and others. 130 | .\" EOF 131 | -------------------------------------------------------------------------------- /kpartx/kpartx.h: -------------------------------------------------------------------------------- 1 | #ifndef _KPARTX_H 2 | #define _KPARTX_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * For each partition type there is a routine that takes 10 | * a block device and a range, and returns the list of 11 | * slices found there in the supplied array SP that can 12 | * hold NS entries. The return value is the number of 13 | * entries stored, or -1 if the appropriate type is not 14 | * present. 15 | */ 16 | 17 | #define likely(x) __builtin_expect(!!(x), 1) 18 | #define unlikely(x) __builtin_expect(!!(x), 0) 19 | 20 | #define safe_snprintf(var, size, format, args...) \ 21 | ({ \ 22 | size_t __size = size; \ 23 | int __ret; \ 24 | \ 25 | __ret = snprintf(var, __size, format, ##args); \ 26 | __ret < 0 || (size_t)__ret >= __size; \ 27 | }) 28 | 29 | #define safe_sprintf(var, format, args...) \ 30 | safe_snprintf(var, sizeof(var), format, ##args) 31 | 32 | #ifndef BLKSSZGET 33 | #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ 34 | #endif 35 | 36 | int 37 | get_sector_size(int filedes); 38 | 39 | /* 40 | * units: 512 byte sectors 41 | */ 42 | struct slice { 43 | uint64_t start; 44 | uint64_t size; 45 | int container; 46 | unsigned int major; 47 | unsigned int minor; 48 | }; 49 | 50 | typedef int (ptreader)(int fd, struct slice all, struct slice *sp, 51 | unsigned int ns); 52 | 53 | extern int force_gpt; 54 | 55 | extern ptreader read_dos_pt; 56 | extern ptreader read_bsd_pt; 57 | extern ptreader read_solaris_pt; 58 | extern ptreader read_unixware_pt; 59 | extern ptreader read_gpt_pt; 60 | extern ptreader read_dasd_pt; 61 | extern ptreader read_mac_pt; 62 | extern ptreader read_sun_pt; 63 | extern ptreader read_ps3_pt; 64 | 65 | int aligned_malloc(void **mem_p, size_t align, size_t *size_p); 66 | char *getblock(int fd, unsigned int secnr); 67 | 68 | static inline unsigned int 69 | four2int(unsigned char *p) { 70 | return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24); 71 | } 72 | 73 | #endif /* _KPARTX_H */ 74 | -------------------------------------------------------------------------------- /kpartx/kpartx.rules: -------------------------------------------------------------------------------- 1 | # 2 | # persistent links for device-mapper devices 3 | # only hardware-backed device-mapper devices (ie multipath, dmraid, 4 | # and kpartx) have meaningful persistent device names 5 | # 6 | 7 | KERNEL!="dm-*", GOTO="kpartx_end" 8 | ACTION!="add|change", GOTO="kpartx_end" 9 | ENV{DM_UUID}!="?*", GOTO="kpartx_end" 10 | ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="kpartx_end" 11 | 12 | # Create dm tables for partitions on multipath devices. 13 | ENV{DM_UUID}!="mpath-?*", GOTO="mpath_kpartx_end" 14 | 15 | # DM_SUBSYSTEM_UDEV_FLAG1 is the "skip_kpartx" flag. 16 | # For events not generated by libdevmapper, we need to fetch it from db: 17 | # - "change" events with DM_ACTIVATION!="1" (e.g. partition table changes) 18 | # - "add" events for which rules are not disabled ("coldplug" case) 19 | ENV{DM_ACTIVATION}!="1", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1" 20 | ACTION=="add", IMPORT{db}="DM_SUBSYSTEM_UDEV_FLAG1" 21 | ENV{DM_SUBSYSTEM_UDEV_FLAG1}=="1", GOTO="mpath_kpartx_end" 22 | 23 | # 11-dm-mpath.rules sets MPATH_UNCHANGED for events that can be ignored. 24 | ENV{MPATH_UNCHANGED}=="1", GOTO="mpath_kpartx_end" 25 | 26 | # Don't run kpartx now if we know it will fail or hang. 27 | ENV{DM_SUSPENDED}=="1", GOTO="mpath_kpartx_end" 28 | ENV{DM_NOSCAN}=="1", GOTO="mpath_kpartx_end" 29 | 30 | # Run kpartx 31 | GOTO="run_kpartx" 32 | LABEL="mpath_kpartx_end" 33 | 34 | ## Code for other subsystems (non-multipath) could be placed here ## 35 | 36 | GOTO="kpartx_end" 37 | 38 | LABEL="run_kpartx" 39 | RUN+="/sbin/kpartx -un -p -part /dev/$name" 40 | 41 | LABEL="kpartx_end" 42 | -------------------------------------------------------------------------------- /kpartx/kpartx_id: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # kpartx_id 4 | # 5 | # Generates ID information for device-mapper tables. 6 | # 7 | # Copyright (C) 2006 SUSE Linux Products GmbH 8 | # Author: 9 | # Hannes Reinecke 10 | # 11 | # 12 | # This program is free software; you can redistribute it and/or modify it 13 | # under the terms of the GNU General Public License as published by the 14 | # Free Software Foundation version 2 of the License. 15 | # 16 | # This script generates ID information used to generate persistent symlinks. 17 | # It relies on the UUID strings generated by the various programs; the name 18 | # of the tables are of no consequence. 19 | # 20 | # Please note that dmraid does not provide the UUIDs (yet); a patch has been 21 | # sent upstream but has not been accepted yet. 22 | # 23 | 24 | DMSETUP=/sbin/dmsetup 25 | 26 | MAJOR=$1 27 | MINOR=$2 28 | UUID=$3 29 | 30 | if [ -z "$MAJOR" -o -z "$MINOR" ]; then 31 | echo "usage: $0 major minor" 32 | exit 1; 33 | fi 34 | 35 | # Device-mapper not installed; not an error 36 | if [ ! -x $DMSETUP ] ; then 37 | exit 0 38 | fi 39 | 40 | 41 | # Table UUIDs are always '-'. 42 | dmuuid=${UUID#*-} 43 | dmtbl=${UUID%%-*} 44 | dmpart=${dmtbl#part} 45 | dmserial= 46 | # kpartx types are 'part' 47 | if [ "$dmpart" = "$dmtbl" ] ; then 48 | dmpart= 49 | else 50 | dmtbl=part 51 | fi 52 | 53 | # Set the name of the table. We're only interested in dmraid, 54 | # multipath, and kpartx tables; everything else is ignored. 55 | if [ "$dmtbl" = "part" ] ; then 56 | dmname=$($DMSETUP info -c --noheadings -o name -u $dmuuid) 57 | echo "DM_MPATH=$dmname" 58 | # We need the dependencies of the parent table to figure out 59 | # the type if the parent is a multipath table 60 | case "$dmuuid" in 61 | mpath-*) 62 | dmdeps=$($DMSETUP deps -u $dmuuid) 63 | dmserial=${dmuuid#mpath-} 64 | ;; 65 | esac 66 | elif [ "$dmtbl" = "mpath" ] ; then 67 | dmname="$dmuuid" 68 | dmserial="$dmuuid" 69 | # We need the dependencies of the table to figure out the type 70 | dmdeps=$($DMSETUP deps -u $UUID) 71 | fi 72 | 73 | [ -n "$dmpart" ] && echo "DM_PART=$dmpart" 74 | 75 | # Figure out the type of the map. For non-multipath maps it's 76 | # always 'raid'. 77 | if [ -n "$dmdeps" ] ; then 78 | case "$dmdeps" in 79 | *\(94,*) 80 | echo "DM_TYPE=ccw" 81 | ;; 82 | *\(104,* | *\(105,* | *\(106,* | *\(107,* | *\(108,* | *\(109,* | *\(110,* | *\(112,*) 83 | echo "DM_TYPE=cciss" 84 | ;; 85 | *\(9*) 86 | echo "DM_TYPE=raid" 87 | ;; 88 | *) 89 | echo "DM_TYPE=scsi" 90 | echo "DM_WWN=0x${dmserial#?}" 91 | ;; 92 | esac 93 | else 94 | echo "DM_TYPE=raid" 95 | fi 96 | if [[ $dmserial ]]; then 97 | echo "DM_SERIAL=$dmserial" 98 | fi 99 | 100 | exit 0 101 | -------------------------------------------------------------------------------- /kpartx/lopart.h: -------------------------------------------------------------------------------- 1 | extern int verbose; 2 | extern int set_loop (const char *, const char *, int, int *); 3 | extern int del_loop (const char *); 4 | extern char * find_unused_loop_device (void); 5 | extern char * find_loop_by_file (const char *); 6 | -------------------------------------------------------------------------------- /kpartx/mac.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include "byteorder.h" 3 | #include 4 | #include 5 | #include "mac.h" 6 | 7 | int 8 | read_mac_pt(int fd, __attribute__((unused)) struct slice all, 9 | struct slice *sp, unsigned int ns) { 10 | struct mac_driver_desc *md; 11 | struct mac_partition *part; 12 | unsigned secsize; 13 | char *data; 14 | unsigned int blk, blocks_in_map; 15 | int n = 0; 16 | 17 | md = (struct mac_driver_desc *) getblock(fd, 0); 18 | if (md == NULL) 19 | return -1; 20 | 21 | if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) 22 | return -1; 23 | 24 | secsize = be16_to_cpu(md->block_size); 25 | data = getblock(fd, secsize/512); 26 | if (!data) 27 | return -1; 28 | part = (struct mac_partition *) (data + secsize%512); 29 | 30 | if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) 31 | return -1; 32 | 33 | blocks_in_map = be32_to_cpu(part->map_count); 34 | for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) { 35 | int pos = blk * secsize; 36 | data = getblock(fd, pos/512); 37 | if (!data) 38 | return -1; 39 | 40 | part = (struct mac_partition *) (data + pos%512); 41 | if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) 42 | break; 43 | 44 | sp[n].start = be32_to_cpu(part->start_block) * (secsize/512); 45 | sp[n].size = be32_to_cpu(part->block_count) * (secsize/512); 46 | } 47 | return n; 48 | } 49 | -------------------------------------------------------------------------------- /kpartx/mac.h: -------------------------------------------------------------------------------- 1 | #ifndef MAC_H 2 | #define MAC_H 3 | 4 | #include 5 | 6 | #define MAC_PARTITION_MAGIC 0x504d 7 | 8 | /* type field value for A/UX or other Unix partitions */ 9 | #define APPLE_AUX_TYPE "Apple_UNIX_SVR2" 10 | 11 | struct mac_partition { 12 | uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ 13 | uint16_t res1; 14 | uint32_t map_count; /* # blocks in partition map */ 15 | uint32_t start_block; /* absolute starting block # of partition */ 16 | uint32_t block_count; /* number of blocks in partition */ 17 | /* there is more stuff after this that we don't need */ 18 | }; 19 | 20 | #define MAC_DRIVER_MAGIC 0x4552 21 | 22 | /* Driver descriptor structure, in block 0 */ 23 | struct mac_driver_desc { 24 | uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */ 25 | uint16_t block_size; 26 | uint32_t block_count; 27 | /* ... more stuff */ 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /kpartx/ps3.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include "byteorder.h" 3 | #include 4 | #include 5 | 6 | #define SECTOR_SIZE 512 7 | #define MAX_ACL_ENTRIES 8 8 | #define MAX_PARTITIONS 8 9 | 10 | #define MAGIC1 0x0FACE0FFULL 11 | #define MAGIC2 0xDEADFACEULL 12 | 13 | struct p_acl_entry { 14 | u_int64_t laid; 15 | u_int64_t rights; 16 | }; 17 | 18 | struct d_partition { 19 | u_int64_t p_start; 20 | u_int64_t p_size; 21 | struct p_acl_entry p_acl[MAX_ACL_ENTRIES]; 22 | }; 23 | 24 | struct disklabel { 25 | u_int8_t d_res1[16]; 26 | u_int64_t d_magic1; 27 | u_int64_t d_magic2; 28 | u_int64_t d_res2; 29 | u_int64_t d_res3; 30 | struct d_partition d_partitions[MAX_PARTITIONS]; 31 | u_int8_t d_pad[0x600 - MAX_PARTITIONS * sizeof(struct d_partition) - 0x30]; 32 | }; 33 | 34 | static int 35 | read_disklabel(int fd, struct disklabel *label) { 36 | unsigned char *data; 37 | unsigned int i; 38 | 39 | for (i = 0; i < sizeof(struct disklabel) / SECTOR_SIZE; i++) { 40 | data = (unsigned char *) getblock(fd, i); 41 | if (!data) 42 | return 0; 43 | 44 | memcpy((unsigned char *) label + i * SECTOR_SIZE, data, SECTOR_SIZE); 45 | } 46 | 47 | return 1; 48 | } 49 | 50 | int 51 | read_ps3_pt(int fd, __attribute__((unused)) struct slice all, 52 | struct slice *sp, __attribute__((unused)) unsigned int ns) { 53 | struct disklabel label; 54 | int n = 0; 55 | int i; 56 | 57 | if (!read_disklabel(fd, &label)) 58 | return -1; 59 | 60 | if ((be64_to_cpu(label.d_magic1) != MAGIC1) || 61 | (be64_to_cpu(label.d_magic2) != MAGIC2)) 62 | return -1; 63 | 64 | for (i = 0; i < MAX_PARTITIONS; i++) { 65 | if (label.d_partitions[i].p_start && label.d_partitions[i].p_size) { 66 | sp[n].start = be64_to_cpu(label.d_partitions[i].p_start); 67 | sp[n].size = be64_to_cpu(label.d_partitions[i].p_size); 68 | n++; 69 | } 70 | } 71 | 72 | return n; 73 | } 74 | -------------------------------------------------------------------------------- /kpartx/solaris.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include 3 | #include 4 | #include /* time_t */ 5 | 6 | #define SOLARIS_X86_NUMSLICE 8 7 | #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) 8 | 9 | struct solaris_x86_slice { 10 | unsigned short s_tag; /* ID tag of partition */ 11 | unsigned short s_flag; /* permission flags */ 12 | __kernel_daddr_t s_start; /* start sector no of partition */ 13 | long s_size; /* # of blocks in partition */ 14 | }; 15 | 16 | struct solaris_x86_vtoc { 17 | unsigned long v_bootinfo[3]; /* info for mboot */ 18 | unsigned long v_sanity; /* to verify vtoc sanity */ 19 | unsigned long v_version; /* layout version */ 20 | char v_volume[8]; /* volume name */ 21 | unsigned short v_sectorsz; /* sector size in bytes */ 22 | unsigned short v_nparts; /* number of partitions */ 23 | unsigned long v_reserved[10]; /* free space */ 24 | struct solaris_x86_slice 25 | v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ 26 | time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */ 27 | char v_asciilabel[128]; /* for compatibility */ 28 | }; 29 | 30 | int 31 | read_solaris_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 32 | struct solaris_x86_vtoc *v; 33 | struct solaris_x86_slice *s; 34 | unsigned int offset = all.start; 35 | unsigned int i, n; 36 | char *bp; 37 | 38 | bp = getblock(fd, offset+1); /* 1 sector suffices */ 39 | if (bp == NULL) 40 | return -1; 41 | 42 | v = (struct solaris_x86_vtoc *) bp; 43 | if(v->v_sanity != SOLARIS_X86_VTOC_SANE) 44 | return -1; 45 | 46 | if(v->v_version != 1) { 47 | fprintf(stderr, "Cannot handle solaris version %ld vtoc\n", 48 | v->v_version); 49 | return 0; 50 | } 51 | 52 | for(i=0, n=0; iv_slice[i]; 54 | 55 | if (s->s_size == 0) 56 | continue; 57 | if (n < ns) { 58 | sp[n].start = offset + s->s_start; 59 | sp[n].size = s->s_size; 60 | n++; 61 | } else { 62 | fprintf(stderr, 63 | "solaris_x86_partition: too many slices\n"); 64 | break; 65 | } 66 | } 67 | return n; 68 | } 69 | -------------------------------------------------------------------------------- /kpartx/sun.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lifted from util-linux' partx sun.c 3 | * 4 | * Copyrights of the original file apply 5 | * Copyright (c) 2007 Hannes Reinecke 6 | */ 7 | #include "kpartx.h" 8 | #include "byteorder.h" 9 | #include 10 | #include 11 | #include /* time_t */ 12 | 13 | #define SUN_DISK_MAGIC 0xDABE /* Disk magic number */ 14 | #define SUN_DISK_MAXPARTITIONS 8 15 | 16 | struct __attribute__ ((packed)) sun_raw_part { 17 | u_int32_t start_cylinder; /* where the part starts... */ 18 | u_int32_t num_sectors; /* ...and it's length */ 19 | }; 20 | 21 | struct __attribute__ ((packed)) sun_part_info { 22 | u_int8_t spare1; 23 | u_int8_t id; /* Partition type */ 24 | u_int8_t spare2; 25 | u_int8_t flags; /* Partition flags */ 26 | }; 27 | 28 | struct __attribute__ ((packed)) sun_disk_label { 29 | char info[128]; /* Informative text string */ 30 | u_int8_t spare0[14]; 31 | struct sun_part_info infos[SUN_DISK_MAXPARTITIONS]; 32 | u_int8_t spare1[246]; /* Boot information etc. */ 33 | u_int16_t rspeed; /* Disk rotational speed */ 34 | u_int16_t pcylcount; /* Physical cylinder count */ 35 | u_int16_t sparecyl; /* extra sects per cylinder */ 36 | u_int8_t spare2[4]; /* More magic... */ 37 | u_int16_t ilfact; /* Interleave factor */ 38 | u_int16_t ncyl; /* Data cylinder count */ 39 | u_int16_t nacyl; /* Alt. cylinder count */ 40 | u_int16_t ntrks; /* Tracks per cylinder */ 41 | u_int16_t nsect; /* Sectors per track */ 42 | u_int8_t spare3[4]; /* Even more magic... */ 43 | struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS]; 44 | u_int16_t magic; /* Magic number */ 45 | u_int16_t csum; /* Label xor'd checksum */ 46 | }; 47 | 48 | /* Checksum Verification */ 49 | static int 50 | sun_verify_checksum (struct sun_disk_label *label) 51 | { 52 | u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1; 53 | u_int16_t csum = 0; 54 | 55 | while (ush >= (u_int16_t *)label) 56 | csum ^= *ush--; 57 | 58 | return !csum; 59 | } 60 | 61 | int 62 | read_sun_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 63 | struct sun_disk_label *l; 64 | struct sun_raw_part *s; 65 | unsigned int offset = all.start, end; 66 | unsigned int i, j, n; 67 | char *bp; 68 | 69 | bp = getblock(fd, offset); 70 | if (bp == NULL) 71 | return -1; 72 | 73 | l = (struct sun_disk_label *) bp; 74 | if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC) 75 | return -1; 76 | 77 | if (!sun_verify_checksum(l)) { 78 | fprintf(stderr, "Corrupted Sun disk label\n"); 79 | return -1; 80 | } 81 | 82 | for(i=0, n=0; ipartitions[i]; 84 | 85 | if (n < ns) { 86 | sp[n].start = offset + 87 | be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks); 88 | sp[n].size = be32_to_cpu(s->num_sectors); 89 | n++; 90 | } else { 91 | fprintf(stderr, 92 | "sun_disklabel: too many slices\n"); 93 | break; 94 | } 95 | } 96 | /* 97 | * Convention has it that the SUN disklabel will always have 98 | * the 'c' partition spanning the entire disk. 99 | * So we have to check for contained slices. 100 | */ 101 | for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { 102 | if (sp[i].size == 0) 103 | continue; 104 | 105 | end = sp[i].start + sp[i].size; 106 | for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) { 107 | if ( i == j ) 108 | continue; 109 | if (sp[j].size == 0) 110 | continue; 111 | 112 | if (sp[i].start < sp[j].start) { 113 | if (end > sp[j].start && 114 | end < sp[j].start + sp[j].size) { 115 | /* Invalid slice */ 116 | fprintf(stderr, 117 | "sun_disklabel: slice %d overlaps with %d\n", i , j); 118 | sp[i].size = 0; 119 | } 120 | } else { 121 | if (end <= sp[j].start + sp[j].size) { 122 | sp[i].container = j + 1; 123 | } 124 | } 125 | } 126 | } 127 | return n; 128 | } 129 | -------------------------------------------------------------------------------- /kpartx/unixware.c: -------------------------------------------------------------------------------- 1 | #include "kpartx.h" 2 | #include 3 | 4 | #define UNIXWARE_FS_UNUSED 0 5 | #define UNIXWARE_NUMSLICE 16 6 | #define UNIXWARE_DISKMAGIC (0xCA5E600D) 7 | #define UNIXWARE_DISKMAGIC2 (0x600DDEEE) 8 | 9 | struct unixware_slice { 10 | unsigned short s_label; /* label */ 11 | unsigned short s_flags; /* permission flags */ 12 | unsigned int start_sect; /* starting sector */ 13 | unsigned int nr_sects; /* number of sectors in slice */ 14 | }; 15 | 16 | struct unixware_disklabel { 17 | unsigned int d_type; /* drive type */ 18 | unsigned char d_magic[4]; /* the magic number */ 19 | unsigned int d_version; /* version number */ 20 | char d_serial[12]; /* serial number of the device */ 21 | unsigned int d_ncylinders; /* # of data cylinders per device */ 22 | unsigned int d_ntracks; /* # of tracks per cylinder */ 23 | unsigned int d_nsectors; /* # of data sectors per track */ 24 | unsigned int d_secsize; /* # of bytes per sector */ 25 | unsigned int d_part_start; /* # of first sector of this partition */ 26 | unsigned int d_unknown1[12]; /* ? */ 27 | unsigned int d_alt_tbl; /* byte offset of alternate table */ 28 | unsigned int d_alt_len; /* byte length of alternate table */ 29 | unsigned int d_phys_cyl; /* # of physical cylinders per device */ 30 | unsigned int d_phys_trk; /* # of physical tracks per cylinder */ 31 | unsigned int d_phys_sec; /* # of physical sectors per track */ 32 | unsigned int d_phys_bytes; /* # of physical bytes per sector */ 33 | unsigned int d_unknown2; /* ? */ 34 | unsigned int d_unknown3; /* ? */ 35 | unsigned int d_pad[8]; /* pad */ 36 | 37 | struct unixware_vtoc { 38 | unsigned char v_magic[4]; /* the magic number */ 39 | unsigned int v_version; /* version number */ 40 | char v_name[8]; /* volume name */ 41 | unsigned short v_nslices; /* # of slices */ 42 | unsigned short v_unknown1; /* ? */ 43 | unsigned int v_reserved[10]; /* reserved */ 44 | struct unixware_slice 45 | v_slice[UNIXWARE_NUMSLICE]; /* slice headers */ 46 | } vtoc; 47 | 48 | }; /* 408 */ 49 | 50 | int 51 | read_unixware_pt(int fd, struct slice all, struct slice *sp, unsigned int ns) { 52 | struct unixware_disklabel *l; 53 | struct unixware_slice *p; 54 | unsigned int offset = all.start; 55 | char *bp; 56 | unsigned int n = 0; 57 | 58 | bp = getblock(fd, offset+29); /* 1 sector suffices */ 59 | if (bp == NULL) 60 | return -1; 61 | 62 | l = (struct unixware_disklabel *) bp; 63 | if (four2int(l->d_magic) != UNIXWARE_DISKMAGIC || 64 | four2int(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) 65 | return -1; 66 | 67 | p = &l->vtoc.v_slice[1]; /* slice 0 is the whole disk. */ 68 | while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { 69 | if (p->s_label == UNIXWARE_FS_UNUSED) 70 | /* nothing */; 71 | else if (n < ns) { 72 | sp[n].start = p->start_sect; 73 | sp[n].size = p->nr_sects; 74 | n++; 75 | } else { 76 | fprintf(stderr, 77 | "unixware_partition: too many slices\n"); 78 | break; 79 | } 80 | p++; 81 | } 82 | return n; 83 | } 84 | -------------------------------------------------------------------------------- /kpartx/xstrncpy.c: -------------------------------------------------------------------------------- 1 | /* NUL-terminated version of strncpy() */ 2 | #include 3 | #include "xstrncpy.h" 4 | 5 | /* caller guarantees n > 0 */ 6 | void 7 | xstrncpy(char *dest, const char *src, size_t n) { 8 | strncpy(dest, src, n-1); 9 | dest[n-1] = 0; 10 | } 11 | -------------------------------------------------------------------------------- /kpartx/xstrncpy.h: -------------------------------------------------------------------------------- 1 | extern void xstrncpy(char *dest, const char *src, size_t n); 2 | -------------------------------------------------------------------------------- /libdmmp/DEV_NOTES: -------------------------------------------------------------------------------- 1 | == Planned features == 2 | * Expose all properties used by /usr/bin/multipath 3 | 4 | == Code style == 5 | * Keep things as simple as possible. 6 | * Linux Kernel code style. 7 | * Don't use typedef. 8 | * Don't use enum. 9 | * We are not smarter than API user, so don't create wrapping function like: 10 | 11 | ``` 12 | dmmp_mpath_search_by_id(struct dmmp_context *ctx, 13 | struct dmmp_mpath **dmmp_mp, 14 | uint32_t dmmp_mp_count, const char *id) 15 | 16 | dmmp_path_group_id_search(struct dmmp_mpath *dmmp_mp, 17 | const char *blk_name) 18 | ``` 19 | * The performance is the same for query single mpath and query all mpaths, 20 | so no `dmmp_mpath_of_wwid(struct dmmp_context *ctx, const char *wwid)` yet. 21 | 22 | == Naming scheme == 23 | * Public constants should be named as `DMMP_XXX_YYY`. 24 | * Public functions should be named as `dmmp__`. 25 | * Private constants should be named as `_DMMP_XXX_YYY`. 26 | * Private functions should be named as `_dmmp__`. 27 | 28 | == Code Layout == 29 | * libdmmp_private.h 30 | Internal functions or macros. 31 | * libdmmp.c 32 | Handling multipathd IPC and generate dmmp_context and 33 | dmmp_mpath_array_get(). 34 | * libdmmp_mp.c 35 | For `struct dmmp_mpath` 36 | * libdmmp_pg.c 37 | For `struct dmmp_path_group` 38 | * libdmmp_path.c 39 | For `struct dmmp_path` 40 | * libdmmp_misc.c 41 | Misc functions. 42 | -------------------------------------------------------------------------------- /libdmmp/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # 3 | # Copyright (C) 2015 - 2016 Red Hat, Inc. 4 | # Gris Ge 5 | # 6 | include ../Makefile.inc 7 | 8 | LIBDMMP_VERSION=0.2.0 9 | SONAME=$(LIBDMMP_VERSION) 10 | DEVLIB = libdmmp.so 11 | LIBS = $(DEVLIB).$(SONAME) 12 | PKGFILE = libdmmp.pc 13 | EXTRA_MAN_FILES = libdmmp.h.3 14 | HEADERS = libdmmp/libdmmp.h 15 | 16 | OBJS = libdmmp.o libdmmp_mp.o libdmmp_pg.o libdmmp_path.o libdmmp_misc.o 17 | 18 | CFLAGS += $(LIB_CFLAGS) -fvisibility=hidden -I$(libdmmpdir) -I$(mpathcmddir) \ 19 | $(shell pkg-config --cflags json-c) 20 | 21 | LIBDEPS += $(shell pkg-config --libs json-c) -L$(mpathcmddir) -lmpathcmd -lpthread 22 | 23 | all: $(LIBS) doc 24 | 25 | $(LIBS): $(OBJS) 26 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) 27 | $(LN) $@ $(DEVLIB) 28 | 29 | install: 30 | mkdir -p $(DESTDIR)$(usrlibdir) 31 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(usrlibdir)/$(LIBS) 32 | $(INSTALL_PROGRAM) -m 644 -D \ 33 | $(HEADERS) $(DESTDIR)$(includedir)/$(HEADERS) 34 | $(LN) $(LIBS) $(DESTDIR)$(usrlibdir)/$(DEVLIB) 35 | $(INSTALL_PROGRAM) -m 644 -D \ 36 | $(PKGFILE).in $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 37 | perl -i -pe 's|__VERSION__|$(LIBDMMP_VERSION)|g' \ 38 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 39 | perl -i -pe 's|__LIBDIR__|$(usrlibdir)|g' \ 40 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 41 | perl -i -pe 's|__INCLUDEDIR__|$(includedir)|g' \ 42 | $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 43 | @for file in docs/man/*.3.gz; do \ 44 | $(INSTALL_PROGRAM) -m 644 -D \ 45 | $$file \ 46 | $(DESTDIR)$(man3dir)/ || exit $?; \ 47 | done 48 | 49 | uninstall: 50 | $(RM) $(DESTDIR)$(usrlibdir)/$(LIBS) 51 | $(RM) $(DESTDIR)$(includedir)/$(HEADERS) 52 | $(RM) $(DESTDIR)$(usrlibdir)/$(DEVLIB) 53 | @for file in $(DESTDIR)$(man3dir)/dmmp_*; do \ 54 | $(RM) $$file; \ 55 | done 56 | $(RM) $(DESTDIR)$(man3dir)/libdmmp.h* 57 | $(RM) $(DESTDIR)$(pkgconfdir)/$(PKGFILE) 58 | 59 | clean: dep_clean 60 | $(RM) core *.a *.o *.gz *.so *.so.* 61 | $(RM) -r docs/man 62 | $(MAKE) -C test clean 63 | 64 | include $(wildcard $(OBJS:.o=.d)) 65 | 66 | check: all 67 | $(MAKE) -C test check 68 | 69 | speed_test: all 70 | $(MAKE) -C test speed_test 71 | 72 | doc: docs/man/$(EXTRA_MAN_FILES).gz 73 | 74 | TEMPFILE := $(shell mktemp) 75 | 76 | docs/man/$(EXTRA_MAN_FILES).gz: $(HEADERS) 77 | @for file in $(EXTRA_MAN_FILES); do \ 78 | $(INSTALL_PROGRAM) -v -m 644 -D docs/$$file docs/man/$$file; \ 79 | done 80 | cat $(HEADERS) | \ 81 | perl docs/doc-preclean.pl > "$(TEMPFILE)" 82 | perl docs/kernel-doc -man "$(TEMPFILE)" | \ 83 | perl docs/split-man.pl docs/man 84 | -rm -f "$(TEMPFILE)" 85 | @for file in docs/man/*.3; do \ 86 | gzip -f $$file; \ 87 | done 88 | find docs/man -type f -name \*[0-9].gz 89 | 90 | dep_clean: 91 | $(RM) $(OBJS:.o=.d) 92 | -------------------------------------------------------------------------------- /libdmmp/docs/doc-preclean.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Copyright (C) 2016 Red Hat, Inc. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | # Author: Gris Ge 18 | 19 | use strict; 20 | 21 | my @REMOVE_KEY_LIST=("DMMP_DLL_EXPORT"); 22 | 23 | while (<>) { 24 | for my $key (@REMOVE_KEY_LIST) { 25 | (s/$key//g); 26 | } 27 | print; 28 | } 29 | -------------------------------------------------------------------------------- /libdmmp/docs/split-man.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Originally From: 3 | # https://www.kernel.org/doc/Documentation/kernel-doc-nano-HOWTO.txt 4 | # 5 | # Changes: 6 | # * Create manpage section 3 instead of 9. 7 | # * Replace 'Kernel Hackers Manual' to 8 | # 'Device Mapper Multipath API - libdmmp Manual' 9 | # * Remove LINUX from header. 10 | # * Remove DMMP_DLL_EXPORT. 11 | $man_sec_num = 3; 12 | $title = 'Device Mapper Multipath API - libdmmp Manual'; 13 | 14 | if ( $#ARGV < 0 ) { 15 | die "where do I put the results?\n"; 16 | } 17 | 18 | mkdir $ARGV[0], 0777; 19 | $state = 0; 20 | while () { 21 | if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { 22 | if ( $state == 1 ) { close OUT } 23 | $state = 1; 24 | $fn = "$ARGV[0]/$1.$man_sec_num"; 25 | print STDERR "Creating $fn\n"; 26 | open OUT, ">$fn" or die "can't open $fn: $!\n"; 27 | 28 | # Change man page code from 9 to $man_sec_num; 29 | s/^\.TH (\"[^\"]*\") 9 \"([^\"]*)\"/\.TH $1 $man_sec_num \"$2\"/; 30 | s/Kernel Hacker's Manual/$title/g; 31 | s/LINUX//g; 32 | 33 | print OUT $_; 34 | } 35 | elsif ( $state != 0 ) { 36 | print OUT $_; 37 | } 38 | } 39 | 40 | close OUT; 41 | -------------------------------------------------------------------------------- /libdmmp/libdmmp.pc.in: -------------------------------------------------------------------------------- 1 | includedir=__INCLUDEDIR__ 2 | libdir=__LIBDIR__ 3 | 4 | Name: libdmmp 5 | Version: __VERSION__ 6 | Description: Device mapper multipath management library 7 | Requires: 8 | Libs: -L${libdir} -ldmmp 9 | Cflags: -I${includedir} 10 | -------------------------------------------------------------------------------- /libdmmp/libdmmp_misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 - 2017 Red Hat, Inc. 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Author: Gris Ge 18 | * Todd Gill 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "libdmmp/libdmmp.h" 31 | #include "libdmmp_private.h" 32 | 33 | #define _DMMP_LOG_STRERR_ALIGN_WIDTH 80 34 | /* ^ Only used in _dmmp_log_stderr() for pretty log output. 35 | * When provided log message is less than 80 bytes, fill it with space, then 36 | * print code file name, function name, line after the 80th bytes. 37 | */ 38 | 39 | static const struct _num_str_conv _DMMP_RC_MSG_CONV[] = { 40 | {DMMP_OK, "OK"}, 41 | {DMMP_ERR_NO_MEMORY, "Out of memory"}, 42 | {DMMP_ERR_BUG, "BUG of libdmmp library"}, 43 | {DMMP_ERR_IPC_TIMEOUT, "Timeout when communicate with multipathd, " 44 | "try to increase it via " 45 | "dmmp_context_timeout_set()"}, 46 | {DMMP_ERR_IPC_ERROR, "Error when communicate with multipathd daemon"}, 47 | {DMMP_ERR_NO_DAEMON, "The multipathd daemon not started"}, 48 | {DMMP_ERR_INCOMPATIBLE, "Incompatible multipathd daemon version"}, 49 | {DMMP_ERR_MPATH_BUSY, "Specified multipath device map is in use"}, 50 | {DMMP_ERR_MPATH_NOT_FOUND, "Specified multipath not found"}, 51 | {DMMP_ERR_INVALID_ARGUMENT, "Invalid argument"}, 52 | {DMMP_ERR_PERMISSION_DENY, "Permission deny"}, 53 | }; 54 | 55 | _dmmp_str_func_gen(dmmp_strerror, int, rc, _DMMP_RC_MSG_CONV); 56 | 57 | static const struct _num_str_conv _DMMP_PRI_CONV[] = { 58 | {DMMP_LOG_PRIORITY_DEBUG, "DEBUG"}, 59 | {DMMP_LOG_PRIORITY_INFO, "INFO"}, 60 | {DMMP_LOG_PRIORITY_WARNING, "WARNING"}, 61 | {DMMP_LOG_PRIORITY_ERROR, "ERROR"}, 62 | }; 63 | _dmmp_str_func_gen(dmmp_log_priority_str, int, priority, _DMMP_PRI_CONV); 64 | 65 | void _dmmp_log_stderr(struct dmmp_context *ctx, int priority, 66 | const char *file, int line, const char *func_name, 67 | const char *format, va_list args) 68 | { 69 | int printed_bytes = 0; 70 | void *userdata = NULL; 71 | 72 | printed_bytes += fprintf(stderr, "libdmmp %s: ", 73 | dmmp_log_priority_str(priority)); 74 | printed_bytes += vfprintf(stderr, format, args); 75 | 76 | userdata = dmmp_context_userdata_get(ctx); 77 | if (userdata != NULL) 78 | fprintf(stderr, "(userdata address: %p)", 79 | userdata); 80 | /* ^ Just demonstrate how userdata could be used and 81 | * bypass clang static analyzer about unused ctx argument warning 82 | */ 83 | 84 | if (printed_bytes < _DMMP_LOG_STRERR_ALIGN_WIDTH) { 85 | fprintf(stderr, "%*s # %s:%s():%d\n", 86 | _DMMP_LOG_STRERR_ALIGN_WIDTH - printed_bytes, "", file, 87 | func_name, line); 88 | } else { 89 | fprintf(stderr, " # %s:%s():%d\n", file, func_name, line); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /libdmmp/libdmmp_path.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 - 2016 Red Hat, Inc. 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Author: Gris Ge 18 | * Todd Gill 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "libdmmp/libdmmp.h" 28 | #include "libdmmp_private.h" 29 | 30 | #define _DMMP_SHOW_PS_INDEX_BLK_NAME 0 31 | #define _DMMP_SHOW_PS_INDEX_SATAUS 1 32 | #define _DMMP_SHOW_PS_INDEX_WWID 2 33 | #define _DMMP_SHOW_PS_INDEX_PGID 3 34 | 35 | struct dmmp_path { 36 | char *blk_name; 37 | uint32_t status; 38 | }; 39 | 40 | static const struct _num_str_conv _DMMP_PATH_STATUS_CONV[] = { 41 | {DMMP_PATH_STATUS_UNKNOWN, "undef"}, 42 | {DMMP_PATH_STATUS_UP, "ready"}, 43 | {DMMP_PATH_STATUS_DOWN, "faulty"}, 44 | {DMMP_PATH_STATUS_SHAKY, "shaky"}, 45 | {DMMP_PATH_STATUS_GHOST, "ghost"}, 46 | {DMMP_PATH_STATUS_PENDING, "i/o pending"}, 47 | {DMMP_PATH_STATUS_TIMEOUT, "i/o timeout"}, 48 | {DMMP_PATH_STATUS_DELAYED, "delayed"}, 49 | }; 50 | 51 | _dmmp_str_func_gen(dmmp_path_status_str, uint32_t, path_status, 52 | _DMMP_PATH_STATUS_CONV); 53 | _dmmp_str_conv_func_gen(_dmmp_path_status_str_conv, ctx, path_status_str, 54 | uint32_t, DMMP_PATH_STATUS_UNKNOWN, 55 | _DMMP_PATH_STATUS_CONV); 56 | 57 | _dmmp_getter_func_gen(dmmp_path_blk_name_get, struct dmmp_path, dmmp_p, 58 | blk_name, const char *); 59 | _dmmp_getter_func_gen(dmmp_path_status_get, struct dmmp_path, dmmp_p, 60 | status, uint32_t); 61 | 62 | struct dmmp_path *_dmmp_path_new(void) 63 | { 64 | struct dmmp_path *dmmp_p = NULL; 65 | 66 | dmmp_p = (struct dmmp_path *) malloc(sizeof(struct dmmp_path)); 67 | 68 | if (dmmp_p != NULL) { 69 | dmmp_p->blk_name = NULL; 70 | dmmp_p->status = DMMP_PATH_STATUS_UNKNOWN; 71 | } 72 | return dmmp_p; 73 | } 74 | 75 | int _dmmp_path_update(struct dmmp_context *ctx, struct dmmp_path *dmmp_p, 76 | json_object *j_obj_p) 77 | { 78 | int rc = DMMP_OK; 79 | const char *blk_name = NULL; 80 | const char *status_str = NULL; 81 | 82 | assert(ctx != NULL); 83 | assert(dmmp_p != NULL); 84 | assert(j_obj_p != NULL); 85 | 86 | _json_obj_get_value(ctx, j_obj_p, blk_name, "dev", 87 | json_type_string, json_object_get_string, rc, out); 88 | _json_obj_get_value(ctx, j_obj_p, status_str, "chk_st", 89 | json_type_string, json_object_get_string, rc, out); 90 | 91 | _dmmp_null_or_empty_str_check(ctx, blk_name, rc, out); 92 | _dmmp_null_or_empty_str_check(ctx, status_str, rc, out); 93 | 94 | dmmp_p->blk_name = strdup(blk_name); 95 | _dmmp_alloc_null_check(ctx, dmmp_p->blk_name, rc, out); 96 | 97 | dmmp_p->status = _dmmp_path_status_str_conv(ctx, status_str); 98 | 99 | _debug(ctx, "Got path blk_name: '%s'", dmmp_p->blk_name); 100 | _debug(ctx, "Got path status: %s(%" PRIu32 ")", 101 | dmmp_path_status_str(dmmp_p->status), dmmp_p->status); 102 | 103 | out: 104 | if (rc != DMMP_OK) 105 | _dmmp_path_free(dmmp_p); 106 | return rc; 107 | } 108 | 109 | void _dmmp_path_free(struct dmmp_path *dmmp_p) 110 | { 111 | if (dmmp_p == NULL) 112 | return; 113 | free(dmmp_p->blk_name); 114 | free(dmmp_p); 115 | } 116 | -------------------------------------------------------------------------------- /libdmmp/test/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # 3 | # Copyright (C) 2015-2016 Gris Ge 4 | # 5 | include ../../Makefile.inc 6 | 7 | _libdmmpdir=../$(libdmmpdir) 8 | _mpathcmddir=../$(mpathcmddir) 9 | 10 | TEST_EXEC = libdmmp_test 11 | SPD_TEST_EXEC = libdmmp_speed_test 12 | CFLAGS += -I$(_libdmmpdir) 13 | LDFLAGS += -L$(_libdmmpdir) -ldmmp 14 | 15 | all: $(TEST_EXEC) $(SPD_TEST_EXEC) 16 | 17 | check: $(TEST_EXEC) $(SPD_TEST_EXEC) 18 | sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ 19 | valgrind --quiet --leak-check=full \ 20 | --show-reachable=no --show-possibly-lost=no \ 21 | --trace-children=yes --error-exitcode=1 \ 22 | ./$(TEST_EXEC) 23 | $(MAKE) speed_test 24 | 25 | speed_test: $(SPD_TEST_EXEC) 26 | sudo env LD_LIBRARY_PATH=$(_libdmmpdir):$(_mpathcmddir) \ 27 | time -p ./$(SPD_TEST_EXEC) 28 | 29 | clean: dep_clean 30 | rm -f $(TEST_EXEC) $(SPD_TEST_EXEC) 31 | 32 | OBJS = $(TEST_EXEC).o $(SPD_TEST_EXEC).o 33 | include $(wildcard $(OBJS:.o=.d)) 34 | 35 | 36 | dep_clean: 37 | $(RM) $(OBJS:.o=.d) 38 | -------------------------------------------------------------------------------- /libdmmp/test/libdmmp_speed_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2016 Red Hat, Inc. 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Author: Gris Ge 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | struct dmmp_context *ctx = NULL; 33 | struct dmmp_mpath **dmmp_mps = NULL; 34 | uint32_t dmmp_mp_count = 0; 35 | int rc = EXIT_SUCCESS; 36 | 37 | ctx = dmmp_context_new(); 38 | dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_WARNING); 39 | 40 | if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) { 41 | printf("FAILED\n"); 42 | rc = EXIT_FAILURE; 43 | } else { 44 | printf("Got %" PRIu32 " mpath\n", dmmp_mp_count); 45 | dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); 46 | } 47 | dmmp_context_free(ctx); 48 | exit(rc); 49 | } 50 | -------------------------------------------------------------------------------- /libmpathcmd/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | SONAME = 0 4 | DEVLIB = libmpathcmd.so 5 | LIBS = $(DEVLIB).$(SONAME) 6 | 7 | CFLAGS += $(LIB_CFLAGS) 8 | 9 | OBJS = mpath_cmd.o 10 | 11 | all: $(LIBS) 12 | 13 | $(LIBS): $(OBJS) 14 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) 15 | $(LN) $@ $(DEVLIB) 16 | 17 | install: $(LIBS) 18 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 19 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 20 | $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 21 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(includedir) 22 | $(INSTALL_PROGRAM) -m 644 mpath_cmd.h $(DESTDIR)$(includedir) 23 | 24 | uninstall: 25 | $(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 26 | $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 27 | $(RM) $(DESTDIR)$(includedir)/mpath_cmd.h 28 | 29 | clean: dep_clean 30 | $(RM) core *.a *.o *.so *.so.* *.gz 31 | 32 | include $(wildcard $(OBJS:.o=.d)) 33 | 34 | 35 | dep_clean: 36 | $(RM) $(OBJS:.o=.d) 37 | -------------------------------------------------------------------------------- /libmpathpersist/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | SONAME = 0 4 | DEVLIB = libmpathpersist.so 5 | LIBS = $(DEVLIB).$(SONAME) 6 | 7 | CFLAGS += $(LIB_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir) 8 | 9 | LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \ 10 | -L$(mpathcmddir) -lmpathcmd 11 | 12 | OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o 13 | 14 | all: $(LIBS) 15 | 16 | $(LIBS): $(OBJS) 17 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ -o $@ $(OBJS) 18 | $(LN) $(LIBS) $(DEVLIB) 19 | $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz 20 | $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz 21 | 22 | install: $(LIBS) 23 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 24 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 25 | $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir) 26 | $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir) 27 | $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(includedir) 28 | $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 29 | $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir) 30 | $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir) 31 | $(INSTALL_PROGRAM) -m 644 mpath_persist.h $(DESTDIR)$(includedir) 32 | 33 | uninstall: 34 | $(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 35 | $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz 36 | $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz 37 | $(RM) $(DESTDIR)$(includedir)/mpath_persist.h 38 | $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 39 | 40 | clean: dep_clean 41 | $(RM) core *.a *.o *.so *.so.* *.gz 42 | 43 | include $(wildcard $(OBJS:.o=.d)) 44 | 45 | 46 | dep_clean: 47 | $(RM) $(OBJS:.o=.d) 48 | -------------------------------------------------------------------------------- /libmpathpersist/mpath_pr_ioctl.h: -------------------------------------------------------------------------------- 1 | #define MPATH_XFER_HOST_DEV 0 /*data transfer from initiator to target */ 2 | #define MPATH_XFER_DEV_HOST 1 /*data transfer from target to initiator */ 3 | #define MPATH_XFER_NONE 2 /*no data transfer */ 4 | #define MPATH_XFER_UNKNOWN 3 /*data transfer direction is unknown */ 5 | 6 | #if 0 7 | static const char * pr_type_strs[] = { 8 | "obsolete [0]", 9 | "Write Exclusive", 10 | "obsolete [2]", 11 | "Exclusive Access", 12 | "obsolete [4]", 13 | "Write Exclusive, registrants only", 14 | "Exclusive Access, registrants only", 15 | "Write Exclusive, all registrants", 16 | "Exclusive Access, all registrants", 17 | "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]", 18 | "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]", 19 | }; 20 | #endif 21 | 22 | typedef unsigned int LWORD; /* unsigned numeric, bit patterns */ 23 | typedef unsigned char BYTE; /* unsigned numeric, bit patterns */ 24 | 25 | typedef struct SenseData 26 | { 27 | BYTE Error_Code; 28 | BYTE Segment_Number; /* not applicable to DAC */ 29 | BYTE Sense_Key; 30 | BYTE Information[ 4 ]; 31 | BYTE Additional_Len; 32 | LWORD Command_Specific_Info; 33 | BYTE ASC; 34 | BYTE ASCQ; 35 | BYTE Field_Replaceable_Unit; 36 | BYTE Sense_Key_Specific_Info[ 3 ]; 37 | BYTE Recovery_Action[ 2 ]; 38 | BYTE Total_Errors; 39 | BYTE Total_Retries; 40 | BYTE ASC_Stack_1; 41 | BYTE ASCQ_Stack_1; 42 | BYTE ASC_Stack_2; 43 | BYTE ASCQ_Stack_2; 44 | BYTE Additional_FRU_Info[ 8 ]; 45 | BYTE Error_Specific_Info[ 3 ]; 46 | BYTE Error_Detection_Point[ 4 ]; 47 | BYTE Original_CDB[10]; 48 | BYTE Host_ID; 49 | BYTE Host_Descriptor[ 2 ]; 50 | BYTE Serial_Number[ 16 ]; 51 | BYTE Array_SW_Revision[ 4 ]; 52 | BYTE Data_Xfer_Operation; 53 | BYTE LUN_Number; 54 | BYTE LUN_Status; 55 | BYTE Drive_ID; 56 | BYTE Xfer_Start_Drive_ID; 57 | BYTE Drive_SW_Revision[ 4 ]; 58 | BYTE Drive_Product_ID[ 16 ]; 59 | BYTE PowerUp_Status[ 2 ]; 60 | BYTE RAID_Level; 61 | BYTE Drive_Sense_ID[ 2 ]; 62 | BYTE Drive_Sense_Data[ 32 ]; 63 | BYTE Reserved2[24]; 64 | } SenseData_t; 65 | 66 | #define MPATH_PRIN_CMD 0x5e 67 | #define MPATH_PRIN_CMDLEN 10 68 | #define MPATH_PROUT_CMD 0x5f 69 | #define MPATH_PROUT_CMDLEN 10 70 | 71 | #define DID_OK 0x00 72 | /* 73 | * Status codes 74 | */ 75 | #define SAM_STAT_GOOD 0x00 76 | #define SAM_STAT_CHECK_CONDITION 0x02 77 | #define SAM_STAT_CONDITION_MET 0x04 78 | #define SAM_STAT_BUSY 0x08 79 | #define SAM_STAT_INTERMEDIATE 0x10 80 | #define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 81 | #define SAM_STAT_RESERVATION_CONFLICT 0x18 82 | #define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */ 83 | #define SAM_STAT_TASK_SET_FULL 0x28 84 | #define SAM_STAT_ACA_ACTIVE 0x30 85 | #define SAM_STAT_TASK_ABORTED 0x40 86 | 87 | #define STATUS_MASK 0x3e 88 | 89 | /* 90 | * SENSE KEYS 91 | */ 92 | 93 | #define NO_SENSE 0x00 94 | #define RECOVERED_ERROR 0x01 95 | #define NOT_READY 0x02 96 | #define MEDIUM_ERROR 0x03 97 | #define HARDWARE_ERROR 0x04 98 | #define ILLEGAL_REQUEST 0x05 99 | #define UNIT_ATTENTION 0x06 100 | #define DATA_PROTECT 0x07 101 | #define BLANK_CHECK 0x08 102 | #define COPY_ABORTED 0x0a 103 | #define ABORTED_COMMAND 0x0b 104 | #define VOLUME_OVERFLOW 0x0d 105 | #define MISCOMPARE 0x0e 106 | 107 | 108 | /* Driver status */ 109 | #define DRIVER_OK 0x00 110 | -------------------------------------------------------------------------------- /libmpathpersist/mpath_updatepr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "debug.h" 15 | #include "mpath_cmd.h" 16 | #include "uxsock.h" 17 | #include "memory.h" 18 | #include "mpathpr.h" 19 | 20 | 21 | static int do_update_pr(char *alias, char *arg) 22 | { 23 | int fd; 24 | char str[256]; 25 | char *reply; 26 | int ret = 0; 27 | 28 | fd = mpath_connect(); 29 | if (fd == -1) { 30 | condlog (0, "ux socket connect error"); 31 | return -1; 32 | } 33 | 34 | snprintf(str,sizeof(str),"map %s %s", alias, arg); 35 | condlog (2, "%s: pr message=%s", alias, str); 36 | if (send_packet(fd, str) != 0) { 37 | condlog(2, "%s: message=%s send error=%d", alias, str, errno); 38 | mpath_disconnect(fd); 39 | return -1; 40 | } 41 | ret = recv_packet(fd, &reply, DEFAULT_REPLY_TIMEOUT); 42 | if (ret < 0) { 43 | condlog(2, "%s: message=%s recv error=%d", alias, str, errno); 44 | ret = -1; 45 | } else { 46 | condlog (2, "%s: message=%s reply=%s", alias, str, reply); 47 | if (reply && strncmp(reply,"ok", 2) == 0) 48 | ret = 0; 49 | else 50 | ret = -1; 51 | } 52 | 53 | free(reply); 54 | mpath_disconnect(fd); 55 | return ret; 56 | } 57 | 58 | int update_prflag(char *mapname, int set) { 59 | return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus"); 60 | } 61 | 62 | int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags) { 63 | char str[256]; 64 | char *flagstr = ""; 65 | 66 | if (sa_flags & MPATH_F_APTPL_MASK) 67 | flagstr = ":aptpl"; 68 | if (prkey) 69 | sprintf(str, "setprkey key %" PRIx64 "%s", prkey, flagstr); 70 | else 71 | sprintf(str, "unsetprkey"); 72 | return do_update_pr(mapname, str); 73 | } 74 | -------------------------------------------------------------------------------- /libmpathpersist/mpathpr.h: -------------------------------------------------------------------------------- 1 | #ifndef MPATHPR_H 2 | #define MPATHPR_H 3 | 4 | #include "structs.h" /* FILE_NAME_SIZE */ 5 | 6 | struct prin_param { 7 | char dev[FILE_NAME_SIZE]; 8 | int rq_servact; 9 | struct prin_resp *resp; 10 | int noisy; 11 | int status; 12 | }; 13 | 14 | struct prout_param { 15 | char dev[FILE_NAME_SIZE]; 16 | int rq_servact; 17 | int rq_scope; 18 | unsigned int rq_type; 19 | struct prout_param_descriptor *paramp; 20 | int noisy; 21 | int status; 22 | }; 23 | 24 | struct threadinfo { 25 | int status; 26 | pthread_t id; 27 | struct prout_param param; 28 | }; 29 | 30 | int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy); 31 | int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope, 32 | unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy); 33 | void * _mpath_pr_update (void *arg); 34 | int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy); 35 | int get_mpvec (vector curmp, vector pathvec, char * refwwid); 36 | void * mpath_prout_pthread_fn(void *p); 37 | void dumpHex(const char* , int len, int no_ascii); 38 | 39 | int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope, 40 | unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); 41 | int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope, 42 | unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); 43 | int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope, 44 | unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); 45 | int send_prout_activepath(char * dev, int rq_servact, int rq_scope, 46 | unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy); 47 | 48 | int update_prflag(char *mapname, int set); 49 | int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags); 50 | #define update_prkey(mapname, prkey) update_prkey_flags(mapname, prkey, 0) 51 | void * mpath_alloc_prin_response(int prin_sa); 52 | int update_map_pr(struct multipath *mpp); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /libmultipath/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | SONAME = 0 7 | DEVLIB = libmultipath.so 8 | LIBS = $(DEVLIB).$(SONAME) 9 | 10 | CFLAGS += $(LIB_CFLAGS) -I$(mpathcmddir) -I$(mpathpersistdir) -I$(nvmedir) 11 | 12 | LIBDEPS += -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd -lurcu -laio 13 | 14 | ifdef SYSTEMD 15 | CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD) 16 | ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1) 17 | LIBDEPS += -lsystemd 18 | else 19 | LIBDEPS += -lsystemd-daemon 20 | endif 21 | endif 22 | 23 | ifneq ($(call check_func,dm_task_no_flush,/usr/include/libdevmapper.h),0) 24 | CFLAGS += -DLIBDM_API_FLUSH -D_GNU_SOURCE 25 | endif 26 | 27 | ifneq ($(call check_func,dm_task_get_errno,/usr/include/libdevmapper.h),0) 28 | CFLAGS += -DLIBDM_API_GET_ERRNO 29 | endif 30 | 31 | ifneq ($(call check_func,dm_task_set_cookie,/usr/include/libdevmapper.h),0) 32 | CFLAGS += -DLIBDM_API_COOKIE 33 | endif 34 | 35 | ifneq ($(call check_func,udev_monitor_set_receive_buffer_size,/usr/include/libudev.h),0) 36 | CFLAGS += -DLIBUDEV_API_RECVBUF 37 | endif 38 | 39 | ifneq ($(call check_func,dm_task_deferred_remove,/usr/include/libdevmapper.h),0) 40 | CFLAGS += -DLIBDM_API_DEFERRED 41 | endif 42 | 43 | ifneq ($(call check_func,dm_hold_control_dev,/usr/include/libdevmapper.h),0) 44 | CFLAGS += -DLIBDM_API_HOLD_CONTROL 45 | endif 46 | 47 | OBJS = memory.o parser.o vector.o devmapper.o callout.o \ 48 | hwtable.o blacklist.o util.o dmparser.o config.o \ 49 | structs.o discovery.o propsel.o dict.o \ 50 | pgpolicies.o debug.o defaults.o uevent.o time-util.o \ 51 | switchgroup.o uxsock.o print.o alias.o log_pthread.o \ 52 | log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \ 53 | lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \ 54 | io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \ 55 | libsg.o valid.o 56 | 57 | all: $(LIBS) 58 | 59 | nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h 60 | $(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $< 61 | 62 | # there are lots of "unused parameters" in dict.c 63 | # because not all handler / snprint methods nees all parameters 64 | dict.o: dict.c 65 | $(CC) $(CFLAGS) -Wno-unused-parameter -c -o $@ $< 66 | 67 | make_static = $(shell sed '/^static/!s/^\([a-z]\{1,\} \)/static \1/' <$1 >$2) 68 | 69 | nvme-ioctl.c: nvme/nvme-ioctl.c 70 | $(call make_static,$<,$@) 71 | 72 | nvme-ioctl.h: nvme/nvme-ioctl.h 73 | $(call make_static,$<,$@) 74 | 75 | $(LIBS): $(OBJS) 76 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ -o $@ $(OBJS) $(LIBDEPS) 77 | $(LN) $@ $(DEVLIB) 78 | 79 | install: 80 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir) 81 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS) 82 | $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir) 83 | $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB) 84 | 85 | uninstall: 86 | $(RM) $(DESTDIR)$(syslibdir)/$(LIBS) 87 | $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB) 88 | 89 | clean: dep_clean 90 | $(RM) core *.a *.o *.so *.so.* *.gz nvme-ioctl.c nvme-ioctl.h 91 | 92 | include $(wildcard $(OBJS:.o=.d)) 93 | 94 | dep_clean: 95 | $(RM) $(OBJS:.o=.d) 96 | -------------------------------------------------------------------------------- /libmultipath/alias.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALIAS_H 2 | #define _ALIAS_H 3 | 4 | int valid_alias(const char *alias); 5 | char *get_user_friendly_alias(const char *wwid, const char *file, 6 | const char *prefix, 7 | int bindings_readonly); 8 | int get_user_friendly_wwid(const char *alias, char *buff, const char *file); 9 | char *use_existing_alias (const char *wwid, const char *file, 10 | const char *alias_old, 11 | const char *prefix, int bindings_read_only); 12 | 13 | struct config; 14 | int check_alias_settings(const struct config *); 15 | 16 | #endif /* _ALIAS_H */ 17 | -------------------------------------------------------------------------------- /libmultipath/blacklist.h: -------------------------------------------------------------------------------- 1 | #ifndef _BLACKLIST_H 2 | #define _BLACKLIST_H 3 | 4 | #include 5 | #include 6 | 7 | #define MATCH_NOTHING 0 8 | #define MATCH_WWID_BLIST 1 9 | #define MATCH_DEVICE_BLIST 2 10 | #define MATCH_DEVNODE_BLIST 3 11 | #define MATCH_PROPERTY_BLIST 4 12 | #define MATCH_PROPERTY_BLIST_MISSING 5 13 | #define MATCH_PROTOCOL_BLIST 6 14 | #define MATCH_WWID_BLIST_EXCEPT -MATCH_WWID_BLIST 15 | #define MATCH_DEVICE_BLIST_EXCEPT -MATCH_DEVICE_BLIST 16 | #define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST 17 | #define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST 18 | #define MATCH_PROTOCOL_BLIST_EXCEPT -MATCH_PROTOCOL_BLIST 19 | 20 | struct blentry { 21 | char * str; 22 | regex_t regex; 23 | bool invert; 24 | int origin; 25 | }; 26 | 27 | struct blentry_device { 28 | char * vendor; 29 | char * product; 30 | regex_t vendor_reg; 31 | regex_t product_reg; 32 | bool vendor_invert; 33 | bool product_invert; 34 | int origin; 35 | }; 36 | 37 | int setup_default_blist (struct config *); 38 | int alloc_ble_device (vector); 39 | int filter_devnode (const struct _vector *, const struct _vector *, 40 | const char *); 41 | int filter_wwid (const struct _vector *, const struct _vector *, 42 | const char *, const char *); 43 | int filter_device (const struct _vector *, const struct _vector *, 44 | const char *, const char *, const char *); 45 | int filter_path (const struct config *, const struct path *); 46 | int filter_property(const struct config *, struct udev_device *, 47 | int, const char*); 48 | int filter_protocol(const struct _vector *, const struct _vector *, 49 | const struct path *); 50 | int store_ble (vector, const char *, int); 51 | int set_ble_device (vector, const char *, const char *, int); 52 | void free_blacklist (vector); 53 | void free_blacklist_device (vector); 54 | void merge_blacklist(vector); 55 | void merge_blacklist_device(vector); 56 | 57 | #endif /* _BLACKLIST_H */ 58 | -------------------------------------------------------------------------------- /libmultipath/byteorder.h: -------------------------------------------------------------------------------- 1 | #ifndef BYTEORDER_H_INCLUDED 2 | #define BYTEORDER_H_INCLUDED 3 | 4 | #ifdef __linux__ 5 | # include 6 | # include 7 | #else 8 | # error unsupported 9 | #endif 10 | 11 | #if BYTE_ORDER == LITTLE_ENDIAN 12 | # define le16_to_cpu(x) (uint16_t)(x) 13 | # define be16_to_cpu(x) bswap_16(x) 14 | # define le32_to_cpu(x) (uint32_t)(x) 15 | # define le64_to_cpu(x) (uint64_t)(x) 16 | # define be32_to_cpu(x) bswap_32(x) 17 | # define be64_to_cpu(x) bswap_64(x) 18 | #elif BYTE_ORDER == BIG_ENDIAN 19 | # define le16_to_cpu(x) bswap_16(x) 20 | # define be16_to_cpu(x) (uint16_t)(x) 21 | # define le32_to_cpu(x) bswap_32(x) 22 | # define le64_to_cpu(x) bswap_64(x) 23 | # define be32_to_cpu(x) (uint32_t)(x) 24 | # define be64_to_cpu(x) (uint64_t)(x) 25 | #else 26 | # error unsupported 27 | #endif 28 | 29 | #define cpu_to_le16(x) le16_to_cpu(x) 30 | #define cpu_to_be16(x) be16_to_cpu(x) 31 | #define cpu_to_le32(x) le32_to_cpu(x) 32 | #define cpu_to_be32(x) be32_to_cpu(x) 33 | #define cpu_to_le64(x) le64_to_cpu(x) 34 | #define cpu_to_be64(x) be64_to_cpu(x) 35 | 36 | struct be64 { 37 | uint64_t _v; 38 | }; 39 | 40 | #define get_be64(x) be64_to_cpu((x)._v) 41 | #define put_be64(x, y) do { (x)._v = cpu_to_be64(y); } while (0) 42 | 43 | 44 | #endif /* BYTEORDER_H_INCLUDED */ 45 | -------------------------------------------------------------------------------- /libmultipath/callout.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALLOUT_H 2 | #define _CALLOUT_H 3 | 4 | int execute_program(char *, char *, int); 5 | int apply_format (char *, char *, struct path *); 6 | 7 | #endif /* _CALLOUT_H */ 8 | -------------------------------------------------------------------------------- /libmultipath/checkers/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../../Makefile.inc 5 | 6 | CFLAGS += $(LIB_CFLAGS) -I.. 7 | 8 | # If you add or remove a checker also update multipath/multipath.conf.5 9 | LIBS= \ 10 | libcheckcciss_tur.so \ 11 | libcheckreadsector0.so \ 12 | libchecktur.so \ 13 | libcheckdirectio.so \ 14 | libcheckemc_clariion.so \ 15 | libcheckhp_sw.so \ 16 | libcheckrdac.so 17 | 18 | all: $(LIBS) 19 | 20 | libcheckdirectio.so: directio.o 21 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -laio 22 | 23 | libcheck%.so: %.o 24 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ 25 | 26 | install: 27 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) 28 | 29 | uninstall: 30 | for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done 31 | 32 | clean: dep_clean 33 | $(RM) core *.a *.o *.gz *.so 34 | 35 | OBJS := $(LIBS:libcheck%.so=%.o) 36 | .SECONDARY: $(OBJS) 37 | 38 | include $(wildcard $(OBJS:.o=.d)) 39 | 40 | dep_clean: 41 | $(RM) $(OBJS:.o=.d) 42 | -------------------------------------------------------------------------------- /libmultipath/checkers/cciss.h: -------------------------------------------------------------------------------- 1 | #ifndef CCISS_H 2 | #define CCISS_H 3 | 4 | #include 5 | #include 6 | 7 | #define CCISS_IOC_MAGIC 'B' 8 | 9 | /* 10 | * transfer direction 11 | */ 12 | #define XFER_NONE 0x00 13 | #define XFER_WRITE 0x01 14 | #define XFER_READ 0x02 15 | #define XFER_RSVD 0x03 16 | 17 | /* 18 | * task attribute 19 | */ 20 | #define ATTR_UNTAGGED 0x00 21 | #define ATTR_SIMPLE 0x04 22 | #define ATTR_HEADOFQUEUE 0x05 23 | #define ATTR_ORDERED 0x06 24 | #define ATTR_ACA 0x07 25 | 26 | /* 27 | * cdb type 28 | */ 29 | #define TYPE_CMD 0x00 30 | #define TYPE_MSG 0x01 31 | 32 | #define SENSEINFOBYTES 32 33 | 34 | /* 35 | * Type defs used in the following structs 36 | */ 37 | #define BYTE __u8 38 | #define WORD __u16 39 | #define HWORD __u16 40 | #define DWORD __u32 41 | 42 | #pragma pack(1) 43 | 44 | //Command List Structure 45 | typedef union _SCSI3Addr_struct { 46 | struct { 47 | BYTE Dev; 48 | BYTE Bus:6; 49 | BYTE Mode:2; // b00 50 | } PeripDev; 51 | struct { 52 | BYTE DevLSB; 53 | BYTE DevMSB:6; 54 | BYTE Mode:2; // b01 55 | } LogDev; 56 | struct { 57 | BYTE Dev:5; 58 | BYTE Bus:3; 59 | BYTE Targ:6; 60 | BYTE Mode:2; // b10 61 | } LogUnit; 62 | } SCSI3Addr_struct; 63 | 64 | typedef struct _PhysDevAddr_struct { 65 | DWORD TargetId:24; 66 | DWORD Bus:6; 67 | DWORD Mode:2; 68 | SCSI3Addr_struct Target[2]; //2 level target device addr 69 | } PhysDevAddr_struct; 70 | 71 | typedef struct _LogDevAddr_struct { 72 | DWORD VolId:30; 73 | DWORD Mode:2; 74 | BYTE reserved[4]; 75 | } LogDevAddr_struct; 76 | 77 | typedef union _LUNAddr_struct { 78 | BYTE LunAddrBytes[8]; 79 | SCSI3Addr_struct SCSI3Lun[4]; 80 | PhysDevAddr_struct PhysDev; 81 | LogDevAddr_struct LogDev; 82 | } LUNAddr_struct; 83 | 84 | typedef struct _RequestBlock_struct { 85 | BYTE CDBLen; 86 | struct { 87 | BYTE Type:3; 88 | BYTE Attribute:3; 89 | BYTE Direction:2; 90 | } Type; 91 | HWORD Timeout; 92 | BYTE CDB[16]; 93 | } RequestBlock_struct; 94 | 95 | typedef union _MoreErrInfo_struct{ 96 | struct { 97 | BYTE Reserved[3]; 98 | BYTE Type; 99 | DWORD ErrorInfo; 100 | } Common_Info; 101 | struct{ 102 | BYTE Reserved[2]; 103 | BYTE offense_size;//size of offending entry 104 | BYTE offense_num; //byte # of offense 0-base 105 | DWORD offense_value; 106 | } Invalid_Cmd; 107 | } MoreErrInfo_struct; 108 | 109 | typedef struct _ErrorInfo_struct { 110 | BYTE ScsiStatus; 111 | BYTE SenseLen; 112 | HWORD CommandStatus; 113 | DWORD ResidualCnt; 114 | MoreErrInfo_struct MoreErrInfo; 115 | BYTE SenseInfo[SENSEINFOBYTES]; 116 | } ErrorInfo_struct; 117 | 118 | #pragma pack() 119 | 120 | typedef struct _IOCTL_Command_struct { 121 | LUNAddr_struct LUN_info; 122 | RequestBlock_struct Request; 123 | ErrorInfo_struct error_info; 124 | WORD buf_size; /* size in bytes of the buf */ 125 | BYTE *buf; 126 | } IOCTL_Command_struct; 127 | 128 | typedef struct _LogvolInfo_struct{ 129 | __u32 LunID; 130 | int num_opens; /* number of opens on the logical volume */ 131 | int num_parts; /* number of partitions configured on logvol */ 132 | } LogvolInfo_struct; 133 | 134 | #define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct) 135 | #define CCISS_GETLUNINFO _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct) 136 | 137 | int cciss_init( struct checker *); 138 | void cciss_free (struct checker * c); 139 | int cciss_tur( struct checker *); 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /libmultipath/checkers/directio.h: -------------------------------------------------------------------------------- 1 | #ifndef _DIRECTIO_H 2 | #define _DIRECTIO_H 3 | 4 | int directio (struct checker *); 5 | int directio_init (struct checker *); 6 | void directio_free (struct checker *); 7 | 8 | #endif /* _DIRECTIO_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/emc_clariion.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMC_CLARIION_H 2 | #define _EMC_CLARIION_H 3 | 4 | int emc_clariion (struct checker *); 5 | int emc_clariion_init (struct checker *); 6 | void emc_clariion_free (struct checker *); 7 | 8 | #endif /* _EMC_CLARIION_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/hp_sw.h: -------------------------------------------------------------------------------- 1 | #ifndef _HP_SW_H 2 | #define _HP_SW_H 3 | 4 | int hp_sw (struct checker *); 5 | int hp_sw_init (struct checker *); 6 | void hp_sw_free (struct checker *); 7 | 8 | #endif /* _HP_SW_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/rdac.h: -------------------------------------------------------------------------------- 1 | #ifndef _RDAC_H 2 | #define _RDAC_H 3 | 4 | int rdac(struct checker *); 5 | int rdac_init(struct checker *); 6 | void rdac_free(struct checker *); 7 | 8 | #endif /* _RDAC_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/readsector0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, 2005 Christophe Varoqui 3 | */ 4 | #include 5 | 6 | #include "checkers.h" 7 | #include "libsg.h" 8 | 9 | struct readsector0_checker_context { 10 | void * dummy; 11 | }; 12 | 13 | int libcheck_init (__attribute__((unused)) struct checker * c) 14 | { 15 | return 0; 16 | } 17 | 18 | void libcheck_free (__attribute__((unused)) struct checker * c) 19 | { 20 | return; 21 | } 22 | 23 | int libcheck_check (struct checker * c) 24 | { 25 | unsigned char buf[4096]; 26 | unsigned char sbuf[SENSE_BUFF_LEN]; 27 | int ret; 28 | 29 | ret = sg_read(c->fd, &buf[0], 4096, &sbuf[0], 30 | SENSE_BUFF_LEN, c->timeout); 31 | 32 | switch (ret) 33 | { 34 | case PATH_DOWN: 35 | c->msgid = CHECKER_MSGID_DOWN; 36 | break; 37 | case PATH_UP: 38 | c->msgid = CHECKER_MSGID_UP; 39 | break; 40 | default: 41 | break; 42 | } 43 | return ret; 44 | } 45 | -------------------------------------------------------------------------------- /libmultipath/checkers/readsector0.h: -------------------------------------------------------------------------------- 1 | #ifndef _READSECTOR0_H 2 | #define _READSECTOR0_H 3 | 4 | int readsector0 (struct checker *); 5 | int readsector0_init (struct checker *); 6 | void readsector0_free (struct checker *); 7 | 8 | #endif /* _READSECTOR0_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/checkers/tur.h: -------------------------------------------------------------------------------- 1 | #ifndef _TUR_H 2 | #define _TUR_H 3 | 4 | int tur (struct checker *); 5 | int tur_init (struct checker *); 6 | void tur_free (struct checker *); 7 | 8 | #endif /* _TUR_H */ 9 | -------------------------------------------------------------------------------- /libmultipath/configure.h: -------------------------------------------------------------------------------- 1 | /* 2 | * configurator actions 3 | */ 4 | #define ACT_NOTHING_STR "unchanged" 5 | #define ACT_REJECT_STR "reject" 6 | #define ACT_RELOAD_STR "reload" 7 | #define ACT_SWITCHPG_STR "switchpg" 8 | #define ACT_RENAME_STR "rename" 9 | #define ACT_CREATE_STR "create" 10 | #define ACT_RESIZE_STR "resize" 11 | 12 | enum actions { 13 | ACT_UNDEF, 14 | ACT_NOTHING, 15 | ACT_REJECT, 16 | ACT_RELOAD, 17 | ACT_SWITCHPG, 18 | ACT_RENAME, 19 | ACT_CREATE, 20 | ACT_RESIZE, 21 | ACT_FORCERENAME, 22 | ACT_DRY_RUN, 23 | ACT_IMPOSSIBLE, 24 | }; 25 | 26 | /* 27 | * Return value of domap() 28 | * DAEMON_RETRY is only used for ACT_CREATE (see domap()). 29 | */ 30 | enum { 31 | DOMAP_RETRY = -1, 32 | DOMAP_FAIL = 0, 33 | DOMAP_OK = 1, 34 | DOMAP_EXIST = 2, 35 | DOMAP_DRY = 3 36 | }; 37 | 38 | /* 39 | * Return value of coalesce_paths() 40 | * CP_RETRY is only used in non-daemon case (multipath). 41 | */ 42 | enum { 43 | CP_OK = 0, 44 | CP_FAIL, 45 | CP_RETRY, 46 | }; 47 | 48 | struct vectors; 49 | 50 | int setup_map (struct multipath * mpp, char * params, int params_size, 51 | struct vectors *vecs ); 52 | void select_action (struct multipath *mpp, const struct _vector *curmp, 53 | int force_reload); 54 | int domap (struct multipath * mpp, char * params, int is_daemon); 55 | int reinstate_paths (struct multipath *mpp); 56 | int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload, enum mpath_cmds cmd); 57 | int get_refwwid (enum mpath_cmds cmd, const char *dev, enum devtypes dev_type, 58 | vector pathvec, char **wwid); 59 | struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type); 60 | void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath); 61 | -------------------------------------------------------------------------------- /libmultipath/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "log_pthread.h" 10 | #include 11 | #include 12 | #include "../third-party/valgrind/drd.h" 13 | #include "vector.h" 14 | #include "config.h" 15 | #include "defaults.h" 16 | #include "debug.h" 17 | 18 | void dlog (int sink, int prio, const char * fmt, ...) 19 | { 20 | va_list ap; 21 | int thres; 22 | struct config *conf; 23 | 24 | va_start(ap, fmt); 25 | conf = get_multipath_config(); 26 | ANNOTATE_IGNORE_READS_BEGIN(); 27 | thres = (conf) ? conf->verbosity : DEFAULT_VERBOSITY; 28 | ANNOTATE_IGNORE_READS_END(); 29 | put_multipath_config(conf); 30 | 31 | if (prio <= thres) { 32 | if (sink < 1) { 33 | if (sink == 0) { 34 | time_t t = time(NULL); 35 | struct tm *tb = localtime(&t); 36 | char buff[16]; 37 | 38 | strftime(buff, sizeof(buff), 39 | "%b %d %H:%M:%S", tb); 40 | buff[sizeof(buff)-1] = '\0'; 41 | 42 | fprintf(stderr, "%s | ", buff); 43 | } 44 | vfprintf(stderr, fmt, ap); 45 | } 46 | else 47 | log_safe(prio + 3, fmt, ap); 48 | } 49 | va_end(ap); 50 | } 51 | -------------------------------------------------------------------------------- /libmultipath/debug.h: -------------------------------------------------------------------------------- 1 | void dlog (int sink, int prio, const char * fmt, ...) 2 | __attribute__((format(printf, 3, 4))); 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include "log_pthread.h" 9 | 10 | extern int logsink; 11 | 12 | #define condlog(prio, fmt, args...) \ 13 | dlog(logsink, prio, fmt "\n", ##args) 14 | -------------------------------------------------------------------------------- /libmultipath/defaults.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | */ 4 | #include 5 | 6 | #include "defaults.h" 7 | #include "memory.h" 8 | 9 | const char * const default_partition_delim = DEFAULT_PARTITION_DELIM; 10 | -------------------------------------------------------------------------------- /libmultipath/defaults.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEFAULTS_H 2 | #define _DEFAULTS_H 3 | #include 4 | 5 | /* 6 | * If you add or modify a value also update multipath/multipath.conf.5 7 | * and the TEMPLATE in libmultipath/hwtable.c 8 | */ 9 | #define DEFAULT_UID_ATTRIBUTE "ID_SERIAL" 10 | #define DEFAULT_NVME_UID_ATTRIBUTE "ID_WWN" 11 | #define DEFAULT_UDEVDIR "/dev" 12 | #define DEFAULT_MULTIPATHDIR "/" LIB_STRING "/multipath" 13 | #define DEFAULT_SELECTOR "service-time 0" 14 | #define DEFAULT_ALIAS_PREFIX "mpath" 15 | #define DEFAULT_FEATURES "0" 16 | #define DEFAULT_HWHANDLER "0" 17 | #define DEFAULT_MINIO 1000 18 | #define DEFAULT_MINIO_RQ 1 19 | #define DEFAULT_PGPOLICY FAILOVER 20 | #define DEFAULT_FAILBACK -FAILBACK_MANUAL 21 | #define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE 22 | #define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF 23 | #define DEFAULT_VERBOSITY 2 24 | #define DEFAULT_REASSIGN_MAPS 0 25 | #define DEFAULT_FIND_MULTIPATHS FIND_MULTIPATHS_STRICT 26 | #define DEFAULT_FAST_IO_FAIL 5 27 | #define DEFAULT_DEV_LOSS_TMO 600 28 | #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_ON 29 | #define DEFAULT_DETECT_PRIO DETECT_PRIO_ON 30 | #define DEFAULT_DETECT_CHECKER DETECT_CHECKER_ON 31 | #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF 32 | #define DEFAULT_DELAY_CHECKS NU_NO 33 | #define DEFAULT_ERR_CHECKS NU_NO 34 | /* half of minimum value for marginal_path_err_sample_time */ 35 | #define IOTIMEOUT_SEC 60 36 | #define DEFAULT_UEVENT_STACKSIZE 256 37 | #define DEFAULT_RETRIGGER_DELAY 10 38 | #define DEFAULT_RETRIGGER_TRIES 3 39 | #define DEFAULT_UEV_WAIT_TIMEOUT 30 40 | #define DEFAULT_PRIO PRIO_CONST 41 | #define DEFAULT_PRIO_ARGS "" 42 | #define DEFAULT_CHECKER TUR 43 | #define DEFAULT_FLUSH FLUSH_DISABLED 44 | #define DEFAULT_USER_FRIENDLY_NAMES USER_FRIENDLY_NAMES_OFF 45 | #define DEFAULT_FORCE_SYNC 0 46 | #define UNSET_PARTITION_DELIM "/UNSET/" 47 | #define DEFAULT_PARTITION_DELIM NULL 48 | #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF 49 | #define DEFAULT_DISABLE_CHANGED_WWIDS 1 50 | #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF 51 | #define DEFAULT_GHOST_DELAY GHOST_DELAY_OFF 52 | #define DEFAULT_FIND_MULTIPATHS_TIMEOUT -10 53 | #define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1 54 | #define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF 55 | /* Enable no foreign libraries by default */ 56 | #define DEFAULT_ENABLE_FOREIGN "NONE" 57 | 58 | #define CHECKINT_UNDEF UINT_MAX 59 | #define DEFAULT_CHECKINT 5 60 | 61 | #define DEV_LOSS_TMO_UNSET 0U 62 | #define MAX_DEV_LOSS_TMO UINT_MAX 63 | #define DEFAULT_PIDFILE "/" RUN_DIR "/multipathd.pid" 64 | #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" 65 | #define DEFAULT_CONFIGFILE "/etc/multipath.conf" 66 | #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" 67 | #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" 68 | #define DEFAULT_PRKEYS_FILE "/etc/multipath/prkeys" 69 | #define DEFAULT_CONFIG_DIR "/etc/multipath/conf.d" 70 | #define MULTIPATH_SHM_BASE "/dev/shm/multipath/" 71 | 72 | 73 | static inline char *set_default(char *str) 74 | { 75 | return strdup(str); 76 | } 77 | extern const char *const default_partition_delim; 78 | #endif /* _DEFAULTS_H */ 79 | -------------------------------------------------------------------------------- /libmultipath/devmapper.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEVMAPPER_H 2 | #define _DEVMAPPER_H 3 | 4 | #include "structs.h" 5 | 6 | #define TGT_MPATH "multipath" 7 | #define TGT_PART "linear" 8 | 9 | #ifdef DM_SUBSYSTEM_UDEV_FLAG0 10 | #define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0 11 | #else 12 | #define MPATH_UDEV_RELOAD_FLAG 0 13 | #endif 14 | 15 | #ifdef DM_SUBSYSTEM_UDEV_FLAG1 16 | #define MPATH_UDEV_NO_KPARTX_FLAG DM_SUBSYSTEM_UDEV_FLAG1 17 | #else 18 | #define MPATH_UDEV_NO_KPARTX_FLAG 0 19 | #endif 20 | 21 | #ifdef DM_SUBSYSTEM_UDEV_FLAG2 22 | #define MPATH_UDEV_NO_PATHS_FLAG DM_SUBSYSTEM_UDEV_FLAG2 23 | #else 24 | #define MPATH_UDEV_NO_PATHS_FLAG 0 25 | #endif 26 | 27 | #define UUID_PREFIX "mpath-" 28 | #define UUID_PREFIX_LEN (sizeof(UUID_PREFIX) - 1) 29 | 30 | enum { 31 | DMP_ERR, 32 | DMP_OK, 33 | DMP_NOT_FOUND, 34 | }; 35 | 36 | void dm_init(int verbosity); 37 | int dm_prereq(unsigned int *v); 38 | void skip_libmp_dm_init(void); 39 | void libmp_udev_set_sync_support(int on); 40 | struct dm_task *libmp_dm_task_create(int task); 41 | int dm_drv_version (unsigned int * version); 42 | int dm_tgt_version (unsigned int * version, char * str); 43 | int dm_simplecmd_flush (int, const char *, uint16_t); 44 | int dm_simplecmd_noflush (int, const char *, uint16_t); 45 | int dm_addmap_create (struct multipath *mpp, char *params); 46 | int dm_addmap_reload (struct multipath *mpp, char *params, int flush); 47 | int dm_map_present (const char *); 48 | int dm_map_present_by_uuid(const char *uuid); 49 | int dm_get_map(const char *, unsigned long long *, char *); 50 | int dm_get_status(const char *, char *); 51 | int dm_type(const char *, char *); 52 | int dm_is_mpath(const char *); 53 | int _dm_flush_map (const char *, int, int, int, int); 54 | int dm_flush_map_nopaths(const char * mapname, int deferred_remove); 55 | #define dm_flush_map(mapname) _dm_flush_map(mapname, 1, 0, 0, 0) 56 | #define dm_flush_map_nosync(mapname) _dm_flush_map(mapname, 0, 0, 0, 0) 57 | #define dm_suspend_and_flush_map(mapname, retries) \ 58 | _dm_flush_map(mapname, 1, 0, 1, retries) 59 | int dm_cancel_deferred_remove(struct multipath *mpp); 60 | int dm_flush_maps (int need_suspend, int retries); 61 | int dm_fail_path(const char * mapname, char * path); 62 | int dm_reinstate_path(const char * mapname, char * path); 63 | int dm_queue_if_no_path(const char *mapname, int enable); 64 | int dm_switchgroup(const char * mapname, int index); 65 | int dm_enablegroup(const char * mapname, int index); 66 | int dm_disablegroup(const char * mapname, int index); 67 | int dm_get_maps (vector mp); 68 | int dm_geteventnr (const char *name); 69 | int dm_is_suspended(const char *name); 70 | int dm_get_major_minor (const char *name, int *major, int *minor); 71 | char * dm_mapname(int major, int minor); 72 | int dm_remove_partmaps (const char * mapname, int need_sync, 73 | int deferred_remove); 74 | int dm_get_uuid(const char *name, char *uuid, int uuid_len); 75 | int dm_get_info (const char * mapname, struct dm_info ** dmi); 76 | int dm_rename (const char * old, char * new, char * delim, int skip_kpartx); 77 | int dm_reassign(const char * mapname); 78 | int dm_reassign_table(const char *name, char *old, char *new); 79 | int dm_setgeometry(struct multipath *mpp); 80 | struct multipath *dm_get_multipath(const char *name); 81 | 82 | #define VERSION_GE(v, minv) ( \ 83 | (v[0] > minv[0]) || \ 84 | ((v[0] == minv[0]) && (v[1] > minv[1])) || \ 85 | ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])) \ 86 | ) 87 | 88 | #ifndef LIBDM_API_GET_ERRNO 89 | #include 90 | #define dm_task_get_errno(x) errno 91 | #endif 92 | 93 | #define dm_log_error(lvl, cmd, dmt) \ 94 | condlog(lvl, "%s: libdm task=%d error: %s", __func__, \ 95 | cmd, strerror(dm_task_get_errno(dmt))) \ 96 | 97 | #endif /* _DEVMAPPER_H */ 98 | -------------------------------------------------------------------------------- /libmultipath/dict.h: -------------------------------------------------------------------------------- 1 | #ifndef _DICT_H 2 | #define _DICT_H 3 | 4 | #ifndef _VECTOR_H 5 | #include "vector.h" 6 | #endif 7 | 8 | #include "byteorder.h" 9 | 10 | void init_keywords(vector keywords); 11 | int get_sys_max_fds(int *); 12 | int print_rr_weight(char *buff, int len, long v); 13 | int print_pgfailback(char *buff, int len, long v); 14 | int print_pgpolicy(char *buff, int len, long v); 15 | int print_no_path_retry(char *buff, int len, long v); 16 | int print_fast_io_fail(char *buff, int len, long v); 17 | int print_dev_loss(char *buff, int len, unsigned long v); 18 | int print_reservation_key(char * buff, int len, struct be64 key, uint8_t 19 | flags, int source); 20 | int print_off_int_undef(char *buff, int len, long v); 21 | #endif /* _DICT_H */ 22 | -------------------------------------------------------------------------------- /libmultipath/discovery.h: -------------------------------------------------------------------------------- 1 | #ifndef DISCOVERY_H 2 | #define DISCOVERY_H 3 | 4 | #define SYSFS_PATH_SIZE 255 5 | #define INQUIRY_CMDLEN 6 6 | #define INQUIRY_CMD 0x12 7 | #define SENSE_BUFF_LEN 32 8 | #define RECOVERED_ERROR 0x01 9 | #define MX_ALLOC_LEN 255 10 | #define TUR_CMD_LEN 6 11 | 12 | #ifndef BLKGETSIZE 13 | #define BLKGETSIZE _IO(0x12,96) 14 | #endif 15 | 16 | #ifndef DEF_TIMEOUT 17 | #define DEF_TIMEOUT 30 18 | #endif 19 | 20 | /* 21 | * excerpt from sg_err.h 22 | */ 23 | #define SCSI_CHECK_CONDITION 0x2 24 | #define SCSI_COMMAND_TERMINATED 0x22 25 | #define SG_ERR_DRIVER_SENSE 0x08 26 | 27 | #define PATHINFO_OK 0 28 | #define PATHINFO_FAILED 1 29 | #define PATHINFO_SKIPPED 2 30 | 31 | struct config; 32 | 33 | int path_discovery (vector pathvec, int flag); 34 | int path_get_tpgs(struct path *pp); /* This function never returns TPGS_UNDEF */ 35 | int do_tur (char *); 36 | int path_offline (struct path *); 37 | int get_state (struct path * pp, struct config * conf, int daemon, int state); 38 | int get_vpd_sgio (int fd, int pg, int vend_id, char * str, int maxlen); 39 | int pathinfo (struct path * pp, struct config * conf, int mask); 40 | int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice, 41 | const char *wwid, int flag, struct path **pp_ptr); 42 | int store_pathinfo (vector pathvec, struct config *conf, 43 | struct udev_device *udevice, int flag, 44 | struct path **pp_ptr); 45 | int sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint); 46 | int sysfs_get_timeout(const struct path *pp, unsigned int *timeout); 47 | int sysfs_get_host_pci_name(const struct path *pp, char *pci_name); 48 | int sysfs_get_iscsi_ip_address(const struct path *pp, char *ip_address); 49 | int sysfs_get_host_adapter_name(const struct path *pp, 50 | char *adapter_name); 51 | ssize_t sysfs_get_vpd (struct udev_device *udev, unsigned char pg, 52 | unsigned char *buff, size_t len); 53 | ssize_t sysfs_get_inquiry(struct udev_device *udev, 54 | unsigned char *buff, size_t len); 55 | int sysfs_get_asymmetric_access_state(struct path *pp, 56 | char *buff, int buflen); 57 | int get_uid(struct path * pp, int path_state, struct udev_device *udev, 58 | int allow_fallback); 59 | 60 | /* 61 | * discovery bitmask 62 | */ 63 | enum discovery_mode { 64 | __DI_SYSFS, 65 | __DI_SERIAL, 66 | __DI_CHECKER, 67 | __DI_PRIO, 68 | __DI_WWID, 69 | __DI_BLACKLIST, 70 | __DI_NOIO, 71 | }; 72 | 73 | #define DI_SYSFS (1 << __DI_SYSFS) 74 | #define DI_SERIAL (1 << __DI_SERIAL) 75 | #define DI_CHECKER (1 << __DI_CHECKER) 76 | #define DI_PRIO (1 << __DI_PRIO) 77 | #define DI_WWID (1 << __DI_WWID) 78 | #define DI_BLACKLIST (1 << __DI_BLACKLIST) 79 | #define DI_NOIO (1 << __DI_NOIO) /* Avoid IO on the device */ 80 | 81 | #define DI_ALL (DI_SYSFS | DI_SERIAL | DI_CHECKER | DI_PRIO | \ 82 | DI_WWID) 83 | 84 | #endif /* DISCOVERY_H */ 85 | -------------------------------------------------------------------------------- /libmultipath/dm-generic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include "generic.h" 21 | #include "dm-generic.h" 22 | #include "structs.h" 23 | #include "structs_vec.h" 24 | #include "config.h" 25 | #include "print.h" 26 | 27 | static const struct _vector* 28 | dm_mp_get_pgs(const struct gen_multipath *gmp) 29 | { 30 | return vector_convert(NULL, gen_multipath_to_dm(gmp)->pg, 31 | struct pathgroup, dm_pathgroup_to_gen); 32 | } 33 | 34 | static void dm_mp_rel_pgs(__attribute__((unused)) 35 | const struct gen_multipath *gmp, 36 | const struct _vector* v) 37 | { 38 | vector_free_const(v); 39 | } 40 | 41 | static const struct _vector* 42 | dm_pg_get_paths(const struct gen_pathgroup *gpg) 43 | { 44 | return vector_convert(NULL, gen_pathgroup_to_dm(gpg)->paths, 45 | struct path, dm_path_to_gen); 46 | } 47 | 48 | static void dm_mp_rel_paths(__attribute__((unused)) 49 | const struct gen_pathgroup *gpg, 50 | const struct _vector* v) 51 | { 52 | vector_free_const(v); 53 | } 54 | 55 | const struct gen_multipath_ops dm_gen_multipath_ops = { 56 | .get_pathgroups = dm_mp_get_pgs, 57 | .rel_pathgroups = dm_mp_rel_pgs, 58 | .snprint = snprint_multipath_attr, 59 | .style = snprint_multipath_style, 60 | }; 61 | 62 | const struct gen_pathgroup_ops dm_gen_pathgroup_ops = { 63 | .get_paths = dm_pg_get_paths, 64 | .rel_paths = dm_mp_rel_paths, 65 | .snprint = snprint_pathgroup_attr, 66 | }; 67 | 68 | const struct gen_path_ops dm_gen_path_ops = { 69 | .snprint = snprint_path_attr, 70 | }; 71 | -------------------------------------------------------------------------------- /libmultipath/dm-generic.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #ifndef _DM_GENERIC_H 18 | #define _DM_GENERIC_H 19 | #include "generic.h" 20 | #include "list.h" /* for container_of */ 21 | #include "structs.h" 22 | 23 | #define dm_multipath_to_gen(mpp) (&((mpp)->generic_mp)) 24 | #define gen_multipath_to_dm(gm) \ 25 | container_of_const((gm), struct multipath, generic_mp) 26 | 27 | #define dm_pathgroup_to_gen(pg) (&(pg->generic_pg)) 28 | #define gen_pathgroup_to_dm(gpg) \ 29 | container_of_const((gpg), struct pathgroup, generic_pg) 30 | 31 | #define dm_path_to_gen(pp) (&((pp)->generic_path)) 32 | #define gen_path_to_dm(gp) \ 33 | container_of_const((gp), struct path, generic_path) 34 | 35 | extern const struct gen_multipath_ops dm_gen_multipath_ops; 36 | extern const struct gen_pathgroup_ops dm_gen_pathgroup_ops; 37 | extern const struct gen_path_ops dm_gen_path_ops; 38 | 39 | #endif /* _DM_GENERIC_H */ 40 | -------------------------------------------------------------------------------- /libmultipath/dmparser.h: -------------------------------------------------------------------------------- 1 | int assemble_map (struct multipath *, char *, int); 2 | int disassemble_map (const struct _vector *, const char *, struct multipath *); 3 | int disassemble_status (const char *, struct multipath *); 4 | -------------------------------------------------------------------------------- /libmultipath/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Benjamin Marzinski, Redhat 3 | */ 4 | 5 | #ifndef _FILE_H 6 | #define _FILE_H 7 | 8 | #include 9 | 10 | #define FILE_TIMEOUT 30 11 | int ensure_directories_exist(const char *str, mode_t dir_mode); 12 | int open_file(const char *file, int *can_write, const char *header); 13 | 14 | #endif /* _FILE_H */ 15 | -------------------------------------------------------------------------------- /libmultipath/foreign/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | TOPDIR=../.. 5 | include ../../Makefile.inc 6 | 7 | CFLAGS += $(LIB_CFLAGS) -I.. -I$(nvmedir) 8 | 9 | LIBS = libforeign-nvme.so 10 | 11 | all: $(LIBS) 12 | 13 | libforeign-%.so: %.o 14 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ 15 | 16 | install: 17 | $(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir) 18 | 19 | uninstall: 20 | for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done 21 | 22 | clean: dep_clean 23 | $(RM) core *.a *.o *.gz *.so 24 | 25 | OBJS := $(LIBS:libforeign-%.so=%.o) 26 | .SECONDARY: $(OBJS) 27 | 28 | include $(wildcard $(OBJS:.o=.d)) 29 | 30 | dep_clean: 31 | $(RM) $(OBJS:.o=.d) 32 | -------------------------------------------------------------------------------- /libmultipath/generic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Martin Wilck, SUSE Linux GmbH 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | 19 | #include 20 | #include "generic.h" 21 | #include "structs.h" 22 | 23 | int generic_style(const struct gen_multipath* gm, 24 | char *buf, int len, __attribute__((unused)) int verbosity) 25 | { 26 | char alias_buf[WWID_SIZE]; 27 | char wwid_buf[WWID_SIZE]; 28 | int n = 0; 29 | 30 | gm->ops->snprint(gm, alias_buf, sizeof(alias_buf), 'n'); 31 | gm->ops->snprint(gm, wwid_buf, sizeof(wwid_buf), 'w'); 32 | 33 | n += snprintf(buf, len, "%%n %s[%%G]:%%d %%s", 34 | strcmp(alias_buf, wwid_buf) ? "(%w) " : ""); 35 | 36 | return (n < len ? n : len - 1); 37 | } 38 | -------------------------------------------------------------------------------- /libmultipath/hwtable.h: -------------------------------------------------------------------------------- 1 | #ifndef _HWTABLE_H 2 | #define _HWTABLE_H 3 | 4 | int setup_default_hwtable (vector hw); 5 | 6 | #endif /* _HWTABLE_H */ 7 | -------------------------------------------------------------------------------- /libmultipath/io_err_stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _IO_ERR_STAT_H 2 | #define _IO_ERR_STAT_H 3 | 4 | #include "vector.h" 5 | #include "lock.h" 6 | 7 | 8 | extern pthread_attr_t io_err_stat_attr; 9 | 10 | int start_io_err_stat_thread(void *data); 11 | void stop_io_err_stat_thread(void); 12 | int io_err_stat_handle_pathfail(struct path *path); 13 | int need_io_err_check(struct path *pp); 14 | 15 | #endif /* _IO_ERR_STAT_H */ 16 | -------------------------------------------------------------------------------- /libmultipath/libsg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, 2005 Christophe Varoqui 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "checkers.h" 10 | #include "libsg.h" 11 | #include "../libmultipath/sg_include.h" 12 | 13 | int 14 | sg_read (int sg_fd, unsigned char * buff, int buff_len, 15 | unsigned char * sense, int sense_len, unsigned int timeout) 16 | { 17 | /* defaults */ 18 | int blocks; 19 | long long start_block = 0; 20 | int bs = 512; 21 | int cdbsz = 10; 22 | 23 | unsigned char rdCmd[cdbsz]; 24 | unsigned char *sbb = sense; 25 | struct sg_io_hdr io_hdr; 26 | int res; 27 | int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; 28 | int sz_ind; 29 | struct stat filestatus; 30 | int retry_count = 3; 31 | 32 | if (fstat(sg_fd, &filestatus) != 0) 33 | return PATH_DOWN; 34 | bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize; 35 | blocks = buff_len / bs; 36 | memset(rdCmd, 0, cdbsz); 37 | sz_ind = 1; 38 | rdCmd[0] = rd_opcode[sz_ind]; 39 | rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff); 40 | rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff); 41 | rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff); 42 | rdCmd[5] = (unsigned char)(start_block & 0xff); 43 | rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff); 44 | rdCmd[8] = (unsigned char)(blocks & 0xff); 45 | 46 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); 47 | io_hdr.interface_id = 'S'; 48 | io_hdr.cmd_len = cdbsz; 49 | io_hdr.cmdp = rdCmd; 50 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 51 | io_hdr.dxfer_len = bs * blocks; 52 | io_hdr.dxferp = buff; 53 | io_hdr.mx_sb_len = sense_len; 54 | io_hdr.sbp = sense; 55 | io_hdr.timeout = timeout * 1000; 56 | io_hdr.pack_id = (int)start_block; 57 | 58 | retry: 59 | memset(sense, 0, sense_len); 60 | while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)); 61 | 62 | if (res < 0) { 63 | if (ENOMEM == errno) { 64 | return PATH_UP; 65 | } 66 | return PATH_DOWN; 67 | } 68 | 69 | if ((0 == io_hdr.status) && 70 | (0 == io_hdr.host_status) && 71 | (0 == io_hdr.driver_status)) { 72 | return PATH_UP; 73 | } else { 74 | int key = 0; 75 | 76 | if (io_hdr.sb_len_wr > 3) { 77 | if (sbb[0] == 0x72 || sbb[0] == 0x73) 78 | key = sbb[1] & 0x0f; 79 | else if (io_hdr.sb_len_wr > 13 && 80 | ((sbb[0] & 0x7f) == 0x70 || 81 | (sbb[0] & 0x7f) == 0x71)) 82 | key = sbb[2] & 0x0f; 83 | } 84 | 85 | /* 86 | * Retry if UNIT_ATTENTION check condition. 87 | */ 88 | if (key == 0x6) { 89 | if (--retry_count) 90 | goto retry; 91 | } 92 | return PATH_DOWN; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /libmultipath/libsg.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBSG_H 2 | #define _LIBSG_H 3 | 4 | #define SENSE_BUFF_LEN 32 5 | 6 | int sg_read (int sg_fd, unsigned char * buff, int buff_len, 7 | unsigned char * sense, int sense_len, unsigned int timeout); 8 | 9 | #endif /* _LIBSG_H */ 10 | -------------------------------------------------------------------------------- /libmultipath/lock.c: -------------------------------------------------------------------------------- 1 | #include "lock.h" 2 | 3 | void cleanup_lock (void * data) 4 | { 5 | struct mutex_lock *lock = data; 6 | 7 | unlock(lock); 8 | } 9 | -------------------------------------------------------------------------------- /libmultipath/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOCK_H 2 | #define _LOCK_H 3 | 4 | #include 5 | 6 | struct mutex_lock { 7 | pthread_mutex_t mutex; 8 | }; 9 | 10 | static inline void lock(struct mutex_lock *a) 11 | { 12 | pthread_mutex_lock(&a->mutex); 13 | } 14 | 15 | static inline int timedlock(struct mutex_lock *a, struct timespec *tmo) 16 | { 17 | return pthread_mutex_timedlock(&a->mutex, tmo); 18 | } 19 | 20 | static inline void unlock(struct mutex_lock *a) 21 | { 22 | pthread_mutex_unlock(&a->mutex); 23 | } 24 | 25 | #define lock_cleanup_pop(a) pthread_cleanup_pop(1) 26 | 27 | void cleanup_lock (void * data); 28 | 29 | #endif /* _LOCK_H */ 30 | -------------------------------------------------------------------------------- /libmultipath/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #define DEFAULT_AREA_SIZE 16384 5 | #define MAX_MSG_SIZE 256 6 | 7 | #ifndef LOGLEVEL 8 | #define LOGLEVEL 5 9 | #endif 10 | 11 | #if LOGDBG 12 | #define logdbg(file, fmt, args...) fprintf(file, fmt, ##args) 13 | #else 14 | #define logdbg(file, fmt, args...) do {} while (0) 15 | #endif 16 | 17 | struct logmsg { 18 | short int prio; 19 | void * next; 20 | char str[0]; 21 | }; 22 | 23 | struct logarea { 24 | int empty; 25 | void * head; 26 | void * tail; 27 | void * start; 28 | void * end; 29 | char * buff; 30 | }; 31 | 32 | extern struct logarea* la; 33 | 34 | int log_init (char * progname, int size); 35 | void log_close (void); 36 | void log_reset (char * progname); 37 | int log_enqueue (int prio, const char * fmt, va_list ap) 38 | __attribute__((format(printf, 2, 0))); 39 | int log_dequeue (void *); 40 | void log_syslog (void *); 41 | void dump_logmsg (void *); 42 | void free_logarea (void); 43 | 44 | #endif /* LOG_H */ 45 | -------------------------------------------------------------------------------- /libmultipath/log_pthread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "memory.h" 12 | 13 | #include "log_pthread.h" 14 | #include "log.h" 15 | #include "lock.h" 16 | 17 | static pthread_t log_thr; 18 | 19 | static pthread_mutex_t logq_lock; 20 | static pthread_mutex_t logev_lock; 21 | static pthread_cond_t logev_cond; 22 | 23 | static int logq_running; 24 | static int log_messages_pending; 25 | 26 | void log_safe (int prio, const char * fmt, va_list ap) 27 | { 28 | if (prio > LOG_DEBUG) 29 | prio = LOG_DEBUG; 30 | 31 | if (log_thr == (pthread_t)0) { 32 | vsyslog(prio, fmt, ap); 33 | return; 34 | } 35 | 36 | pthread_mutex_lock(&logq_lock); 37 | log_enqueue(prio, fmt, ap); 38 | pthread_mutex_unlock(&logq_lock); 39 | 40 | pthread_mutex_lock(&logev_lock); 41 | log_messages_pending = 1; 42 | pthread_cond_signal(&logev_cond); 43 | pthread_mutex_unlock(&logev_lock); 44 | } 45 | 46 | static void flush_logqueue (void) 47 | { 48 | int empty; 49 | 50 | do { 51 | pthread_mutex_lock(&logq_lock); 52 | empty = log_dequeue(la->buff); 53 | pthread_mutex_unlock(&logq_lock); 54 | if (!empty) 55 | log_syslog(la->buff); 56 | } while (empty == 0); 57 | } 58 | 59 | static void * log_thread (__attribute__((unused)) void * et) 60 | { 61 | int running; 62 | 63 | pthread_mutex_lock(&logev_lock); 64 | logq_running = 1; 65 | pthread_mutex_unlock(&logev_lock); 66 | 67 | mlockall(MCL_CURRENT | MCL_FUTURE); 68 | logdbg(stderr,"enter log_thread\n"); 69 | 70 | while (1) { 71 | pthread_mutex_lock(&logev_lock); 72 | if (logq_running && !log_messages_pending) 73 | pthread_cond_wait(&logev_cond, &logev_lock); 74 | log_messages_pending = 0; 75 | running = logq_running; 76 | pthread_mutex_unlock(&logev_lock); 77 | if (!running) 78 | break; 79 | flush_logqueue(); 80 | } 81 | return NULL; 82 | } 83 | 84 | void log_thread_start (pthread_attr_t *attr) 85 | { 86 | logdbg(stderr,"enter log_thread_start\n"); 87 | 88 | pthread_mutex_init(&logq_lock, NULL); 89 | pthread_mutex_init(&logev_lock, NULL); 90 | pthread_cond_init(&logev_cond, NULL); 91 | 92 | if (log_init("multipathd", 0)) { 93 | fprintf(stderr,"can't initialize log buffer\n"); 94 | exit(1); 95 | } 96 | if (pthread_create(&log_thr, attr, log_thread, NULL)) { 97 | fprintf(stderr,"can't start log thread\n"); 98 | exit(1); 99 | } 100 | 101 | return; 102 | } 103 | 104 | void log_thread_reset (void) 105 | { 106 | logdbg(stderr,"resetting log\n"); 107 | 108 | pthread_mutex_lock(&logq_lock); 109 | log_reset("multipathd"); 110 | pthread_mutex_unlock(&logq_lock); 111 | } 112 | 113 | void log_thread_stop (void) 114 | { 115 | logdbg(stderr,"enter log_thread_stop\n"); 116 | 117 | pthread_mutex_lock(&logev_lock); 118 | logq_running = 0; 119 | pthread_cond_signal(&logev_cond); 120 | pthread_mutex_unlock(&logev_lock); 121 | 122 | pthread_mutex_lock(&logq_lock); 123 | pthread_cancel(log_thr); 124 | pthread_mutex_unlock(&logq_lock); 125 | pthread_join(log_thr, NULL); 126 | log_thr = (pthread_t)0; 127 | 128 | flush_logqueue(); 129 | 130 | pthread_mutex_destroy(&logq_lock); 131 | pthread_mutex_destroy(&logev_lock); 132 | pthread_cond_destroy(&logev_cond); 133 | 134 | log_close(); 135 | } 136 | -------------------------------------------------------------------------------- /libmultipath/log_pthread.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_PTHREAD_H 2 | #define _LOG_PTHREAD_H 3 | 4 | #include 5 | 6 | void log_safe(int prio, const char * fmt, va_list ap) 7 | __attribute__((format(printf, 2, 0))); 8 | void log_thread_start(pthread_attr_t *attr); 9 | void log_thread_reset (void); 10 | void log_thread_stop(void); 11 | 12 | #endif /* _LOG_PTHREAD_H */ 13 | -------------------------------------------------------------------------------- /libmultipath/memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Part: memory.c include file. 3 | * 4 | * Version: $Id: memory.h,v 1.1.11 2005/03/01 01:22:13 acassen Exp $ 5 | * 6 | * Authors: Alexandre Cassen, 7 | * Jan Holmberg, 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * This program is free software; you can redistribute it and/or 15 | * modify it under the terms of the GNU General Public License 16 | * as published by the Free Software Foundation; either version 17 | * 2 of the License, or (at your option) any later version. 18 | * 19 | * Copyright (C) 2001-2005 Alexandre Cassen, 20 | */ 21 | 22 | #ifndef _MEMORY_H 23 | #define _MEMORY_H 24 | 25 | /* system includes */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* Local defines */ 32 | #ifdef _DEBUG_ 33 | 34 | int debug; 35 | 36 | #define MAX_ALLOC_LIST 2048 37 | 38 | #define MALLOC(n) ( dbg_malloc((n), \ 39 | (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) 40 | #define FREE(b) ( dbg_free((b), \ 41 | (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) 42 | #define REALLOC(b,n) ( dbg_realloc((b), (n), \ 43 | (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) 44 | #define STRDUP(n) ( dbg_strdup((n), \ 45 | (__FILE__), (char *)(__FUNCTION__), (__LINE__)) ) 46 | 47 | /* Memory debug prototypes defs */ 48 | extern void *dbg_malloc(unsigned long, char *, char *, int); 49 | extern int dbg_free(void *, char *, char *, int); 50 | extern void *dbg_realloc(void *, unsigned long, char *, char *, int); 51 | extern char *dbg_strdup(char *, char *, char *, int); 52 | extern void dbg_free_final(char *); 53 | 54 | #else 55 | 56 | #define MALLOC(n) (calloc(1,(n))) 57 | #define FREE(p) do { free(p); p = NULL; } while(0) 58 | #define REALLOC(p,n) (realloc((p),(n))) 59 | #define STRDUP(n) (strdup(n)) 60 | 61 | #endif 62 | 63 | /* Common defines */ 64 | #define FREE_PTR(P) if((P)) FREE((P)); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /libmultipath/nvme-lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* avoid inclusion of standard API */ 3 | #define _NVME_LIB_C 1 4 | #include "nvme-lib.h" 5 | #include "nvme-ioctl.c" 6 | #include "debug.h" 7 | 8 | int log_nvme_errcode(int err, const char *dev, const char *msg) 9 | { 10 | if (err > 0) 11 | condlog(3, "%s: %s: NVMe status %d", dev, msg, err); 12 | else if (err < 0) 13 | condlog(3, "%s: %s: %s", dev, msg, strerror(errno)); 14 | return err; 15 | } 16 | 17 | int libmp_nvme_get_nsid(int fd) 18 | { 19 | return nvme_get_nsid(fd); 20 | } 21 | 22 | int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl) 23 | { 24 | return nvme_identify_ctrl(fd, ctrl); 25 | } 26 | 27 | int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, 28 | struct nvme_id_ns *ns) 29 | { 30 | return nvme_identify_ns(fd, nsid, present, ns); 31 | } 32 | 33 | int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo) 34 | { 35 | return nvme_ana_log(fd, ana_log, ana_log_len, rgo); 36 | } 37 | 38 | int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl) 39 | { 40 | int rc; 41 | struct nvme_id_ctrl c; 42 | 43 | rc = nvme_identify_ctrl(fd, &c); 44 | if (rc < 0) 45 | return rc; 46 | if (ctrl) 47 | *ctrl = c; 48 | return c.cmic & (1 << 3) ? 1 : 0; 49 | } 50 | -------------------------------------------------------------------------------- /libmultipath/nvme-lib.h: -------------------------------------------------------------------------------- 1 | #ifndef NVME_LIB_H 2 | #define NVME_LIB_H 3 | 4 | #include "nvme.h" 5 | 6 | int log_nvme_errcode(int err, const char *dev, const char *msg); 7 | int libmp_nvme_get_nsid(int fd); 8 | int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl); 9 | int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present, 10 | struct nvme_id_ns *ns); 11 | int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo); 12 | /* 13 | * Identify controller, and return true if ANA is supported 14 | * ctrl will be filled in if controller is identified, even w/o ANA 15 | * ctrl may be NULL 16 | */ 17 | int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl); 18 | 19 | #ifndef _NVME_LIB_C 20 | /* 21 | * In all files except nvme-lib.c, the nvme functions can be called 22 | * by their usual name. 23 | */ 24 | #define nvme_get_nsid libmp_nvme_get_nsid 25 | #define nvme_identify_ctrl libmp_nvme_identify_ctrl 26 | #define nvme_identify_ns libmp_nvme_identify_ns 27 | #define nvme_ana_log libmp_nvme_ana_log 28 | /* 29 | * Undefine these to avoid clashes with libmultipath's byteorder.h 30 | */ 31 | #undef cpu_to_le16 32 | #undef cpu_to_le32 33 | #undef cpu_to_le64 34 | #undef le16_to_cpu 35 | #undef le32_to_cpu 36 | #undef le64_to_cpu 37 | #endif 38 | 39 | #endif /* NVME_LIB_H */ 40 | -------------------------------------------------------------------------------- /libmultipath/nvme/argconfig.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright 2014 PMC-Sierra, Inc. 4 | // 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | // 19 | //////////////////////////////////////////////////////////////////////// 20 | 21 | //////////////////////////////////////////////////////////////////////// 22 | // 23 | // Author: Logan Gunthorpe 24 | // Logan Gunthorpe 25 | // 26 | // Date: Oct 23 2014 27 | // 28 | // Description: 29 | // Header file for argconfig.c 30 | // 31 | //////////////////////////////////////////////////////////////////////// 32 | 33 | #ifndef argconfig_H 34 | #define argconfig_H 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | enum argconfig_types { 41 | CFG_NONE, 42 | CFG_STRING, 43 | CFG_INT, 44 | CFG_SIZE, 45 | CFG_LONG, 46 | CFG_LONG_SUFFIX, 47 | CFG_DOUBLE, 48 | CFG_BOOL, 49 | CFG_BYTE, 50 | CFG_SHORT, 51 | CFG_POSITIVE, 52 | CFG_INCREMENT, 53 | CFG_SUBOPTS, 54 | CFG_FILE_A, 55 | CFG_FILE_W, 56 | CFG_FILE_R, 57 | CFG_FILE_AP, 58 | CFG_FILE_WP, 59 | CFG_FILE_RP, 60 | }; 61 | 62 | struct argconfig_commandline_options { 63 | const char *option; 64 | const char short_option; 65 | const char *meta; 66 | enum argconfig_types config_type; 67 | void *default_value; 68 | int argument_type; 69 | const char *help; 70 | }; 71 | 72 | #define CFG_MAX_SUBOPTS 500 73 | #define MAX_HELP_FUNC 20 74 | 75 | #ifdef __cplusplus 76 | extern "C" { 77 | #endif 78 | 79 | typedef void argconfig_help_func(); 80 | void argconfig_append_usage(const char *str); 81 | void argconfig_print_help(const char *program_desc, 82 | const struct argconfig_commandline_options *options); 83 | int argconfig_parse(int argc, char *argv[], const char *program_desc, 84 | const struct argconfig_commandline_options *options, 85 | void *config_out, size_t config_size); 86 | int argconfig_parse_subopt_string(char *string, char **options, 87 | size_t max_options); 88 | unsigned argconfig_parse_comma_sep_array(char *string, int *ret, 89 | unsigned max_length); 90 | unsigned argconfig_parse_comma_sep_array_long(char *string, 91 | unsigned long long *ret, 92 | unsigned max_length); 93 | void argconfig_register_help_func(argconfig_help_func * f); 94 | 95 | void print_word_wrapped(const char *s, int indent, int start); 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | #endif 100 | -------------------------------------------------------------------------------- /libmultipath/nvme/json.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSON__H 2 | #define __JSON__H 3 | 4 | struct json_object; 5 | struct json_array; 6 | struct json_pair; 7 | 8 | #define JSON_TYPE_STRING 0 9 | #define JSON_TYPE_INTEGER 1 10 | #define JSON_TYPE_FLOAT 2 11 | #define JSON_TYPE_OBJECT 3 12 | #define JSON_TYPE_ARRAY 4 13 | #define JSON_TYPE_UINT 5 14 | #define JSON_PARENT_TYPE_PAIR 0 15 | #define JSON_PARENT_TYPE_ARRAY 1 16 | struct json_value { 17 | int type; 18 | union { 19 | long long integer_number; 20 | unsigned long long uint_number; 21 | long double float_number; 22 | char *string; 23 | struct json_object *object; 24 | struct json_array *array; 25 | }; 26 | int parent_type; 27 | union { 28 | struct json_pair *parent_pair; 29 | struct json_array *parent_array; 30 | }; 31 | }; 32 | 33 | struct json_array { 34 | struct json_value **values; 35 | int value_cnt; 36 | struct json_value *parent; 37 | }; 38 | 39 | struct json_object { 40 | struct json_pair **pairs; 41 | int pair_cnt; 42 | struct json_value *parent; 43 | }; 44 | 45 | struct json_pair { 46 | char *name; 47 | struct json_value *value; 48 | struct json_object *parent; 49 | }; 50 | 51 | struct json_object *json_create_object(void); 52 | struct json_array *json_create_array(void); 53 | 54 | void json_free_object(struct json_object *obj); 55 | 56 | int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...); 57 | #define json_object_add_value_int(obj, name, val) \ 58 | json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val)) 59 | #define json_object_add_value_uint(obj, name, val) \ 60 | json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val)) 61 | #define json_object_add_value_float(obj, name, val) \ 62 | json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val)) 63 | #define json_object_add_value_string(obj, name, val) \ 64 | json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val)) 65 | #define json_object_add_value_object(obj, name, val) \ 66 | json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val)) 67 | #define json_object_add_value_array(obj, name, val) \ 68 | json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val)) 69 | int json_array_add_value_type(struct json_array *array, int type, ...); 70 | #define json_array_add_value_int(obj, val) \ 71 | json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val)) 72 | #define json_array_add_value_uint(obj, val) \ 73 | json_array_add_value_type((obj), JSON_TYPE_UINT, (val)) 74 | #define json_array_add_value_float(obj, val) \ 75 | json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val)) 76 | #define json_array_add_value_string(obj, val) \ 77 | json_array_add_value_type((obj), JSON_TYPE_STRING, (val)) 78 | #define json_array_add_value_object(obj, val) \ 79 | json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val)) 80 | #define json_array_add_value_array(obj, val) \ 81 | json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val)) 82 | 83 | #define json_array_last_value_object(obj) \ 84 | (obj->values[obj->value_cnt - 1]->object) 85 | 86 | void json_print_object(struct json_object *obj, void *); 87 | #endif 88 | -------------------------------------------------------------------------------- /libmultipath/nvme/linux/nvme_ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Definitions for the NVM Express ioctl interface 3 | * Copyright (c) 2011-2014, Intel Corporation. 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms and conditions of the GNU General Public License, 7 | * version 2, as published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | */ 14 | 15 | #ifndef _UAPI_LINUX_NVME_IOCTL_H 16 | #define _UAPI_LINUX_NVME_IOCTL_H 17 | 18 | #include 19 | #include 20 | 21 | struct nvme_user_io { 22 | __u8 opcode; 23 | __u8 flags; 24 | __u16 control; 25 | __u16 nblocks; 26 | __u16 rsvd; 27 | __u64 metadata; 28 | __u64 addr; 29 | __u64 slba; 30 | __u32 dsmgmt; 31 | __u32 reftag; 32 | __u16 apptag; 33 | __u16 appmask; 34 | }; 35 | 36 | struct nvme_passthru_cmd { 37 | __u8 opcode; 38 | __u8 flags; 39 | __u16 rsvd1; 40 | __u32 nsid; 41 | __u32 cdw2; 42 | __u32 cdw3; 43 | __u64 metadata; 44 | __u64 addr; 45 | __u32 metadata_len; 46 | __u32 data_len; 47 | __u32 cdw10; 48 | __u32 cdw11; 49 | __u32 cdw12; 50 | __u32 cdw13; 51 | __u32 cdw14; 52 | __u32 cdw15; 53 | __u32 timeout_ms; 54 | __u32 result; 55 | }; 56 | 57 | #define nvme_admin_cmd nvme_passthru_cmd 58 | 59 | #define NVME_IOCTL_ID _IO('N', 0x40) 60 | #define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd) 61 | #define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io) 62 | #define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd) 63 | #define NVME_IOCTL_RESET _IO('N', 0x44) 64 | #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) 65 | #define NVME_IOCTL_RESCAN _IO('N', 0x46) 66 | 67 | #endif /* _UAPI_LINUX_NVME_IOCTL_H */ 68 | -------------------------------------------------------------------------------- /libmultipath/nvme/plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef PLUGIN_H 2 | #define PLUGIN_H 3 | 4 | #include 5 | 6 | struct program { 7 | const char *name; 8 | const char *version; 9 | const char *usage; 10 | const char *desc; 11 | const char *more; 12 | struct command **commands; 13 | struct plugin *extensions; 14 | }; 15 | 16 | struct plugin { 17 | const char *name; 18 | const char *desc; 19 | struct command **commands; 20 | struct program *parent; 21 | struct plugin *next; 22 | struct plugin *tail; 23 | }; 24 | 25 | struct command { 26 | char *name; 27 | char *help; 28 | int (*fn)(int argc, char **argv, struct command *command, struct plugin *plugin); 29 | char *alias; 30 | }; 31 | 32 | void usage(struct plugin *plugin); 33 | void general_help(struct plugin *plugin); 34 | int handle_plugin(int argc, char **argv, struct plugin *plugin); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /libmultipath/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Soft: Keepalived is a failover program for the LVS project 3 | * . It monitor & manipulate 4 | * a loadbalanced server pool using multi-layer checks. 5 | * 6 | * Part: cfreader.c include file. 7 | * 8 | * Version: $Id: parser.h,v 1.0.3 2003/05/11 02:28:03 acassen Exp $ 9 | * 10 | * Author: Alexandre Cassen, 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | * See the GNU General Public License for more details. 16 | * 17 | * This program is free software; you can redistribute it and/or 18 | * modify it under the terms of the GNU General Public License 19 | * as published by the Free Software Foundation; either version 20 | * 2 of the License, or (at your option) any later version. 21 | */ 22 | 23 | #ifndef _PARSER_H 24 | #define _PARSER_H 25 | 26 | /* system includes */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /* local includes */ 35 | #include "vector.h" 36 | #include "config.h" 37 | 38 | /* Global definitions */ 39 | #define EOB "}" 40 | #define MAXBUF 1024 41 | 42 | /* ketword definition */ 43 | struct keyword { 44 | char *string; 45 | int (*handler) (struct config *, vector); 46 | int (*print) (struct config *, char *, int, const void *); 47 | vector sub; 48 | int unique; 49 | }; 50 | 51 | /* Reloading helpers */ 52 | #define SET_RELOAD (reload = 1) 53 | #define UNSET_RELOAD (reload = 0) 54 | #define RELOAD_DELAY 5 55 | 56 | /* iterator helper */ 57 | #define iterate_sub_keywords(k,p,i) \ 58 | for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++) 59 | 60 | /* Prototypes */ 61 | extern int keyword_alloc(vector keywords, char *string, 62 | int (*handler) (struct config *, vector), 63 | int (*print) (struct config *, char *, int, 64 | const void *), 65 | int unique); 66 | #define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1) 67 | extern void install_sublevel(void); 68 | extern void install_sublevel_end(void); 69 | extern int _install_keyword(vector keywords, char *string, 70 | int (*handler) (struct config *, vector), 71 | int (*print) (struct config *, char *, int, 72 | const void *), 73 | int unique); 74 | #define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1) 75 | #define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0) 76 | extern void dump_keywords(vector keydump, int level); 77 | extern void free_keywords(vector keywords); 78 | extern vector alloc_strvec(char *string); 79 | extern void *set_value(vector strvec); 80 | extern int process_file(struct config *conf, char *conf_file); 81 | extern struct keyword * find_keyword(vector keywords, vector v, char * name); 82 | int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, 83 | const void *data); 84 | bool is_quote(const char* token); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /libmultipath/pgpolicies.h: -------------------------------------------------------------------------------- 1 | #ifndef _PGPOLICIES_H 2 | #define _PGPOLICIES_H 3 | 4 | #if 0 5 | #ifndef _MAIN_H 6 | #include "main.h" 7 | #endif 8 | #endif 9 | 10 | #define POLICY_NAME_SIZE 32 11 | 12 | /* Storage controllers capabilities */ 13 | enum iopolicies { 14 | IOPOLICY_UNDEF, 15 | FAILOVER, 16 | MULTIBUS, 17 | GROUP_BY_SERIAL, 18 | GROUP_BY_PRIO, 19 | GROUP_BY_NODE_NAME 20 | }; 21 | 22 | int get_pgpolicy_id(char *); 23 | int get_pgpolicy_name (char *, int, int); 24 | int group_paths(struct multipath *, int); 25 | /* 26 | * policies 27 | */ 28 | int one_path_per_group(struct multipath *, vector); 29 | int one_group(struct multipath *, vector); 30 | int group_by_serial(struct multipath *, vector); 31 | int group_by_prio(struct multipath *, vector); 32 | int group_by_node_name(struct multipath *, vector); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /libmultipath/prio.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIO_H 2 | #define _PRIO_H 3 | 4 | /* 5 | * knowing about path struct gives flexibility to prioritizers 6 | */ 7 | #include "checkers.h" 8 | #include "vector.h" 9 | 10 | /* forward declaration to avoid circular dependency */ 11 | struct path; 12 | 13 | #include "list.h" 14 | #include "memory.h" 15 | #include "defaults.h" 16 | 17 | /* 18 | * Known prioritizers for use in hwtable.c 19 | */ 20 | #define PRIO_ALUA "alua" 21 | #define PRIO_CONST "const" 22 | #define PRIO_DATACORE "datacore" 23 | #define PRIO_EMC "emc" 24 | #define PRIO_HDS "hds" 25 | #define PRIO_HP_SW "hp_sw" 26 | #define PRIO_IET "iet" 27 | #define PRIO_ONTAP "ontap" 28 | #define PRIO_RANDOM "random" 29 | #define PRIO_RDAC "rdac" 30 | #define PRIO_WEIGHTED_PATH "weightedpath" 31 | #define PRIO_SYSFS "sysfs" 32 | #define PRIO_PATH_LATENCY "path_latency" 33 | #define PRIO_ANA "ana" 34 | 35 | /* 36 | * Value used to mark the fact prio was not defined 37 | */ 38 | #define PRIO_UNDEF -1 39 | 40 | /* 41 | * strings lengths 42 | */ 43 | #define LIB_PRIO_NAMELEN 255 44 | #define PRIO_NAME_LEN 16 45 | #define PRIO_ARGS_LEN 255 46 | 47 | struct prio { 48 | void *handle; 49 | int refcount; 50 | struct list_head node; 51 | char name[PRIO_NAME_LEN]; 52 | char args[PRIO_ARGS_LEN]; 53 | int (*getprio)(struct path *, char *, unsigned int); 54 | }; 55 | 56 | unsigned int get_prio_timeout(unsigned int checker_timeout, 57 | unsigned int default_timeout); 58 | int init_prio (char *); 59 | void cleanup_prio (void); 60 | struct prio * add_prio (char *, char *); 61 | int prio_getprio (struct prio *, struct path *, unsigned int); 62 | void prio_get (char *, struct prio *, char *, char *); 63 | void prio_put (struct prio *); 64 | int prio_selected (const struct prio *); 65 | const char * prio_name (const struct prio *); 66 | const char * prio_args (const struct prio *); 67 | int prio_set_args (struct prio *, const char *); 68 | 69 | /* The only function exported by prioritizer dynamic libraries (.so) */ 70 | int getprio(struct path *, char *, unsigned int); 71 | 72 | #endif /* _PRIO_H */ 73 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2007 Christophe Varoqui, 3 | # 4 | include ../../Makefile.inc 5 | 6 | CFLAGS += $(LIB_CFLAGS) -I.. 7 | 8 | # If you add or remove a prioritizer also update multipath/multipath.conf.5 9 | LIBS = \ 10 | libprioalua.so \ 11 | libprioconst.so \ 12 | libpriodatacore.so \ 13 | libprioemc.so \ 14 | libpriohds.so \ 15 | libpriohp_sw.so \ 16 | libprioiet.so \ 17 | libprioontap.so \ 18 | libpriorandom.so \ 19 | libpriordac.so \ 20 | libprioweightedpath.so \ 21 | libpriopath_latency.so \ 22 | libpriosysfs.so 23 | 24 | ifneq ($(call check_file,/usr/include/linux/nvme_ioctl.h),0) 25 | LIBS += libprioana.so 26 | CFLAGS += -I../nvme 27 | endif 28 | 29 | all: $(LIBS) 30 | 31 | libpriopath_latency.so: path_latency.o 32 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ -lm 33 | 34 | libprio%.so: %.o 35 | $(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@ $^ 36 | 37 | install: $(LIBS) 38 | $(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir) 39 | 40 | uninstall: 41 | for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done 42 | 43 | clean: dep_clean 44 | $(RM) core *.a *.o *.gz *.so 45 | 46 | OBJS = $(LIBS:libprio%.so=%.o) alua_rtpg.o 47 | .SECONDARY: $(OBJS) 48 | 49 | include $(wildcard $(OBJS:.o=.d)) 50 | 51 | dep_clean: 52 | $(RM) $(OBJS:.o=.d) 53 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/alua.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALUA_H 2 | #define _ALUA_H 3 | 4 | #include "alua_rtpg.h" 5 | 6 | #define PRIO_ALUA "alua" 7 | int prio_alua(struct path * pp); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/alua_rtpg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved. 3 | * 4 | * rtpg.h 5 | * 6 | * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access. 7 | * It determines the ALUA state of a device and prints a priority value to 8 | * stdout. 9 | * 10 | * Author(s): Jan Kunigk 11 | * S. Bader 12 | * 13 | * This file is released under the GPL. 14 | */ 15 | #ifndef __RTPG_H__ 16 | #define __RTPG_H__ 17 | #include "alua_spc3.h" 18 | 19 | #define RTPG_SUCCESS 0 20 | #define RTPG_INQUIRY_FAILED 1 21 | #define RTPG_NO_TPG_IDENTIFIER 2 22 | #define RTPG_RTPG_FAILED 3 23 | #define RTPG_TPG_NOT_FOUND 4 24 | 25 | int get_target_port_group_support(const struct path *pp, unsigned int timeout); 26 | int get_target_port_group(const struct path *pp, unsigned int timeout); 27 | int get_asymmetric_access_state(const struct path *pp, 28 | unsigned int tpg, unsigned int timeout); 29 | 30 | #endif /* __RTPG_H__ */ 31 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/const.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "prio.h" 4 | 5 | int getprio(__attribute__((unused)) struct path * pp, 6 | __attribute__((unused)) char * args, 7 | __attribute__((unused)) unsigned int timeout) 8 | { 9 | return 1; 10 | } 11 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/datacore.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2010 Christophe Varoqui 3 | * (C) 2009 Dembach Goo Infromatik GmbH & Co KG 4 | * Manon Goo 5 | * 6 | * datacore.c 7 | * Version 0.9 8 | * 9 | * This program was inspired by work from 10 | * Matthias Rudolph 11 | * 12 | * This work is made available on the basis of the 13 | * GPLv2 for detials see . 14 | * 15 | * Manon Goo 2009 16 | * 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include "sg_include.h" 25 | #include "debug.h" 26 | #include "prio.h" 27 | #include "structs.h" 28 | 29 | #define INQ_REPLY_LEN 255 30 | #define INQ_CMD_CODE 0x12 31 | #define INQ_CMD_LEN 6 32 | 33 | #define dc_log(prio, msg) condlog(prio, "%s: datacore prio: " msg, dev) 34 | 35 | int datacore_prio (const char *dev, int sg_fd, char * args) 36 | { 37 | int k; 38 | char sdsname[32]; 39 | unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 }; 40 | unsigned char inqBuff[INQ_REPLY_LEN]; 41 | unsigned char *inqBuffp = inqBuff; 42 | unsigned char sense_buffer[32]; 43 | sg_io_hdr_t io_hdr; 44 | 45 | int timeout = 2000; 46 | char preferredsds_buff[255] = ""; 47 | char * preferredsds = &preferredsds_buff[0]; 48 | 49 | if (!args) { 50 | dc_log(0, "need prio_args with preferredsds set"); 51 | return 0; 52 | } 53 | 54 | if (sscanf(args, "timeout=%i preferredsds=%s", 55 | &timeout, preferredsds) == 2) {} 56 | else if (sscanf(args, "preferredsds=%s timeout=%i", 57 | preferredsds, &timeout) == 2) {} 58 | else if (sscanf(args, "preferredsds=%s", 59 | preferredsds) == 1) {} 60 | else { 61 | dc_log(0, "unexpected prio_args format"); 62 | return 0; 63 | } 64 | 65 | // on error just return prio 0 66 | if (strlen(preferredsds) <= 1) { 67 | dc_log(0, "prio args: preferredsds too short (1 character min)"); 68 | return 0; 69 | } 70 | if ((timeout < 500) || (timeout > 20000)) { 71 | dc_log(0, "prio args: timeout out of bounds [500:20000]"); 72 | return 0; 73 | } 74 | if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) 75 | return 0; 76 | 77 | memset (&io_hdr, 0, sizeof (sg_io_hdr_t)); 78 | io_hdr.interface_id = 'S'; 79 | io_hdr.cmd_len = sizeof (inqCmdBlk); 80 | io_hdr.mx_sb_len = sizeof (sense_buffer); 81 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 82 | io_hdr.dxfer_len = INQ_REPLY_LEN; 83 | io_hdr.dxferp = inqBuff; 84 | io_hdr.cmdp = inqCmdBlk; 85 | io_hdr.sbp = sense_buffer; 86 | io_hdr.timeout = timeout; 87 | 88 | // on error just return prio 0 89 | if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) 90 | return 0; 91 | if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) 92 | return 0; 93 | 94 | snprintf(sdsname, sizeof(sdsname), "%.16s", inqBuffp + 112); 95 | 96 | if (strstr(sdsname , preferredsds)) 97 | return 1; 98 | return 0; 99 | } 100 | 101 | int getprio(struct path * pp, char * args, 102 | __attribute__((unused)) unsigned int timeout) 103 | { 104 | return datacore_prio(pp->dev, pp->fd, args); 105 | } 106 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/emc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "sg_include.h" 6 | #include "debug.h" 7 | #include "prio.h" 8 | #include "structs.h" 9 | 10 | #define INQUIRY_CMD 0x12 11 | #define INQUIRY_CMDLEN 6 12 | 13 | #define pp_emc_log(prio, msg) condlog(prio, "%s: emc prio: " msg, dev) 14 | 15 | int emc_clariion_prio(const char *dev, int fd, unsigned int timeout) 16 | { 17 | unsigned char sense_buffer[128]; 18 | unsigned char sb[128]; 19 | unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0, 20 | sizeof(sense_buffer), 0}; 21 | struct sg_io_hdr io_hdr; 22 | int ret = PRIO_UNDEF; 23 | 24 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 25 | memset(&sense_buffer, 0, 128); 26 | io_hdr.interface_id = 'S'; 27 | io_hdr.cmd_len = sizeof (inqCmdBlk); 28 | io_hdr.mx_sb_len = sizeof (sb); 29 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 30 | io_hdr.dxfer_len = sizeof (sense_buffer); 31 | io_hdr.dxferp = sense_buffer; 32 | io_hdr.cmdp = inqCmdBlk; 33 | io_hdr.sbp = sb; 34 | io_hdr.timeout = get_prio_timeout(timeout, 60000); 35 | io_hdr.pack_id = 0; 36 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 37 | pp_emc_log(0, "sending query command failed"); 38 | goto out; 39 | } 40 | if (io_hdr.info & SG_INFO_OK_MASK) { 41 | pp_emc_log(0, "query command indicates error"); 42 | goto out; 43 | } 44 | 45 | if (/* Verify the code page - right page & revision */ 46 | sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) { 47 | pp_emc_log(0, "path unit report page in unknown format"); 48 | goto out; 49 | } 50 | 51 | if ( /* Effective initiator type */ 52 | sense_buffer[27] != 0x03 53 | /* 54 | * Failover mode should be set to 1 (PNR failover mode) 55 | * or 4 (ALUA failover mode). 56 | */ 57 | || (((sense_buffer[28] & 0x07) != 0x04) && 58 | ((sense_buffer[28] & 0x07) != 0x06)) 59 | /* Arraycommpath should be set to 1 */ 60 | || (sense_buffer[30] & 0x04) != 0x04) { 61 | pp_emc_log(0, "path not correctly configured for failover"); 62 | goto out; 63 | } 64 | 65 | if ( /* LUN operations should indicate normal operations */ 66 | sense_buffer[48] != 0x00) { 67 | pp_emc_log(0, "path not available for normal operations"); 68 | goto out; 69 | } 70 | 71 | /* LUN state: unbound, bound, or owned */ 72 | ret = sense_buffer[4]; 73 | 74 | /* Is the default owner equal to this path? */ 75 | /* Note this will switch to the default priority group, even if 76 | * it is not the currently active one. */ 77 | if (sense_buffer[5] == sense_buffer[8]) 78 | ret+=2; 79 | 80 | out: 81 | return(ret); 82 | } 83 | 84 | int getprio (struct path *pp, __attribute__((unused)) char *args, 85 | unsigned int timeout) 86 | { 87 | return emc_clariion_prio(pp->dev, pp->fd, timeout); 88 | } 89 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/hp_sw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Path priority checker for HP active/standby controller 3 | * 4 | * Check the path state and sort them into groups. 5 | * There is actually a preferred path in the controller; 6 | * we should ask HP on how to retrieve that information. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "sg_include.h" 16 | #include "debug.h" 17 | #include "prio.h" 18 | #include "structs.h" 19 | 20 | #define TUR_CMD_LEN 6 21 | #define SCSI_CHECK_CONDITION 0x2 22 | #define SCSI_COMMAND_TERMINATED 0x22 23 | #define SG_ERR_DRIVER_SENSE 0x08 24 | #define RECOVERED_ERROR 0x01 25 | #define NOT_READY 0x02 26 | #define UNIT_ATTENTION 0x06 27 | 28 | #define HP_PATH_ACTIVE 0x04 29 | #define HP_PATH_STANDBY 0x02 30 | #define HP_PATH_FAILED 0x00 31 | 32 | #define pp_hp_sw_log(prio, fmt, args...) \ 33 | condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args) 34 | 35 | int hp_sw_prio(const char *dev, int fd, unsigned int timeout) 36 | { 37 | unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; 38 | unsigned char sb[128]; 39 | struct sg_io_hdr io_hdr; 40 | int ret = HP_PATH_FAILED; 41 | 42 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 43 | io_hdr.interface_id = 'S'; 44 | io_hdr.cmd_len = sizeof (turCmdBlk); 45 | io_hdr.mx_sb_len = sizeof (sb); 46 | io_hdr.dxfer_direction = SG_DXFER_NONE; 47 | io_hdr.cmdp = turCmdBlk; 48 | io_hdr.sbp = sb; 49 | io_hdr.timeout = get_prio_timeout(timeout, 60000); 50 | io_hdr.pack_id = 0; 51 | retry: 52 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 53 | pp_hp_sw_log(0, "sending tur command failed"); 54 | goto out; 55 | } 56 | io_hdr.status &= 0x7e; 57 | if ((0 == io_hdr.status) && (0 == io_hdr.host_status) && 58 | (0 == io_hdr.driver_status)) { 59 | /* Command completed normally, path is active */ 60 | ret = HP_PATH_ACTIVE; 61 | } 62 | 63 | if ((SCSI_CHECK_CONDITION == io_hdr.status) || 64 | (SCSI_COMMAND_TERMINATED == io_hdr.status) || 65 | (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) { 66 | if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) { 67 | int sense_key, asc, asq; 68 | unsigned char * sense_buffer = io_hdr.sbp; 69 | if (sense_buffer[0] & 0x2) { 70 | sense_key = sense_buffer[1] & 0xf; 71 | asc = sense_buffer[2]; 72 | asq = sense_buffer[3]; 73 | } else { 74 | sense_key = sense_buffer[2] & 0xf; 75 | asc = sense_buffer[12]; 76 | asq = sense_buffer[13]; 77 | } 78 | if(RECOVERED_ERROR == sense_key) 79 | ret = HP_PATH_ACTIVE; 80 | if(NOT_READY == sense_key) { 81 | if (asc == 0x04 && asq == 0x02) { 82 | /* This is a standby path */ 83 | ret = HP_PATH_STANDBY; 84 | } 85 | } 86 | if(UNIT_ATTENTION == sense_key) { 87 | if (asc == 0x29) { 88 | /* Retry for device reset */ 89 | goto retry; 90 | } 91 | } 92 | } 93 | } 94 | out: 95 | return(ret); 96 | } 97 | 98 | int getprio (struct path *pp, __attribute__((unused)) char *args, 99 | unsigned int timeout) 100 | { 101 | return hp_sw_prio(pp->dev, pp->fd, timeout); 102 | } 103 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "prio.h" 7 | 8 | int getprio(__attribute__((unused)) struct path *pp, 9 | __attribute__((unused)) char *args, 10 | __attribute__((unused)) unsigned int timeout) 11 | { 12 | struct timeval tv; 13 | 14 | gettimeofday(&tv, NULL); 15 | srand((unsigned int)tv.tv_usec); 16 | return 1+(int) (10.0*rand()/(RAND_MAX+1.0)); 17 | } 18 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/rdac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "sg_include.h" 6 | #include "debug.h" 7 | #include "prio.h" 8 | #include "structs.h" 9 | 10 | #define INQUIRY_CMD 0x12 11 | #define INQUIRY_CMDLEN 6 12 | 13 | #define pp_rdac_log(prio, msg) condlog(prio, "%s: rdac prio: " msg, dev) 14 | 15 | int rdac_prio(const char *dev, int fd, unsigned int timeout) 16 | { 17 | unsigned char sense_buffer[128]; 18 | unsigned char sb[128]; 19 | unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0, 20 | sizeof(sense_buffer), 0}; 21 | struct sg_io_hdr io_hdr; 22 | int ret = 0; 23 | 24 | memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); 25 | memset(sense_buffer, 0, 128); 26 | io_hdr.interface_id = 'S'; 27 | io_hdr.cmd_len = sizeof (inqCmdBlk); 28 | io_hdr.mx_sb_len = sizeof (sb); 29 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; 30 | io_hdr.dxfer_len = sizeof (sense_buffer); 31 | io_hdr.dxferp = sense_buffer; 32 | io_hdr.cmdp = inqCmdBlk; 33 | io_hdr.sbp = sb; 34 | io_hdr.timeout = get_prio_timeout(timeout, 60000); 35 | io_hdr.pack_id = 0; 36 | if (ioctl(fd, SG_IO, &io_hdr) < 0) { 37 | pp_rdac_log(0, "sending inquiry command failed"); 38 | goto out; 39 | } 40 | if (io_hdr.info & SG_INFO_OK_MASK) { 41 | pp_rdac_log(0, "inquiry command indicates error"); 42 | goto out; 43 | } 44 | 45 | if (/* Verify the code page - right page & page identifier */ 46 | sense_buffer[1] != 0xc9 || 47 | sense_buffer[3] != 0x2c || 48 | sense_buffer[4] != 'v' || 49 | sense_buffer[5] != 'a' || 50 | sense_buffer[6] != 'c' ) { 51 | pp_rdac_log(0, "volume access control page in unknown format"); 52 | goto out; 53 | } 54 | 55 | if ( /* Current Volume Path Bit */ 56 | ( sense_buffer[8] & 0x01) == 0x01 ) { 57 | /* 58 | * This volume was owned by the controller receiving 59 | * the inquiry command. 60 | */ 61 | ret |= 0x02; 62 | } 63 | 64 | /* Volume Preferred Path Priority */ 65 | switch ( sense_buffer[9] & 0x0F ) { 66 | case 0x01: 67 | /* 68 | * Access to this volume is most preferred through 69 | * this path and other paths with this value. 70 | */ 71 | ret |= 0x04; 72 | break; 73 | case 0x02: 74 | /* 75 | * Access to this volume through this path is to be used 76 | * as a secondary path. Typically this path would be used 77 | * for fail-over situations. 78 | */ 79 | ret |= 0x01; 80 | break; 81 | default: 82 | /* Reserved values */ 83 | break; 84 | } 85 | 86 | /* For ioship mode set the bit 3 (00001000) */ 87 | if ((sense_buffer[8] >> 5) & 0x01) 88 | ret |= 0x08; 89 | 90 | out: 91 | return(ret); 92 | } 93 | 94 | int getprio (struct path *pp, __attribute__((unused)) char *args, 95 | unsigned int timeout) 96 | { 97 | return rdac_prio(pp->dev, pp->fd, timeout); 98 | } 99 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/sysfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sysfs.c 3 | * 4 | * Copyright(c) 2016 Hannes Reinecke, SUSE Linux GmbH 5 | */ 6 | 7 | #include 8 | 9 | #include "structs.h" 10 | #include "discovery.h" 11 | #include "prio.h" 12 | 13 | static const struct { 14 | unsigned char value; 15 | char *name; 16 | } sysfs_access_state_map[] = { 17 | { 50, "active/optimized" }, 18 | { 10, "active/non-optimized" }, 19 | { 5, "lba-dependent" }, 20 | { 1, "standby" }, 21 | }; 22 | 23 | int get_exclusive_pref_arg(char *args) 24 | { 25 | char *ptr; 26 | 27 | if (args == NULL) 28 | return 0; 29 | ptr = strstr(args, "exclusive_pref_bit"); 30 | if (!ptr) 31 | return 0; 32 | if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t') 33 | return 0; 34 | if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t') 35 | return 0; 36 | return 1; 37 | } 38 | 39 | int getprio (struct path * pp, char *args, 40 | __attribute__((unused)) unsigned int timeout) 41 | { 42 | int prio = 0, rc, i; 43 | char buff[512]; 44 | int exclusive_pref; 45 | 46 | exclusive_pref = get_exclusive_pref_arg(args); 47 | rc = sysfs_get_asymmetric_access_state(pp, buff, 512); 48 | if (rc < 0) 49 | return PRIO_UNDEF; 50 | prio = 0; 51 | for (i = 0; i < 4; i++) { 52 | if (!strncmp(buff, sysfs_access_state_map[i].name, 53 | strlen(sysfs_access_state_map[i].name))) { 54 | prio = sysfs_access_state_map[i].value; 55 | break; 56 | } 57 | } 58 | if (rc > 0 && (prio != 50 || exclusive_pref)) 59 | prio += 80; 60 | 61 | return prio; 62 | } 63 | -------------------------------------------------------------------------------- /libmultipath/prioritizers/weightedpath.h: -------------------------------------------------------------------------------- 1 | #ifndef _WEIGHTED_PATH_H 2 | #define _WEIGHTED_PATH_H 3 | 4 | #define PRIO_WEIGHTED_PATH "weightedpath" 5 | #define HBTL "hbtl" 6 | #define DEV_NAME "devname" 7 | #define SERIAL "serial" 8 | #define WWN "wwn" 9 | #define DEFAULT_PRIORITY 0 10 | 11 | int prio_path_weight(struct path *pp, char *prio_args); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /libmultipath/prkey.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRKEY_H 2 | #define _PRKEY_H 3 | 4 | #include "structs.h" 5 | #include 6 | 7 | #define PRKEYS_FILE_HEADER \ 8 | "# Multipath persistent reservation keys, Version : 1.0\n" \ 9 | "# NOTE: this file is automatically maintained by the multipathd program.\n" \ 10 | "# You should not need to edit this file in normal circumstances.\n" \ 11 | "#\n" \ 12 | "# Format:\n" \ 13 | "# prkey wwid\n" \ 14 | "#\n" 15 | 16 | int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey, 17 | uint8_t sa_flags); 18 | int get_prkey(struct config *conf, struct multipath *mpp, uint64_t *prkey, 19 | uint8_t *sa_flags); 20 | 21 | #endif /* _PRKEY_H */ 22 | -------------------------------------------------------------------------------- /libmultipath/propsel.h: -------------------------------------------------------------------------------- 1 | int select_rr_weight (struct config *conf, struct multipath * mp); 2 | int select_pgfailback (struct config *conf, struct multipath * mp); 3 | int select_pgpolicy (struct config *conf, struct multipath * mp); 4 | int select_selector (struct config *conf, struct multipath * mp); 5 | int select_alias (struct config *conf, struct multipath * mp); 6 | int select_features (struct config *conf, struct multipath * mp); 7 | int select_hwhandler (struct config *conf, struct multipath * mp); 8 | int select_checker(struct config *conf, struct path *pp); 9 | int select_getuid (struct config *conf, struct path * pp); 10 | int select_prio (struct config *conf, struct path * pp); 11 | int select_find_multipaths_timeout(struct config *conf, struct path *pp); 12 | int select_no_path_retry(struct config *conf, struct multipath *mp); 13 | int select_flush_on_last_del(struct config *conf, struct multipath *mp); 14 | int select_minio(struct config *conf, struct multipath *mp); 15 | int select_mode(struct config *conf, struct multipath *mp); 16 | int select_uid(struct config *conf, struct multipath *mp); 17 | int select_gid(struct config *conf, struct multipath *mp); 18 | int select_fast_io_fail(struct config *conf, struct multipath *mp); 19 | int select_dev_loss(struct config *conf, struct multipath *mp); 20 | int select_reservation_key(struct config *conf, struct multipath *mp); 21 | int select_retain_hwhandler (struct config *conf, struct multipath * mp); 22 | int select_detect_prio(struct config *conf, struct path * pp); 23 | int select_detect_checker(struct config *conf, struct path * pp); 24 | int select_deferred_remove(struct config *conf, struct multipath *mp); 25 | int select_delay_checks(struct config *conf, struct multipath * mp); 26 | int select_skip_kpartx (struct config *conf, struct multipath * mp); 27 | int select_max_sectors_kb (struct config *conf, struct multipath * mp); 28 | int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp); 29 | int select_san_path_err_threshold(struct config *conf, struct multipath *mp); 30 | int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp); 31 | int select_marginal_path_err_sample_time(struct config *conf, struct multipath *mp); 32 | int select_marginal_path_err_rate_threshold(struct config *conf, struct multipath *mp); 33 | int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multipath *mp); 34 | int select_marginal_path_double_failed_time(struct config *conf, struct multipath *mp); 35 | int select_ghost_delay(struct config *conf, struct multipath * mp); 36 | void reconcile_features_with_options(const char *id, char **features, 37 | int* no_path_retry, 38 | int *retain_hwhandler); 39 | int select_all_tg_pt (struct config *conf, struct multipath * mp); 40 | int select_vpd_vendor_id (struct path *pp); 41 | -------------------------------------------------------------------------------- /libmultipath/sg_include.h: -------------------------------------------------------------------------------- 1 | #define __user 2 | #include 3 | 4 | #ifndef DID_OK 5 | #define DID_OK 0x00 /* NO error */ 6 | #define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ 7 | #define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ 8 | #define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ 9 | #define DID_BAD_TARGET 0x04 /* BAD target. */ 10 | #define DID_ABORT 0x05 /* Told to abort for some other reason */ 11 | #define DID_PARITY 0x06 /* Parity error */ 12 | #define DID_ERROR 0x07 /* Internal error */ 13 | #define DID_RESET 0x08 /* Reset by somebody. */ 14 | #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ 15 | #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ 16 | #define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ 17 | #define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ 18 | #define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also 19 | * without decrementing the retry count */ 20 | #define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution 21 | * and the driver blocked the port to 22 | * recover the link. Transport class will 23 | * retry or fail IO */ 24 | #define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */ 25 | #endif 26 | -------------------------------------------------------------------------------- /libmultipath/structs_vec.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRUCTS_VEC_H 2 | #define _STRUCTS_VEC_H 3 | 4 | #include "vector.h" 5 | #include "config.h" 6 | #include "lock.h" 7 | 8 | struct vectors { 9 | struct mutex_lock lock; /* defined in lock.h */ 10 | vector pathvec; 11 | vector mpvec; 12 | }; 13 | 14 | void __set_no_path_retry(struct multipath *mpp, bool check_features); 15 | #define set_no_path_retry(mpp) __set_no_path_retry(mpp, true) 16 | 17 | int adopt_paths (vector pathvec, struct multipath * mpp); 18 | void orphan_paths(vector pathvec, struct multipath *mpp, 19 | const char *reason); 20 | void orphan_path (struct path * pp, const char *reason); 21 | void set_path_removed(struct path *pp); 22 | 23 | int verify_paths(struct multipath *mpp); 24 | bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp, 25 | int pathinfo_flags); 26 | int update_mpp_paths(struct multipath * mpp, vector pathvec); 27 | int update_multipath_strings (struct multipath *mpp, vector pathvec); 28 | void extract_hwe_from_path(struct multipath * mpp); 29 | 30 | enum { 31 | KEEP_VEC, 32 | PURGE_VEC, 33 | }; 34 | 35 | void remove_map (struct multipath *mpp, vector pathvec, vector mpvec, 36 | int purge_vec); 37 | void remove_map_by_alias(const char *alias, struct vectors * vecs, 38 | int purge_vec); 39 | void remove_maps (struct vectors * vecs); 40 | 41 | void sync_map_state (struct multipath *); 42 | struct multipath * add_map_with_path (struct vectors * vecs, 43 | struct path * pp, int add_vec); 44 | void update_queue_mode_del_path(struct multipath *mpp); 45 | void update_queue_mode_add_path(struct multipath *mpp); 46 | int update_multipath_table (struct multipath *mpp, vector pathvec, int flags); 47 | int update_multipath_status (struct multipath *mpp); 48 | vector get_used_hwes(const struct _vector *pathvec); 49 | 50 | #endif /* _STRUCTS_VEC_H */ 51 | -------------------------------------------------------------------------------- /libmultipath/switchgroup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Christophe Varoqui 3 | * Copyright (c) 2005 Edward Goggin, EMC 4 | */ 5 | #include "checkers.h" 6 | #include "vector.h" 7 | #include "structs.h" 8 | #include "switchgroup.h" 9 | 10 | void path_group_prio_update(struct pathgroup *pgp) 11 | { 12 | int i; 13 | int priority = 0; 14 | int marginal = 0; 15 | struct path * pp; 16 | 17 | pgp->enabled_paths = 0; 18 | if (!pgp->paths) { 19 | pgp->priority = 0; 20 | return; 21 | } 22 | vector_foreach_slot (pgp->paths, pp, i) { 23 | if (pp->marginal) 24 | marginal++; 25 | if (pp->state == PATH_UP || 26 | pp->state == PATH_GHOST) { 27 | priority += pp->priority; 28 | pgp->enabled_paths++; 29 | } 30 | } 31 | if (pgp->enabled_paths) 32 | pgp->priority = priority / pgp->enabled_paths; 33 | else 34 | pgp->priority = 0; 35 | if (marginal && marginal == i) 36 | pgp->marginal = 1; 37 | } 38 | 39 | int select_path_group(struct multipath *mpp) 40 | { 41 | int i; 42 | int normal_pgp = 0; 43 | int max_priority = 0; 44 | int bestpg = 1; 45 | int max_enabled_paths = 1; 46 | struct pathgroup * pgp; 47 | 48 | if (!mpp->pg) 49 | return 1; 50 | 51 | vector_foreach_slot (mpp->pg, pgp, i) { 52 | if (!pgp->paths) 53 | continue; 54 | 55 | path_group_prio_update(pgp); 56 | if (pgp->marginal && normal_pgp) 57 | continue; 58 | if (pgp->enabled_paths) { 59 | if (!pgp->marginal && !normal_pgp) { 60 | normal_pgp = 1; 61 | max_priority = pgp->priority; 62 | max_enabled_paths = pgp->enabled_paths; 63 | bestpg = i + 1; 64 | } else if (pgp->priority > max_priority) { 65 | max_priority = pgp->priority; 66 | max_enabled_paths = pgp->enabled_paths; 67 | bestpg = i + 1; 68 | } else if (pgp->priority == max_priority) { 69 | if (pgp->enabled_paths > max_enabled_paths) { 70 | max_enabled_paths = pgp->enabled_paths; 71 | bestpg = i + 1; 72 | } 73 | } 74 | } 75 | } 76 | return bestpg; 77 | } 78 | -------------------------------------------------------------------------------- /libmultipath/switchgroup.h: -------------------------------------------------------------------------------- 1 | void path_group_prio_update (struct pathgroup * pgp); 2 | int select_path_group (struct multipath * mpp); 3 | -------------------------------------------------------------------------------- /libmultipath/sysfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sysfs.h 3 | */ 4 | 5 | #ifndef _LIBMULTIPATH_SYSFS_H 6 | #define _LIBMULTIPATH_SYSFS_H 7 | #include 8 | 9 | ssize_t sysfs_attr_set_value(struct udev_device *dev, const char *attr_name, 10 | const char * value, size_t value_len); 11 | ssize_t sysfs_attr_get_value(struct udev_device *dev, const char *attr_name, 12 | char * value, size_t value_len); 13 | ssize_t sysfs_bin_attr_get_value(struct udev_device *dev, const char *attr_name, 14 | unsigned char * value, size_t value_len); 15 | int sysfs_get_size (struct path *pp, unsigned long long * size); 16 | int sysfs_check_holders(char * check_devt, char * new_devt); 17 | bool sysfs_is_multipathed(struct path *pp, bool set_wwid); 18 | #endif 19 | -------------------------------------------------------------------------------- /libmultipath/time-util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "time-util.h" 5 | 6 | void get_monotonic_time(struct timespec *res) 7 | { 8 | struct timespec ts; 9 | int rv = clock_gettime(CLOCK_MONOTONIC, &ts); 10 | 11 | assert(rv == 0); 12 | *res = ts; 13 | } 14 | 15 | /* Initialize @cond as a condition variable that uses the monotonic clock */ 16 | void pthread_cond_init_mono(pthread_cond_t *cond) 17 | { 18 | pthread_condattr_t attr; 19 | int res; 20 | 21 | res = pthread_condattr_init(&attr); 22 | assert(res == 0); 23 | res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 24 | assert(res == 0); 25 | res = pthread_cond_init(cond, &attr); 26 | assert(res == 0); 27 | res = pthread_condattr_destroy(&attr); 28 | assert(res == 0); 29 | } 30 | 31 | /* Ensure that 0 <= ts->tv_nsec && ts->tv_nsec < 1000 * 1000 * 1000. */ 32 | void normalize_timespec(struct timespec *ts) 33 | { 34 | while (ts->tv_nsec < 0) { 35 | ts->tv_nsec += 1000L * 1000 * 1000; 36 | ts->tv_sec--; 37 | } 38 | while (ts->tv_nsec >= 1000L * 1000 * 1000) { 39 | ts->tv_nsec -= 1000L * 1000 * 1000; 40 | ts->tv_sec++; 41 | } 42 | } 43 | 44 | /* Compute *res = *a - *b */ 45 | void timespecsub(const struct timespec *a, const struct timespec *b, 46 | struct timespec *res) 47 | { 48 | res->tv_sec = a->tv_sec - b->tv_sec; 49 | res->tv_nsec = a->tv_nsec - b->tv_nsec; 50 | normalize_timespec(res); 51 | } 52 | -------------------------------------------------------------------------------- /libmultipath/time-util.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIME_UTIL_H_ 2 | #define _TIME_UTIL_H_ 3 | 4 | #include 5 | 6 | struct timespec; 7 | 8 | void get_monotonic_time(struct timespec *res); 9 | void pthread_cond_init_mono(pthread_cond_t *cond); 10 | void normalize_timespec(struct timespec *ts); 11 | void timespecsub(const struct timespec *a, const struct timespec *b, 12 | struct timespec *res); 13 | 14 | #endif /* _TIME_UTIL_H_ */ 15 | -------------------------------------------------------------------------------- /libmultipath/uevent.h: -------------------------------------------------------------------------------- 1 | #ifndef _UEVENT_H 2 | #define _UEVENT_H 3 | 4 | /* 5 | * buffer for environment variables, the kernel's size in 6 | * lib/kobject_uevent.c should fit in 7 | */ 8 | #define HOTPLUG_BUFFER_SIZE 2048 9 | #define HOTPLUG_NUM_ENVP 32 10 | #define OBJECT_SIZE 512 11 | 12 | struct udev; 13 | 14 | struct uevent { 15 | struct list_head node; 16 | struct list_head merge_node; 17 | struct udev_device *udev; 18 | char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; 19 | char *devpath; 20 | char *action; 21 | char *kernel; 22 | const char *wwid; 23 | unsigned long seqnum; 24 | char *envp[HOTPLUG_NUM_ENVP]; 25 | }; 26 | 27 | struct uevent *alloc_uevent(void); 28 | int is_uevent_busy(void); 29 | 30 | int uevent_listen(struct udev *udev); 31 | int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data), 32 | void * trigger_data); 33 | bool uevent_is_mpath(const struct uevent *uev); 34 | void uevent_get_wwid(struct uevent *uev); 35 | 36 | int uevent_get_env_positive_int(const struct uevent *uev, 37 | const char *attr); 38 | 39 | static inline int uevent_get_major(const struct uevent *uev) 40 | { 41 | return uevent_get_env_positive_int(uev, "MAJOR"); 42 | } 43 | 44 | static inline int uevent_get_minor(const struct uevent *uev) 45 | { 46 | return uevent_get_env_positive_int(uev, "MINOR"); 47 | } 48 | 49 | static inline int uevent_get_disk_ro(const struct uevent *uev) 50 | { 51 | return uevent_get_env_positive_int(uev, "DISK_RO"); 52 | } 53 | 54 | char *uevent_get_dm_str(const struct uevent *uev, char *attr); 55 | 56 | static inline char *uevent_get_dm_name(const struct uevent *uev) 57 | { 58 | return uevent_get_dm_str(uev, "DM_NAME"); 59 | } 60 | 61 | static inline char *uevent_get_dm_path(const struct uevent *uev) 62 | { 63 | return uevent_get_dm_str(uev, "DM_PATH"); 64 | } 65 | 66 | static inline char *uevent_get_dm_action(const struct uevent *uev) 67 | { 68 | return uevent_get_dm_str(uev, "DM_ACTION"); 69 | } 70 | 71 | #endif /* _UEVENT_H */ 72 | -------------------------------------------------------------------------------- /libmultipath/unaligned.h: -------------------------------------------------------------------------------- 1 | #ifndef _UNALIGNED_H_ 2 | #define _UNALIGNED_H_ 3 | 4 | #include 5 | 6 | static inline uint16_t get_unaligned_be16(const void *ptr) 7 | { 8 | const uint8_t *p = ptr; 9 | 10 | return p[0] << 8 | p[1]; 11 | } 12 | 13 | static inline uint32_t get_unaligned_be32(const void *ptr) 14 | { 15 | const uint8_t *p = ptr; 16 | 17 | return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 18 | } 19 | 20 | static inline uint64_t get_unaligned_be64(const void *ptr) 21 | { 22 | uint32_t low = get_unaligned_be32(ptr + 4); 23 | uint64_t high = get_unaligned_be32(ptr); 24 | 25 | return high << 32 | low; 26 | } 27 | 28 | static inline void put_unaligned_be16(uint16_t val, void *ptr) 29 | { 30 | uint8_t *p = ptr; 31 | 32 | p[0] = val >> 8; 33 | p[1] = val; 34 | } 35 | 36 | static inline void put_unaligned_be32(uint32_t val, void *ptr) 37 | { 38 | uint8_t *p = ptr; 39 | 40 | p[0] = val >> 24; 41 | p[1] = val >> 16; 42 | p[2] = val >> 8; 43 | p[3] = val; 44 | } 45 | 46 | static inline void put_unaligned_be64(uint64_t val, void *ptr) 47 | { 48 | uint8_t *p = ptr; 49 | 50 | put_unaligned_be32(val >> 32, p); 51 | put_unaligned_be32(val, p + 4); 52 | } 53 | 54 | #endif /* _UNALIGNED_H_ */ 55 | -------------------------------------------------------------------------------- /libmultipath/uxsock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Original author : tridge@samba.org, January 2002 3 | * 4 | * Copyright (c) 2005 Christophe Varoqui 5 | * Copyright (c) 2005 Alasdair Kergon, Redhat 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #ifdef USE_SYSTEMD 20 | #include 21 | #endif 22 | #include "mpath_cmd.h" 23 | 24 | #include "memory.h" 25 | #include "uxsock.h" 26 | #include "debug.h" 27 | 28 | /* 29 | * Code is similar with mpath_recv_reply() with data size limitation 30 | * and debug-able malloc. 31 | * When limit == 0, it means no limit on data size, used for socket client 32 | * to receiving data from multipathd. 33 | */ 34 | static int _recv_packet(int fd, char **buf, unsigned int timeout, 35 | ssize_t limit); 36 | 37 | /* 38 | * create a unix domain socket and start listening on it 39 | * return a file descriptor open on the socket 40 | */ 41 | int ux_socket_listen(const char *name) 42 | { 43 | int fd; 44 | size_t len; 45 | #ifdef USE_SYSTEMD 46 | int num; 47 | #endif 48 | struct sockaddr_un addr; 49 | 50 | #ifdef USE_SYSTEMD 51 | num = sd_listen_fds(0); 52 | if (num > 1) { 53 | condlog(3, "sd_listen_fds returned %d fds", num); 54 | return -1; 55 | } else if (num == 1) { 56 | fd = SD_LISTEN_FDS_START + 0; 57 | condlog(3, "using fd %d from sd_listen_fds", fd); 58 | return fd; 59 | } 60 | #endif 61 | fd = socket(AF_LOCAL, SOCK_STREAM, 0); 62 | if (fd == -1) { 63 | condlog(3, "Couldn't create ux_socket, error %d", errno); 64 | return -1; 65 | } 66 | 67 | memset(&addr, 0, sizeof(addr)); 68 | addr.sun_family = AF_LOCAL; 69 | addr.sun_path[0] = '\0'; 70 | len = strlen(name) + 1; 71 | if (len >= sizeof(addr.sun_path)) 72 | len = sizeof(addr.sun_path) - 1; 73 | memcpy(&addr.sun_path[1], name, len); 74 | 75 | len += sizeof(sa_family_t); 76 | if (bind(fd, (struct sockaddr *)&addr, len) == -1) { 77 | condlog(3, "Couldn't bind to ux_socket, error %d", errno); 78 | close(fd); 79 | return -1; 80 | } 81 | 82 | if (listen(fd, 10) == -1) { 83 | condlog(3, "Couldn't listen to ux_socket, error %d", errno); 84 | close(fd); 85 | return -1; 86 | } 87 | return fd; 88 | } 89 | 90 | /* 91 | * send a packet in length prefix format 92 | */ 93 | int send_packet(int fd, const char *buf) 94 | { 95 | if (mpath_send_cmd(fd, buf) < 0) 96 | return -errno; 97 | return 0; 98 | } 99 | 100 | static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit) 101 | { 102 | int err = 0; 103 | ssize_t len = 0; 104 | 105 | *buf = NULL; 106 | len = mpath_recv_reply_len(fd, timeout); 107 | if (len == 0) 108 | return len; 109 | if (len < 0) 110 | return -errno; 111 | if ((limit > 0) && (len > limit)) 112 | return -EINVAL; 113 | (*buf) = MALLOC(len); 114 | if (!*buf) 115 | return -ENOMEM; 116 | err = mpath_recv_reply_data(fd, *buf, len, timeout); 117 | if (err != 0) { 118 | FREE(*buf); 119 | (*buf) = NULL; 120 | return -errno; 121 | } 122 | return err; 123 | } 124 | 125 | /* 126 | * receive a packet in length prefix format 127 | */ 128 | int recv_packet(int fd, char **buf, unsigned int timeout) 129 | { 130 | return _recv_packet(fd, buf, timeout, 0 /* no limit */); 131 | } 132 | 133 | int recv_packet_from_client(int fd, char **buf, unsigned int timeout) 134 | { 135 | return _recv_packet(fd, buf, timeout, _MAX_CMD_LEN); 136 | } 137 | -------------------------------------------------------------------------------- /libmultipath/uxsock.h: -------------------------------------------------------------------------------- 1 | /* some prototypes */ 2 | int ux_socket_listen(const char *name); 3 | int send_packet(int fd, const char *buf); 4 | int recv_packet(int fd, char **buf, unsigned int timeout); 5 | 6 | #define _MAX_CMD_LEN 512 7 | 8 | /* 9 | * Used for receiving socket command from untrusted socket client where data 10 | * size is restricted to 512(_MAX_CMD_LEN) at most. 11 | * Return -EINVAL if data length requested by client exceeded the _MAX_CMD_LEN. 12 | */ 13 | int recv_packet_from_client(int fd, char **buf, unsigned int timeout); 14 | -------------------------------------------------------------------------------- /libmultipath/valid.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Benjamin Marzinski, IBM 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #include 18 | #include 19 | #include 20 | 21 | #include "vector.h" 22 | #include "config.h" 23 | #include "debug.h" 24 | #include "util.h" 25 | #include "devmapper.h" 26 | #include "discovery.h" 27 | #include "wwids.h" 28 | #include "sysfs.h" 29 | #include "blacklist.h" 30 | #include "mpath_cmd.h" 31 | #include "valid.h" 32 | 33 | int 34 | is_path_valid(const char *name, struct config *conf, struct path *pp, 35 | bool check_multipathd) 36 | { 37 | int r; 38 | int fd; 39 | 40 | if (!pp || !name || !conf) 41 | return PATH_IS_ERROR; 42 | 43 | if (conf->find_multipaths <= FIND_MULTIPATHS_UNDEF || 44 | conf->find_multipaths >= __FIND_MULTIPATHS_LAST) 45 | return PATH_IS_ERROR; 46 | 47 | if (safe_sprintf(pp->dev, "%s", name)) 48 | return PATH_IS_ERROR; 49 | 50 | if (sysfs_is_multipathed(pp, true)) { 51 | if (pp->wwid[0] == '\0') 52 | return PATH_IS_ERROR; 53 | return PATH_IS_VALID_NO_CHECK; 54 | } 55 | 56 | /* 57 | * "multipath -u" may be run before the daemon is started. In this 58 | * case, systemd might own the socket but might delay multipathd 59 | * startup until some other unit (udev settle!) has finished 60 | * starting. With many LUNs, the listen backlog may be exceeded, which 61 | * would cause connect() to block. This causes udev workers calling 62 | * "multipath -u" to hang, and thus creates a deadlock, until "udev 63 | * settle" times out. To avoid this, call connect() in non-blocking 64 | * mode here, and take EAGAIN as indication for a filled-up systemd 65 | * backlog. 66 | */ 67 | 68 | if (check_multipathd) { 69 | fd = __mpath_connect(1); 70 | if (fd < 0) { 71 | if (errno != EAGAIN && !systemd_service_enabled(name)) { 72 | condlog(3, "multipathd not running or enabled"); 73 | return PATH_IS_NOT_VALID; 74 | } 75 | } else 76 | mpath_disconnect(fd); 77 | } 78 | 79 | pp->udev = udev_device_new_from_subsystem_sysname(udev, "block", name); 80 | if (!pp->udev) 81 | return PATH_IS_ERROR; 82 | 83 | r = pathinfo(pp, conf, DI_SYSFS | DI_WWID | DI_BLACKLIST); 84 | if (r == PATHINFO_SKIPPED) 85 | return PATH_IS_NOT_VALID; 86 | else if (r) 87 | return PATH_IS_ERROR; 88 | 89 | if (pp->wwid[0] == '\0') 90 | return PATH_IS_NOT_VALID; 91 | 92 | if (pp->udev && pp->uid_attribute && 93 | filter_property(conf, pp->udev, 3, pp->uid_attribute) > 0) 94 | return PATH_IS_NOT_VALID; 95 | 96 | r = is_failed_wwid(pp->wwid); 97 | if (r != WWID_IS_NOT_FAILED) { 98 | if (r == WWID_IS_FAILED) 99 | return PATH_IS_NOT_VALID; 100 | return PATH_IS_ERROR; 101 | } 102 | 103 | if (conf->find_multipaths == FIND_MULTIPATHS_GREEDY) 104 | return PATH_IS_VALID; 105 | 106 | if (check_wwids_file(pp->wwid, 0) == 0) 107 | return PATH_IS_VALID_NO_CHECK; 108 | 109 | if (dm_map_present_by_uuid(pp->wwid) == 1) 110 | return PATH_IS_VALID; 111 | 112 | /* all these act like FIND_MULTIPATHS_STRICT for finding if a 113 | * path is valid */ 114 | if (conf->find_multipaths != FIND_MULTIPATHS_SMART) 115 | return PATH_IS_NOT_VALID; 116 | 117 | return PATH_IS_MAYBE_VALID; 118 | } 119 | -------------------------------------------------------------------------------- /libmultipath/valid.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Benjamin Marzinski, IBM 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #ifndef _VALID_H 18 | #define _VALID_H 19 | 20 | /* 21 | * PATH_IS_VALID_NO_CHECK is returned when multipath should claim 22 | * the path, regardless of whether is has been released to systemd 23 | * already. 24 | * PATH_IS_VALID is returned by is_path_valid, when the path is 25 | * valid only if it hasn't been released to systemd already. 26 | * PATH_IS_MAYBE_VALID is returned when the the path would be valid 27 | * if other paths with the same wwid existed. It is up to the caller 28 | * to check for these other paths. 29 | */ 30 | enum is_path_valid_result { 31 | PATH_IS_ERROR = -1, 32 | PATH_IS_NOT_VALID, 33 | PATH_IS_VALID, 34 | PATH_IS_VALID_NO_CHECK, 35 | PATH_IS_MAYBE_VALID, 36 | PATH_MAX_VALID_RESULT, /* only for bounds checking */ 37 | }; 38 | 39 | int is_path_valid(const char *name, struct config *conf, struct path *pp, 40 | bool check_multipathd); 41 | 42 | #endif /* _VALID_D */ 43 | -------------------------------------------------------------------------------- /libmultipath/vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Soft: Keepalived is a failover program for the LVS project 3 | * . It monitor & manipulate 4 | * a loadbalanced server pool using multi-layer checks. 5 | * 6 | * Part: vector.c include file. 7 | * 8 | * Version: $Id: vector.h,v 1.0.3 2003/05/11 02:28:03 acassen Exp $ 9 | * 10 | * Author: Alexandre Cassen, 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | * See the GNU General Public License for more details. 16 | * 17 | * This program is free software; you can redistribute it and/or 18 | * modify it under the terms of the GNU General Public License 19 | * as published by the Free Software Foundation; either version 20 | * 2 of the License, or (at your option) any later version. 21 | */ 22 | 23 | #ifndef _VECTOR_H 24 | #define _VECTOR_H 25 | 26 | #include 27 | 28 | /* vector definition */ 29 | struct _vector { 30 | int allocated; 31 | void **slot; 32 | }; 33 | typedef struct _vector *vector; 34 | 35 | #define VECTOR_DEFAULT_SIZE 1 36 | #define VECTOR_SIZE(V) ((V) ? ((V)->allocated) / VECTOR_DEFAULT_SIZE : 0) 37 | #define VECTOR_SLOT(V,E) (((V) && (E) < VECTOR_SIZE(V) && (E) >= 0) ? (V)->slot[(E)] : NULL) 38 | #define VECTOR_LAST_SLOT(V) (((V) && VECTOR_SIZE(V) > 0) ? (V)->slot[(VECTOR_SIZE(V) - 1)] : NULL) 39 | 40 | #define vector_foreach_slot(v,p,i) \ 41 | for (i = 0; (v) && (int)i < VECTOR_SIZE(v) && ((p) = (v)->slot[i]); i++) 42 | #define vector_foreach_slot_after(v,p,i) \ 43 | for (; (v) && (int)i < VECTOR_SIZE(v) && ((p) = (v)->slot[i]); i++) 44 | #define vector_foreach_slot_backwards(v,p,i) \ 45 | for (i = VECTOR_SIZE(v) - 1; (int)i >= 0 && ((p) = (v)->slot[i]); i--) 46 | 47 | #define identity(x) (x) 48 | /* 49 | * Given a vector vec with elements of given type, 50 | * return a newly allocated vector with elements conv(e) for each element 51 | * e in vec. "conv" may be a macro or a function. 52 | * Use "identity" for a simple copy. 53 | */ 54 | #define vector_convert(new, vec, type, conv) \ 55 | ({ \ 56 | const struct _vector *__v = (vec); \ 57 | vector __t = (new); \ 58 | type *__j; \ 59 | int __i; \ 60 | \ 61 | if (__t == NULL) \ 62 | __t = vector_alloc(); \ 63 | if (__t != NULL) { \ 64 | vector_foreach_slot(__v, __j, __i) { \ 65 | if (!vector_alloc_slot(__t)) { \ 66 | vector_free(__t); \ 67 | __t = NULL; \ 68 | break; \ 69 | } \ 70 | vector_set_slot(__t, conv(__j)); \ 71 | } \ 72 | } \ 73 | __t; \ 74 | }) 75 | 76 | /* Prototypes */ 77 | extern vector vector_alloc(void); 78 | extern bool vector_alloc_slot(vector v); 79 | vector vector_reset(vector v); 80 | extern void vector_free(vector v); 81 | #define vector_free_const(x) vector_free((vector)(long)(x)) 82 | extern void free_strvec(vector strvec); 83 | extern void vector_set_slot(vector v, void *value); 84 | extern void vector_del_slot(vector v, int slot); 85 | extern void *vector_insert_slot(vector v, int slot, void *value); 86 | int find_slot(vector v, void * addr); 87 | int vector_find_or_add_slot(vector v, void *value); 88 | extern void vector_repack(vector v); 89 | extern void vector_dump(vector v); 90 | extern void dump_strvec(vector strvec); 91 | extern int vector_move_up(vector v, int src, int dest); 92 | #endif 93 | -------------------------------------------------------------------------------- /libmultipath/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Soft: multipath device mapper target autoconfig 3 | * 4 | * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $ 5 | * 6 | * Author: Christophe Varoqui 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU General Public License 15 | * as published by the Free Software Foundation; either version 16 | * 2 of the License, or (at your option) any later version. 17 | * 18 | * Copyright (c) 2006 Christophe Varoqui 19 | */ 20 | #ifndef _VERSION_H 21 | #define _VERSION_H 22 | 23 | #define VERSION_CODE 0x000805 24 | #define DATE_CODE 0x0b0914 25 | 26 | #define PROG "multipath-tools" 27 | 28 | #define MULTIPATH_VERSION(version) \ 29 | (version >> 16) & 0xFF, \ 30 | (version >> 8) & 0xFF, \ 31 | version & 0xFF 32 | 33 | #define VERSION_STRING PROG" v%d.%d.%d (%.2d/%.2d, 20%.2d)\n", \ 34 | MULTIPATH_VERSION(VERSION_CODE), \ 35 | MULTIPATH_VERSION(DATE_CODE) 36 | 37 | #endif /* _VERSION_H */ 38 | -------------------------------------------------------------------------------- /libmultipath/wwids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Benjamin Marzinski, Redhat 3 | */ 4 | 5 | #ifndef _WWIDS_H 6 | #define _WWIDS_H 7 | 8 | #define WWIDS_FILE_HEADER \ 9 | "# Multipath wwids, Version : 1.0\n" \ 10 | "# NOTE: This file is automatically maintained by multipath and multipathd.\n" \ 11 | "# You should not need to edit this file in normal circumstances.\n" \ 12 | "#\n" \ 13 | "# Valid WWIDs:\n" 14 | 15 | int should_multipath(struct path *pp, vector pathvec, vector mpvec); 16 | int remember_wwid(char *wwid); 17 | int check_wwids_file(char *wwid, int write_wwid); 18 | int remove_wwid(char *wwid); 19 | int replace_wwids(vector mp); 20 | 21 | enum { 22 | WWID_IS_NOT_FAILED = 0, 23 | WWID_IS_FAILED, 24 | WWID_FAILED_UNCHANGED, 25 | WWID_FAILED_CHANGED, 26 | WWID_FAILED_ERROR = -1, 27 | }; 28 | 29 | int is_failed_wwid(const char *wwid); 30 | int mark_failed_wwid(const char *wwid); 31 | int unmark_failed_wwid(const char *wwid); 32 | #endif /* _WWIDS_H */ 33 | -------------------------------------------------------------------------------- /mpathpersist/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) 4 | LDFLAGS += $(BIN_LDFLAGS) 5 | 6 | LIBDEPS += -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath \ 7 | -L$(mpathcmddir) -lmpathcmd -lpthread -ldevmapper -ludev 8 | 9 | EXEC = mpathpersist 10 | 11 | OBJS = main.o 12 | 13 | all: $(EXEC) 14 | 15 | $(EXEC): $(OBJS) 16 | $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS) $(LIBDEPS) 17 | $(GZIP) $(EXEC).8 > $(EXEC).8.gz 18 | 19 | install: 20 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 21 | $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ 22 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir) 23 | $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir) 24 | 25 | clean: dep_clean 26 | $(RM) core *.o $(EXEC) *.gz 27 | 28 | include $(wildcard $(OBJS:.o=.d)) 29 | 30 | uninstall: 31 | $(RM) $(DESTDIR)$(bindir)/$(EXEC) 32 | $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz 33 | 34 | dep_clean: 35 | $(RM) $(OBJS:.o=.d) 36 | -------------------------------------------------------------------------------- /mpathpersist/main.h: -------------------------------------------------------------------------------- 1 | static struct option long_options[] = { 2 | {"verbose", 1, NULL, 'v'}, 3 | {"clear", 0, NULL, 'C'}, 4 | {"device", 1, NULL, 'd'}, 5 | {"batch-file", 1, NULL, 'f' }, 6 | {"help", 0, NULL, 'h'}, 7 | {"hex", 0, NULL, 'H'}, 8 | {"in", 0, NULL, 'i'}, 9 | {"out", 0, NULL, 'o'}, 10 | {"param-alltgpt", 0, NULL, 'Y'}, 11 | {"param-aptpl", 0, NULL, 'Z'}, 12 | {"param-rk", 1, NULL, 'K'}, 13 | {"param-sark", 1, NULL, 'S'}, 14 | {"preempt", 0, NULL, 'P'}, 15 | {"preempt-abort", 0, NULL, 'A'}, 16 | {"prout-type", 1, NULL, 'T'}, 17 | {"read-full-status", 0, NULL, 's'}, 18 | {"read-keys", 0, NULL, 'k'}, 19 | {"read-reservation", 0, NULL, 'r'}, 20 | {"register", 0, NULL, 'G'}, 21 | {"register-ignore", 0, NULL, 'I'}, 22 | {"release", 0, NULL, 'L'}, 23 | {"report-capabilities", 0, NULL, 'c'}, 24 | {"reserve", 0, NULL, 'R'}, 25 | {"transport-id", 1, NULL, 'X'}, 26 | {"alloc-length", 1, NULL, 'l'}, 27 | {NULL, 0, NULL, 0} 28 | }; 29 | 30 | static void usage(void); 31 | -------------------------------------------------------------------------------- /multipath/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2003 Christophe Varoqui, 3 | # 4 | include ../Makefile.inc 5 | 6 | CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) 7 | LDFLAGS += $(BIN_LDFLAGS) 8 | LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathcmddir) -lmpathcmd \ 9 | -lpthread -ldevmapper -ldl -ludev 10 | 11 | EXEC = multipath 12 | 13 | OBJS = main.o 14 | 15 | all: $(EXEC) 16 | 17 | $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so 18 | $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS) 19 | $(GZIP) $(EXEC).8 > $(EXEC).8.gz 20 | $(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz 21 | 22 | install: 23 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 24 | $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ 25 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) 26 | $(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) 27 | $(INSTALL_PROGRAM) -m 644 $(EXEC).rules $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules 28 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir) 29 | $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir) 30 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir) 31 | $(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir) 32 | 33 | uninstall: 34 | $(RM) $(DESTDIR)$(bindir)/$(EXEC) 35 | $(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules 36 | $(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules 37 | $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz 38 | $(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz 39 | 40 | clean: dep_clean 41 | $(RM) core *.o $(EXEC) *.gz 42 | 43 | include $(wildcard $(OBJS:.o=.d)) 44 | 45 | dep_clean: 46 | $(RM) $(OBJS:.o=.d) 47 | -------------------------------------------------------------------------------- /multipathd/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | ifneq ($(call check_func,dm_task_get_errno,/usr/include/libdevmapper.h),0) 4 | CFLAGS += -DLIBDM_API_GET_ERRNO 5 | endif 6 | 7 | # 8 | # debugging stuff 9 | # 10 | #CFLAGS += -DLCKDBG 11 | #CFLAGS += -D_DEBUG_ 12 | #CFLAGS += -DLOGDBG 13 | CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathpersistdir) \ 14 | -I$(mpathcmddir) -I$(thirdpartydir) 15 | LDFLAGS += $(BIN_LDFLAGS) 16 | LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \ 17 | -L$(mpathcmddir) -lmpathcmd -ludev -ldl -lurcu -lpthread \ 18 | -ldevmapper -lreadline 19 | 20 | ifdef SYSTEMD 21 | CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD) 22 | ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1) 23 | LIBDEPS += -lsystemd 24 | else 25 | LIBDEPS += -lsystemd-daemon 26 | endif 27 | endif 28 | ifeq ($(ENABLE_DMEVENTS_POLL),0) 29 | CFLAGS += -DNO_DMEVENTS_POLL 30 | endif 31 | 32 | OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o waiter.o \ 33 | dmevents.o 34 | 35 | EXEC = multipathd 36 | 37 | all : $(EXEC) 38 | 39 | $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so 40 | $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(EXEC) $(LIBDEPS) 41 | $(GZIP) $(EXEC).8 > $(EXEC).8.gz 42 | 43 | cli_handlers.o: cli_handlers.c 44 | $(CC) $(CFLAGS) -Wno-unused-parameter -c -o $@ $< 45 | 46 | install: 47 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir) 48 | $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir) 49 | ifdef SYSTEMD 50 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(unitdir) 51 | $(INSTALL_PROGRAM) -m 644 $(EXEC).service $(DESTDIR)$(unitdir) 52 | $(INSTALL_PROGRAM) -m 644 $(EXEC).socket $(DESTDIR)$(unitdir) 53 | endif 54 | $(INSTALL_PROGRAM) -d $(DESTDIR)$(man8dir) 55 | $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(man8dir) 56 | 57 | uninstall: 58 | $(RM) $(DESTDIR)$(bindir)/$(EXEC) 59 | $(RM) $(DESTDIR)$(man8dir)/$(EXEC).8.gz 60 | $(RM) $(DESTDIR)$(unitdir)/$(EXEC).service 61 | $(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket 62 | 63 | clean: dep_clean 64 | $(RM) core *.o $(EXEC) *.gz 65 | 66 | include $(wildcard $(OBJS:.o=.d)) 67 | 68 | dep_clean: 69 | $(RM) $(OBJS:.o=.d) 70 | -------------------------------------------------------------------------------- /multipathd/cli.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLI_H_ 2 | #define _CLI_H_ 3 | 4 | #include 5 | 6 | enum { 7 | __LIST, 8 | __ADD, 9 | __DEL, 10 | __SWITCH, 11 | __SUSPEND, 12 | __RESUME, 13 | __REINSTATE, 14 | __FAIL, 15 | __RESIZE, 16 | __RESET, 17 | __RELOAD, 18 | __FORCEQ, 19 | __DISABLEQ, 20 | __RESTOREQ, 21 | __PATHS, 22 | __MAPS, 23 | __PATH, 24 | __MAP, 25 | __GROUP, 26 | __RECONFIGURE, 27 | __DAEMON, 28 | __STATUS, 29 | __STATS, 30 | __TOPOLOGY, 31 | __CONFIG, 32 | __BLACKLIST, 33 | __DEVICES, 34 | __RAW, 35 | __WILDCARDS, 36 | __QUIT, 37 | __SHUTDOWN, 38 | __GETPRSTATUS, 39 | __SETPRSTATUS, 40 | __UNSETPRSTATUS, 41 | __FMT, 42 | __JSON, 43 | __GETPRKEY, 44 | __SETPRKEY, 45 | __UNSETPRKEY, 46 | __KEY, 47 | __LOCAL, 48 | __SETMARGINAL, 49 | __UNSETMARGINAL, 50 | }; 51 | 52 | #define LIST (1 << __LIST) 53 | #define ADD (1 << __ADD) 54 | #define DEL (1 << __DEL) 55 | #define SWITCH (1 << __SWITCH) 56 | #define SUSPEND (1 << __SUSPEND) 57 | #define RESUME (1 << __RESUME) 58 | #define REINSTATE (1 << __REINSTATE) 59 | #define FAIL (1 << __FAIL) 60 | #define RESIZE (1 << __RESIZE) 61 | #define RESET (1 << __RESET) 62 | #define RELOAD (1 << __RELOAD) 63 | #define FORCEQ (1 << __FORCEQ) 64 | #define DISABLEQ (1 << __DISABLEQ) 65 | #define RESTOREQ (1 << __RESTOREQ) 66 | #define PATHS (1 << __PATHS) 67 | #define MAPS (1 << __MAPS) 68 | #define PATH (1 << __PATH) 69 | #define MAP (1 << __MAP) 70 | #define GROUP (1 << __GROUP) 71 | #define RECONFIGURE (1 << __RECONFIGURE) 72 | #define DAEMON (1 << __DAEMON) 73 | #define STATUS (1 << __STATUS) 74 | #define STATS (1 << __STATS) 75 | #define TOPOLOGY (1 << __TOPOLOGY) 76 | #define CONFIG (1 << __CONFIG) 77 | #define BLACKLIST (1 << __BLACKLIST) 78 | #define DEVICES (1 << __DEVICES) 79 | #define RAW (1 << __RAW) 80 | #define COUNT (1 << __COUNT) 81 | #define WILDCARDS (1 << __WILDCARDS) 82 | #define QUIT (1 << __QUIT) 83 | #define SHUTDOWN (1 << __SHUTDOWN) 84 | #define GETPRSTATUS (1ULL << __GETPRSTATUS) 85 | #define SETPRSTATUS (1ULL << __SETPRSTATUS) 86 | #define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) 87 | #define FMT (1ULL << __FMT) 88 | #define JSON (1ULL << __JSON) 89 | #define GETPRKEY (1ULL << __GETPRKEY) 90 | #define SETPRKEY (1ULL << __SETPRKEY) 91 | #define UNSETPRKEY (1ULL << __UNSETPRKEY) 92 | #define KEY (1ULL << __KEY) 93 | #define LOCAL (1ULL << __LOCAL) 94 | #define SETMARGINAL (1ULL << __SETMARGINAL) 95 | #define UNSETMARGINAL (1ULL << __UNSETMARGINAL) 96 | 97 | #define INITIAL_REPLY_LEN 1200 98 | 99 | #define REALLOC_REPLY(r, a, m) \ 100 | do { \ 101 | if ((a)) { \ 102 | char *tmp = (r); \ 103 | \ 104 | if (m >= MAX_REPLY_LEN) { \ 105 | condlog(1, "Warning: max reply length exceeded"); \ 106 | free(tmp); \ 107 | (r) = NULL; \ 108 | } else { \ 109 | (r) = REALLOC((r), (m) * 2); \ 110 | if ((r)) { \ 111 | memset((r) + (m), 0, (m)); \ 112 | (m) *= 2; \ 113 | } \ 114 | else \ 115 | free(tmp); \ 116 | } \ 117 | } \ 118 | } while (0) 119 | 120 | struct key { 121 | char * str; 122 | char * param; 123 | uint64_t code; 124 | int has_param; 125 | }; 126 | 127 | struct handler { 128 | uint64_t fingerprint; 129 | int locked; 130 | int (*fn)(void *, char **, int *, void *); 131 | }; 132 | 133 | int alloc_handlers (void); 134 | int add_handler (uint64_t fp, int (*fn)(void *, char **, int *, void *)); 135 | int set_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *)); 136 | int set_unlocked_handler_callback (uint64_t fp, int (*fn)(void *, char **, int *, void *)); 137 | int parse_cmd (char * cmd, char ** reply, int * len, void *, int); 138 | int load_keys (void); 139 | char * get_keyparam (vector v, uint64_t code); 140 | void free_keys (vector vec); 141 | void free_handlers (void); 142 | int cli_init (void); 143 | void cli_exit(void); 144 | char * key_generator (const char * str, int state); 145 | 146 | #endif /* _CLI_H_ */ 147 | -------------------------------------------------------------------------------- /multipathd/dmevents.h: -------------------------------------------------------------------------------- 1 | #ifndef _DMEVENTS_H 2 | #define _DMEVENTS_H 3 | 4 | #include "structs_vec.h" 5 | 6 | int dmevent_poll_supported(void); 7 | int init_dmevent_waiter(struct vectors *vecs); 8 | void cleanup_dmevent_waiter(void); 9 | int watch_dmevents(char *name); 10 | void unwatch_all_dmevents(void); 11 | void *wait_dmevents (void *unused); 12 | 13 | #endif /* _DMEVENTS_H */ 14 | -------------------------------------------------------------------------------- /multipathd/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | 4 | #define MAPGCINT 5 5 | 6 | enum daemon_status { 7 | DAEMON_INIT = 0, 8 | DAEMON_START, 9 | DAEMON_CONFIGURE, 10 | DAEMON_IDLE, 11 | DAEMON_RUNNING, 12 | DAEMON_SHUTDOWN, 13 | DAEMON_STATUS_SIZE, 14 | }; 15 | 16 | struct prout_param_descriptor; 17 | struct prin_resp; 18 | 19 | extern pid_t daemon_pid; 20 | extern int uxsock_timeout; 21 | 22 | void exit_daemon(void); 23 | const char * daemon_status(void); 24 | enum daemon_status wait_for_state_change_if(enum daemon_status oldstate, 25 | unsigned long ms); 26 | int need_to_delay_reconfig (struct vectors *); 27 | int reconfigure (struct vectors *); 28 | int ev_add_path (struct path *, struct vectors *, int); 29 | int ev_remove_path (struct path *, struct vectors *, int); 30 | int ev_add_map (char *, const char *, struct vectors *); 31 | int ev_remove_map (char *, char *, int, struct vectors *); 32 | int flush_map(struct multipath *, struct vectors *, int); 33 | int set_config_state(enum daemon_status); 34 | void * mpath_alloc_prin_response(int prin_sa); 35 | int prin_do_scsi_ioctl(char *, int rq_servact, struct prin_resp * resp, 36 | int noisy); 37 | void dumpHex(const char * , int len, int no_ascii); 38 | int prout_do_scsi_ioctl(char * , int rq_servact, int rq_scope, 39 | unsigned int rq_type, 40 | struct prout_param_descriptor *param, int noisy); 41 | int mpath_pr_event_handle(struct path *pp); 42 | void * mpath_pr_event_handler_fn (void * ); 43 | int update_map_pr(struct multipath *mpp); 44 | void * mpath_pr_event_handler_fn (void * pathp ); 45 | void handle_signals(bool); 46 | int __setup_multipath (struct vectors * vecs, struct multipath * mpp, 47 | int reset); 48 | #define setup_multipath(vecs, mpp) __setup_multipath(vecs, mpp, 1) 49 | int update_multipath (struct vectors *vecs, char *mapname, int reset); 50 | int reload_and_sync_map(struct multipath *mpp, struct vectors *vecs, 51 | int refresh); 52 | 53 | #endif /* MAIN_H */ 54 | -------------------------------------------------------------------------------- /multipathd/multipathd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Device-Mapper Multipath Device Controller 3 | Wants=systemd-udev-trigger.service systemd-udev-settle.service 4 | Before=iscsi.service iscsid.service lvm2-activation-early.service 5 | Before=local-fs-pre.target blk-availability.service 6 | After=multipathd.socket systemd-udev-trigger.service systemd-udev-settle.service 7 | DefaultDependencies=no 8 | Conflicts=shutdown.target 9 | ConditionKernelCommandLine=!nompath 10 | ConditionKernelCommandLine=!multipath=off 11 | 12 | [Service] 13 | Type=notify 14 | NotifyAccess=main 15 | LimitCORE=infinity 16 | ExecStartPre=-/sbin/modprobe -a scsi_dh_alua scsi_dh_emc scsi_dh_rdac dm-multipath 17 | ExecStart=/sbin/multipathd -d -s 18 | ExecReload=/sbin/multipathd reconfigure 19 | TasksMax=infinity 20 | 21 | [Install] 22 | WantedBy=sysinit.target 23 | Also=multipathd.socket 24 | -------------------------------------------------------------------------------- /multipathd/multipathd.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=multipathd control socket 3 | DefaultDependencies=no 4 | Before=sockets.target 5 | 6 | [Socket] 7 | ListenStream=@/org/kernel/linux/storage/multipathd 8 | 9 | [Install] 10 | WantedBy=sockets.target 11 | -------------------------------------------------------------------------------- /multipathd/pidfile.c: -------------------------------------------------------------------------------- 1 | #include /* for pid_t */ 2 | #include /* for open */ 3 | #include /* for EACCESS and EAGAIN */ 4 | #include /* for snprintf() */ 5 | #include /* for memset() */ 6 | #include /* for ftruncate() */ 7 | #include /* for fcntl() */ 8 | 9 | #include "debug.h" 10 | 11 | #include "pidfile.h" 12 | 13 | int pidfile_create(const char *pidFile, pid_t pid) 14 | { 15 | char buf[20]; 16 | struct flock lock; 17 | int fd, value; 18 | 19 | if((fd = open(pidFile, O_WRONLY | O_CREAT, 20 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { 21 | condlog(0, "Cannot open pidfile [%s], error was [%s]", 22 | pidFile, strerror(errno)); 23 | return -errno; 24 | } 25 | lock.l_type = F_WRLCK; 26 | lock.l_start = 0; 27 | lock.l_whence = SEEK_SET; 28 | lock.l_len = 0; 29 | 30 | if (fcntl(fd, F_SETLK, &lock) < 0) { 31 | if (errno != EACCES && errno != EAGAIN) 32 | condlog(0, "Cannot lock pidfile [%s], error was [%s]", 33 | pidFile, strerror(errno)); 34 | else 35 | condlog(0, "process is already running"); 36 | goto fail; 37 | } 38 | if (ftruncate(fd, 0) < 0) { 39 | condlog(0, "Cannot truncate pidfile [%s], error was [%s]", 40 | pidFile, strerror(errno)); 41 | goto fail; 42 | } 43 | memset(buf, 0, sizeof(buf)); 44 | snprintf(buf, sizeof(buf)-1, "%u", pid); 45 | if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) { 46 | condlog(0, "Cannot write pid to pidfile [%s], error was [%s]", 47 | pidFile, strerror(errno)); 48 | goto fail; 49 | } 50 | if ((value = fcntl(fd, F_GETFD, 0)) < 0) { 51 | condlog(0, "Cannot get close-on-exec flag from pidfile [%s], " 52 | "error was [%s]", pidFile, strerror(errno)); 53 | goto fail; 54 | } 55 | value |= FD_CLOEXEC; 56 | if (fcntl(fd, F_SETFD, value) < 0) { 57 | condlog(0, "Cannot set close-on-exec flag from pidfile [%s], " 58 | "error was [%s]", pidFile, strerror(errno)); 59 | goto fail; 60 | } 61 | return fd; 62 | fail: 63 | close(fd); 64 | return -errno; 65 | } 66 | -------------------------------------------------------------------------------- /multipathd/pidfile.h: -------------------------------------------------------------------------------- 1 | int pidfile_create(const char *pidFile, pid_t pid); 2 | -------------------------------------------------------------------------------- /multipathd/uxclnt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Original author : tridge@samba.org, January 2002 3 | * 4 | * Copyright (c) 2005 Christophe Varoqui 5 | * Copyright (c) 2005 Benjamin Marzinski, Redhat 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "mpath_cmd.h" 22 | #include "uxsock.h" 23 | #include "memory.h" 24 | #include "defaults.h" 25 | 26 | #include "vector.h" 27 | #include "cli.h" 28 | #include "uxclnt.h" 29 | 30 | static void print_reply(char *s) 31 | { 32 | if (!s) 33 | return; 34 | 35 | if (isatty(1)) { 36 | printf("%s", s); 37 | return; 38 | } 39 | /* strip ANSI color markers */ 40 | while (*s != '\0') { 41 | if ((*s == 0x1b) && (*(s+1) == '[')) 42 | while ((*s++ != 'm') && (*s != '\0')) {}; 43 | putchar(*s++); 44 | } 45 | } 46 | 47 | static int need_quit(char *str, size_t len) 48 | { 49 | char *ptr, *start; 50 | size_t trimed_len = len; 51 | 52 | for (ptr = str; trimed_len && isspace(*ptr); 53 | trimed_len--, ptr++) 54 | ; 55 | 56 | start = ptr; 57 | 58 | for (ptr = str + len - 1; trimed_len && isspace(*ptr); 59 | trimed_len--, ptr--) 60 | ; 61 | 62 | if ((trimed_len == 4 && !strncmp(start, "exit", 4)) || 63 | (trimed_len == 4 && !strncmp(start, "quit", 4))) 64 | return 1; 65 | 66 | return 0; 67 | } 68 | 69 | /* 70 | * process the client 71 | */ 72 | static void process(int fd, unsigned int timeout) 73 | { 74 | char *line; 75 | char *reply; 76 | int ret; 77 | 78 | cli_init(); 79 | rl_readline_name = "multipathd"; 80 | rl_completion_entry_function = key_generator; 81 | while ((line = readline("multipathd> "))) { 82 | size_t llen = strlen(line); 83 | 84 | if (!llen) { 85 | free(line); 86 | continue; 87 | } 88 | 89 | if (need_quit(line, llen)) 90 | break; 91 | 92 | if (send_packet(fd, line) != 0) break; 93 | ret = recv_packet(fd, &reply, timeout); 94 | if (ret != 0) break; 95 | 96 | print_reply(reply); 97 | 98 | if (line && *line) 99 | add_history(line); 100 | 101 | free(line); 102 | FREE(reply); 103 | } 104 | } 105 | 106 | static int process_req(int fd, char * inbuf, unsigned int timeout) 107 | { 108 | char *reply; 109 | int ret; 110 | 111 | if (send_packet(fd, inbuf) != 0) { 112 | printf("cannot send packet\n"); 113 | return 1; 114 | } 115 | ret = recv_packet(fd, &reply, timeout); 116 | if (ret < 0) { 117 | if (ret == -ETIMEDOUT) 118 | printf("timeout receiving packet\n"); 119 | else 120 | printf("error %d receiving packet\n", ret); 121 | return 1; 122 | } else { 123 | printf("%s", reply); 124 | ret = (strcmp(reply, "fail\n") == 0); 125 | FREE(reply); 126 | return ret; 127 | } 128 | } 129 | 130 | /* 131 | * entry point 132 | */ 133 | int uxclnt(char * inbuf, unsigned int timeout) 134 | { 135 | int fd, ret = 0; 136 | 137 | fd = mpath_connect(); 138 | if (fd == -1) 139 | exit(1); 140 | 141 | if (inbuf) 142 | ret = process_req(fd, inbuf, timeout); 143 | else 144 | process(fd, timeout); 145 | mpath_disconnect(fd); 146 | return ret; 147 | } 148 | -------------------------------------------------------------------------------- /multipathd/uxclnt.h: -------------------------------------------------------------------------------- 1 | int uxclnt(char * inbuf, unsigned int timeout); 2 | -------------------------------------------------------------------------------- /multipathd/uxlsnr.h: -------------------------------------------------------------------------------- 1 | #ifndef _UXLSNR_H 2 | #define _UXLSNR_H 3 | 4 | #include 5 | 6 | typedef int (uxsock_trigger_fn)(char *, char **, int *, bool, void *); 7 | 8 | void uxsock_cleanup(void *arg); 9 | void *uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock, 10 | void * trigger_data); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /multipathd/waiter.h: -------------------------------------------------------------------------------- 1 | #ifndef _WAITER_H 2 | #define _WAITER_H 3 | 4 | extern pthread_attr_t waiter_attr; 5 | 6 | struct event_thread { 7 | struct dm_task *dmt; 8 | pthread_t thread; 9 | int event_nr; 10 | char mapname[WWID_SIZE]; 11 | struct vectors *vecs; 12 | }; 13 | 14 | void stop_waiter_thread (struct multipath *mpp); 15 | int start_waiter_thread (struct multipath *mpp, struct vectors *vecs); 16 | 17 | #endif /* _WAITER_H */ 18 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # multipath-tools unit tests 2 | 3 | Unit tests are built and run by running `make test` in the top directory, 4 | or simply `make` in the `tests` subdirectory. The test output is saved as 5 | `.out`. The test programs are called `-test`, and can 6 | be run standalone e.g. for debugging purposes. 7 | 8 | ## Running tests under valgrind 9 | 10 | The unit tests can be run under the valgrind debugger with `make valgrind` 11 | in the `tests` directory, or `make valgrind-test` in the top directory. 12 | If valgrind detects a bad memory access or leak, the test will fail. The 13 | output of the test run, including valgrind output, is stored as 14 | `.vgr`. 15 | 16 | ## Notes on individual tests 17 | 18 | ### Tests that require root permissions 19 | 20 | The following tests must be run as root, otherwise some test items will be 21 | skipped because of missing permissions, or the test will fail outright: 22 | 23 | * `dmevents` 24 | * `directio` (if `DIO_TEST_DEV` is set, see below) 25 | 26 | To run these tests, after building the tests as non-root user, change to the 27 | `tests` directory and run `make test-clean`; then run `make` again as root. 28 | 29 | ### directio test 30 | 31 | This test includes test items that require a access to a block device. The 32 | device will be opened in read-only mode; you don't need to worry about data 33 | loss. However, the user needs to specify a device to be used. Set the 34 | environment variable `DIO_TEST_DEV` to the path of the device. 35 | Alternatively, create a file `directio_test_dev` under 36 | the `tests` directory containting a single line that sets this environment 37 | variable in Bourne Shell syntax, like this: 38 | 39 | DIO_TEST_DEV=/dev/sdc3 40 | 41 | After that, run `make directio.out` as root in the `tests` directory to 42 | perform the test. 43 | 44 | ## Adding tests 45 | 46 | The unit tests are based on the [cmocka test framework](https://cmocka.org/), 47 | and make use of cmocka's "mock objects" feature to simulate how the code behaves 48 | for different input values. cmocka achieves this by modifying the symbol 49 | lookup at link time, substituting "wrapper functions" for the originally 50 | called function. The Makefile contains code to make sure that `__wrap_xyz()` 51 | wrapper functions are automatically passed to the linker with matching 52 | `-Wl,--wrap` command line arguments, so that tests are correctly rebuilt if 53 | wrapper functions are added or removed. 54 | 55 | ### Making sure symbol wrapping works: OBJDEPS 56 | 57 | Special care must be taken to wrap function calls inside a library. Suppose you want 58 | to wrap a function which is both defined in libmultipath and called from other 59 | functions in libmultipath, such as `checker_check()`. When `libmultipath.so` is 60 | created, the linker resolves calls to `checker_check()` inside the `.so` 61 | file. When later the test executable is built by linking the test object file with 62 | `libmultipath.so`, these calls can't be wrapped any more, because they've 63 | already been resolved, and wrapping works only for *unresolved* symbols. 64 | Therefore, object files from libraries that contain calls to functions 65 | which need to be wrapped must be explicitly listed on the linker command line 66 | in order to make the wrapping work. To enforce this, add these object files to 67 | the `xyz-test_OBJDEPS` variable in the Makefile. 68 | 69 | ### Using wrapper function libraries: TESTDEPS 70 | 71 | Some wrapper functions are useful in multiple tests. These are maintained in 72 | separate input files, such as `test-lib.c` or `test-log.c`. List these files 73 | in the `xyz-test_TESTDEPS` variable for your test program if you need these 74 | wrappers. 75 | 76 | ### Specifying library dependencies: LIBDEPS 77 | 78 | In order to keep the tests lean, not all libraries that libmultipath 79 | normally pulls in are used for every test. Add libraries you need (such as 80 | `-lpthread`) to the `xyz-test_LIBDEPS` variable. 81 | -------------------------------------------------------------------------------- /tests/globals.c: -------------------------------------------------------------------------------- 1 | #include "structs.h" 2 | #include "config.h" 3 | 4 | /* Required globals */ 5 | struct udev *udev; 6 | int logsink = -1; 7 | struct config conf = { 8 | .verbosity = 4, 9 | }; 10 | 11 | struct config *get_multipath_config(void) 12 | { 13 | return &conf; 14 | } 15 | 16 | void put_multipath_config(void *arg) 17 | {} 18 | -------------------------------------------------------------------------------- /tests/test-lib.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB_H 2 | #define __LIB_H 3 | 4 | extern const int default_mask; 5 | extern const char default_devnode[]; 6 | extern const char default_wwid[]; 7 | extern const char default_wwid_1[]; 8 | 9 | enum { 10 | BL_BY_DEVNODE = (1 << 0), 11 | BL_BY_DEVICE = (1 << 1), 12 | BL_BY_WWID = (1 << 2), 13 | BL_BY_PROPERTY = (1 << 3), 14 | BL_MASK = BL_BY_DEVNODE|BL_BY_DEVICE|BL_BY_WWID|BL_BY_PROPERTY, 15 | NEED_SELECT_PRIO = (1 << 8), 16 | NEED_FD = (1 << 9), 17 | USE_GETUID = (1 << 10), 18 | DEV_HIDDEN = (1 << 11), 19 | }; 20 | 21 | struct mocked_path { 22 | const char *vendor; 23 | const char *product; 24 | const char *rev; 25 | const char *wwid; 26 | const char *devnode; 27 | unsigned int flags; 28 | }; 29 | 30 | struct mocked_path *fill_mocked_path(struct mocked_path *mp, 31 | const char *vendor, 32 | const char *product, 33 | const char *rev, 34 | const char *wwid, 35 | const char *devnode, 36 | unsigned int flags); 37 | 38 | struct mocked_path *mocked_path_from_path(struct mocked_path *mp, 39 | const struct path *pp); 40 | 41 | void mock_pathinfo(int mask, const struct mocked_path *mp); 42 | void mock_store_pathinfo(int mask, const struct mocked_path *mp); 43 | struct path *__mock_path(vector pathvec, 44 | const char *vnd, const char *prd, 45 | const char *rev, const char *wwid, 46 | const char *dev, 47 | unsigned int flags, int mask); 48 | 49 | #define mock_path(v, p) \ 50 | __mock_path(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 51 | 0, default_mask) 52 | #define mock_path_flags(v, p, f) \ 53 | __mock_path(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 54 | (f), default_mask) 55 | #define mock_path_blacklisted(v, p) \ 56 | __mock_path(hwt->vecs->pathvec, (v), (p), "0", NULL, NULL, \ 57 | BL_BY_DEVICE, default_mask) 58 | #define mock_path_wwid(v, p, w) \ 59 | __mock_path(hwt->vecs->pathvec, (v), (p), "0", (w), NULL, \ 60 | 0, default_mask) 61 | #define mock_path_wwid_flags(v, p, w, f) \ 62 | __mock_path(hwt->vecs->pathvec, (v), (p), "0", (w), \ 63 | NULL, (f), default_mask) 64 | 65 | struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp); 66 | #define mock_multipath(pp) __mock_multipath(hwt->vecs, (pp)) 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /tests/test-log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "log.h" 8 | #include "test-log.h" 9 | 10 | __attribute__((format(printf, 3, 0))) 11 | void __wrap_dlog (int sink, int prio, const char * fmt, ...) 12 | { 13 | char buff[MAX_MSG_SIZE]; 14 | va_list ap; 15 | char *expected; 16 | 17 | check_expected(prio); 18 | va_start(ap, fmt); 19 | vsnprintf(buff, MAX_MSG_SIZE, fmt, ap); 20 | va_end(ap); 21 | expected = mock_ptr_type(char *); 22 | assert_memory_equal(buff, expected, strlen(expected)); 23 | } 24 | 25 | void expect_condlog(int prio, char *string) 26 | { 27 | expect_value(__wrap_dlog, prio, prio); 28 | will_return(__wrap_dlog, string); 29 | } 30 | -------------------------------------------------------------------------------- /tests/test-log.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEST_LOG_H 2 | #define _TEST_LOG_H 3 | 4 | void __wrap_dlog (int sink, int prio, const char * fmt, ...); 5 | void expect_condlog(int prio, char *string); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /tests/unaligned.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "unaligned.h" 11 | 12 | #define SIZE 16 13 | static const char memory[8] = { 14 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 15 | }; 16 | 17 | static const uint64_t intval64 = 0x0123456789abcdef; 18 | static const uint32_t intval32 = 0x01234567; 19 | static const uint16_t intval16 = 0x0123; 20 | 21 | #include "globals.c" 22 | 23 | static int setup(void **state) 24 | { 25 | return posix_memalign(state, 16, 2 * SIZE); 26 | } 27 | 28 | static int teardown(void **state) 29 | { 30 | free(*state); 31 | return 0; 32 | } 33 | 34 | 35 | #define make_test(bits, offset) \ 36 | static void test_ ## bits ## _ ## offset(void **state) \ 37 | { \ 38 | int len = bits/8; \ 39 | uint8_t *c = *state; \ 40 | uint8_t *p = *state + SIZE; \ 41 | uint64_t u; \ 42 | \ 43 | assert_in_range(len, 1, SIZE); \ 44 | assert_in_range(offset + len, 1, SIZE); \ 45 | memset(c, 0, 2 * SIZE); \ 46 | memcpy(c + offset, memory, len); \ 47 | \ 48 | u = get_unaligned_be##bits(c + offset); \ 49 | assert_int_equal(u, intval##bits); \ 50 | put_unaligned_be##bits(u, p + offset); \ 51 | assert_memory_equal(c + offset, p + offset, len); \ 52 | } 53 | 54 | make_test(16, 0); 55 | make_test(16, 1); 56 | make_test(32, 0); 57 | make_test(32, 1); 58 | make_test(32, 2); 59 | make_test(32, 3); 60 | make_test(64, 0); 61 | make_test(64, 1); 62 | make_test(64, 2); 63 | make_test(64, 3); 64 | make_test(64, 4); 65 | make_test(64, 5); 66 | make_test(64, 6); 67 | make_test(64, 7); 68 | 69 | int test_unaligned(void) 70 | { 71 | const struct CMUnitTest tests[] = { 72 | cmocka_unit_test(test_16_0), 73 | cmocka_unit_test(test_16_1), 74 | cmocka_unit_test(test_32_0), 75 | cmocka_unit_test(test_32_1), 76 | cmocka_unit_test(test_32_2), 77 | cmocka_unit_test(test_32_3), 78 | cmocka_unit_test(test_64_0), 79 | cmocka_unit_test(test_64_1), 80 | cmocka_unit_test(test_64_2), 81 | cmocka_unit_test(test_64_3), 82 | cmocka_unit_test(test_64_4), 83 | cmocka_unit_test(test_64_5), 84 | cmocka_unit_test(test_64_6), 85 | cmocka_unit_test(test_64_7), 86 | }; 87 | return cmocka_run_group_tests(tests, setup, teardown); 88 | } 89 | 90 | int main(void) 91 | { 92 | int ret = 0; 93 | 94 | ret += test_unaligned(); 95 | return ret; 96 | } 97 | --------------------------------------------------------------------------------