multipathd/multipathd
mpathpersist/mpathpersist
.nfs*
+*.swp
+*.patch
+++ /dev/null
-Christophe Varoqui, <christophe.varoqui@opensvc.com>
-
- GNU LIBRARY GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
- Preamble
+ Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
\f
- GNU LIBRARY GENERAL PUBLIC LICENSE
+ GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
- NO WARRANTY
+ NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
- END OF TERMS AND CONDITIONS
+ END OF TERMS AND CONDITIONS
\f
- Appendix: How to Apply These Terms to Your New Libraries
+ How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
+++ /dev/null
-More at http://christophe.varoqui.free.fr/faq.html
-See also http://christophe.varoqui.free.fr/usage.html
-
-1. How to set up System-on-multipath ?
-======================================
-
-prerequisite : udev and multipath-tools installed
-
-here are the steps on a Debian SID system :
-
-* add dm-mpath and dm-multipath to /etc/mkinitrd/modules
-* copy $tools_dir/multipath/0[12]_* to /etc/mkinitrd/scripts
-* define a friendly alias for your multipathed root disk
- (in /etc/multipath.conf). Example : "system"
-* enable busybox in /etc/mkinitrd/mkinitrd.conf and set ROOT
- to any valid block-device (but not a /dev/dm-* one, due to
- an mkintrd misbelief that all dm-* are managed by LVM2)
-* run mkinitrd
-* in /boot/grub/menu.lst, define the root= kernel parameter
- Example : root=/dev/system1
-* modify /etc/fstab to reference /dev/system* partitions
-
-At reboot, you should see some info like :
-
-path /dev/sda : multipath system
-...
-gpt: 0 slices
-dos: 5 slices
-reduced size of partition #2 to 63
-Added system1 : 0 70685937 linear /dev/system 63
-Added system2 : 0 63 linear /dev/system 7068600
-Added system5 : 0 995967 linear /dev/system 70686063
-...
-
-2. How does it compare to commercial product XXX ?
-==================================================
-
-Here are a few distinctive features :
-
-* you can mix HBA models, even different vendors, different speed ...
-* you can mix storage controllers on your SAN, and access them all, applying
- different path grouping policy
-* completely event-driven model : no administration burden if you accept the
- default behaviours
-* extensible : you can plug your own policies if the available ones don't fill
- your needs
-* supports root FS on multipathed SAN
-* free, open-source software
-
-3. LVM2 doesn't see my multipathed devices as PV, what's up ?
-=============================================================
-
-By default, lvm2 does not consider device-mapper block devices (such as a
-dm-crypt device) for use as physical volumes.
-
-In order to use a dm-crypt device as an lvm2 pv, add this line to the
-devices block in /etc/lvm/lvm.conf:
-
-types = [ "device-mapper", 16 ]
-
-If /etc/lvm/lvm.conf does not exist, you can create one based on your
-current/default config like so:
-
-lvm dumpconfig > /etc/lvm/lvm.conf
-
-(tip from Christophe Saout)
-
-4. I see a lot of "io_setup failed" message using the directio checker
-======================================================================
-
-The directio path checker makes use of the asynchronous I/O API (aio) provided
-by modern Linux systems. Asynchronous I/O allows an application to submit I/O
-requests asynchronously and be notified later of their completion status. To
-allow this, we must allocate an asynchronous I/O context (an object of type
-aio_context_t) and this task is handled by the io_setup system call.
-
-A system wide limit on the number of AIO contexts that may be active
-simultaneously is imposed via the aio-max-nr sysctl parameter.
-
-Once this limit has been reached further calls to io_setup will fail with the
-error number EAGAIN leading to the "io_setup failed" messages seen for e.g. when
-running "multipath -ll".
-
-To avoid this problem the number of available aio contexts should be increased
-by setting the aio-max-nr parameter. This can be set on a one-time basis via the
-/proc file system, for e.g.:
-
- # echo 131072 > /proc/sys/fs/aio-max-nr
-
-Doubles the number of available contexts from the default value of 65536.
-
-To make this setting persistent a line may be added to /etc/sysctl.conf:
-
- fs.aio-max-nr = 131072
-
-Consult appropriate application and operating system tuning recommendations for
-guidance on appropriate values for this parameter.
recurse:
@for dir in $(BUILDDIRS); do \
- $(MAKE) -C $$dir BUILD=$(BUILD) VERSION=$(VERSION) \
+ $(MAKE) -C $$dir VERSION=$(VERSION) \
KRNLSRC=$(KRNLSRC) KRNLOBJ=$(KRNLOBJ) || exit $?; \
done
done
clean: recurse_clean
- rm -f multipath-tools.spec
- rm -rf rpms
install: recurse_install
etags -a libmultipath/*.h
etags -a multipathd/*.c
etags -a multipathd/*.h
-
-release:
- sed -e "s/__VERSION__/${VERSION}/" \
- multipath-tools.spec.in > multipath-tools.spec
-
-rpm: release
- rpmbuild -bb multipath-tools.spec
SYSTEMDPATH=usr/lib
endif
-prefix =
+prefix =
exec_prefix = $(prefix)
bindir = $(exec_prefix)/sbin
libudevdir = $(prefix)/$(SYSTEMDPATH)/udev
mandir = $(prefix)/usr/share/man/man8
man5dir = $(prefix)/usr/share/man/man5
man3dir = $(prefix)/usr/share/man/man3
-rcdir = $(prefix)/etc/init.d
syslibdir = $(prefix)/$(LIB)
incdir = $(prefix)/usr/include
libdir = $(prefix)/$(LIB)/multipath
mpathcmddir = $(TOPDIR)/libmpathcmd
GZIP = gzip -9 -c
+RM = rm -f
+LN = ln -sf
INSTALL_PROGRAM = install
-ifndef RPM_OPT_FLAGS
- RPM_OPT_FLAGS = -O2 -g -pipe -Wformat-security -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
-endif
+OPTFLAGS = -Wunused -Wstrict-prototypes -O2 -g -pipe -Wformat-security -Wall \
+ -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4
-OPTFLAGS = $(RPM_OPT_FLAGS) -Wunused -Wstrict-prototypes
CFLAGS = $(OPTFLAGS) -fPIC -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\"
SHARED_FLAGS = -shared
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
-
multipath-tools for Linux <http://christophe.varoqui.free.fr/>
+
This package provides the following binaries to drive the
Device Mapper multipathing driver:
multipath - Device mapper target autoconfig.
multipathd - Multipath daemon.
mpathpersist - Manages SCSI persistent reservations on dm multipath devices.
-kpartxrtx - Create device maps from partition tables.
+kpartx - Create device maps from partition tables.
+
+
+tarballs are not generated anymore, to get a specific release do:
+git clone http://git.opensvc.com/multipath-tools/.git
+cd multipath-tools
+git tag
+git archive --format=tar.gz --prefix=multipath-tools-X.Y.Z/ X.Y.Z > ../multipath-tools-X.Y.Z.tar.gz
-To get latest code: git clone http://git.opensvc.com/multipath-tools/.git
+Alternatively it may be obtained from gitweb, go to:
+http://git.opensvc.com/?p=multipath-tools/.git;a=tags
+select a release-tag and then click on "snapshot".
+
+
+To get latest devel code: git clone http://git.opensvc.com/multipath-tools/.git
Mailing list: http://www.redhat.com/mailman/listinfo/dm-devel
Gitweb: http://git.opensvc.com/?p=multipath-tools/.git
+Patchwork: http://patchwork.kernel.org/project/dm-devel/list/
+
+Current maintainer is Christophe Varoqui <christophe.varoqui@opensvc.com>
+++ /dev/null
-002:
-* convert to kpartx name everywhere
-* remove all HDGEO ioctl code
-* now work with files by mapping loops on the fly
-* merged and massage lopart.[ch] from lomount.[ch]
- (due credit to original author here : hpa ?)
-* added a fn find_loop_by_file in lopart.[ch]
-001:
-* Initial release
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
uninstall:
- rm -f $(DESTDIR)$(bindir)/$(EXEC)
- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
- rm -f $(DESTDIR)$(libudevdir)/kpartx_id
- rm -f $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules
- rm -f $(DESTDIR)$(libudevdir)/rules.d/67-kpartx-compat.rules
+ $(RM) $(DESTDIR)$(bindir)/$(EXEC)
+ $(RM) $(DESTDIR)$(mandir)/$(EXEC).8.gz
+ $(RM) $(DESTDIR)$(libudevdir)/kpartx_id
+ $(RM) $(DESTDIR)$(libudevdir)/rules.d/66-kpartx.rules
+ $(RM) $(DESTDIR)$(libudevdir)/rules.d/67-kpartx-compat.rules
clean:
- rm -f core *.o $(EXEC) *.gz
+ $(RM) core *.o $(EXEC) *.gz
+++ /dev/null
-This version of partx is intented to be build
-static against klibc.
-
-It creates partitions as device maps.
-
-With due respect to the original authors,
-
-have fun,
-cvaroqui
-/*
+/*
* crc32.c
* This code is in the public domain; copyright abandoned.
* Liability for non-performance of this code is limited to the amount
* other uses, or the previous crc32 value if computing incrementally.
* @p - pointer to buffer over which CRC is run
* @len - length of buffer @p
- *
+ *
*/
uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
{
* other uses, or the previous crc32 value if computing incrementally.
* @p - pointer to buffer over which CRC is run
* @len - length of buffer @p
- *
+ *
*/
uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
{
* other uses, or the previous crc32 value if computing incrementally.
* @p - pointer to buffer over which CRC is run
* @len - length of buffer @p
- *
+ *
*/
uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
{
* other uses, or the previous crc32 value if computing incrementally.
* @p - pointer to buffer over which CRC is run
* @len - length of buffer @p
- *
+ *
*/
uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
{
*
* A big-endian CRC written this way would be coded like:
* for (i = 0; i < input_bits; i++) {
- * multiple = remainder & 0x80000000 ? CRCPOLY : 0;
- * remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * remainder = (remainder << 1 | next_input_bit()) ^ multiple;
* }
* Notice how, to get at bit 32 of the shifted remainder, we look
* at bit 31 of the remainder *before* shifting it.
* This changes the code to:
* for (i = 0; i < input_bits; i++) {
* remainder ^= next_input_bit() << 31;
- * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- * remainder = (remainder << 1) ^ multiple;
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
* }
* With this optimization, the little-endian code is simpler:
* for (i = 0; i < input_bits; i++) {
* remainder ^= next_input_bit();
- * multiple = (remainder & 1) ? CRCPOLY : 0;
- * remainder = (remainder >> 1) ^ multiple;
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder >> 1) ^ multiple;
* }
*
* Note that the other details of endianness have been hidden in CRCPOLY
* order, we can actually do the merging 8 or more bits at a time rather
* than one bit at a time:
* for (i = 0; i < input_bytes; i++) {
- * remainder ^= next_input_byte() << 24;
- * for (j = 0; j < 8; j++) {
- * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- * remainder = (remainder << 1) ^ multiple;
- * }
+ * remainder ^= next_input_byte() << 24;
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
* }
* Or in little-endian:
* for (i = 0; i < input_bytes; i++) {
- * remainder ^= next_input_byte();
- * for (j = 0; j < 8; j++) {
- * multiple = (remainder & 1) ? CRCPOLY : 0;
- * remainder = (remainder << 1) ^ multiple;
- * }
+ * remainder ^= next_input_byte();
+ * for (j = 0; j < 8; j++) {
+ * multiple = (remainder & 1) ? CRCPOLY : 0;
+ * remainder = (remainder << 1) ^ multiple;
+ * }
* }
* If the input is a multiple of 32 bits, you can even XOR in a 32-bit
* word at a time and increase the inner loop count to 32.
* in the correct multiple to subtract, we can shift a byte at a time.
* This produces a 40-bit (rather than a 33-bit) intermediate remainder,
* but again the multiple of the polynomial to subtract depends only on
- * the high bits, the high 8 bits in this case.
+ * the high bits, the high 8 bits in this case.
*
* The multile we need in that case is the low 32 bits of a 40-bit
* value whose high 8 bits are given, and which is a multiple of the
/**
* init_crc32(): generates CRC32 tables
- *
+ *
* On successful initialization, use count is increased.
* This guarantees that the library functions will stay resident
* in memory, and prevents someone from 'rmmod crc32' while
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
/*
*/
-int
+int
read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
{
int retval = -1;
* major/minor into an openable device file, so we have
* to create one for ourselves.
*/
-
+
sprintf(pathname, "/dev/.kpartx-node-%u-%u",
(unsigned int)major(dev), (unsigned int)minor(dev));
if ((fd_dasd = open(pathname, O_RDONLY)) == -1) {
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DASD_H
#define _DASD_H
-typedef struct ttr
+typedef struct ttr
{
- uint16_t tt;
- uint8_t r;
+ uint16_t tt;
+ uint8_t r;
} __attribute__ ((packed)) ttr_t;
-typedef struct cchhb
+typedef struct cchhb
{
- uint16_t cc;
- uint16_t hh;
- uint8_t b;
+ uint16_t cc;
+ uint16_t hh;
+ uint8_t b;
} __attribute__ ((packed)) cchhb_t;
-typedef struct cchh
+typedef struct cchh
{
- uint16_t cc;
- uint16_t hh;
+ uint16_t cc;
+ uint16_t hh;
} __attribute__ ((packed)) cchh_t;
-typedef struct labeldate
+typedef struct labeldate
{
- uint8_t year;
- uint16_t day;
+ uint8_t year;
+ uint16_t day;
} __attribute__ ((packed)) labeldate_t;
-typedef struct volume_label
+typedef struct volume_label
{
- char volkey[4]; /* volume key = volume label */
+ char volkey[4]; /* volume key = volume label */
char vollbl[4]; /* volume label */
char volid[6]; /* volume identifier */
uint8_t security; /* security byte */
cchhb_t vtoc; /* VTOC address */
char res1[5]; /* reserved */
- char cisize[4]; /* CI-size for FBA,... */
- /* ...blanks for CKD */
+ char cisize[4]; /* CI-size for FBA,... */
+ /* ...blanks for CKD */
char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */
char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */
char res2[4]; /* reserved */
} __attribute__ ((packed)) volume_label_t;
-typedef struct extent
+typedef struct extent
{
- uint8_t typeind; /* extent type indicator */
- uint8_t seqno; /* extent sequence number */
- cchh_t llimit; /* starting point of this extent */
- cchh_t ulimit; /* ending point of this extent */
+ uint8_t typeind; /* extent type indicator */
+ uint8_t seqno; /* extent sequence number */
+ cchh_t llimit; /* starting point of this extent */
+ cchh_t ulimit; /* ending point of this extent */
} __attribute__ ((packed)) extent_t;
-typedef struct dev_const
+typedef struct dev_const
{
- uint16_t DS4DSCYL; /* number of logical cyls */
- uint16_t DS4DSTRK; /* number of tracks in a logical cylinder */
- uint16_t DS4DEVTK; /* device track length */
- uint8_t DS4DEVI; /* non-last keyed record overhead */
- uint8_t DS4DEVL; /* last keyed record overhead */
- uint8_t DS4DEVK; /* non-keyed record overhead differential */
- uint8_t DS4DEVFG; /* flag byte */
- uint16_t DS4DEVTL; /* device tolerance */
- uint8_t DS4DEVDT; /* number of DSCB's per track */
- uint8_t DS4DEVDB; /* number of directory blocks per track */
+ uint16_t DS4DSCYL; /* number of logical cyls */
+ uint16_t DS4DSTRK; /* number of tracks in a logical cylinder */
+ uint16_t DS4DEVTK; /* device track length */
+ uint8_t DS4DEVI; /* non-last keyed record overhead */
+ uint8_t DS4DEVL; /* last keyed record overhead */
+ uint8_t DS4DEVK; /* non-keyed record overhead differential */
+ uint8_t DS4DEVFG; /* flag byte */
+ uint16_t DS4DEVTL; /* device tolerance */
+ uint8_t DS4DEVDT; /* number of DSCB's per track */
+ uint8_t DS4DEVDB; /* number of directory blocks per track */
} __attribute__ ((packed)) dev_const_t;
-typedef struct format1_label
+typedef struct format1_label
{
char DS1DSNAM[44]; /* data set name */
uint8_t DS1FMTID; /* format identifier */
labeldate_t DS1CREDT; /* creation date: ydd */
labeldate_t DS1EXPDT; /* expiration date */
uint8_t DS1NOEPV; /* number of extents on volume */
- uint8_t DS1NOBDB; /* no. of bytes used in last direction blk */
+ uint8_t DS1NOBDB; /* no. of bytes used in last direction blk */
uint8_t DS1FLAG1; /* flag 1 */
char DS1SYSCD[13]; /* system code */
labeldate_t DS1REFD; /* date last referenced */
- uint8_t DS1SMSFG; /* system managed storage indicators */
- uint8_t DS1SCXTF; /* sec. space extension flag byte */
- uint16_t DS1SCXTV; /* secondary space extension value */
- uint8_t DS1DSRG1; /* data set organisation byte 1 */
- uint8_t DS1DSRG2; /* data set organisation byte 2 */
- uint8_t DS1RECFM; /* record format */
+ uint8_t DS1SMSFG; /* system managed storage indicators */
+ uint8_t DS1SCXTF; /* sec. space extension flag byte */
+ uint16_t DS1SCXTV; /* secondary space extension value */
+ uint8_t DS1DSRG1; /* data set organisation byte 1 */
+ uint8_t DS1DSRG2; /* data set organisation byte 2 */
+ uint8_t DS1RECFM; /* record format */
uint8_t DS1OPTCD; /* option code */
uint16_t DS1BLKL; /* block length */
uint16_t DS1LRECL; /* record length */
uint8_t DS1KEYL; /* key length */
uint16_t DS1RKP; /* relative key position */
uint8_t DS1DSIND; /* data set indicators */
- uint8_t DS1SCAL1; /* secondary allocation flag byte */
- char DS1SCAL3[3]; /* secondary allocation quantity */
+ uint8_t DS1SCAL1; /* secondary allocation flag byte */
+ char DS1SCAL3[3]; /* secondary allocation quantity */
ttr_t DS1LSTAR; /* last used track and block on track */
uint16_t DS1TRBAL; /* space remaining on last used track */
- uint16_t res1; /* reserved */
+ uint16_t res1; /* reserved */
extent_t DS1EXT1; /* first extent description */
extent_t DS1EXT2; /* second extent description */
extent_t DS1EXT3; /* third extent description */
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
- -ENP ->LF */
+ -ENP ->LF */
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
- -IUS */
+ -IUS */
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
- -INP */
+ -INP */
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
- -SW */
+ -SW */
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
};
-static inline void
+static inline void
vtoc_ebcdic_dec (const char *source, char *target, int l)
{
int i;
- for (i = 0; i < l; i++)
+ for (i = 0; i < l; i++)
target[i]=(char)EBCtoASC[(unsigned char)(source[i])];
}
#ifdef LIBDM_API_COOKIE
if (!udev_sync)
udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
- if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags)) {
- dm_udev_complete(cookie);
+ if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
- }
#endif
r = dm_task_run(dmt);
#ifdef LIBDM_API_COOKIE
- if (udev_wait_flag) {
- if (!r)
- dm_udev_complete(cookie);
- else
+ if (udev_wait_flag)
dm_udev_wait(cookie);
- }
#endif
out:
dm_task_destroy(dmt);
if (!udev_sync)
udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (task == DM_DEVICE_CREATE &&
- !dm_task_set_cookie(dmt, &cookie, udev_flags)) {
- dm_udev_complete(cookie);
+ !dm_task_set_cookie(dmt, &cookie, udev_flags))
goto addout;
- }
#endif
r = dm_task_run (dmt);
#ifdef LIBDM_API_COOKIE
- if (task == DM_DEVICE_CREATE) {
- if (!r)
- dm_udev_complete(cookie);
- else
+ if (task == DM_DEVICE_CREATE)
dm_udev_wait(cookie);
- }
#endif
addout:
dm_task_destroy (dmt);
{
int r = 1;
struct dm_task *dmt;
- void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params = NULL;
goto out;
/* Fetch 1st target */
- next = dm_get_next_target(dmt, next, &start, &length,
- &target_type, ¶ms);
+ dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, ¶ms);
if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
r = 0;
/*
* Source: copy of util-linux' partx dos.c
*
- * Copyrights of the original file apply
+ * Copyrights of the original file apply
* Copyright (c) 2005 Bastian Blank
*/
#include "kpartx.h"
unsigned long offset = all.start;
int i, n=4;
unsigned char *bp;
- int sector_size_mul = get_sector_size(fd)/512;
+ uint64_t sector_size_mul = get_sector_size(fd)/512;
bp = (unsigned char *)getblock(fd, offset);
if (bp == NULL)
/*
efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
-
+
Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EFI_H
/*
gpt.[ch]
- Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
EFI GUID Partition Table handling
Per Intel EFI Specification v1.02
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#endif
struct blkdev_ioctl_param {
- unsigned int block;
- size_t content_length;
- char * block_contents;
+ unsigned int block;
+ size_t content_length;
+ char * block_contents;
};
/**
* @len - length of buf
*
* Description: Returns EFI-style CRC32 value for @buf
- *
+ *
* This function uses the little endian Ethernet polynomial
* but seeds the function with ~0, and xor's with ~0 at the end.
* Note, the EFI Specification, v1.02, has a reference to
signature = (__le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
for (i = 0; signature && i < 4; i++) {
if (mbr->partition[i].sys_type ==
- EFI_PMBR_OSTYPE_EFI_GPT) {
+ EFI_PMBR_OSTYPE_EFI_GPT) {
found = 1;
break;
}
* - filedes is an open file descriptor, suitable for reading
* Modifies: nothing
* Returns:
- * Last LBA value on success
+ * Last LBA value on success
* 0 on error
*
* Try getting BLKGETSIZE64 and BLKSSZGET first,
/************************************************************
* last_lba(): return number of last logical block of device
- *
+ *
* @fd
- *
+ *
* Description: returns Last LBA value on success, 0 on error.
* Notes: The value st_blocks gives the size of the file
* in 512-byte blocks, which is OK if
static ssize_t
read_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count)
{
- int rc;
- struct blkdev_ioctl_param ioctl_param;
+ int rc;
+ struct blkdev_ioctl_param ioctl_param;
- if (!buffer) return 0;
+ if (!buffer) return 0;
- ioctl_param.block = 0; /* read the last sector */
- ioctl_param.content_length = count;
- ioctl_param.block_contents = buffer;
+ ioctl_param.block = 0; /* read the last sector */
+ ioctl_param.content_length = count;
+ ioctl_param.block_contents = buffer;
- rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param);
- if (rc == -1) perror("read failed");
+ rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param);
+ if (rc == -1) perror("read failed");
- return !rc;
+ return !rc;
}
static ssize_t
int sector_size = get_sector_size(fd);
off_t offset = lba * sector_size;
uint64_t lastlba;
- ssize_t bytesread;
+ ssize_t bytesread;
- lseek(fd, offset, SEEK_SET);
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return 0;
bytesread = read(fd, buffer, bytes);
lastlba = last_lba(fd);
if (!lastlba)
return bytesread;
- /* Kludge. This is necessary to read/write the last
- block of an odd-sized disk, until Linux 2.5.x kernel fixes.
- This is only used by gpt.c, and only to read
- one sector, so we don't have to be fancy.
- */
- if (!bytesread && !(lastlba & 1) && lba == lastlba) {
- bytesread = read_lastoddsector(fd, lba, buffer, bytes);
- }
- return bytesread;
+ /* Kludge. This is necessary to read/write the last
+ block of an odd-sized disk, until Linux 2.5.x kernel fixes.
+ This is only used by gpt.c, and only to read
+ one sector, so we don't have to be fancy.
+ */
+ if (!bytesread && !(lastlba & 1) && lba == lastlba) {
+ bytesread = read_lastoddsector(fd, lba, buffer, bytes);
+ }
+ return bytesread;
}
/**
* alloc_read_gpt_entries(): reads partition entries from disk
* @fd is an open file descriptor to the whole disk
- * @gpt is a buffer into which the GPT will be put
+ * @gpt is a buffer into which the GPT will be put
* Description: Returns ptes on success, NULL on error.
* Allocates space for PTEs based on information found in @gpt.
* Notes: remember to free pte when you're done!
alloc_read_gpt_entries(int fd, gpt_header * gpt)
{
gpt_entry *pte;
- size_t count = __le32_to_cpu(gpt->num_partition_entries) *
- __le32_to_cpu(gpt->sizeof_partition_entry);
+ size_t count = __le32_to_cpu(gpt->num_partition_entries) *
+ __le32_to_cpu(gpt->sizeof_partition_entry);
- if (!count) return NULL;
+ if (!count) return NULL;
pte = (gpt_entry *)malloc(count);
if (!pte)
memset(pte, 0, count);
if (!read_lba(fd, __le64_to_cpu(gpt->partition_entry_lba), pte,
- count)) {
+ count)) {
free(pte);
return NULL;
}
* alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
* @fd is an open file descriptor to the whole disk
* @lba is the Logical Block Address of the partition table
- *
+ *
* Description: returns GPT header on success, NULL on error. Allocates
* and fills a GPT header starting at @ from @bdev.
* Note: remember to free gpt when finished with it.
*/
static int
is_gpt_valid(int fd, uint64_t lba,
- gpt_header ** gpt, gpt_entry ** ptes)
+ gpt_header ** gpt, gpt_entry ** ptes)
{
int rc = 0; /* default to not valid */
uint32_t crc, origcrc;
if (!gpt || !ptes)
- return 0;
+ return 0;
if (!(*gpt = alloc_read_gpt_header(fd, lba)))
return 0;
/* Check the GUID Partition Table signature */
if (__le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
- /*
+ /*
printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
__le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
*/
if (__le64_to_cpu((*gpt)->my_lba) != lba) {
/*
printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n",
- __le64_to_cpu((*gpt)->my_lba), lba);
+ __le64_to_cpu((*gpt)->my_lba), lba);
*/
free(*gpt);
*gpt = NULL;
/* Check the GUID Partition Entry Array CRC */
crc = efi_crc32(*ptes,
- __le32_to_cpu((*gpt)->num_partition_entries) *
+ __le32_to_cpu((*gpt)->num_partition_entries) *
__le32_to_cpu((*gpt)->sizeof_partition_entry));
if (crc != __le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
// printf("GUID Partitition Entry Array CRC check failed.\n");
* @lastlba is the last LBA number
* Description: Returns nothing. Sanity checks pgpt and agpt fields
* and prints warnings on discrepancies.
- *
+ *
*/
static void
compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
return;
if (__le64_to_cpu(pgpt->my_lba) != __le64_to_cpu(agpt->alternate_lba)) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:Primary header LBA != Alt. header alternate_lba\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
__le64_to_cpu(pgpt->my_lba),
- __le64_to_cpu(agpt->alternate_lba));
+ __le64_to_cpu(agpt->alternate_lba));
#endif
}
if (__le64_to_cpu(pgpt->alternate_lba) != __le64_to_cpu(agpt->my_lba)) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:Primary header alternate_lba != Alt. header my_lba\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
__le64_to_cpu(pgpt->alternate_lba),
- __le64_to_cpu(agpt->my_lba));
+ __le64_to_cpu(agpt->my_lba));
#endif
}
if (__le64_to_cpu(pgpt->first_usable_lba) !=
- __le64_to_cpu(agpt->first_usable_lba)) {
+ __le64_to_cpu(agpt->first_usable_lba)) {
error_found++;
fprintf(stderr, "GPT:first_usable_lbas don't match.\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
__le64_to_cpu(pgpt->first_usable_lba),
- __le64_to_cpu(agpt->first_usable_lba));
+ __le64_to_cpu(agpt->first_usable_lba));
#endif
}
if (__le64_to_cpu(pgpt->last_usable_lba) !=
- __le64_to_cpu(agpt->last_usable_lba)) {
+ __le64_to_cpu(agpt->last_usable_lba)) {
error_found++;
fprintf(stderr, "GPT:last_usable_lbas don't match.\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
__le64_to_cpu(pgpt->last_usable_lba),
- __le64_to_cpu(agpt->last_usable_lba));
+ __le64_to_cpu(agpt->last_usable_lba));
#endif
}
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
fprintf(stderr, "GPT:disk_guids don't match.\n");
}
if (__le32_to_cpu(pgpt->num_partition_entries) !=
- __le32_to_cpu(agpt->num_partition_entries)) {
+ __le32_to_cpu(agpt->num_partition_entries)) {
error_found++;
fprintf(stderr, "GPT:num_partition_entries don't match: "
"0x%x != 0x%x\n",
__le32_to_cpu(agpt->num_partition_entries));
}
if (__le32_to_cpu(pgpt->sizeof_partition_entry) !=
- __le32_to_cpu(agpt->sizeof_partition_entry)) {
+ __le32_to_cpu(agpt->sizeof_partition_entry)) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:sizeof_partition_entry values don't match: "
"0x%x != 0x%x\n",
- __le32_to_cpu(pgpt->sizeof_partition_entry),
+ __le32_to_cpu(pgpt->sizeof_partition_entry),
__le32_to_cpu(agpt->sizeof_partition_entry));
}
if (__le32_to_cpu(pgpt->partition_entry_array_crc32) !=
- __le32_to_cpu(agpt->partition_entry_array_crc32)) {
+ __le32_to_cpu(agpt->partition_entry_array_crc32)) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:partition_entry_array_crc32 values don't match: "
"0x%x != 0x%x\n",
- __le32_to_cpu(pgpt->partition_entry_array_crc32),
+ __le32_to_cpu(pgpt->partition_entry_array_crc32),
__le32_to_cpu(agpt->partition_entry_array_crc32));
}
if (__le64_to_cpu(pgpt->alternate_lba) != lastlba) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
if (__le64_to_cpu(agpt->my_lba) != lastlba) {
error_found++;
- fprintf(stderr,
+ fprintf(stderr,
"GPT:Alternate GPT header not at the end of the disk.\n");
#ifdef DEBUG
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
}
if (error_found)
- fprintf(stderr,
+ fprintf(stderr,
"GPT: Use GNU Parted to correct GPT errors.\n");
return;
}
static int
find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
{
- extern int force_gpt;
+ extern int force_gpt;
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
gpt_header *pgpt = NULL, *agpt = NULL;
gpt_entry *pptes = NULL, *aptes = NULL;
return 0;
good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
&pgpt, &pptes);
- if (good_pgpt) {
+ if (good_pgpt) {
good_agpt = is_gpt_valid(fd,
- __le64_to_cpu(pgpt->alternate_lba),
+ __le64_to_cpu(pgpt->alternate_lba),
&agpt, &aptes);
- if (!good_agpt) {
- good_agpt = is_gpt_valid(fd, lastlba,
- &agpt, &aptes);
- }
- }
- else {
- good_agpt = is_gpt_valid(fd, lastlba,
- &agpt, &aptes);
- }
-
- /* The obviously unsuccessful case */
- if (!good_pgpt && !good_agpt) {
- goto fail;
- }
+ if (!good_agpt) {
+ good_agpt = is_gpt_valid(fd, lastlba,
+ &agpt, &aptes);
+ }
+ }
+ else {
+ good_agpt = is_gpt_valid(fd, lastlba,
+ &agpt, &aptes);
+ }
+
+ /* The obviously unsuccessful case */
+ if (!good_pgpt && !good_agpt) {
+ goto fail;
+ }
/* This will be added to the EFI Spec. per Intel after v1.02. */
- legacymbr = malloc(sizeof (*legacymbr));
- if (legacymbr) {
- memset(legacymbr, 0, sizeof (*legacymbr));
- read_lba(fd, 0, (uint8_t *) legacymbr,
- sizeof (*legacymbr));
- good_pmbr = is_pmbr_valid(legacymbr);
- free(legacymbr);
- legacymbr=NULL;
- }
-
- /* Failure due to bad PMBR */
- if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
- fprintf(stderr,
- " Warning: Disk has a valid GPT signature "
- "but invalid PMBR.\n"
- " Assuming this disk is *not* a GPT disk anymore.\n"
- " Use gpt kernel option to override. "
- "Use GNU Parted to correct disk.\n");
- goto fail;
- }
-
- /* Would fail due to bad PMBR, but force GPT anyhow */
- if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
- fprintf(stderr,
- " Warning: Disk has a valid GPT signature but "
- "invalid PMBR.\n"
- " Use GNU Parted to correct disk.\n"
- " gpt option taken, disk treated as GPT.\n");
- }
-
- compare_gpts(pgpt, agpt, lastlba);
-
- /* The good cases */
- if (good_pgpt && (good_pmbr || force_gpt)) {
- *gpt = pgpt;
- *ptes = pptes;
- if (agpt) { free(agpt); agpt = NULL; }
- if (aptes) { free(aptes); aptes = NULL; }
- if (!good_agpt) {
- fprintf(stderr,
+ legacymbr = malloc(sizeof (*legacymbr));
+ if (legacymbr) {
+ memset(legacymbr, 0, sizeof (*legacymbr));
+ read_lba(fd, 0, (uint8_t *) legacymbr,
+ sizeof (*legacymbr));
+ good_pmbr = is_pmbr_valid(legacymbr);
+ free(legacymbr);
+ legacymbr=NULL;
+ }
+
+ /* Failure due to bad PMBR */
+ if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
+ fprintf(stderr,
+ " Warning: Disk has a valid GPT signature "
+ "but invalid PMBR.\n"
+ " Assuming this disk is *not* a GPT disk anymore.\n"
+ " Use gpt kernel option to override. "
+ "Use GNU Parted to correct disk.\n");
+ goto fail;
+ }
+
+ /* Would fail due to bad PMBR, but force GPT anyhow */
+ if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
+ fprintf(stderr,
+ " Warning: Disk has a valid GPT signature but "
+ "invalid PMBR.\n"
+ " Use GNU Parted to correct disk.\n"
+ " gpt option taken, disk treated as GPT.\n");
+ }
+
+ compare_gpts(pgpt, agpt, lastlba);
+
+ /* The good cases */
+ if (good_pgpt && (good_pmbr || force_gpt)) {
+ *gpt = pgpt;
+ *ptes = pptes;
+ if (agpt) { free(agpt); agpt = NULL; }
+ if (aptes) { free(aptes); aptes = NULL; }
+ if (!good_agpt) {
+ fprintf(stderr,
"Alternate GPT is invalid, "
- "using primary GPT.\n");
- }
- return 1;
- }
- else if (good_agpt && (good_pmbr || force_gpt)) {
- *gpt = agpt;
- *ptes = aptes;
- if (pgpt) { free(pgpt); pgpt = NULL; }
- if (pptes) { free(pptes); pptes = NULL; }
- fprintf(stderr,
- "Primary GPT is invalid, using alternate GPT.\n");
- return 1;
- }
+ "using primary GPT.\n");
+ }
+ return 1;
+ }
+ else if (good_agpt && (good_pmbr || force_gpt)) {
+ *gpt = agpt;
+ *ptes = aptes;
+ if (pgpt) { free(pgpt); pgpt = NULL; }
+ if (pptes) { free(pptes); pptes = NULL; }
+ fprintf(stderr,
+ "Primary GPT is invalid, using alternate GPT.\n");
+ return 1;
+ }
fail:
- if (pgpt) { free(pgpt); pgpt=NULL; }
- if (agpt) { free(agpt); agpt=NULL; }
- if (pptes) { free(pptes); pptes=NULL; }
- if (aptes) { free(aptes); aptes=NULL; }
- *gpt = NULL;
- *ptes = NULL;
- return 0;
+ if (pgpt) { free(pgpt); pgpt=NULL; }
+ if (agpt) { free(agpt); agpt=NULL; }
+ if (pptes) { free(pptes); pptes=NULL; }
+ if (aptes) { free(aptes); aptes=NULL; }
+ *gpt = NULL;
+ *ptes = NULL;
+ return 0;
}
/**
- * read_gpt_pt()
+ * read_gpt_pt()
* @fd
* @all - slice with start/size of whole disk
*
gpt_entry *ptes = NULL;
uint32_t i;
int n = 0;
- int last_used_index=-1;
+ int last_used_index=-1;
int sector_size_mul = get_sector_size(fd)/512;
if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
sp[n].size = sector_size_mul *
(__le64_to_cpu(ptes[i].ending_lba) -
__le64_to_cpu(ptes[i].starting_lba) + 1);
- last_used_index=n;
+ last_used_index=n;
n++;
}
}
/*
gpt.[ch]
- Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
EFI GUID Partition Table handling
Per Intel EFI Specification v1.02
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GPT_H
typedef struct _gpt_entry_attributes {
uint64_t required_to_function:1;
uint64_t reserved:47;
- uint64_t type_guid_specific:16;
+ uint64_t type_guid_specific:16;
} __attribute__ ((packed)) gpt_entry_attributes;
typedef struct _gpt_entry {
} __attribute__ ((packed)) gpt_entry;
-/*
+/*
These values are only defaults. The actual on-disk structures
may define different sizes, so use those unless creating a new GPT disk!
*/
#define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384
-/*
+/*
Number of actual partition entries should be calculated
- as:
+ as:
*/
#define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \
- (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
- sizeof(gpt_entry))
+ (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
+ sizeof(gpt_entry))
/* Protected Master Boot Record & Legacy MBR share same structure */
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 4
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
.RB wholedisk
.SH DESCRIPTION
This tool, derived from util-linux' partx, reads partition
-tables on specified device and create device maps over partitions
-segments detected. It is called from hotplug upon device maps
+tables on specified device and create device maps over partitions
+segments detected. It is called from hotplug upon device maps
creation and deletion.
.SH OPTIONS
.TP
.PP
This will output lines such as:
.IP
-loop3p1 : 0 20964762 /dev/loop3 63
+add map loop1p1 (254:4): 0 409597 linear 7:1 3
.PP
-The
-.I loop3p1
-is the name of a device file under
+The
+.I loop1p1
+is the name of a device file under
.I /dev/mapper
which you can use to access the partition, for example to fsck it:
.IP
-fsck /dev/mapper/loop3p1
+fsck /dev/mapper/loop1p1
.PP
When you're done, you need to remove the devices:
.IP
This man page was assembled By Patrick Caulfield
for the Debian project. From documentation provided
by the multipath author Christophe Varoqui, <christophe.varoqui@opensvc.com> and others.
-
get_hotplug_device(void)
{
unsigned int major, minor, off, len;
- const char *mapname;
+ char *mapname;
char *devname = NULL;
char *device = NULL;
char *var = NULL;
len = strlen(mapname);
/* Dirname + mapname + \0 */
- if (!(device = (char *)malloc(sizeof(char) * (off + len + 1))))
+ if (!(device = (char *)malloc(sizeof(char) * (off + len + 1)))) {
+ free(mapname);
return NULL;
+ }
/* Create new device name. */
snprintf(device, off + 1, "%s", devname);
snprintf(device + off, len + 1, "%s", mapname);
- if (strlen(device) != (off + len))
+ if (strlen(device) != (off + len)) {
+ free(device);
+ free(mapname);
return NULL;
-
+ }
+ free(mapname);
return device;
}
printf("del devmap : %s\n", partname);
}
- if (S_ISREG (buf.st_mode)) {
- if (del_loop(device)) {
+ if (loopdev) {
+ if (del_loop(loopdev)) {
if (verbose)
printf("can't del loop : %s\n",
- device);
+ loopdev);
exit(1);
}
- printf("loop deleted : %s\n", device);
+ printf("loop deleted : %s\n", loopdev);
}
break;
RUN+="/sbin/kpartx -u -p -part /dev/$name"
LABEL="kpartx_end"
-
-
#include <sys/mman.h>
#include <sys/types.h>
#include <dirent.h>
-#include <sysmacros.h>
+#include "sysmacros.h"
#include <linux/loop.h>
#include "lopart.h"
#endif
#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
- && !defined (__s390x__)
+ && !defined (__s390x__)
#define int2ptr(x) ((void *) ((int) x))
#else
#define int2ptr(x) ((void *) ((long) x))
loopmajor = 0;
if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
-
+
while (fgets (line, sizeof(line), procdev)) {
-
+
if ((cp = strstr (line, " loop\n")) != NULL) {
*cp='\0';
loopmajor=atoi(line);
continue;
sprintf(dev, "/dev/%s", dent->d_name);
- if (stat (dev, &statbuf) != 0 ||
- !S_ISBLK(statbuf.st_mode))
- continue;
-
fd = open (dev, O_RDONLY);
if (fd < 0)
break;
+ if (fstat (fd, &statbuf) != 0 ||
+ !S_ISBLK(statbuf.st_mode)) {
+ close (fd);
+ continue;
+ }
+
if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
close (fd);
continue;
while (next_loop_dev == NULL) {
if (stat("/dev/loop-control", &statbuf) == 0 &&
S_ISCHR(statbuf.st_mode)) {
- fd = open("/dev/loop-control", O_RDWR);
- if (fd < 0)
+ int next_loop_fd;
+
+ next_loop_fd = open("/dev/loop-control", O_RDWR);
+ if (next_loop_fd < 0)
return NULL;
- next_loop = ioctl(fd, LOOP_CTL_GET_FREE);
+ next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
+ close(next_loop_fd);
if (next_loop < 0)
return NULL;
- close(fd);
}
sprintf(dev, "/dev/loop%d", next_loop);
- if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
- somedev++;
- fd = open (dev, O_RDONLY);
-
- if (fd >= 0) {
-
+ fd = open (dev, O_RDONLY);
+ if (fd >= 0) {
+ if (fstat (fd, &statbuf) == 0 &&
+ S_ISBLK(statbuf.st_mode)) {
+ somedev++;
if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
someloop++; /* in use */
-
- else if (errno == ENXIO) {
- close (fd);
+ else if (errno == ENXIO)
next_loop_dev = xstrdup(dev);
- }
- close (fd);
}
+ close (fd);
/* continue trying as long as devices exist */
continue;
}
if ((fd = open (device, mode)) < 0) {
+ close(ffd);
perror (device);
return 1;
}
return 0;
}
-extern int
+extern int
del_loop (const char *device)
{
- int retries = 3;
+ int retries = 5;
int fd;
if ((fd = open (device, O_RDONLY)) < 0) {
int
read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
struct mac_driver_desc *md;
- struct mac_partition *part;
+ struct mac_partition *part;
unsigned secsize;
char *data;
int blk, blocks_in_map;
- int n = 0;
+ int n = 0;
md = (struct mac_driver_desc *) getblock(fd, 0);
if (md == NULL)
#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
struct mac_partition {
- uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
- uint16_t res1;
- uint32_t map_count; /* # blocks in partition map */
- uint32_t start_block; /* absolute starting block # of partition */
- uint32_t block_count; /* number of blocks in partition */
- /* there is more stuff after this that we don't need */
+ uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
+ uint16_t res1;
+ uint32_t map_count; /* # blocks in partition map */
+ uint32_t start_block; /* absolute starting block # of partition */
+ uint32_t block_count; /* number of blocks in partition */
+ /* there is more stuff after this that we don't need */
};
#define MAC_DRIVER_MAGIC 0x4552
/* Driver descriptor structure, in block 0 */
struct mac_driver_desc {
- uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
- uint16_t block_size;
- uint32_t block_count;
+ uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
+ uint16_t block_size;
+ uint32_t block_count;
/* ... more stuff */
};
int
read_ps3_pt(int fd, struct slice all, struct slice *sp, int ns) {
struct disklabel label;
- int n = 0;
+ int n = 0;
int i;
if (!read_disklabel(fd, &label))
return n;
}
-
-
-
-
-
struct solaris_x86_slice {
unsigned short s_tag; /* ID tag of partition */
unsigned short s_flag; /* permision flags */
- daddr_t s_start; /* start sector no of partition */
+ daddr_t s_start; /* start sector no of partition */
long s_size; /* # of blocks in partition */
};
int i, n;
char *bp;
- bp = getblock(fd, offset+1); /* 1 sector suffices */
+ bp = getblock(fd, offset+1); /* 1 sector suffices */
if (bp == NULL)
return -1;
}
return n;
}
-
unsigned int d_type; /* drive type */
unsigned char d_magic[4]; /* the magic number */
unsigned int d_version; /* version number */
- char d_serial[12]; /* serial number of the device */
+ char d_serial[12]; /* serial number of the device */
unsigned int d_ncylinders; /* # of data cylinders per device */
unsigned int d_ntracks; /* # of tracks per cylinder */
unsigned int d_nsectors; /* # of data sectors per track */
struct unixware_vtoc {
unsigned char v_magic[4]; /* the magic number */
unsigned int v_version; /* version number */
- char v_name[8]; /* volume name */
+ char v_name[8]; /* volume name */
unsigned short v_nslices; /* # of slices */
unsigned short v_unknown1; /* ? */
unsigned int v_reserved[10]; /* reserved */
char *bp;
int n = 0;
- bp = getblock(fd, offset+29); /* 1 sector suffices */
+ bp = getblock(fd, offset+29); /* 1 sector suffices */
if (bp == NULL)
return -1;
$(LIBS): $(OBJS)
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS)
- ln -sf $@ $(DEVLIB)
+ $(LN) $@ $(DEVLIB)
install: $(LIBS)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
- ln -sf $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(incdir)
- $(INSTALL_PROGRAM) -m 755 mpath_cmd.h $(DESTDIR)$(incdir)
+ $(INSTALL_PROGRAM) -m 644 mpath_cmd.h $(DESTDIR)$(incdir)
uninstall:
- rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
- rm -f $(DESTDIR)$(syslibdir)/$(DEVLIB)
- rm -f $(DESTDIR)$(incdir)/mpath_cmd.h
+ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+ $(RM) $(DESTDIR)$(incdir)/mpath_cmd.h
clean:
- rm -f core *.a *.o *.gz *.so *.so.*
+ $(RM) core *.a *.o *.gz *.so *.so.*
len = mpath_recv_reply_len(fd, timeout);
if (len <= 0)
return len;
+ if (len > MAX_REPLY_LEN)
+ return -EINVAL;
*reply = malloc(len);
if (!*reply)
return -1;
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIB_MPATH_CMD_H
#define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd"
#define DEFAULT_REPLY_TIMEOUT 1000
+#define MAX_REPLY_LEN 65536
/*
* DESCRIPTION:
- * Connect to the running multipathd daemon. On systems with the
- * multipathd.socket systemd unit file installed, this command will
- * start multipathd if it is not already running. This function
- * must be run before any of the others in this library
+ * Connect to the running multipathd daemon. On systems with the
+ * multipathd.socket systemd unit file installed, this command will
+ * start multipathd if it is not already running. This function
+ * must be run before any of the others in this library
*
* RETURNS:
- * A file descriptor on success. -1 on failure (with errno set).
+ * A file descriptor on success. -1 on failure (with errno set).
*/
int mpath_connect(void);
/*
* DESCRIPTION:
- * Disconnect from the multipathd daemon. This function must be
- * run after after processing all the multipath commands.
+ * Disconnect from the multipathd daemon. This function must be
+ * run after after processing all the multipath commands.
*
* RETURNS:
- * 0 on success. -1 on failure (with errno set).
+ * 0 on success. -1 on failure (with errno set).
*/
int mpath_disconnect(int fd);
/*
* DESCRIPTION
- * Send multipathd a command and return the reply. This function
- * does the same as calling mpath_send_cmd() and then
+ * Send multipathd a command and return the reply. This function
+ * does the same as calling mpath_send_cmd() and then
* mpath_recv_reply()
*
* RETURNS:
- * 0 on successs, and reply will either be NULL (if there was no
- * reply data), or point to the reply string, which must be freed by
- * the caller. -1 on failure (with errno set).
+ * 0 on successs, and reply will either be NULL (if there was no
+ * reply data), or point to the reply string, which must be freed by
+ * the caller. -1 on failure (with errno set).
*/
int mpath_process_cmd(int fd, const char *cmd, char **reply,
unsigned int timeout);
/*
* DESCRIPTION:
- * Send a command to multipathd
+ * Send a command to multipathd
*
* RETURNS:
- * 0 on success. -1 on failure (with errno set)
+ * 0 on success. -1 on failure (with errno set)
*/
int mpath_send_cmd(int fd, const char *cmd);
/*
* DESCRIPTION:
- * Return a reply from multipathd for a previously sent command.
- * This is equivalent to calling mpath_recv_reply_len(), allocating
- * a buffer of the appropriate size, and then calling
+ * Return a reply from multipathd for a previously sent command.
+ * This is equivalent to calling mpath_recv_reply_len(), allocating
+ * a buffer of the appropriate size, and then calling
* mpath_recv_reply_data() with that buffer.
*
* RETURNS:
- * 0 on success, and reply will either be NULL (if there was no
- * reply data), or point to the reply string, which must be freed by
- * the caller, -1 on failure (with errno set).
+ * 0 on success, and reply will either be NULL (if there was no
+ * reply data), or point to the reply string, which must be freed by
+ * the caller, -1 on failure (with errno set).
*/
int mpath_recv_reply(int fd, char **reply, unsigned int timeout);
/*
* DESCRIPTION:
- * Return the size of the upcoming reply data from the sent multipath
- * command. This must be called before calling mpath_recv_reply_data().
+ * Return the size of the upcoming reply data from the sent multipath
+ * command. This must be called before calling mpath_recv_reply_data().
*
* RETURNS:
- * The required size of the reply data buffer on success. -1 on
- * failure (with errno set).
+ * The required size of the reply data buffer on success. -1 on
+ * failure (with errno set).
*/
ssize_t mpath_recv_reply_len(int fd, unsigned int timeout);
/*
* DESCRIPTION:
- * Return the reply data from the sent multipath command.
- * mpath_recv_reply_len must be called first. reply must point to a
- * buffer of len size.
+ * Return the reply data from the sent multipath command.
+ * mpath_recv_reply_len must be called first. reply must point to a
+ * buffer of len size.
*
* RETURNS:
- * 0 on success, and reply will contain the reply data string. -1
- * on failure (with errno set).
+ * 0 on success, and reply will contain the reply data string. -1
+ * on failure (with errno set).
*/
int mpath_recv_reply_data(int fd, char *reply, size_t len,
unsigned int timeout);
# Makefile
#
-BUILD = glibc
include ../Makefile.inc
-INSTALL_PROGRAM = install
-
SONAME=0
DEVLIB = libmpathpersist.so
LIBS = $(DEVLIB).$(SONAME)
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -I$(mpathcmddir)
LIBDEPS += -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath \
-L$(mpathcmddir) -lmpathcmd
-OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o
+OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o
all: $(LIBS)
-$(LIBS):
- $(CC) -Wall -fPIC -c $(CFLAGS) *.c
- $(CC) -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS)
- ln -s $(LIBS) $(DEVLIB)
- $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz
- $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz
+$(LIBS):
+ $(CC) -Wall -fPIC -c $(CFLAGS) *.c
+ $(CC) $(SHARED_FLAGS) $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS)
+ $(LN) $(LIBS) $(DEVLIB)
+ $(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz
+ $(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz
install: $(LIBS)
$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir)
$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(incdir)
- $(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/share/doc/mpathpersist/
- ln -sf $(DESTDIR)$(syslibdir)/$(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
- install -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir)
- install -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir)
- install -m 644 mpath_persist.h $(DESTDIR)$(incdir)
+ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+ $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir)
+ $(INSTALL_PROGRAM) -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir)
+ $(INSTALL_PROGRAM) -m 644 mpath_persist.h $(DESTDIR)$(incdir)
uninstall:
- rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
- rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz
- rm $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz
+ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_in.3.gz
+ $(RM) $(DESTDIR)$(man3dir)/mpath_persistent_reserve_out.3.gz
+ $(RM) $(DESTDIR)$(incdir)/mpath_persist.h
+ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
clean:
- rm -f core *.a *.o
- rm -f libmpathpersist.so.0
- rm -f libmpathpersist.so
- rm -f mpath_persistent_reserve_in.3.gz mpath_persistent_reserve_out.3.gz
+ $(RM) core *.a *.o
+ $(RM) libmpathpersist.so.0
+ $(RM) libmpathpersist.so
+ $(RM) mpath_persistent_reserve_in.3.gz mpath_persistent_reserve_out.3.gz
#include <libdevmapper.h>
-#include <defaults.h>
+#include "defaults.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <vector.h>
-#include <checkers.h>
-#include <structs.h>
-#include <structs_vec.h>
+#include "vector.h"
+#include "checkers.h"
+#include "structs.h"
+#include "structs_vec.h"
#include <libudev.h>
-#include <prio.h>
+#include "prio.h"
#include <unistd.h>
-#include <devmapper.h>
-#include <debug.h>
-#include <config.h>
-#include <switchgroup.h>
-#include <discovery.h>
-#include <dmparser.h>
+#include "devmapper.h"
+#include "debug.h"
+#include "config.h"
+#include "switchgroup.h"
+#include "discovery.h"
+#include "dmparser.h"
#include <ctype.h>
-#include <propsel.h>
-#include <util.h>
+#include "propsel.h"
+#include "util.h"
#include "mpath_persist.h"
#include "mpathpr.h"
#define __STDC_FORMAT_MACROS 1
+struct udev *udev;
-int
+struct config *
mpath_lib_init (struct udev *udev)
{
- if (load_config(DEFAULT_CONFIGFILE, udev)){
+ struct config *conf;
+
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf) {
condlog(0, "Failed to initialize multipath config.");
- return 1;
+ return NULL;
}
if (conf->max_fds) {
conf->max_fds, strerror(errno));
}
- return 0;
+ return conf;
}
int
-mpath_lib_exit (void)
+mpath_lib_exit (struct config *conf)
{
dm_lib_release();
dm_lib_exit();
vector_foreach_slot (pgp->paths, pp, j){
if (!strlen(pp->dev)){
- if (devt2devname(pp->dev, PATH_SIZE,
+ if (devt2devname(pp->dev, FILE_NAME_SIZE,
pp->dev_t)){
/*
* path is not in sysfs anymore
continue;
}
pp->mpp = mpp;
- pathinfo(pp, conf->hwtable, DI_ALL);
+ pathinfo(pp, conf, DI_ALL);
continue;
}
pp->mpp = mpp;
if (pp->state == PATH_UNCHECKED ||
pp->state == PATH_WILD)
- pathinfo(pp, conf->hwtable, DI_CHECKER);
+ pathinfo(pp, conf, DI_CHECKER);
if (pp->priority == PRIO_UNDEF)
- pathinfo(pp, conf->hwtable, DI_PRIO);
+ pathinfo(pp, conf, DI_PRIO);
}
}
return 0;
if (!curmp || !pathvec){
condlog (0, "%s: vector allocation failed.", alias);
ret = MPATH_PR_DMMP_ERROR;
+ if (curmp)
+ vector_free(curmp);
+ if (pathvec)
+ vector_free(pathvec);
goto out;
}
- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
+ if (path_discovery(pathvec, DI_SYSFS | DI_CHECKER) < 0) {
ret = MPATH_PR_DMMP_ERROR;
goto out1;
}
if (!curmp || !pathvec){
condlog (0, "%s: vector allocation failed.", alias);
ret = MPATH_PR_DMMP_ERROR;
+ if (curmp)
+ vector_free(curmp);
+ if (pathvec)
+ vector_free(pathvec);
goto out;
}
- if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER) < 0) {
+ if (path_discovery(pathvec, DI_SYSFS | DI_CHECKER) < 0) {
ret = MPATH_PR_DMMP_ERROR;
goto out1;
}
goto out1;
}
- select_reservation_key(mpp);
+ select_reservation_key(conf, mpp);
switch(rq_servact)
{
/*
* discard out of scope maps
*/
- if (mpp->alias && refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE)){
+ if (mpp->alias && refwwid &&
+ strncmp (mpp->alias, refwwid, WWID_SIZE - 1)){
free_multipath (mpp, KEEP_PATHS);
vector_del_slot (curmp, i);
i--;
condlog(3, "params = %s", params);
dm_get_status(mpp->alias, status);
condlog(3, "status = %s", status);
- disassemble_map (pathvec, params, mpp);
+ disassemble_map (pathvec, params, mpp, 0);
/*
* disassemble_map() can add new paths to pathvec.
condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
continue;
}
- strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
+ strncpy(thread[count].param.dev, pp->dev,
+ FILE_NAME_SIZE - 1);
if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
/*
memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
memset(&thread[i].param.paramp->sa_key, 0, 8);
thread[i].param.status = MPATH_PR_SUCCESS;
- rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
+ rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn,
(void *)(&thread[i].param));
if (rc){
condlog (0, "%s: failed to create thread for rollback. %d", mpp->wwid, rc);
int rc;
memset(&thread, 0, sizeof(thread));
- strncpy(param.dev, dev, FILE_NAME_SIZE);
+ strncpy(param.dev, dev, FILE_NAME_SIZE - 1);
/* Initialize and set thread joinable attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
continue;
}
- strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
+ strncpy(thread[count].param.dev, pp->dev,
+ FILE_NAME_SIZE - 1);
condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
(void *) (&thread[count].param));
free(resp);
return MPATH_PR_SUCCESS;
}
-
-
-
#define MPATH_MAX_PARAM_LEN 8192
-#define MPATH_MX_TIDS 32 /* Max number of transport ids"*/
+#define MPATH_MX_TIDS 32 /* Max number of transport ids"*/
#define MPATH_MX_TID_LEN 256 /* Max lenght of transport id */
/* PRIN Service Actions */
#define MPATH_LU_SCOPE 0x00 /* LU_SCOPE */
/* Persistent reservations type */
-#define MPATH_PRTPE_WE 0x01 /* Write Exclusive */
-#define MPATH_PRTPE_EA 0x03 /* Exclusive Access*/
-#define MPATH_PRTPE_WE_RO 0x05 /* WriteExclusive Registrants Only */
-#define MPATH_PRTPE_EA_RO 0x06 /* Exclusive Access. Registrants Only*/
+#define MPATH_PRTPE_WE 0x01 /* Write Exclusive */
+#define MPATH_PRTPE_EA 0x03 /* Exclusive Access*/
+#define MPATH_PRTPE_WE_RO 0x05 /* WriteExclusive Registrants Only */
+#define MPATH_PRTPE_EA_RO 0x06 /* Exclusive Access. Registrants Only*/
#define MPATH_PRTPE_WE_AR 0x07 /* Write Exclusive. All Registrants*/
-#define MPATH_PRTPE_EA_AR 0x08 /* Exclusive Access. All Registrants */
+#define MPATH_PRTPE_EA_AR 0x08 /* Exclusive Access. All Registrants */
/* PR RETURN_STATUS */
-#define MPATH_PR_SUCCESS 0
+#define MPATH_PR_SUCCESS 0
#define MPATH_PR_SYNTAX_ERROR 1 /* syntax error or invalid parameter */
/* status for check condition */
-#define MPATH_PR_SENSE_NOT_READY 2 /* [sk,asc,ascq: 0x2,*,*] */
+#define MPATH_PR_SENSE_NOT_READY 2 /* [sk,asc,ascq: 0x2,*,*] */
#define MPATH_PR_SENSE_MEDIUM_ERROR 3 /* [sk,asc,ascq: 0x3,*,*] */
#define MPATH_PR_SENSE_HARDWARE_ERROR 4 /* [sk,asc,ascq: 0x4,*,*] */
-#define MPATH_PR_ILLEGAL_REQ 5 /* [sk,asc,ascq: 0x5,*,*]*/
+#define MPATH_PR_ILLEGAL_REQ 5 /* [sk,asc,ascq: 0x5,*,*]*/
#define MPATH_PR_SENSE_UNIT_ATTENTION 6 /* [sk,asc,ascq: 0x6,*,*] */
-#define MPATH_PR_SENSE_INVALID_OP 7 /* [sk,asc,ascq: 0x5,0x20,0x0]*/
+#define MPATH_PR_SENSE_INVALID_OP 7 /* [sk,asc,ascq: 0x5,0x20,0x0]*/
#define MPATH_PR_SENSE_ABORTED_COMMAND 8 /* [sk,asc,ascq: 0xb,*,*] */
#define MPATH_PR_NO_SENSE 9 /* [sk,asc,ascq: 0x0,*,*] */
#define MPATH_F_APTPL_MASK 0x01 /* APTPL MASK*/
#define MPATH_F_ALL_TG_PT_MASK 0x04 /* ALL_TG_PT MASK*/
#define MPATH_F_SPEC_I_PT_MASK 0x08 /* SPEC_I_PT MASK*/
-#define MPATH_PR_TYPE_MASK 0x0f /* TYPE MASK*/
+#define MPATH_PR_TYPE_MASK 0x0f /* TYPE MASK*/
#define MPATH_PR_SCOPE_MASK 0xf0 /* SCOPE MASK*/
/*Transport ID PROTOCOL IDENTIFIER values */
struct prin_fulldescr
{
uint8_t key[8];
- uint8_t flag; /* All_tg_pt and reservation holder */
+ uint8_t flag; /* All_tg_pt and reservation holder */
uint8_t scope_type; /* Use PR SCOPE AND TYPE MASK specified above.
Meaningful only for reservation holder */
uint16_t rtpi;
}prin_descriptor;
};
-struct prout_param_descriptor { /* PROUT parameter descriptor */
+struct prout_param_descriptor { /* PROUT parameter descriptor */
uint8_t key[8];
uint8_t sa_key[8];
uint32_t _obsolete;
* before performing reservation management functions.
* RESTRICTIONS:
*
- * RETURNS: 0->Success, 1->Failed.
+ * RETURNS: struct config ->Success, NULL->Failed.
*/
-extern int mpath_lib_init (struct udev *udev);
+extern struct config * mpath_lib_init (struct udev *udev);
/*
*
* RETURNS: 0->Success, 1->Failed.
*/
-extern int mpath_lib_exit (void );
+extern int mpath_lib_exit (struct config *conf);
/*
* @fd: The file descriptor of a multipath device. Input argument.
* @rq_servact: PRIN command service action. Input argument
* @resp: The response from PRIN service action. The resp is a struct specified above. The caller should
- * manage the memory allocation of this struct
+ * manage the memory allocation of this struct
* @noisy: Turn on debugging trace: Input argument. 0->Disable, 1->Enable
* @verbose: Set verbosity level. Input argument. value:[0-3]. 0->disabled, 3->Max verbose
*
* 7h (Write exclusive - All registrants)
* 8h (Exclusive access - All registrants).
* @paramp: PROUT command parameter data. The paramp is a struct which describes PROUT
- * parameter list. The caller should manage the memory allocation of this struct.
+ * parameter list. The caller should manage the memory allocation of this struct.
* @noisy: Turn on debugging trace: Input argument.0->Disable, 1->Enable.
* @verbose: Set verbosity level. Input argument. value:0 to 3. 0->disabled, 3->Max verbose
*
.\"
-.TH MPATH_PERSISTENT_RESERVE_IN 3 2011-04-08 "Linux Manpage"
+.TH MPATH_PERSISTENT_RESERVE_IN 3 2011-04-08 "Linux Manpage"
.SH NAME
mpath_persistent_reserve_in
.SH SYNOPSIS
.I MPATH_PR_SUCCESS
.B if PR command successful
.br
-.I MPATH_PR_SYNTAX_ERROR
+.I MPATH_PR_SYNTAX_ERROR
.B if syntax error or invalid parameter
.br
-.I MPATH_PR_SENSE_NOT_READY
+.I MPATH_PR_SENSE_NOT_READY
.B if command fails with [sk,asc,ascq: 0x2,*,*]
.br
.I MPATH_PR_SENSE_MEDIUM_ERROR
.I MPATH_PR_NO_SENSE
.B if command fails with [sk,asc,ascq: 0x0,*,*]
.br
-.I MPATH_PR_SENSE_MALFORMED
+.I MPATH_PR_SENSE_MALFORMED
.B if command fails with SCSI command malformed
.br
.I MPATH_PR_FILE_ERROR
.B if command fails while accessing file (device node) problems(e.g. not found)
.br
.I MPATH_PR_DMMP_ERROR
-.B if Device Mapper related error.(e.g Error in getting dm info)
+.B if Device Mapper related error.(e.g Error in getting dm info)
.br
.I MPATH_PR_OTHER
.B if other error/warning has occurred(e.g transport or driver error)
.\"
-.TH MPATH_PERSISTENT_RESERVE_OUT 3 2011-04-08 "Linux Manpage"
+.TH MPATH_PERSISTENT_RESERVE_OUT 3 2011-04-08 "Linux Manpage"
.SH NAME
mpath_persistent_reserve_out
.SH SYNOPSIS
.br
.BI Parameters:
.br
-.I fd
+.I fd
.B The file descriptor of a multipath device. Input argument.
.br
.I rq_servact
.I MPATH_PR_SUCCESS
.B if PR command successful else returns any one of the status mentioned below
.br
-.I MPATH_PR_SYNTAX_ERROR
+.I MPATH_PR_SYNTAX_ERROR
.B if syntax error or invalid parameter
.br
-.I MPATH_PR_SENSE_NOT_READY
+.I MPATH_PR_SENSE_NOT_READY
.B if command fails with [sk,asc,ascq: 0x2,*,*]
.br
.I MPATH_PR_SENSE_MEDIUM_ERROR
.I MPATH_PR_NO_SENSE
.B if command fails with [sk,asc,ascq: 0x0,*,*]
.br
-.I MPATH_PR_SENSE_MALFORMED
+.I MPATH_PR_SENSE_MALFORMED
.B if command fails with SCSI command malformed
.br
.I MPATH_PR_RESERV_CONFLICT
.B if command fails while accessing file (device node) problems(e.g. not found)
.br
.I MPATH_PR_DMMP_ERROR
-.B if Device Mapper related error.(e.g Error in getting dm info)
+.B if Device Mapper related error.(e.g Error in getting dm info)
.br
.I MPATH_PR_OTHER
.B if other error/warning has occurred(e.g transport or driver error)
.SH "SEE ALSO"
-.I mpath_persistent_reserve_in mpathpersist /usr/share/doc/mpathpersist/README
+.I mpath_persistent_reserve_in mpathpersist /usr/share/doc/mpathpersist/README
.br
#include <unistd.h>
#include <libudev.h>
#include "mpath_pr_ioctl.h"
-#include <mpath_persist.h>
+#include "mpath_persist.h"
-#include <debug.h>
+#include "debug.h"
#define FILE_NAME_SIZE 256
int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
void mpath_format_readkeys(struct prin_resp *pr_buff, int len , int noisy);
void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy);
-int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy);
+int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
+ SenseData_t *Sensedata, int noisy);
void dumpHex(const char* str, int len, int no_ascii);
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
uint32_t format_transportids(struct prout_param_descriptor *paramp);
void mpath_reverse_uint32_byteorder(uint32_t *num);
void mpath_reverse_uint16_byteorder(uint16_t *num);
extern unsigned int mpath_mx_alloc_len;
int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
{
int status, paramlen = 24, ret = 0;
{
translen = format_transportids(paramp);
paramlen = 24 + translen;
- }
+ }
else
paramlen = 24;
cdb[8] = (unsigned char)(paramlen & 0xff);
retry :
- condlog(3, "%s: rq_servact = %d", dev, rq_servact);
+ condlog(3, "%s: rq_servact = %d", dev, rq_servact);
condlog(3, "%s: rq_scope = %d ", dev, rq_scope);
condlog(3, "%s: rq_type = %d ", dev, rq_type);
condlog(3, "%s: paramlen = %d", dev, paramlen);
condlog(2, "%s: Duration=%u (ms)", dev, io_hdr.duration);
- status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
+ status = mpath_translate_response(dev, io_hdr, &Sensedata, noisy);
condlog(3, "%s: status = %d", dev, status);
if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
{
--retry;
- condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d",
+ condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d",
dev, retry);
goto retry;
}
goto retry;
}
- close(fd);
+ close(fd);
return status;
}
uint32_t format_transportids(struct prout_param_descriptor *paramp)
{
- int i = 0, len;
+ int i = 0, len;
uint32_t buff_offset = 4;
memset(paramp->private_buffer, 0, MPATH_MAX_PARAM_LEN);
for (i=0; i < paramp->num_transportid; i++ )
break;
case MPATH_PROTOCOL_ID_ISCSI:
buff_offset += 1;
- len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;
+ len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;
memcpy(¶mp->private_buffer[buff_offset], ¶mp->trnptid_list[i]->iscsi_name,len);
- buff_offset += len ;
+ buff_offset += len ;
break;
}
}
- buff_offset -= 4;
+ buff_offset -= 4;
paramp->private_buffer[0] = (unsigned char)((buff_offset >> 24) & 0xff);
paramp->private_buffer[1] = (unsigned char)((buff_offset >> 16) & 0xff);
paramp->private_buffer[2] = (unsigned char)((buff_offset >> 8) & 0xff);
paramp->private_buffer[3] = (unsigned char)(buff_offset & 0xff);
- buff_offset += 4;
- return buff_offset;
+ buff_offset += 4;
+ return buff_offset;
}
void mpath_format_readkeys( struct prin_resp *pr_buff, int len, int noisy)
{
- mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
- mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
+ mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
+ mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
}
void mpath_format_readresv(struct prin_resp *pr_buff, int len, int noisy)
{
- mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
- mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
+ mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
+ mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
- return;
+ return;
}
void mpath_format_reportcapabilities(struct prin_resp *pr_buff, int len, int noisy)
{
- mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.length);
- mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.pr_type_mask);
+ mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.length);
+ mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.pr_type_mask);
- return;
+ return;
}
void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy)
{MPATH_PRIN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
- fd = open(devname, O_WRONLY);
- if(fd < 0){
- condlog(0, "%s: Unable to open device ", dev);
+ fd = open(devname, O_WRONLY);
+ if(fd < 0){
+ condlog(0, "%s: Unable to open device ", dev);
return MPATH_PR_FILE_ERROR;
- }
+ }
if (mpath_mx_alloc_len)
mx_resp_len = mpath_mx_alloc_len;
condlog(2, "%s: duration = %u (ms)", dev, io_hdr.duration);
condlog(2, "%s: persistent reservation in: requested %d bytes but got %d bytes)", dev, mx_resp_len, got);
- status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
+ status = mpath_translate_response(dev, io_hdr, &Sensedata, noisy);
if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
{
return status;
}
-int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy)
+int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
+ SenseData_t *Sensedata, int noisy)
{
- condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev,
+ condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev,
io_hdr.driver_status, io_hdr.host_status ,io_hdr.status);
io_hdr.status &= 0x7e;
- if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status))
- {
+ if ((0 == io_hdr.status) &&
+ (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status))
return MPATH_PR_SUCCESS;
- }
- switch(io_hdr.status)
- {
+ switch(io_hdr.status) {
case SAM_STAT_GOOD:
break;
case SAM_STAT_CHECK_CONDITION:
- condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x", dev,
- Sensedata.Sense_Key, Sensedata.ASC, Sensedata.ASCQ);
- switch(Sensedata.Sense_Key)
- {
+ condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x",
+ dev, Sensedata->Sense_Key,
+ Sensedata->ASC, Sensedata->ASCQ);
+ switch(Sensedata->Sense_Key) {
case NO_SENSE:
return MPATH_PR_NO_SENSE;
case RECOVERED_ERROR:
return MPATH_PR_OTHER;
}
- switch(io_hdr.host_status)
- {
+ switch(io_hdr.host_status) {
case DID_OK :
break;
default :
int get_prin_length(int rq_servact)
{
- int mx_resp_len;
- switch (rq_servact)
- {
- case MPATH_PRIN_RKEY_SA:
- mx_resp_len = sizeof(struct prin_readdescr);
- break;
- case MPATH_PRIN_RRES_SA :
- mx_resp_len = sizeof(struct prin_resvdescr);
- break;
- case MPATH_PRIN_RCAP_SA :
- mx_resp_len = sizeof(struct prin_capdescr);
- break;
- case MPATH_PRIN_RFSTAT_SA:
- mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
- break;
+ int mx_resp_len;
+ switch (rq_servact)
+ {
+ case MPATH_PRIN_RKEY_SA:
+ mx_resp_len = sizeof(struct prin_readdescr);
+ break;
+ case MPATH_PRIN_RRES_SA :
+ mx_resp_len = sizeof(struct prin_resvdescr);
+ break;
+ case MPATH_PRIN_RCAP_SA :
+ mx_resp_len = sizeof(struct prin_capdescr);
+ break;
+ case MPATH_PRIN_RFSTAT_SA:
+ mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
+ break;
default:
condlog(0, "invalid service action, %d", rq_servact);
mx_resp_len = 0;
break;
- }
- return mx_resp_len;
+ }
+ return mx_resp_len;
}
/* Driver status */
#define DRIVER_OK 0x00
-
-
-#include<stdio.h>
-#include<unistd.h>
+#include <stdio.h>
+#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <errno.h>
-#include <debug.h>
-#include <mpath_cmd.h>
-#include <uxsock.h>
+#include "debug.h"
+#include "mpath_cmd.h"
+#include "uxsock.h"
#include "memory.h"
unsigned long mem_allocated; /* Total memory used in Bytes */
snprintf(str,sizeof(str),"map %s %s", arg1, arg2);
condlog (2, "%s: pr flag message=%s", arg1, str);
- send_packet(fd, str);
+ if (send_packet(fd, str) != 0) {
+ condlog(2, "%s: message=%s send error=%d", arg1, str, errno);
+ mpath_disconnect(fd);
+ return -2;
+ }
ret = recv_packet(fd, &reply, DEFAULT_REPLY_TIMEOUT);
if (ret < 0) {
- condlog(2, "%s: message=%s error=%d", arg1, str, errno);
+ condlog(2, "%s: message=%s recv error=%d", arg1, str, errno);
ret = -2;
} else {
condlog (2, "%s: message=%s reply=%s", arg1, str, reply);
struct prin_param {
char dev[FILE_NAME_SIZE];
- int rq_servact;
- struct prin_resp *resp;
- int noisy;
- int status;
+ int rq_servact;
+ struct prin_resp *resp;
+ int noisy;
+ int status;
};
struct prout_param {
char dev[FILE_NAME_SIZE];
- int rq_servact;
- int rq_scope;
- unsigned int rq_type;
- struct prout_param_descriptor *paramp;
- int noisy;
- int status;
+ int rq_servact;
+ int rq_scope;
+ unsigned int rq_type;
+ struct prout_param_descriptor *paramp;
+ int noisy;
+ int status;
};
struct threadinfo {
- int status;
- pthread_t id;
- struct prout_param param;
+ int status;
+ pthread_t id;
+ struct prout_param param;
};
int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy);
int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
void * _mpath_pr_update (void *arg);
int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy);
int get_mpvec (vector curmp, vector pathvec, char * refwwid);
void dumpHex(const char* , int len, int no_ascii);
int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
- unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
+ unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy);
int update_prflag(char * arg1, char * arg2, int noisy);
void * mpath_alloc_prin_response(int prin_sa);
$(LIBS): $(OBJS)
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS)
- ln -sf $@ $(DEVLIB)
+ $(LN) $@ $(DEVLIB)
install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir)
+ $(LN) $(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
uninstall:
- rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(RM) $(DESTDIR)$(syslibdir)/$(LIBS)
+ $(RM) $(DESTDIR)$(syslibdir)/$(DEVLIB)
clean:
- rm -f core *.a *.o *.gz *.so *.so.*
+ $(RM) core *.a *.o *.gz *.so *.so.*
* See the file COPYING included with this distribution for more details.
*/
+int
+valid_alias(char *alias)
+{
+ if (strchr(alias, '/') != NULL)
+ return 0;
+ return 1;
+}
+
static int
format_devname(char *name, int id, int len, char *prefix)
return NULL;
}
c = strchr(buf, ' ');
- *c = '\0';
+ if (c)
+ *c = '\0';
alias = strdup(buf);
if (alias == NULL)
condlog(0, "cannot copy new alias from bindings file : %s",
"# alias wwid\n" \
"#\n"
+int valid_alias(char *alias);
char *get_user_friendly_alias(char *wwid, char *file, char *prefix,
int bindings_readonly);
int get_user_friendly_wwid(char *alias, char *buff, char *file);
#define _BLACKLIST_H
#include <libudev.h>
-#include "regex.h"
+#include <regex.h>
#define MATCH_NOTHING 0
#define MATCH_WWID_BLIST 1
/* Ignore writes to stderr */
null_fd = open("/dev/null", O_WRONLY);
if (null_fd > 0) {
+ int err_fd __attribute__ ((unused));
+
close(STDERR_FILENO);
- retval = dup(null_fd);
+ err_fd = dup(null_fd);
close(null_fd);
}
#include "debug.h"
#include "checkers.h"
#include "vector.h"
-#include "config.h"
char *checker_state_names[] = {
"wild",
return checker_state_names[i];
}
-int init_checkers (void)
+int init_checkers (char *multipath_dir)
{
- if (!add_checker(DEFAULT_CHECKER))
+ if (!add_checker(multipath_dir, DEFAULT_CHECKER))
return 1;
return 0;
}
if (!strncmp(name, c->name, CHECKER_NAME_LEN))
return c;
}
- return add_checker(name);
+ return NULL;
}
-struct checker * add_checker (char * name)
+struct checker * add_checker (char *multipath_dir, char * name)
{
char libname[LIB_CHECKER_NAMELEN];
struct stat stbuf;
return NULL;
snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
- conf->multipath_dir, name);
+ multipath_dir, name);
if (stat(libname,&stbuf) < 0) {
condlog(0,"Checker '%s' not found in %s",
- name, conf->multipath_dir);
+ name, multipath_dir);
goto out;
}
condlog(3, "loading %s checker", libname);
c->message[0] = '\0';
}
-void checker_get (struct checker * dst, char * name)
+void checker_get (char *multipath_dir, struct checker * dst, char * name)
{
- struct checker * src = checker_lookup(name);
+ struct checker * src = NULL;
if (!dst)
return;
+ if (name && strlen(name)) {
+ src = checker_lookup(name);
+ if (!src)
+ src = add_checker(multipath_dir, name);
+ }
if (!src) {
dst->check = NULL;
return;
#define READSECTOR0 "readsector0"
#define CCISS_TUR "cciss_tur"
-#define DEFAULT_CHECKER DIRECTIO
+#define DEFAULT_CHECKER TUR
#define ASYNC_TIMEOUT_SEC 30
#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
char * checker_state_name (int);
-int init_checkers (void);
+int init_checkers (char *);
void cleanup_checkers (void);
-struct checker * add_checker (char *);
+struct checker * add_checker (char *, char *);
struct checker * checker_lookup (char *);
int checker_init (struct checker *, void **);
void checker_put (struct checker *);
char * checker_name (struct checker *);
char * checker_message (struct checker *);
void checker_clear_message (struct checker *c);
-void checker_get (struct checker *, char *);
+void checker_get (char *, struct checker *, char *);
#endif /* _CHECKERS_H */
$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)
uninstall:
- for file in $(LIBS); do rm -f $(DESTDIR)$(libdir)/$$file; done
+ for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done
clean:
- rm -f core *.a *.o *.gz *.so
+ $(RM) core *.a *.o *.gz *.so
int cciss_tur( struct checker *);
#endif
-
* for more details. *
* *
* You should have received a copy of the GNU General Public License along *
- * with this program; if not, write to the Free Software Foundation, Inc., *
- * 675 Mass Ave, Cambridge, MA 02139, USA. *
- * *
- * The copy of the GNU General Public License is available at *
- * /opt/hp/HPDMmultipath-tool directoy *
+ * with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*****************************************************************************
*/
if (ct->reset_flags) {
if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
+ int ret __attribute__ ((unused));
+
flags &= ~O_DIRECT;
/* No point in checking for errors */
- fcntl(c->fd, F_SETFL, flags);
+ ret = fcntl(c->fd, F_SETFL, flags);
}
}
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
-#include <memory.h>
#include "../libmultipath/sg_include.h"
#include "libsg.h"
#include "checkers.h"
#include "debug.h"
+#include "memory.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
long long start_block = 0;
int bs = 512;
int cdbsz = 10;
- int * diop = NULL;
unsigned char rdCmd[cdbsz];
unsigned char *sbb = sense;
io_hdr.sbp = sense;
io_hdr.timeout = timeout * 1000;
io_hdr.pack_id = (int)start_block;
- if (diop && *diop)
- io_hdr.flags |= SG_FLAG_DIRECT_IO;
retry:
memset(sense, 0, sense_len);
unsigned char sbuf[SENSE_BUFF_LEN];
int ret;
- ret = sg_read(c->fd, &buf[0], 4069, &sbuf[0],
+ ret = sg_read(c->fd, &buf[0], 4096, &sbuf[0],
SENSE_BUFF_LEN, c->timeout);
switch (ret)
setup_thread_attr(&attr, 32 * 1024, 1);
r = pthread_create(&ct->thread, &attr, tur_thread, ct);
if (r) {
+ pthread_spin_lock(&ct->hldr_lock);
+ ct->holders--;
+ pthread_spin_unlock(&ct->hldr_lock);
pthread_mutex_unlock(&ct->lock);
ct->thread = 0;
- ct->holders--;
condlog(3, "%d:%d: failed to start tur thread, using"
" sync mode", TUR_DEVT(ct));
return tur_check(c->fd, c->timeout, c->message);
}
extern struct mpentry *
-find_mpe (char * wwid)
+find_mpe (vector mptable, char * wwid)
{
int i;
struct mpentry * mpe;
if (!wwid)
return NULL;
- vector_foreach_slot (conf->mptable, mpe, i)
+ vector_foreach_slot (mptable, mpe, i)
if (mpe->wwid && !strcmp(mpe->wwid, wwid))
return mpe;
}
extern char *
-get_mpe_wwid (char * alias)
+get_mpe_wwid (vector mptable, char * alias)
{
int i;
struct mpentry * mpe;
if (!alias)
return NULL;
- vector_foreach_slot (conf->mptable, mpe, i)
+ vector_foreach_slot (mptable, mpe, i)
if (mpe->alias && strcmp(mpe->alias, alias) == 0)
return mpe->wwid;
hwe->user_friendly_names = dhwe->user_friendly_names;
hwe->retain_hwhandler = dhwe->retain_hwhandler;
hwe->detect_prio = dhwe->detect_prio;
- conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
goto out;
if (!conf)
return;
- if (conf->dev)
- FREE(conf->dev);
-
if (conf->multipath_dir)
FREE(conf->multipath_dir);
/* if multipath fails to process the config directory, it should continue,
* with just a warning message */
static void
-process_config_dir(vector keywords, char *dir)
+process_config_dir(struct config *conf, vector keywords, char *dir)
{
struct dirent **namelist;
int i, n;
old_hwtable_size = VECTOR_SIZE(conf->hwtable);
snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
path[LINE_MAX-1] = '\0';
- process_file(path);
+ process_file(conf, path);
if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
factorize_hwtable(conf->hwtable, old_hwtable_size);
}
}
-int
-load_config (char * file, struct udev *udev)
+struct config *
+load_config (char * file)
{
- if (!conf)
- conf = alloc_config();
+ struct config *conf = alloc_config();
- if (!conf || !udev)
- return 1;
+ if (!conf)
+ return NULL;
/*
* internal defaults
if (!conf->verbosity)
conf->verbosity = DEFAULT_VERBOSITY;
- conf->udev = udev;
- conf->dev_type = DEV_NONE;
conf->minio = DEFAULT_MINIO;
conf->minio_rq = DEFAULT_MINIO_RQ;
get_sys_max_fds(&conf->max_fds);
conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
+ conf->deferred_remove = DEFAULT_DEFERRED_REMOVE;
/*
* preload default hwtable
/*
* read the config file
*/
- set_current_keywords(&conf->keywords);
- alloc_keywords();
- init_keywords();
+ conf->keywords = vector_alloc();
+ init_keywords(conf->keywords);
if (filepresent(file)) {
int builtin_hwtable_size;
builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
- if (process_file(file)) {
+ if (process_file(conf, file)) {
condlog(0, "error parsing config file");
goto out;
}
if (conf->config_dir == NULL)
conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
if (conf->config_dir && conf->config_dir[0] != '\0')
- process_config_dir(conf->keywords, conf->config_dir);
+ process_config_dir(conf, conf->keywords, conf->config_dir);
/*
* fill the voids left in the config file
!conf->wwids_file)
goto out;
- return 0;
+ return conf;
out:
free_config(conf);
- return 1;
+ return NULL;
}
-
#include <sys/types.h>
#include <stdint.h>
+#include <urcu.h>
#define ORIGIN_DEFAULT 0
#define ORIGIN_CONFIG 1
};
enum mpath_cmds {
+ CMD_NONE,
CMD_CREATE,
CMD_DRY_RUN,
CMD_LIST_SHORT,
};
struct config {
+ struct rcu_head rcu;
int verbosity;
- enum mpath_cmds cmd;
int pgpolicy_flag;
int pgpolicy;
- enum devtypes dev_type;
int minio;
int minio_rq;
int checkint;
int queue_without_daemon;
int ignore_wwids;
int checker_timeout;
- int daemon;
int flush_on_last_del;
int attribute_flags;
int fast_io_fail;
int uev_wait_timeout;
unsigned int version[3];
- char * dev;
- struct udev * udev;
char * multipath_dir;
char * selector;
char * uid_attribute;
vector elist_property;
};
-struct config * conf;
+extern struct udev * udev;
struct hwentry * find_hwe (vector hwtable, char * vendor, char * product, char *revision);
-struct mpentry * find_mpe (char * wwid);
-char * get_mpe_wwid (char * alias);
+struct mpentry * find_mpe (vector mptable, char * wwid);
+char * get_mpe_wwid (vector mptable, char * alias);
struct hwentry * alloc_hwe (void);
struct mpentry * alloc_mpe (void);
int store_hwe (vector hwtable, struct hwentry *);
-int load_config (char * file, struct udev * udev);
+struct config *load_config (char * file);
struct config * alloc_config (void);
void free_config (struct config * conf);
+extern struct config *get_multipath_config(void);
+extern void put_multipath_config(struct config *);
#endif
#include <errno.h>
#include <libdevmapper.h>
#include <libudev.h>
-#include <mpath_cmd.h>
+#include "mpath_cmd.h"
#include "checkers.h"
#include "vector.h"
goto out;
agp->pgp = pgp;
- strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE);
+ strncpy(agp->adapter_name, adapter_name1, SLOT_NAME_SIZE - 1);
store_adaptergroup(adapters, agp);
/* create a new host port group
setup_map (struct multipath * mpp, char * params, int params_size)
{
struct pathgroup * pgp;
+ struct config *conf;
int i;
/*
/*
* properties selectors
*/
- select_pgfailback(mpp);
- select_pgpolicy(mpp);
- select_selector(mpp);
- select_features(mpp);
- select_hwhandler(mpp);
- select_rr_weight(mpp);
- select_minio(mpp);
- select_no_path_retry(mpp);
- select_mode(mpp);
- select_uid(mpp);
- select_gid(mpp);
- select_fast_io_fail(mpp);
- select_dev_loss(mpp);
- select_reservation_key(mpp);
- select_retain_hwhandler(mpp);
- select_deferred_remove(mpp);
- select_delay_watch_checks(mpp);
- select_delay_wait_checks(mpp);
-
- sysfs_set_scsi_tmo(mpp);
+ conf = get_multipath_config();
+ select_pgfailback(conf, mpp);
+ select_pgpolicy(conf, mpp);
+ select_selector(conf, mpp);
+ select_features(conf, mpp);
+ select_hwhandler(conf, mpp);
+ select_rr_weight(conf, mpp);
+ select_minio(conf, mpp);
+ select_no_path_retry(conf, mpp);
+ select_mode(conf, mpp);
+ select_uid(conf, mpp);
+ select_gid(conf, mpp);
+ select_fast_io_fail(conf, mpp);
+ select_dev_loss(conf, mpp);
+ select_reservation_key(conf, mpp);
+ select_retain_hwhandler(conf, mpp);
+ select_deferred_remove(conf, mpp);
+ select_delay_watch_checks(conf, mpp);
+ select_delay_wait_checks(conf, mpp);
+
+ sysfs_set_scsi_tmo(mpp, conf->checkint);
+ put_multipath_config(conf);
/*
* assign paths to path groups -- start with no groups and all paths
* in mpp->paths
if (cmpp) {
condlog(2, "%s: rename %s to %s", mpp->wwid,
cmpp->alias, mpp->alias);
- strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
+ strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE - 1);
mpp->action = ACT_RENAME;
if (force_reload)
mpp->action = ACT_FORCERENAME;
if (!cmpp) {
condlog(2, "%s: remove (wwid changed)", mpp->alias);
dm_flush_map(mpp->alias);
- strncpy(cmpp_by_name->wwid, mpp->wwid, WWID_SIZE);
+ strncpy(cmpp_by_name->wwid, mpp->wwid, WWID_SIZE - 1);
drop_multipath(curmp, cmpp_by_name->wwid, KEEP_PATHS);
mpp->action = ACT_CREATE;
condlog(3, "%s: set ACT_CREATE (map wwid change)",
return;
}
if (mpp->retain_hwhandler != RETAIN_HWHANDLER_ON &&
- (strlen(cmpp->hwhandler) != strlen(mpp->hwhandler) ||
+ (strlen(cmpp->hwhandler) != strlen(mpp->hwhandler) ||
strncmp(cmpp->hwhandler, mpp->hwhandler,
strlen(mpp->hwhandler)))) {
mpp->action = ACT_RELOAD;
#define DOMAP_DRY 3
extern int
-domap (struct multipath * mpp, char * params)
+domap (struct multipath * mpp, char * params, int is_daemon)
{
int r = DOMAP_FAIL;
+ struct config *conf;
/*
* last chance to quit before touching the devmaps
*/
- if (conf->cmd == CMD_DRY_RUN && mpp->action != ACT_NOTHING) {
+ if (mpp->action == ACT_DRY_RUN) {
+ conf = get_multipath_config();
print_multipath_topology(mpp, conf->verbosity);
+ put_multipath_config(conf);
return DOMAP_DRY;
}
break;
case ACT_RENAME:
- r = dm_rename(mpp->alias_old, mpp->alias);
+ conf = get_multipath_config();
+ r = dm_rename(mpp->alias_old, mpp->alias,
+ conf->partition_delim);
+ put_multipath_config(conf);
break;
case ACT_FORCERENAME:
- r = dm_rename(mpp->alias_old, mpp->alias);
+ conf = get_multipath_config();
+ r = dm_rename(mpp->alias_old, mpp->alias,
+ conf->partition_delim);
+ put_multipath_config(conf);
if (r)
r = dm_addmap_reload(mpp, params, 0);
break;
*/
if (mpp->action == ACT_CREATE)
remember_wwid(mpp->wwid);
- if (!conf->daemon) {
+ if (!is_daemon) {
/* multipath client mode */
dm_switchgroup(mpp->alias, mpp->bestpg);
} else {
if (mpp->action != ACT_CREATE)
mpp->action = ACT_NOTHING;
else {
+ conf = get_multipath_config();
mpp->wait_for_udev = 1;
mpp->uev_wait_tick = conf->uev_wait_timeout;
+ put_multipath_config(conf);
}
}
dm_setgeometry(mpp);
int fd;
char *reply;
int ret = 0;
+ unsigned int timeout;
+ struct config *conf;
fd = mpath_connect();
if (fd == -1)
if (send_packet(fd, "show daemon") != 0)
goto out;
- if (recv_packet(fd, &reply, conf->uxsock_timeout) != 0)
+ conf = get_multipath_config();
+ timeout = conf->uxsock_timeout;
+ put_multipath_config(conf);
+ if (recv_packet(fd, &reply, timeout) != 0)
goto out;
if (strstr(reply, "shutdown"))
}
extern int
-coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_reload)
+coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_reload, enum mpath_cmds cmd)
{
int r = 1;
int k, i;
+ int is_daemon = (cmd == CMD_NONE) ? 1 : 0;
char params[PARAMS_SIZE];
struct multipath * mpp;
struct path * pp1;
struct path * pp2;
vector curmp = vecs->mpvec;
vector pathvec = vecs->pathvec;
+ struct config *conf;
+ int allow_queueing;
/* ignore refwwid if it's empty */
if (refwwid && !strlen(refwwid))
/* skip this path for some reason */
/* 1. if path has no unique id or wwid blacklisted */
+ conf = get_multipath_config();
if (strlen(pp1->wwid) == 0 ||
filter_path(conf, pp1) > 0) {
+ put_multipath_config(conf);
orphan_path(pp1, "wwid blacklisted");
continue;
}
+ put_multipath_config(conf);
/* 2. if path already coalesced */
if (pp1->mpp)
}
/* 4. path is out of scope */
- if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
+ if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE - 1))
continue;
/* If find_multipaths was selected check if the path is valid */
continue;
}
+ if (cmd == CMD_DRY_RUN)
+ mpp->action = ACT_DRY_RUN;
if (mpp->action == ACT_UNDEF)
select_action(mpp, curmp, force_reload);
- r = domap(mpp, params);
+ r = domap(mpp, params, is_daemon);
if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
condlog(3, "%s: domap (%u) failure "
if (r == DOMAP_DRY)
continue;
- if (!conf->daemon && !conf->allow_queueing && !check_daemon()) {
+ conf = get_multipath_config();
+ allow_queueing = conf->allow_queueing;
+ put_multipath_config(conf);
+ if (!is_daemon && !allow_queueing && !check_daemon()) {
if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF &&
mpp->no_path_retry != NO_PATH_RETRY_FAIL)
condlog(3, "%s: multipathd not running, unset "
}
}
- if (!conf->daemon && mpp->action != ACT_NOTHING)
+ if (!is_daemon && mpp->action != ACT_NOTHING) {
+ conf = get_multipath_config();
print_multipath_topology(mpp, conf->verbosity);
+ put_multipath_config(conf);
+ }
if (newmp) {
if (mpp->action != ACT_REJECT) {
if (newmp) {
vector_foreach_slot (newmp, mpp, i) {
char alias[WWID_SIZE];
- int j;
if (!deadmap(mpp))
continue;
- strncpy(alias, mpp->alias, WWID_SIZE);
-
- if ((j = find_slot(newmp, (void *)mpp)) != -1)
- vector_del_slot(newmp, j);
+ strncpy(alias, mpp->alias, WWID_SIZE - 1);
+ vector_del_slot(newmp, i);
+ i--;
remove_map(mpp, vecs, 0);
if (dm_flush_map(alias))
* 2 - blacklist
*/
extern int
-get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid)
+get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
+ vector pathvec, char **wwid)
{
int ret = 1;
struct path * pp;
char buff[FILE_NAME_SIZE];
char * refwwid = NULL, tmpwwid[WWID_SIZE];
+ int flags = DI_SYSFS | DI_WWID;
+ struct config *conf;
if (!wwid)
return 1;
if (dev_type == DEV_NONE)
return 1;
+ if (cmd != CMD_REMOVE_WWID)
+ flags |= DI_BLACKLIST;
+
if (dev_type == DEV_DEVNODE) {
if (basenamecpy(dev, buff, FILE_NAME_SIZE) == 0) {
condlog(1, "basename failed for '%s' (%s)",
pp = find_path_by_dev(pathvec, buff);
if (!pp) {
- struct udev_device *udevice = udev_device_new_from_subsystem_sysname(conf->udev, "block", buff);
+ struct udev_device *udevice = udev_device_new_from_subsystem_sysname(udev, "block", buff);
if (!udevice) {
condlog(2, "%s: can't get udev device", buff);
return 1;
}
- ret = store_pathinfo(pathvec, conf->hwtable, udevice,
- DI_SYSFS | DI_WWID, &pp);
+ conf = get_multipath_config();
+ ret = store_pathinfo(pathvec, conf, udevice,
+ flags, &pp);
+ put_multipath_config(conf);
udev_device_unref(udevice);
if (!pp) {
if (ret == 1)
return ret;
}
}
+ conf = get_multipath_config();
if (pp->udev && pp->uid_attribute &&
- filter_property(conf, pp->udev) > 0)
+ filter_property(conf, pp->udev) > 0) {
+ put_multipath_config(conf);
return 2;
+ }
+ put_multipath_config(conf);
refwwid = pp->wwid;
goto out;
}
pp = find_path_by_dev(pathvec, buff);
if (!pp) {
- struct udev_device *udevice = udev_device_new_from_devnum(conf->udev, 'b', parse_devt(dev));
+ struct udev_device *udevice = udev_device_new_from_devnum(udev, 'b', parse_devt(dev));
if (!udevice) {
condlog(2, "%s: can't get udev device", dev);
return 1;
}
- ret = store_pathinfo(pathvec, conf->hwtable, udevice,
- DI_SYSFS | DI_WWID, &pp);
+ conf = get_multipath_config();
+ ret = store_pathinfo(pathvec, conf, udevice,
+ flags, &pp);
+ put_multipath_config(conf);
udev_device_unref(udevice);
if (!pp) {
if (ret == 1)
return ret;
}
}
+ conf = get_multipath_config();
if (pp->udev && pp->uid_attribute &&
- filter_property(conf, pp->udev) > 0)
+ filter_property(conf, pp->udev) > 0) {
+ put_multipath_config(conf);
return 2;
-
+ }
+ put_multipath_config(conf);
refwwid = pp->wwid;
goto out;
}
if (dev_type == DEV_UEVENT) {
- struct udev_device *udevice = udev_device_new_from_environment(conf->udev);
+ struct udev_device *udevice = udev_device_new_from_environment(udev);
if (!udevice) {
condlog(2, "%s: can't get udev device", dev);
return 1;
}
- ret = store_pathinfo(pathvec, conf->hwtable, udevice,
- DI_SYSFS | DI_WWID, &pp);
+ conf = get_multipath_config();
+ ret = store_pathinfo(pathvec, conf, udevice,
+ flags, &pp);
udev_device_unref(udevice);
if (!pp) {
if (ret == 1)
condlog(0, "%s: can't store path info",
dev);
+ put_multipath_config(conf);
return ret;
}
if (pp->udev && pp->uid_attribute &&
- filter_property(conf, pp->udev) > 0)
+ filter_property(conf, pp->udev) > 0) {
+ put_multipath_config(conf);
return 2;
-
+ }
+ put_multipath_config(conf);
refwwid = pp->wwid;
goto out;
}
if (dev_type == DEV_DEVMAP) {
+ conf = get_multipath_config();
if (((dm_get_uuid(dev, tmpwwid)) == 0) && (strlen(tmpwwid))) {
refwwid = tmpwwid;
goto check;
if (get_user_friendly_wwid(dev, tmpwwid,
conf->bindings_file) == 0) {
refwwid = tmpwwid;
+ put_multipath_config(conf);
goto check;
}
/*
* or may be an alias
*/
- refwwid = get_mpe_wwid(dev);
+ refwwid = get_mpe_wwid(conf->mptable, dev);
/*
* or directly a wwid
check:
if (refwwid && strlen(refwwid)) {
if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
- refwwid, NULL) > 0)
- return 2;
+ refwwid, NULL) > 0) {
+ put_multipath_config(conf);
+ return 2;
+ }
}
+ put_multipath_config(conf);
}
out:
if (refwwid && strlen(refwwid)) {
return 1;
}
-extern int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh)
+extern int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon)
{
char params[PARAMS_SIZE] = {0};
struct path *pp;
update_mpp_paths(mpp, vecs->pathvec);
if (refresh) {
vector_foreach_slot (mpp->paths, pp, i) {
- r = pathinfo(pp, conf->hwtable, DI_PRIO);
+ struct config *conf = get_multipath_config();
+ r = pathinfo(pp, conf, DI_PRIO);
+ put_multipath_config(conf);
if (r) {
condlog(2, "%s: failed to refresh pathinfo",
mpp->alias);
}
select_action(mpp, vecs->mpvec, 1);
- r = domap(mpp, params);
+ r = domap(mpp, params, is_daemon);
if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
condlog(3, "%s: domap (%u) failure "
"for reload map", mpp->alias, r);
ACT_CREATE,
ACT_RESIZE,
ACT_FORCERENAME,
+ ACT_DRY_RUN,
};
#define FLUSH_ONE 1
#define FLUSH_ALL 2
int setup_map (struct multipath * mpp, char * params, int params_size );
-int domap (struct multipath * mpp, char * params);
+int domap (struct multipath * mpp, char * params, int is_daemon);
int reinstate_paths (struct multipath *mpp);
-int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
-int get_refwwid (char * dev, enum devtypes dev_type, vector pathvec, char **wwid);
-int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh);
+int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload, enum mpath_cmds cmd);
+int get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
+ vector pathvec, char **wwid);
+int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon);
int sysfs_get_host_adapter_name(struct path *pp, char *adapter_name);
{
va_list ap;
int thres;
+ struct config *conf;
va_start(ap, fmt);
+ conf = get_multipath_config();
thres = (conf) ? conf->verbosity : 0;
+ put_multipath_config(conf);
if (prio <= thres) {
if (sink < 1) {
#define DEFAULT_HWHANDLER "0"
#define DEFAULT_MINIO 1000
#define DEFAULT_MINIO_RQ 1
-#define DEFAULT_PGPOLICY FAILOVER
-#define DEFAULT_FAILBACK -FAILBACK_MANUAL
-#define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE
-#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
+#define DEFAULT_PGPOLICY GROUP_BY_PRIO
+#define DEFAULT_FAILBACK -FAILBACK_IMMEDIATE
+#define DEFAULT_RR_WEIGHT RR_WEIGHT_NONE
+#define DEFAULT_NO_PATH_RETRY NO_PATH_RETRY_UNDEF
#define DEFAULT_VERBOSITY 2
#define DEFAULT_REASSIGN_MAPS 0
#define DEFAULT_FIND_MULTIPATHS 0
#define DEFAULT_FAST_IO_FAIL 5
-#define DEFAULT_DEV_LOSS_TMO 600
-#define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
-#define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
-#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
-#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
+#define DEFAULT_DEV_LOSS_TMO 600
+#define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_ON
+#define DEFAULT_DETECT_PRIO DETECT_PRIO_ON
+#define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
+#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
#define DEFAULT_UEVENT_STACKSIZE 256
-#define DEFAULT_RETRIGGER_DELAY 10
-#define DEFAULT_RETRIGGER_TRIES 3
+#define DEFAULT_RETRIGGER_DELAY 10
+#define DEFAULT_RETRIGGER_TRIES 3
#define DEFAULT_UEV_WAIT_TIMEOUT 30
#define DEFAULT_CHECKINT 5
#include "debug.h"
#include "memory.h"
#include "devmapper.h"
-#include "config.h"
#include "sysfs.h"
#include "log_pthread.h"
#define UUID_PREFIX "mpath-"
#define UUID_PREFIX_LEN 6
+static int dm_conf_verbosity;
+
#ifdef LIBDM_API_DEFERRED
static int dm_cancel_remove_partmaps(const char * mapname);
#endif
if (level > 6)
level = 6;
- thres = (conf) ? conf->verbosity : 0;
+ thres = dm_conf_verbosity;
if (thres <= 3 || level > thres)
return;
}
extern void
-dm_init(void) {
+dm_init(int v) {
dm_log_init(&dm_write_log);
- dm_log_init_verbose(conf ? conf->verbosity + 3 : 0);
+ dm_log_init_verbose(v + 3);
}
static int
dm_get_library_version(version, sizeof(version));
condlog(3, "libdevmapper version %s", version);
- sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]);
+ if (sscanf(version, "%d.%d.%d ", &v[0], &v[1], &v[2]) != 3) {
+ condlog(0, "invalid libdevmapper version %s", version);
+ return 1;
+ }
if VERSION_GE(v, minv)
return 0;
goto out;
}
v = target->version;
- version[0] = v[0];
- version[1] = v[1];
- version[2] = v[2];
+ version[0] = v[0];
+ version[1] = v[1];
+ version[2] = v[2];
r = 0;
out:
dm_task_destroy(dmt);
{
unsigned int minv[3] = {1, 0, 3};
unsigned int version[3] = {0, 0, 0};
- unsigned int * v = version;
+ unsigned int * v = version;
if (dm_drv_version(v, TGT_MPATH)) {
/* in doubt return not capable */
r = dm_task_run (dmt);
- if (udev_wait_flag) {
- if (!r)
- dm_udev_complete(cookie);
- else
+ if (udev_wait_flag)
dm_udev_wait(cookie);
- }
out:
dm_task_destroy (dmt);
return r;
r = dm_task_run (dmt);
- if (task == DM_DEVICE_CREATE) {
- if (!r)
- dm_udev_complete(cookie);
- else
+ if (task == DM_DEVICE_CREATE)
dm_udev_wait(cookie);
- }
freeout:
if (prefixed_uuid)
FREE(prefixed_uuid);
{
int r = 1;
struct dm_task *dmt;
- void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params = NULL;
goto out;
/* Fetch 1st target */
- next = dm_get_next_target(dmt, next, &start, &length,
- &target_type, ¶ms);
+ dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, ¶ms);
if (size)
*size = length;
{
int r = 1;
struct dm_task *dmt;
- void *next = NULL;
uint64_t start, length;
char *target_type;
char *status;
goto out;
/* Fetch 1st target */
- next = dm_get_next_target(dmt, next, &start, &length,
- &target_type, &status);
+ dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, &status);
if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
r = 0;
{
int r = 0;
struct dm_task *dmt;
- void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
goto out;
/* Fetch 1st target */
- next = dm_get_next_target(dmt, next, &start, &length,
- &target_type, ¶ms);
+ dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, ¶ms);
if (!target_type)
r = -1;
for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */
snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim,
name + offset);
- dm_rename(name, buff);
+ dm_rename(name, buff, rd->delim);
condlog(4, "partition map %s renamed", name);
return 0;
}
int
-dm_rename_partmaps (const char * old, char * new)
+dm_rename_partmaps (const char * old, char * new, char *delim)
{
struct rename_data rd;
rd.old = old;
rd.new = new;
- if (conf->partition_delim)
- rd.delim = conf->partition_delim;
+ if (delim)
+ rd.delim = delim;
if (isdigit(new[strlen(new)-1]))
rd.delim = "p";
else
}
int
-dm_rename (const char * old, char * new)
+dm_rename (const char * old, char * new, char *delim)
{
int r = 0;
struct dm_task *dmt;
uint32_t cookie;
- if (dm_rename_partmaps(old, new))
+ if (dm_rename_partmaps(old, new, delim))
return r;
if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
goto out;
r = dm_task_run(dmt);
- if (!r)
- dm_udev_complete(cookie);
- else
- dm_udev_wait(cookie);
+ dm_udev_wait(cookie);
out:
dm_task_destroy(dmt);
void dm_reassign_deps(char *table, char *dep, char *newdep)
{
char *p, *n;
- char newtable[PARAMS_SIZE];
+ char *newtable;
- strcpy(newtable, table);
+ newtable = strdup(table);
+ if (!newtable)
+ return;
p = strstr(newtable, dep);
n = table + (p - newtable);
strcpy(n, newdep);
n += strlen(newdep);
p += strlen(dep);
strcat(n, p);
+ free(newtable);
}
int dm_reassign_table(const char *name, char *old, char *new)
{
- int r, modified = 0;
+ int r = 0, modified = 0;
uint64_t start, length;
struct dm_task *dmt, *reload_dmt;
char *target, *params = NULL;
- char buff[PARAMS_SIZE];
+ char *buff;
void *next = NULL;
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target, ¶ms);
- memset(buff, 0, PARAMS_SIZE);
- strcpy(buff, params);
+ buff = strdup(params);
+ if (!buff) {
+ condlog(3, "%s: failed to replace target %s, "
+ "out of memory", name, target);
+ goto out_reload;
+ }
if (strcmp(target, TGT_MPATH) && strstr(params, old)) {
condlog(3, "%s: replace target %s %s",
name, target, buff);
modified++;
}
dm_task_add_target(reload_dmt, start, length, target, buff);
+ free(buff);
} while (next);
if (modified) {
#define MPATH_UDEV_RELOAD_FLAG 0
#endif
-void dm_init(void);
+void dm_init(int verbosity);
int dm_prereq (void);
int dm_drv_version (unsigned int * version, char * str);
int dm_simplecmd_flush (int, const char *, uint16_t);
int deferred_remove);
int dm_get_uuid(char *name, char *uuid);
int dm_get_info (char * mapname, struct dm_info ** dmi);
-int dm_rename (const char * old, char * new);
+int dm_rename (const char * old, char * new, char * delim);
int dm_reassign(const char * mapname);
int dm_reassign_table(const char *name, char *old, char *new);
int dm_setgeometry(struct multipath *mpp);
#include "blacklist.h"
#include "defaults.h"
#include "prio.h"
-#include "errno.h"
+#include <errno.h>
#include <inttypes.h>
-#include <mpath_cmd.h>
+#include "mpath_cmd.h"
static int
set_int(vector strvec, void *ptr)
#define declare_def_handler(option, function) \
static int \
-def_ ## option ## _handler (vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
return function (strvec, &conf->option); \
}
#define declare_def_snprint(option, function) \
static int \
-snprint_def_ ## option (char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
return function (buff, len, &conf->option); \
}
#define declare_def_snprint_defint(option, function, value) \
static int \
-snprint_def_ ## option (char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
int i = value; \
if (!conf->option) \
#define declare_def_snprint_defstr(option, function, value) \
static int \
-snprint_def_ ## option (char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
char *s = value; \
if (!conf->option) \
#define declare_hw_handler(option, function) \
static int \
-hw_ ## option ## _handler (vector strvec) \
+hw_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); \
if (!hwe) \
#define declare_hw_snprint(option, function) \
static int \
-snprint_hw_ ## option (char * buff, int len, void * data) \
+snprint_hw_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
struct hwentry * hwe = (struct hwentry *)data; \
return function (buff, len, &hwe->option); \
#define declare_ovr_handler(option, function) \
static int \
-ovr_ ## option ## _handler (vector strvec) \
+ovr_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
if (!conf->overrides) \
return 1; \
#define declare_ovr_snprint(option, function) \
static int \
-snprint_ovr_ ## option (char * buff, int len, void * data) \
+snprint_ovr_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
return function (buff, len, &conf->overrides->option); \
}
#define declare_mp_handler(option, function) \
static int \
-mp_ ## option ## _handler (vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
#define declare_mp_snprint(option, function) \
static int \
-snprint_mp_ ## option (char * buff, int len, void * data) \
+snprint_mp_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
struct mpentry * mpe = (struct mpentry *)data; \
return function (buff, len, &mpe->option); \
declare_def_handler(queue_without_daemon, set_yes_no)
static int
-snprint_def_queue_without_daemon (char * buff, int len, void * data)
+snprint_def_queue_without_daemon (struct config *conf,
+ char * buff, int len, void * data)
{
switch (conf->queue_without_daemon) {
case QUE_NO_DAEMON_OFF:
declare_def_snprint(strict_timing, print_yes_no)
static int
-def_config_dir_handler(vector strvec)
+def_config_dir_handler(struct config *conf, vector strvec)
{
/* this is only valid in the main config file */
if (conf->processed_main_config)
#define declare_def_attr_handler(option, function) \
static int \
-def_ ## option ## _handler (vector strvec) \
+def_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
return function (strvec, &conf->option, &conf->attribute_flags);\
}
#define declare_def_attr_snprint(option, function) \
static int \
-snprint_def_ ## option (char * buff, int len, void * data) \
+snprint_def_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
return function (buff, len, &conf->option, \
&conf->attribute_flags); \
#define declare_mp_attr_handler(option, function) \
static int \
-mp_ ## option ## _handler (vector strvec) \
+mp_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable); \
if (!mpe) \
#define declare_mp_attr_snprint(option, function) \
static int \
-snprint_mp_ ## option (char * buff, int len, void * data) \
+snprint_mp_ ## option (struct config *conf, char * buff, int len, void * data) \
{ \
struct mpentry * mpe = (struct mpentry *)data; \
return function (buff, len, &mpe->option, \
static int
-max_fds_handler(vector strvec)
+max_fds_handler(struct config *conf, vector strvec)
{
char * buff;
int r = 0, max_fds;
}
static int
-snprint_max_fds (char * buff, int len, void * data)
+snprint_max_fds (struct config *conf, char * buff, int len, void * data)
{
int r = 0, max_fds;
char * buff;
buff = set_value(strvec);
+ if (!buff)
+ return 1;
if (strlen(buff) == 6 && !strcmp(buff, "manual"))
*int_ptr = -FAILBACK_MANUAL;
declare_mp_snprint(no_path_retry, print_no_path_retry)
static int
-def_log_checker_err_handler(vector strvec)
+def_log_checker_err_handler(struct config *conf, vector strvec)
{
char * buff;
}
static int
-snprint_def_log_checker_err (char * buff, int len, void * data)
+snprint_def_log_checker_err (struct config *conf, char * buff, int len, void * data)
{
if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
return snprintf(buff, len, "once");
declare_mp_snprint(delay_wait_checks, print_delay_checks)
static int
-def_uxsock_timeout_handler(vector strvec)
+def_uxsock_timeout_handler(struct config *conf, vector strvec)
{
unsigned int uxsock_timeout;
char *buff;
* blacklist block handlers
*/
static int
-blacklist_handler(vector strvec)
+blacklist_handler(struct config *conf, vector strvec)
{
if (!conf->blist_devnode)
conf->blist_devnode = vector_alloc();
}
static int
-blacklist_exceptions_handler(vector strvec)
+blacklist_exceptions_handler(struct config *conf, vector strvec)
{
if (!conf->elist_devnode)
conf->elist_devnode = vector_alloc();
#define declare_ble_handler(option) \
static int \
-ble_ ## option ## _handler (vector strvec) \
+ble_ ## option ## _handler (struct config *conf, vector strvec) \
{ \
char * buff; \
\
#define declare_ble_device_handler(name, option, vend, prod) \
static int \
-ble_ ## option ## _ ## name ## _handler (vector strvec) \
+ble_ ## option ## _ ## name ## _handler (struct config *conf, vector strvec) \
{ \
char * buff; \
\
declare_ble_handler(elist_property)
static int
-snprint_def_uxsock_timeout(char * buff, int len, void * data)
+snprint_def_uxsock_timeout(struct config *conf, char * buff, int len, void * data)
{
return snprintf(buff, len, "%u", conf->uxsock_timeout);
}
static int
-snprint_ble_simple (char * buff, int len, void * data)
+snprint_ble_simple (struct config *conf, char * buff, int len, void * data)
{
struct blentry * ble = (struct blentry *)data;
}
static int
-ble_device_handler(vector strvec)
+ble_device_handler(struct config *conf, vector strvec)
{
return alloc_ble_device(conf->blist_device);
}
static int
-ble_except_device_handler(vector strvec)
+ble_except_device_handler(struct config *conf, vector strvec)
{
return alloc_ble_device(conf->elist_device);
}
declare_ble_device_handler(product, elist_device, NULL, buff)
static int
-snprint_bled_vendor (char * buff, int len, void * data)
+snprint_bled_vendor (struct config *conf, char * buff, int len, void * data)
{
struct blentry_device * bled = (struct blentry_device *)data;
}
static int
-snprint_bled_product (char * buff, int len, void * data)
+snprint_bled_product (struct config *conf, char * buff, int len, void * data)
{
struct blentry_device * bled = (struct blentry_device *)data;
* devices block handlers
*/
static int
-devices_handler(vector strvec)
+devices_handler(struct config *conf, vector strvec)
{
if (!conf->hwtable)
conf->hwtable = vector_alloc();
}
static int
-device_handler(vector strvec)
+device_handler(struct config *conf, vector strvec)
{
struct hwentry * hwe;
* overrides handlers
*/
static int
-overrides_handler(vector strvec)
+overrides_handler(struct config *conf, vector strvec)
{
if (!conf->overrides)
conf->overrides = alloc_hwe();
* multipaths block handlers
*/
static int
-multipaths_handler(vector strvec)
+multipaths_handler(struct config *conf, vector strvec)
{
if (!conf->mptable)
conf->mptable = vector_alloc();
}
static int
-multipath_handler(vector strvec)
+multipath_handler(struct config *conf, vector strvec)
{
struct mpentry * mpe;
*/
static int
-deprecated_handler(vector strvec)
+deprecated_handler(struct config *conf, vector strvec)
{
char * buff;
}
static int
-snprint_deprecated (char * buff, int len, void * data)
+snprint_deprecated (struct config *conf, char * buff, int len, void * data)
{
return 0;
}
#define __deprecated
void
-init_keywords(void)
+init_keywords(vector keywords)
{
install_keyword_root("defaults", NULL);
install_keyword("verbosity", &def_verbosity_handler, &snprint_def_verbosity);
#include "vector.h"
#endif
-void init_keywords(void);
+void init_keywords(vector keywords);
int get_sys_max_fds(int *);
int print_rr_weight (char * buff, int len, void *ptr);
int print_pgfailback (char * buff, int len, void *ptr);
#include "defaults.h"
int
-alloc_path_with_pathinfo (vector hwtable, struct udev_device *udevice,
+alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
int flag, struct path **pp_ptr)
{
int err = PATHINFO_FAILED;
condlog(0, "pp->dev too small");
} else {
pp->udev = udev_device_ref(udevice);
- err = pathinfo(pp, hwtable, flag | DI_BLACKLIST);
+ err = pathinfo(pp, conf, flag | DI_BLACKLIST);
}
if (err)
}
int
-store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
- int flag, struct path **pp_ptr)
+store_pathinfo (vector pathvec, struct config *conf,
+ struct udev_device *udevice, int flag, struct path **pp_ptr)
{
int err = PATHINFO_FAILED;
struct path * pp;
goto out;
}
pp->udev = udev_device_ref(udevice);
- err = pathinfo(pp, hwtable,
- (conf->cmd == CMD_REMOVE_WWID)? flag :
- (flag | DI_BLACKLIST));
+ err = pathinfo(pp, conf, flag);
if (err)
goto out;
pp = find_path_by_dev(pathvec, (char *)devname);
if (!pp) {
- return store_pathinfo(pathvec, conf->hwtable,
+ return store_pathinfo(pathvec, conf,
udevice, flag, NULL);
}
- return pathinfo(pp, conf->hwtable, flag);
+ return pathinfo(pp, conf, flag);
}
int
-path_discovery (vector pathvec, struct config * conf, int flag)
+path_discovery (vector pathvec, int flag)
{
struct udev_enumerate *udev_iter;
struct udev_list_entry *entry;
struct udev_device *udevice;
+ struct config *conf;
const char *devpath;
int num_paths = 0, total_paths = 0;
- udev_iter = udev_enumerate_new(conf->udev);
+ udev_iter = udev_enumerate_new(udev);
if (!udev_iter)
return -ENOMEM;
const char *devtype;
devpath = udev_list_entry_get_name(entry);
condlog(4, "Discover device %s", devpath);
- udevice = udev_device_new_from_syspath(conf->udev, devpath);
+ udevice = udev_device_new_from_syspath(udev, devpath);
if (!udevice) {
condlog(4, "%s: no udev information", devpath);
continue;
devtype = udev_device_get_devtype(udevice);
if(devtype && !strncmp(devtype, "disk", 4)) {
total_paths++;
+ conf = get_multipath_config();
if (path_discover(pathvec, conf,
udevice, flag) == PATHINFO_OK)
num_paths++;
+ put_multipath_config(conf);
}
udev_device_unref(udevice);
}
declare_sysfs_get_str(vendor);
declare_sysfs_get_str(model);
declare_sysfs_get_str(rev);
+declare_sysfs_get_str(access_state);
+declare_sysfs_get_str(preferred_path);
ssize_t
sysfs_get_vpd (struct udev_device * udev, int pg,
value = udev_device_get_sysname(tgtdev);
if (sscanf(value, "rport-%d:%d-%d",
&host, &channel, &tgtid) == 3) {
- tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
+ tgtdev = udev_device_new_from_subsystem_sysname(udev,
"fc_remote_ports", value);
if (tgtdev) {
condlog(3, "SCSI target %d:%d:%d -> "
tgtid = -1;
}
if (parent && tgtname) {
- tgtdev = udev_device_new_from_subsystem_sysname(conf->udev,
+ tgtdev = udev_device_new_from_subsystem_sysname(udev,
"iscsi_session", tgtname);
if (tgtdev) {
const char *value;
return 1;
sprintf(host_name, "host%d", pp->sg_id.host_no);
- hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
+ hostdev = udev_device_new_from_subsystem_sysname(udev,
"scsi_host", host_name);
if (!hostdev)
return 1;
const char *value;
sprintf(host_name, "host%d", pp->sg_id.host_no);
- hostdev = udev_device_new_from_subsystem_sysname(conf->udev,
+ hostdev = udev_device_new_from_subsystem_sysname(udev,
"iscsi_host", host_name);
if (hostdev) {
value = udev_device_get_sysattr_value(hostdev,
return 1;
}
+int
+sysfs_get_asymmetric_access_state(struct path *pp, char *buff, int buflen)
+{
+ struct udev_device *parent = pp->udev;
+ char value[16], *eptr;
+ unsigned int preferred;
+
+ while (parent) {
+ const char *subsys = udev_device_get_subsystem(parent);
+ if (subsys && !strncmp(subsys, "scsi", 4))
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+
+ if (!parent)
+ return -1;
+
+ if (sysfs_get_access_state(parent, buff, buflen) <= 0)
+ return -1;
+
+ if (sysfs_get_preferred_path(parent, value, 16) <= 0)
+ return 0;
+
+ preferred = strtoul(value, &eptr, 0);
+ if (value == eptr || preferred == ULONG_MAX) {
+ /* Parse error, ignore */
+ return 0;
+ }
+ return preferred;
+}
+
static void
sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp)
{
sprintf(rport_id, "rport-%d:%d-%d",
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
- rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+ rport_dev = udev_device_new_from_subsystem_sysname(udev,
"fc_remote_ports", rport_id);
if (!rport_dev) {
condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
char value[11];
sprintf(session_id, "session%d", pp->sg_id.transport_id);
- session_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+ session_dev = udev_device_new_from_subsystem_sysname(udev,
"iscsi_session", session_id);
if (!session_dev) {
condlog(1, "%s: No iscsi session for '%s'", pp->dev,
sprintf(end_dev_id, "end_device-%d:%d",
pp->sg_id.host_no, pp->sg_id.transport_id);
- sas_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+ sas_dev = udev_device_new_from_subsystem_sysname(udev,
"sas_end_device", end_dev_id);
if (!sas_dev) {
condlog(1, "%s: No SAS end device for '%s'", pp->dev,
}
int
-sysfs_set_scsi_tmo (struct multipath *mpp)
+sysfs_set_scsi_tmo (struct multipath *mpp, int checkint)
{
struct path *pp;
int i;
int dev_loss_tmo = mpp->dev_loss;
if (mpp->no_path_retry > 0) {
- int no_path_retry_tmo = mpp->no_path_retry * conf->checkint;
+ uint64_t no_path_retry_tmo = mpp->no_path_retry * checkint;
if (no_path_retry_tmo > MAX_DEV_LOSS_TMO)
no_path_retry_tmo = MAX_DEV_LOSS_TMO;
}
static int
-scsi_sysfs_pathinfo (struct path * pp)
+scsi_sysfs_pathinfo (struct path * pp, vector hwtable)
{
struct udev_device *parent;
const char *attr_path = NULL;
/*
* set the hwe configlet pointer
*/
- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
+ pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id, pp->rev);
/*
* host / bus / target / lun
}
static int
-ccw_sysfs_pathinfo (struct path * pp)
+ccw_sysfs_pathinfo (struct path * pp, vector hwtable)
{
struct udev_device *parent;
char attr_buff[NAME_SIZE];
/*
* set the hwe configlet pointer
*/
- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, NULL);
+ pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id, NULL);
/*
* host / bus / target / lun
*/
attr_path = udev_device_get_sysname(parent);
pp->sg_id.lun = 0;
- sscanf(attr_path, "%i.%i.%x",
- &pp->sg_id.host_no,
- &pp->sg_id.channel,
- &pp->sg_id.scsi_id);
- condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+ if (sscanf(attr_path, "%i.%i.%x",
+ &pp->sg_id.host_no,
+ &pp->sg_id.channel,
+ &pp->sg_id.scsi_id) == 3) {
+ condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
pp->dev,
pp->sg_id.host_no,
pp->sg_id.channel,
pp->sg_id.scsi_id,
pp->sg_id.lun);
+ }
return 0;
}
static int
-cciss_sysfs_pathinfo (struct path * pp)
+cciss_sysfs_pathinfo (struct path * pp, vector hwtable)
{
const char * attr_path = NULL;
struct udev_device *parent;
/*
* set the hwe configlet pointer
*/
- pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id, pp->rev);
+ pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id, pp->rev);
/*
* host / bus / target / lun
}
int
-sysfs_pathinfo(struct path * pp)
+sysfs_pathinfo(struct path * pp, vector hwtable)
{
if (common_sysfs_pathinfo(pp))
return 1;
if (pp->bus == SYSFS_BUS_UNDEF)
return 0;
else if (pp->bus == SYSFS_BUS_SCSI) {
- if (scsi_sysfs_pathinfo(pp))
+ if (scsi_sysfs_pathinfo(pp, hwtable))
return 1;
} else if (pp->bus == SYSFS_BUS_CCW) {
- if (ccw_sysfs_pathinfo(pp))
+ if (ccw_sysfs_pathinfo(pp, hwtable))
return 1;
} else if (pp->bus == SYSFS_BUS_CCISS) {
- if (cciss_sysfs_pathinfo(pp))
+ if (cciss_sysfs_pathinfo(pp, hwtable))
return 1;
}
return 0;
}
int
-get_state (struct path * pp, int daemon)
+get_state (struct path * pp, struct config *conf, int daemon)
{
struct checker * c = &pp->checker;
int state;
if (!checker_selected(c)) {
if (daemon) {
- if (pathinfo(pp, conf->hwtable, DI_SYSFS) != PATHINFO_OK) {
+ if (pathinfo(pp, conf, DI_SYSFS) != PATHINFO_OK) {
condlog(3, "%s: couldn't get sysfs pathinfo",
pp->dev);
return PATH_UNCHECKED;
}
}
- select_checker(pp);
+ select_checker(conf, pp);
if (!checker_selected(c)) {
condlog(3, "%s: No checker selected", pp->dev);
return PATH_UNCHECKED;
static int
get_prio (struct path * pp)
{
+ struct prio * p;
+ struct config *conf;
+
if (!pp)
return 0;
- struct prio * p = &pp->prio;
-
+ p = &pp->prio;
if (!prio_selected(p)) {
- select_detect_prio(pp);
- select_prio(pp);
+ conf = get_multipath_config();
+ select_detect_prio(conf, pp);
+ select_prio(conf, pp);
+ put_multipath_config(conf);
if (!prio_selected(p)) {
condlog(3, "%s: no prio selected", pp->dev);
pp->priority = PRIO_UNDEF;
return 1;
}
}
- pp->priority = prio_getprio(p, pp);
+ conf = get_multipath_config();
+ pp->priority = prio_getprio(p, pp, conf->checker_timeout);
+ put_multipath_config(conf);
if (pp->priority < 0) {
condlog(3, "%s: %s prio error", pp->dev, prio_name(p));
pp->priority = PRIO_UNDEF;
value = udev_device_get_property_value(pp->udev,
uid_attribute);
- if ((!value || strlen(value) == 0) && conf->cmd == CMD_VALID_PATH)
+ if (!value || strlen(value) == 0)
value = getenv(uid_attribute);
if (value && strlen(value)) {
if (strlen(value) + 1 > WWID_SIZE) {
char *c;
const char *origin = "unknown";
ssize_t len = 0;
+ struct config *conf;
- if (!pp->uid_attribute && !pp->getuid)
- select_getuid(pp);
+ if (!pp->uid_attribute && !pp->getuid) {
+ conf = get_multipath_config();
+ select_getuid(conf, pp);
+ put_multipath_config(conf);
+ }
if (!pp->udev) {
condlog(1, "%s: no udev information", pp->dev);
len = strlen(pp->wwid);
origin = "callout";
} else {
+ int retrigger;
+
if (pp->uid_attribute) {
len = get_udev_uid(pp, pp->uid_attribute);
origin = "udev";
"%s: failed to get udev uid: %s",
pp->dev, strerror(-len));
+ } else {
+ len = get_vpd_uid(pp);
+ origin = "sysfs";
}
- if (len <= 0 && pp->retriggers >= conf->retrigger_tries &&
+ conf = get_multipath_config();
+ retrigger = conf->retrigger_tries;
+ put_multipath_config(conf);
+ if (len <= 0 && pp->retriggers >= retrigger &&
!strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) {
len = get_vpd_uid(pp);
origin = "sysfs";
}
extern int
-pathinfo (struct path *pp, vector hwtable, int mask)
+pathinfo (struct path *pp, struct config *conf, int mask)
{
int path_state;
/*
* fetch info available in sysfs
*/
- if (mask & DI_SYSFS && sysfs_pathinfo(pp))
+ if (mask & DI_SYSFS && sysfs_pathinfo(pp, conf->hwtable))
return PATHINFO_FAILED;
if (mask & DI_BLACKLIST && mask & DI_SYSFS) {
if (mask & DI_CHECKER) {
if (path_state == PATH_UP) {
- pp->chkrstate = pp->state = get_state(pp, 0);
+ pp->chkrstate = pp->state = get_state(pp, conf, 0);
if (pp->state == PATH_UNCHECKED ||
pp->state == PATH_WILD)
goto blank;
}
}
- pp->initialized = INIT_OK;
+ if ((mask & DI_ALL) == DI_ALL)
+ pp->initialized = INIT_OK;
return PATHINFO_OK;
blank:
struct config;
-int path_discovery (vector pathvec, struct config * conf, int flag);
+int path_discovery (vector pathvec, int flag);
int do_tur (char *);
int path_offline (struct path *);
-int get_state (struct path * pp, int daemon);
-int pathinfo (struct path *, vector hwtable, int mask);
-int alloc_path_with_pathinfo (vector hwtable, struct udev_device *udevice,
+int get_state (struct path * pp, struct config * conf, int daemon);
+int pathinfo (struct path * pp, struct config * conf, int mask);
+int alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
int flag, struct path **pp_ptr);
-int store_pathinfo (vector pathvec, vector hwtable,
+int store_pathinfo (vector pathvec, struct config *conf,
struct udev_device *udevice, int flag,
struct path **pp_ptr);
-int sysfs_set_scsi_tmo (struct multipath *mpp);
+int sysfs_set_scsi_tmo (struct multipath *mpp, int checkint);
int sysfs_get_timeout(struct path *pp, unsigned int *timeout);
int sysfs_get_host_pci_name(struct path *pp, char *pci_name);
int sysfs_get_iscsi_ip_address(struct path *pp, char *ip_address);
ssize_t sysfs_get_vpd (struct udev_device * udev, int pg, unsigned char * buff,
size_t len);
+int sysfs_get_asymmetric_access_state(struct path *pp,
+ char *buff, int buflen);
/*
* discovery bitmask
#include "structs.h"
#include "util.h"
#include "debug.h"
-#include "config.h"
#define WORD_SIZE 64
}
extern int
-disassemble_map (vector pathvec, char * params, struct multipath * mpp)
+disassemble_map (vector pathvec, char * params, struct multipath * mpp,
+ int is_daemon)
{
char * word;
char * p;
if (!pp)
goto out1;
- strncpy(pp->dev_t, word, BLK_DEV_SIZE);
- strncpy(pp->dev, devname, FILE_NAME_SIZE);
+ strncpy(pp->dev_t, word, BLK_DEV_SIZE - 1);
+ strncpy(pp->dev, devname, FILE_NAME_SIZE - 1);
if (strlen(mpp->wwid)) {
- strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
+ strncpy(pp->wwid, mpp->wwid,
+ WWID_SIZE - 1);
}
/* Only call this in multipath client mode */
- if (!conf->daemon && store_path(pathvec, pp))
+ if (!is_daemon && store_path(pathvec, pp))
goto out1;
} else {
if (!strlen(pp->wwid) &&
strlen(mpp->wwid))
- strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
+ strncpy(pp->wwid, mpp->wwid,
+ WWID_SIZE - 1);
}
FREE(word);
* in the get_dm_mpvec() code path
*/
if (!strlen(mpp->wwid))
- strncpy(mpp->wwid, pp->wwid, WWID_SIZE);
+ strncpy(mpp->wwid, pp->wwid,
+ WWID_SIZE - 1);
/*
* Update wwid for paths which may not have been
* active at the time the getuid callout was run
*/
else if (!strlen(pp->wwid))
- strncpy(pp->wwid, mpp->wwid, WWID_SIZE);
+ strncpy(pp->wwid, mpp->wwid,
+ WWID_SIZE - 1);
pgp->id ^= (long)pp;
pp->pgindex = i + 1;
int assemble_map (struct multipath *, char *, int);
-int disassemble_map (vector, char *, struct multipath *);
+int disassemble_map (vector, char *, struct multipath *, int);
int disassemble_status (char *, struct multipath *);
/*
* Tuning suggestions on these parameters should go to
- * dm-devel@redhat.com
- *
+ * dm-devel@redhat.com (subscribers-only, see README)
+ *
* You are welcome to claim maintainership over a controller
* family. Please mail the currently enlisted maintainer and
* the upstream package maintainer.
+ *
+ * Please, use the TEMPLATE below to add new hardware.
+ *
+ * WARNING:
+ *
+ * Devices with a proprietary handler must also be included in
+ * the kernel side. Currently at drivers/scsi/scsi_dh.c
*/
static struct hwentry default_hw[] = {
/*
- * Compellent Technologies, Inc.
- *
- * Maintainer : Jim Lester, Compellent
- * Mail : jim.lester@compellent.com
+ * Compellent Technologies/DELL
*/
{
.vendor = "COMPELNT",
.product = "Compellent Vol",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * Apple controller family
+ * Apple
*
* Maintainer : Shyam Sundar
* Mail : g.shyamsundar@yahoo.co.in
*/
{
- .vendor = "APPLE*",
- .product = "Xserve RAID ",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
+ .vendor = "APPLE.*",
+ .product = "Xserve RAID",
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DEFAULT_CHECKER,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * StorageWorks controller family
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * StorageWorks/HPE
*/
{
.vendor = "3PARdata",
.product = "VV",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DEFAULT_CHECKER,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "DEC",
.product = "HSG80",
.features = "1 queue_if_no_path",
.hwhandler = "1 hp_sw",
- .pgpolicy = GROUP_BY_PRIO,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
.checker_name = HP_SW,
.prio_name = PRIO_HP_SW,
- .prio_args = NULL,
},
{
.vendor = "HP",
.product = "A6189A",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */
.product = "(MSA|HSV)1.0.*",
.features = "1 queue_if_no_path",
.hwhandler = "1 hp_sw",
- .pgpolicy = GROUP_BY_PRIO,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
.minio = 100,
.checker_name = HP_SW,
.prio_name = PRIO_HP_SW,
- .prio_args = NULL,
},
{
/* MSA 1000/1500 with new firmware */
.vendor = "(COMPAQ|HP)",
.product = "MSA VOLUME",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
/* EVA 3000/5000 with new firmware, EVA 4000/6000/8000 */
.vendor = "(COMPAQ|HP)",
.product = "HSV1[01]1|HSV2[01]0|HSV3[046]0|HSV4[05]0",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
- /* HP MSA2000 product family with old firmware */
+ /* HP MSA2000 family with old firmware */
.vendor = "HP",
.product = "MSA2[02]12fc|MSA2012i",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 18,
.minio = 100,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
- /* HP MSA2000 product family with new firmware */
+ /* HP MSA2000 family with new firmware */
.vendor = "HP",
.product = "MSA2012sa|MSA23(12|24)(fc|i|sa)|MSA2000s VOLUME",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 18,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
- /* HP MSA 1040/2040 product family */
+ /* HP MSA 1040/2040 family */
.vendor = "HP",
.product = "MSA (1|2)040 SA(N|S)",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 18,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
-
{
/* HP SVSP */
.vendor = "HP",
.product = "HSVX700",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
-
{
/* HP Smart Array */
.vendor = "HP",
.product = "LOGICAL VOLUME.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
- /* HP P2000 family arrays */
+ /* HP P2000 family */
.vendor = "HP",
.product = "P2000 G3 FC|P2000G3 FC/iSCSI|P2000 G3 SAS|P2000 G3 iSCSI",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 18,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
/*
- * DDN controller family
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * DDN
*/
{
.vendor = "DDN",
.product = "SAN DataDirector",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * EMC / Clariion controller family
+ * EMC/DELL
*
* Maintainer : Edward Goggin, EMC
* Mail : egoggin@emc.com
{
.vendor = "EMC",
.product = "SYMMETRIX",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 6,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
- .vendor = "DGC",
- .product = ".*",
+ /* DGC CLARiiON CX/AX and EMC VNX */
+ .vendor = "^DGC",
+ .product = "^RAID|^DISK|^VRAID",
.bl_product = "LUNZ",
.features = "1 queue_if_no_path",
.hwhandler = "1 emc",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = (300 / DEFAULT_CHECKINT),
.checker_name = EMC_CLARIION,
.prio_name = PRIO_EMC,
- .prio_args = NULL,
- .retain_hwhandler = RETAIN_HWHANDLER_ON,
- .detect_prio = DETECT_PRIO_ON,
},
{
.vendor = "EMC",
.product = "Invista",
.bl_product = "LUNZ",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 5,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "XtremIO",
.product = "XtremApp",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.selector = "queue-length 0",
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .checker_name = TUR,
- .fast_io_fail = 5,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * Fujitsu controller family
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * Fujitsu
*/
{
.vendor = "FSC",
.product = "CentricStor",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = GROUP_BY_SERIAL,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "FUJITSU",
.product = "ETERNUS_DX(H|L|M|400|8000)",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 10,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
/*
- * Hitachi controller family
+ * Hitachi
*
* Maintainer : Matthias Rudolph
* Mail : matthias.rudolph@hds.com
{
.vendor = "(HITACHI|HP)",
.product = "OPEN-.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "HITACHI",
.product = "DF.*",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_HDS,
- .prio_args = NULL,
},
/*
- * IBM controller family
+ * IBM
*
* Maintainer : Hannes Reinecke, SuSE
* Mail : hare@suse.de
{
.vendor = "IBM",
.product = "ProFibre 4000R",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM FAStT 1722-600 */
.bl_product = "Universal Xport",
.features = "1 queue_if_no_path",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 300,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
/* IBM DS4100 */
.bl_product = "Universal Xport",
.features = "1 queue_if_no_path",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 300,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
/* IBM DS3200 / DS3300 / DS3400 */
.bl_product = "Universal Xport",
.features = "1 queue_if_no_path",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 300,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
/* IBM DS4400 / DS4500 / FAStT700 */
.vendor = "IBM",
.product = "^1742",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
.vendor = "IBM",
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 15,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
- /* IBM DS4700 */
+ /* IBM DS4700 */
.vendor = "IBM",
.product = "^1814",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
- /* IBM DS4800 */
+ /* IBM DS4800 */
.vendor = "IBM",
.product = "^1815",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
- /* IBM DS5000 */
+ /* IBM DS5000 */
.vendor = "IBM",
.product = "^1818",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
/* IBM Netfinity Fibre Channel RAID Controller Unit */
.vendor = "IBM",
.product = "^3526",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
/* IBM DS4200 / FAStT200 */
.vendor = "IBM",
.product = "^3542",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = GROUP_BY_SERIAL,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM ESS F20 aka Shark */
.vendor = "IBM",
.product = "^2105800",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = GROUP_BY_SERIAL,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM ESS F20 aka Shark */
.vendor = "IBM",
.product = "^2105F20",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = GROUP_BY_SERIAL,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM DS6000 */
.vendor = "IBM",
.product = "^1750500",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
/* IBM DS8000 */
.vendor = "IBM",
.product = "^2107900",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM SAN Volume Controller */
.vendor = "IBM",
.product = "^2145",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
/* IBM S/390 ECKD DASD */
.vendor = "IBM",
.product = "S/390 DASD ECKD",
- .bl_product = "S/390.*",
+ .bl_product = "S/390.*",
.uid_attribute = "ID_UID",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM S/390 FBA DASD */
.vendor = "IBM",
.product = "S/390 DASD FBA",
- .bl_product = "S/390.*",
+ .bl_product = "S/390.*",
.uid_attribute = "ID_UID",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
/* IBM IPR */
.product = "^IPR.*",
.features = "1 queue_if_no_path",
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
/* IBM RSSM */
.vendor = "IBM",
.product = "1820N00",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.minio = 100,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
- /* IBM XIV Storage System */
+ /* IBM XIV Storage System */
.vendor = "IBM",
.product = "2810XIV",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = 15,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
.minio = 15,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
* IBM Power Virtual SCSI Devices
/* AIX VDASD */
.vendor = "AIX",
.product = "VDASD",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = (300 / DEFAULT_CHECKINT),
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
- /* IBM 3303 NVDISK */
+ /* IBM 3303 NVDISK */
.vendor = "IBM",
.product = "3303 NVDISK",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = FAILOVER,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = (300 / DEFAULT_CHECKINT),
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
+ .pgpolicy = FAILOVER,
},
{
/* AIX NVDISK */
.vendor = "AIX",
.product = "NVDISK",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = (300 / DEFAULT_CHECKINT),
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
+ /*
+ * DELL
+ */
{
/* DELL MD3000 */
.vendor = "DELL",
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = 15,
- .checker_name = RDAC,
- .prio_name = PRIO_RDAC,
- .prio_args = NULL,
- },
- {
- /* DELL MD3000i */
- .vendor = "DELL",
- .product = "MD3000i",
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = 15,
- .checker_name = RDAC,
- .prio_name = PRIO_RDAC,
- .prio_args = NULL,
- },
- {
- /* DELL MD32xx */
- .vendor = "DELL",
- .product = "MD32xx",
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = 15,
- .checker_name = RDAC,
- .prio_name = PRIO_RDAC,
- .prio_args = NULL,
- },
- {
- /* DELL MD32xxi */
- .vendor = "DELL",
- .product = "MD32xxi",
- .bl_product = "Universal Xport",
- .features = "2 pg_init_retries 50",
- .hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 15,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
- /* DELL MD36xxi */
+ /* DELL MD32xx/MD36xx */
.vendor = "DELL",
- .product = "MD36xxi",
+ .product = "MD32xx|MD36xx",
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 15,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
- /* DELL MD36xxf */
+ /* DELL MD34xx/MD38xx */
.vendor = "DELL",
- .product = "MD36xxf",
+ .product = "MD34xx|MD38xx",
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 15,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
/*
- * NETAPP controller family
+ * NETAPP ONTAP family
*
- * Maintainer : Dave Wysochanski
- * Mail : davidw@netapp.com
+ * Maintainer : Martin George
+ * Mail : marting@netapp.com
*/
{
.vendor = "NETAPP",
.product = "LUN.*",
.features = "3 queue_if_no_path pg_init_retries 50",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
.flush_on_last_del = FLUSH_ENABLED,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
.minio = 128,
.dev_loss = MAX_DEV_LOSS_TMO,
- .checker_name = TUR,
.prio_name = PRIO_ONTAP,
- .prio_args = NULL,
- .retain_hwhandler = RETAIN_HWHANDLER_ON,
- .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
- .detect_prio = DETECT_PRIO_ON,
+ },
+ {
+ /* IBM NSeries */
+ .vendor = "IBM",
+ .product = "Nseries.*",
+ .features = "1 queue_if_no_path",
+ .minio = 128,
+ .prio_name = PRIO_ONTAP,
},
/*
- * NEXENTA/COMSTAR controller family
+ * NEXENTA
*
* Maintainer : Yacine Kheddache
* Mail : yacine@alyseo.com
.vendor = "NEXENTA",
.product = "COMSTAR",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = GROUP_BY_SERIAL,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 30,
.minio = 128,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * IBM NSeries (NETAPP) controller family
- *
- * Maintainer : Dave Wysochanski
- * Mail : davidw@netapp.com
- */
- {
- .vendor = "IBM",
- .product = "Nseries.*",
- .features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .minio = 128,
- .checker_name = DIRECTIO,
- .prio_name = PRIO_ONTAP,
- .prio_args = NULL,
- },
- /*
- * Pillar Data controller family
+ * Pillar Data/Oracle
*
* Maintainer : Srinivasan Ramani
- * Mail : sramani@pillardata.com
+ * Mail : srinivas.ramani@oracle.com
*/
{
.vendor = "Pillar",
.product = "Axiom.*",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
-
/*
- * SGI arrays
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * SGI
*/
{
.vendor = "SGI",
.product = "TP9[13]00",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "SGI",
.product = "TP9[45]00",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
.vendor = "SGI",
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 15,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
- /* NEC Storage M Series */
+ /*
+ * NEC
+ */
{
+ /* M-Series */
.vendor = "NEC",
.product = "DISK ARRAY",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
/*
- * STK arrays
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * STK/Oracle
*/
{
.vendor = "STK",
.product = "OPENstorage D280",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
+ .checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
/*
- * SUN arrays
- *
- * Maintainer : Christophe Varoqui
- * Mail : christophe.varoqui@opensvc.com
+ * SUN/Oracle
*/
{
.vendor = "SUN",
.product = "(StorEdge 3510|T4)",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DIRECTIO,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "SUN",
.product = "STK6580_6780",
- .features = DEFAULT_FEATURES,
+ .bl_product = "Universal Xport",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = TUR,
+ .checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
.vendor = "EUROLOGC",
.product = "FC2502",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
- .checker_name = DEFAULT_CHECKER,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
/*
- * Pivot3 RAIGE
+ * Pivot3
*
* Maintainer : Bart Brooks, Pivot3
* Mail : bartb@pivot3.com
.vendor = "PIVOT3",
.product = "RAIGE VOLUME",
.features = "1 queue_if_no_path",
- .hwhandler = DEFAULT_HWHANDLER,
.pgpolicy = MULTIBUS,
.pgfailback = FAILBACK_UNDEF,
- .rr_weight = RR_WEIGHT_NONE,
- .no_path_retry = NO_PATH_RETRY_UNDEF,
.minio = 100,
- .checker_name = TUR,
- .prio_name = DEFAULT_PRIO,
- .prio_args = NULL,
},
{
.vendor = "SUN",
.product = "CSM200_R",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
/* SUN/LSI 2510, 2540, 2530, 2540 */
{
.vendor = "SUN",
.product = "LCSM100_[IEFS]",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
/* StorageTek 6180 */
{
.vendor = "SUN",
.product = "SUN_6180",
- .features = DEFAULT_FEATURES,
+ .bl_product = "Universal Xport",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .minio = DEFAULT_MINIO,
- .minio_rq = DEFAULT_MINIO_RQ,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
},
- /* LSI/Engenio/NetApp E-Series RDAC storage
+ /* LSI/Engenio/NetApp RDAC
*
* Maintainer : Sean Stewart
* Mail : sean.stewart@netapp.com
.bl_product = "Universal Xport",
.features = "2 pg_init_retries 50",
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 30,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
- .detect_prio = DETECT_PRIO_ON,
- .retain_hwhandler = RETAIN_HWHANDLER_ON,
},
{
.vendor = "STK",
.product = "FLEXLINE 380",
.bl_product = "Universal Xport",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 rdac",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name = RDAC,
.prio_name = PRIO_RDAC,
- .prio_args = NULL,
},
{
.vendor = "Intel",
.product = "Multi-Flex",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
.vendor = "(LIO-ORG|SUSE)",
.product = "RBD",
- .features = DEFAULT_FEATURES,
.hwhandler = "1 alua",
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = 12,
- .checker_name = TUR,
.minio = 100,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
.vendor = "DataCore",
.product = "SANmelody",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
.vendor = "DataCore",
.product = "Virtual Disk",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
- .pgpolicy = GROUP_BY_PRIO,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .rr_weight = RR_WEIGHT_NONE,
.no_path_retry = NO_PATH_RETRY_QUEUE,
- .checker_name = TUR,
.prio_name = PRIO_ALUA,
- .prio_args = NULL,
},
{
.vendor = "PURE",
.product = "FlashArray",
- .features = DEFAULT_FEATURES,
- .hwhandler = DEFAULT_HWHANDLER,
.selector = "queue-length 0",
.pgpolicy = MULTIBUS,
- .pgfailback = -FAILBACK_IMMEDIATE,
- .checker_name = TUR,
.fast_io_fail = 10,
- .user_friendly_names = USER_FRIENDLY_NAMES_OFF,
- .prio_name = DEFAULT_PRIO,
.no_path_retry = 0,
.dev_loss = 60,
- .prio_args = NULL,
},
+ {
+ .vendor = "HUAWEI",
+ .product = "XSG1",
+ .pgpolicy = MULTIBUS,
+ },
+ /*
+ * Violin Memory
+ */
+ {
+ .vendor = "VIOLIN",
+ .product = "CONCERTO ARRAY",
+ .selector = "round-robin 0",
+ .pgpolicy = MULTIBUS,
+ .prio_name = PRIO_ALUA,
+ .minio = 100,
+ .rr_weight = RR_WEIGHT_PRIO,
+ .features = "1 queue_if_no_path",
+ .no_path_retry = 300,
+ },
+ /*
+ * Infinidat
+ */
+ {
+ .vendor = "NFINIDAT",
+ .product = "InfiniBox.*",
+ .prio_name = PRIO_ALUA,
+ .selector = "round-robin 0",
+ .pgfailback = 30,
+ .rr_weight = RR_WEIGHT_PRIO,
+ .no_path_retry = NO_PATH_RETRY_FAIL,
+ .flush_on_last_del = FLUSH_ENABLED,
+ .dev_loss = 30,
+ },
+ /*
+ * Tegile Systems
+ */
+ {
+ .vendor = "TEGILE",
+ .product = "ZEBI-(FC|ISCSI)|INTELLIFLASH",
+ .hwhandler = "1 alua",
+ .selector = "round-robin 0",
+ .no_path_retry = 10,
+ .dev_loss = 50,
+ .prio_name = PRIO_ALUA,
+ .pgfailback = 30,
+ .minio = 128,
+ },
+#if 0
+ /*
+ * Copy this TEMPLATE to add new hardware.
+ *
+ * Keep only mandatory and modified attributes.
+ * Standard attributes must be removed.
+ *
+ * COMPANY_NAME
+ *
+ * Maintainer : XXX
+ * Mail : XXX
+ */
+ {
+ .vendor = "VENDOR", (Mandatory)
+ .product = "PRODUCT", (Mandatory)
+ .revision = "REVISION",
+ .bl_product = "BL_PRODUCT",
+ .pgpolicy = GROUP_BY_PRIO,
+ .uid_attribute = "ID_SERIAL",
+ .selector = "service-time 0",
+ .checker_name = TUR,
+ .features = "0",
+ .hwhandler = "0",
+ .prio_name = "const",
+ .prio_args = "",
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = 1000,
+ .minio_rq = 1,
+ .flush_on_last_del = FLUSH_DISABLED,
+ .fast_io_fail = 5,
+ .dev_loss = 600,
+ .retain_hwhandler = RETAIN_HWHANDLER_ON,
+ .detect_prio = DETECT_PRIO_ON,
+ .deferred_remove = DEFERRED_REMOVE_OFF,
+ .delay_watch_checks = DELAY_CHECKS_OFF,
+ .delay_wait_checks = DELAY_CHECKS_OFF,
+ },
+#endif
/*
* EOL
*/
} while (0)
/*
- * Insert a new entry between two known consecutive entries.
+ * Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
+ INIT_LIST_HEAD(entry);
}
/**
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* _LIST_H */
{
unlock ((*(struct mutex_lock *)data));
}
-
#include <pthread.h>
#include <sys/mman.h>
-#include <memory.h>
+#include "memory.h"
#include "log_pthread.h"
#include "log.h"
log_close();
}
-
#define MAX_ALLOC_LIST 2048
#define MALLOC(n) ( dbg_malloc((n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
#define FREE(b) ( dbg_free((b), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
#define REALLOC(b,n) ( dbg_realloc((b), (n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
#define STRDUP(n) ( dbg_strdup((n), \
- (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
+ (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
/* Memory debug prototypes defs */
extern void *dbg_malloc(unsigned long, char *, char *, int);
#include <syslog.h>
#include <errno.h>
+#include "vector.h"
+#include "config.h"
#include "parser.h"
#include "memory.h"
#include "debug.h"
/* local vars */
static int sublevel = 0;
-static vector keywords = NULL;
-static vector *keywords_addr = NULL;
static int line_nr;
-void set_current_keywords (vector *k)
-{
- keywords_addr = k;
- keywords = NULL;
-}
-
int
-keyword_alloc(vector keywords, char *string, int (*handler) (vector),
- int (*print) (char *, int, void *), int unique)
+keyword_alloc(vector keywords, char *string,
+ int (*handler) (struct config *, vector),
+ int (*print) (struct config *, char *, int, void *), int unique)
{
struct keyword *keyword;
return 0;
}
-int
-install_keyword_root(char *string, int (*handler) (vector))
-{
- int r = keyword_alloc(keywords, string, handler, NULL, 1);
- if (!r)
- *keywords_addr = keywords;
- return r;
-}
-
void
install_sublevel(void)
{
}
int
-_install_keyword(char *string, int (*handler) (vector),
- int (*print) (char *, int, void *), int unique)
+_install_keyword(vector keywords, char *string,
+ int (*handler) (struct config *, vector),
+ int (*print) (struct config *, char *, int, void *), int unique)
{
int i = 0;
struct keyword *keyword;
}
struct keyword *
-find_keyword(vector v, char * name)
+find_keyword(vector keywords, vector v, char * name)
{
struct keyword *keyword;
int i;
!strcmp(keyword->string, name))
return keyword;
if (keyword->sub) {
- keyword = find_keyword(keyword->sub, name);
+ keyword = find_keyword(keywords, keyword->sub, name);
if (keyword)
return keyword;
}
int r;
int fwd = 0;
char *f = fmt;
+ struct config *conf;
if (!kw || !kw->print)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
break;
case 'v':
- r = kw->print(buff + fwd, len - fwd, data);
+ conf = get_multipath_config();
+ r = kw->print(conf, buff + fwd, len - fwd, data);
+ put_multipath_config(conf);
if (!r) { /* no output if no value */
buff = '\0';
return 0;
}
static int
-process_stream(FILE *stream, vector keywords, char *file)
+process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
{
int i;
int r = 0, t;
goto out;
}
if (keyword->handler) {
- t = (*keyword->handler) (strvec);
+ t = (*keyword->handler) (conf, strvec);
r += t;
if (t)
condlog(1, "multipath.conf +%d, parsing failed: %s",
if (keyword->sub) {
kw_level++;
- r += process_stream(stream,
+ r += process_stream(conf, stream,
keyword->sub, file);
kw_level--;
}
return r;
}
-int alloc_keywords(void)
-{
- if (!keywords)
- keywords = vector_alloc();
-
- if (!keywords)
- return 1;
-
- return 0;
-}
-
/* Data initialization */
int
-process_file(char *file)
+process_file(struct config *conf, char *file)
{
int r;
FILE *stream;
- if (!keywords) {
+ if (!conf->keywords) {
condlog(0, "No keywords alocated");
return 1;
}
/* Stream handling */
line_nr = 0;
- r = process_stream(stream, keywords, file);
+ r = process_stream(conf, stream, conf->keywords, file);
fclose(stream);
//free_keywords(keywords);
-/*
+/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
- *
+ *
* Part: cfreader.c include file.
- *
+ *
* Version: $Id: parser.h,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
/* local includes */
#include "vector.h"
+#include "config.h"
/* Global definitions */
#define EOB "}"
/* ketword definition */
struct keyword {
char *string;
- int (*handler) (vector);
- int (*print) (char *, int, void *);
+ int (*handler) (struct config *, vector);
+ int (*print) (struct config *, char *, int, void *);
vector sub;
int unique;
};
for (i = 0; i < (k)->sub->allocated && ((p) = (k)->sub->slot[i]); i++)
/* Prototypes */
-extern int keyword_alloc(vector keywords, char *string, int (*handler) (vector),
- int (*print) (char *, int, void *), int unique);
-extern int install_keyword_root(char *string, int (*handler) (vector));
+extern int keyword_alloc(vector keywords, char *string,
+ int (*handler) (struct config *, vector),
+ int (*print) (struct config *, char *, int, void *), int unique);
+#define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1)
extern void install_sublevel(void);
extern void install_sublevel_end(void);
-extern int _install_keyword(char *string, int (*handler) (vector),
- int (*print) (char *, int, void *), int unique);
-#define install_keyword(str, vec, pri) _install_keyword(str, vec, pri, 1)
-#define install_keyword_multi(str, vec, pri) _install_keyword(str, vec, pri, 0)
+extern int _install_keyword(vector keywords, char *string,
+ int (*handler) (struct config *, vector),
+ int (*print) (struct config *, char *, int, void *), int unique);
+#define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1)
+#define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0)
extern void dump_keywords(vector keydump, int level);
extern void free_keywords(vector keywords);
extern vector alloc_strvec(char *string);
extern void *set_value(vector strvec);
-extern int alloc_keywords(void);
-extern int process_file(char *conf_file);
-extern struct keyword * find_keyword(vector v, char * name);
-void set_current_keywords (vector *k);
+extern int process_file(struct config *conf, char *conf_file);
+extern struct keyword * find_keyword(vector keywords, vector v, char * name);
int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
void *data);
if (!pgp)
goto out;
- if (store_path(pgp->paths, VECTOR_SLOT(mp->paths, 0)))
- goto out;
+ if (store_path(pgp->paths, VECTOR_SLOT(mp->paths, 0))) {
+ free_pathgroup(pgp, KEEP_PATHS);
+ goto out;
+ }
vector_del_slot(mp->paths, 0);
* Store the new path group into the vector.
*/
if (i < VECTOR_SIZE(mp->pg)) {
- if (!vector_insert_slot(mp->pg, i, pgp))
+ if (!vector_insert_slot(mp->pg, i, pgp)) {
+ free_pathgroup(pgp, KEEP_PATHS);
goto out;
+ }
} else {
- if (store_pathgroup(mp->pg, pgp))
+ if (store_pathgroup(mp->pg, pgp)) {
+ free_pathgroup(pgp, KEEP_PATHS);
goto out;
+ }
}
/*
#define POLICY_NAME_SIZE 32
/* Storage controllers capabilities */
-enum iopolicies {
+enum iopolicies {
IOPOLICY_UNDEF,
FAILOVER,
MULTIBUS,
#include "vector.h"
#include "structs.h"
#include "structs_vec.h"
-#include "print.h"
#include "dmparser.h"
#include "config.h"
#include "configure.h"
#include "pgpolicies.h"
+#include "print.h"
#include "defaults.h"
#include "parser.h"
#include "blacklist.h"
return snprintf(buff, len, "##,##");
}
+
+static int
+snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ vector_foreach_slot(mpp->pg, pgp, i) {
+ if (!pgp)
+ continue;
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (strlen(pp->vendor_id))
+ return snprintf(buff, len, "%s", pp->vendor_id);
+ }
+ }
+ return snprintf(buff, len, "##");
+}
+
+static int
+snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ vector_foreach_slot(mpp->pg, pgp, i) {
+ if (!pgp)
+ continue;
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (strlen(pp->product_id))
+ return snprintf(buff, len, "%s", pp->product_id);
+ }
+ }
+ return snprintf(buff, len, "##");
+}
+
+static int
+snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ vector_foreach_slot(mpp->pg, pgp, i) {
+ if (!pgp)
+ continue;
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (strlen(pp->rev))
+ return snprintf(buff, len, "%s", pp->rev);
+ }
+ }
+ return snprintf(buff, len, "##");
+}
+
static int
snprint_action (char * buff, size_t len, struct multipath * mpp)
{
if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
return snprintf(buff, len, "[undef]");
sprintf(host_id, "host%d", pp->sg_id.host_no);
- host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host",
+ host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
host_id);
if (!host_dev) {
condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
return snprintf(buff, len, "[undef]");
sprintf(rport_id, "rport-%d:%d-%d",
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
- rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+ rport_dev = udev_device_new_from_subsystem_sysname(udev,
"fc_remote_ports", rport_id);
if (!rport_dev) {
condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
{'3', "total_q_time", 0, snprint_total_q_time},
{'4', "q_timeouts", 0, snprint_q_timeouts},
{'s', "vend/prod/rev", 0, snprint_multipath_vpr},
+ {'v', "vend", 0, snprint_multipath_vend},
+ {'p', "prod", 0, snprint_multipath_prod},
+ {'e', "rev", 0, snprint_multipath_rev},
{0, NULL, 0 , NULL}
};
int fwd;
struct multipath_data * data;
- memset(line, 0, len);
-
do {
if (!TAIL)
break;
struct multipath_data * data;
char buff[MAX_FIELD_LEN] = {};
- memset(line, 0, len);
-
do {
if (!TAIL)
break;
int fwd;
struct path_data * data;
- memset(line, 0, len);
-
do {
if (!TAIL)
break;
struct path_data * data;
char buff[MAX_FIELD_LEN];
- memset(line, 0, len);
-
do {
if (!TAIL)
break;
struct pathgroup_data * data;
char buff[MAX_FIELD_LEN];
- memset(line, 0, len);
-
do {
if (!TAIL)
break;
}
static int
-snprint_hwentry (char * buff, int len, struct hwentry * hwe)
+snprint_json (char * buff, int len, int indent, char *json_str)
+{
+ int fwd = 0, i;
+
+ for (i = 0; i < indent; i++) {
+ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
+ if (fwd > len)
+ return fwd;
+ }
+
+ fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
+ return fwd;
+}
+
+static int
+snprint_json_header (char * buff, int len)
+{
+ int fwd = 0;
+
+ fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION,
+ PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
+ return fwd;
+}
+
+static int
+snprint_json_elem_footer (char * buff, int len, int indent, int last)
+{
+ int fwd = 0, i;
+
+ for (i = 0; i < indent; i++) {
+ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
+ if (fwd > len)
+ return fwd;
+ }
+
+ if (last == 1)
+ fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
+ else
+ fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
+ return fwd;
+}
+
+static int
+snprint_multipath_fields_json (char * buff, int len,
+ struct multipath * mpp, int last)
+{
+ int i, j, fwd = 0;
+ struct path *pp;
+ struct pathgroup *pgp;
+
+ fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
+ if (fwd > len)
+ return fwd;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+
+ pgp->selector = mpp->selector;
+ fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
+ if (fwd > len)
+ return fwd;
+
+ vector_foreach_slot (pgp->paths, pp, j) {
+ fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprint_json_elem_footer(buff + fwd,
+ len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
+ if (fwd > len)
+ return fwd;
+ }
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprint_json_elem_footer(buff + fwd,
+ len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
+ if (fwd > len)
+ return fwd;
+ }
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
+ if (fwd > len)
+ return fwd;
+
+ fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
+ return fwd;
+}
+
+int
+snprint_multipath_map_json (char * buff, int len,
+ struct multipath * mpp, int last){
+ int fwd = 0;
+
+ fwd += snprint_json_header(buff, len);
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, "\n");
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+int
+snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)
+{
+ int i, fwd = 0;
+ struct multipath * mpp;
+
+ fwd += snprint_json_header(buff, len);
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS);
+ if (fwd > len)
+ return len;
+
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
+ mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
+ if (fwd > len)
+ return len;
+ }
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
+ if (fwd > len)
+ return len;
+
+ fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+static int
+snprint_hwentry (struct config *conf, char * buff, int len, struct hwentry * hwe)
{
int i;
int fwd = 0;
struct keyword * kw;
struct keyword * rootkw;
- rootkw = find_keyword(NULL, "devices");
+ rootkw = find_keyword(conf->keywords, NULL, "devices");
if (!rootkw || !rootkw->sub)
return 0;
- rootkw = find_keyword(rootkw->sub, "device");
+ rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
if (!rootkw)
return 0;
}
extern int
-snprint_hwtable (char * buff, int len, vector hwtable)
+snprint_hwtable (struct config *conf, char * buff, int len, vector hwtable)
{
int fwd = 0;
int i;
struct hwentry * hwe;
struct keyword * rootkw;
- rootkw = find_keyword(NULL, "devices");
+ rootkw = find_keyword(conf->keywords, NULL, "devices");
if (!rootkw)
return 0;
if (fwd > len)
return len;
vector_foreach_slot (hwtable, hwe, i) {
- fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
+ fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
if (fwd > len)
return len;
}
}
static int
-snprint_mpentry (char * buff, int len, struct mpentry * mpe)
+snprint_mpentry (struct config *conf, char * buff, int len, struct mpentry * mpe)
{
int i;
int fwd = 0;
struct keyword * kw;
struct keyword * rootkw;
- rootkw = find_keyword(NULL, "multipath");
+ rootkw = find_keyword(conf->keywords, NULL, "multipath");
if (!rootkw)
return 0;
}
extern int
-snprint_mptable (char * buff, int len, vector mptable)
+snprint_mptable (struct config *conf, char * buff, int len, vector mptable)
{
int fwd = 0;
int i;
struct mpentry * mpe;
struct keyword * rootkw;
- rootkw = find_keyword(NULL, "multipaths");
+ rootkw = find_keyword(conf->keywords, NULL, "multipaths");
if (!rootkw)
return 0;
if (fwd > len)
return len;
vector_foreach_slot (mptable, mpe, i) {
- fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
+ fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe);
if (fwd > len)
return len;
}
}
extern int
-snprint_overrides (char * buff, int len, struct hwentry *overrides)
+snprint_overrides (struct config *conf, char * buff, int len, struct hwentry *overrides)
{
int fwd = 0;
int i;
struct keyword *rootkw;
struct keyword *kw;
- rootkw = find_keyword(NULL, "overrides");
+ rootkw = find_keyword(conf->keywords, NULL, "overrides");
if (!rootkw)
return 0;
}
extern int
-snprint_defaults (char * buff, int len)
+snprint_defaults (struct config *conf, char * buff, int len)
{
int fwd = 0;
int i;
struct keyword *rootkw;
struct keyword *kw;
- rootkw = find_keyword(NULL, "defaults");
+ rootkw = find_keyword(conf->keywords, NULL, "defaults");
if (!rootkw)
return 0;
}
extern int
-snprint_blacklist_report (char * buff, int len)
+snprint_blacklist_report (struct config *conf, char * buff, int len)
{
int threshold = MAX_LINE_LEN;
int fwd = 0;
}
extern int
-snprint_blacklist (char * buff, int len)
+snprint_blacklist (struct config *conf, char * buff, int len)
{
int i;
struct blentry * ble;
struct keyword *rootkw;
struct keyword *kw;
- rootkw = find_keyword(NULL, "blacklist");
+ rootkw = find_keyword(conf->keywords, NULL, "blacklist");
if (!rootkw)
return 0;
return len;
vector_foreach_slot (conf->blist_devnode, ble, i) {
- kw = find_keyword(rootkw->sub, "devnode");
+ kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
return len;
}
vector_foreach_slot (conf->blist_wwid, ble, i) {
- kw = find_keyword(rootkw->sub, "wwid");
+ kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
return len;
}
vector_foreach_slot (conf->blist_property, ble, i) {
- kw = find_keyword(rootkw->sub, "property");
+ kw = find_keyword(conf->keywords, rootkw->sub, "property");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
if (fwd > len)
return len;
}
- rootkw = find_keyword(rootkw->sub, "device");
+ rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
if (!rootkw)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
if (fwd > len)
return len;
- kw = find_keyword(rootkw->sub, "vendor");
+ kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, bled);
if (fwd > len)
return len;
- kw = find_keyword(rootkw->sub, "product");
+ kw = find_keyword(conf->keywords, rootkw->sub, "product");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
}
extern int
-snprint_blacklist_except (char * buff, int len)
+snprint_blacklist_except (struct config *conf, char * buff, int len)
{
int i;
struct blentry * ele;
struct keyword *rootkw;
struct keyword *kw;
- rootkw = find_keyword(NULL, "blacklist_exceptions");
+ rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
if (!rootkw)
return 0;
return len;
vector_foreach_slot (conf->elist_devnode, ele, i) {
- kw = find_keyword(rootkw->sub, "devnode");
+ kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
return len;
}
vector_foreach_slot (conf->elist_wwid, ele, i) {
- kw = find_keyword(rootkw->sub, "wwid");
+ kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
return len;
}
vector_foreach_slot (conf->elist_property, ele, i) {
- kw = find_keyword(rootkw->sub, "property");
+ kw = find_keyword(conf->keywords, rootkw->sub, "property");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
if (fwd > len)
return len;
}
- rootkw = find_keyword(rootkw->sub, "device");
+ rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
if (!rootkw)
return 0;
fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
if (fwd > len)
return len;
- kw = find_keyword(rootkw->sub, "vendor");
+ kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
kw, eled);
if (fwd > len)
return len;
- kw = find_keyword(rootkw->sub, "product");
+ kw = find_keyword(conf->keywords, rootkw->sub, "product");
if (!kw)
return 0;
fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
checker_state_name(i), count[i]);
}
- int monitored_count = 0;
+ int monitored_count = 0;
- vector_foreach_slot(vecs->pathvec, pp, i)
- if (pp->fd != -1)
- monitored_count++;
- fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
+ vector_foreach_slot(vecs->pathvec, pp, i)
+ if (pp->fd != -1)
+ monitored_count++;
+ fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
monitored_count, is_uevent_busy()? "True" : "False");
if (fwd > len)
}
extern int
-snprint_devices (char * buff, int len, struct vectors *vecs)
+snprint_devices (struct config *conf, char * buff, int len, struct vectors *vecs)
{
DIR *blkdir;
struct dirent *blkdev;
vector_foreach_slot (pathvec, pp, i)
print_path(pp, fmt);
}
-
#define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r"
#define PRINT_PG_INDENT "policy='%s' prio=%p status=%t"
+#define PRINT_JSON_MULTIPLIER 5
+#define PRINT_JSON_MAJOR_VERSION 0
+#define PRINT_JSON_MINOR_VERSION 1
+#define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \
+ " \"minor_version\": %d,\n"
+#define PRINT_JSON_START_ELEM "{\n"
+#define PRINT_JSON_START_MAP " \"map\":"
+#define PRINT_JSON_START_MAPS "\"maps\": ["
+#define PRINT_JSON_START_PATHS "\"paths\": ["
+#define PRINT_JSON_START_GROUPS "\"path_groups\": ["
+#define PRINT_JSON_END_ELEM "},"
+#define PRINT_JSON_END_LAST_ELEM "}"
+#define PRINT_JSON_END_LAST "}\n"
+#define PRINT_JSON_END_ARRAY "]\n"
+#define PRINT_JSON_INDENT " "
+#define PRINT_JSON_MAP "{\n" \
+ " \"name\" : \"%n\",\n" \
+ " \"uuid\" : \"%w\",\n" \
+ " \"sysfs\" : \"%d\",\n" \
+ " \"failback\" : \"%F\",\n" \
+ " \"queueing\" : \"%Q\",\n" \
+ " \"paths\" : %N,\n" \
+ " \"write_prot\" : \"%r\",\n" \
+ " \"dm_st\" : \"%t\",\n" \
+ " \"features\" : \"%f\",\n" \
+ " \"hwhandler\" : \"%h\",\n" \
+ " \"action\" : \"%A\",\n" \
+ " \"path_faults\" : %0,\n" \
+ " \"vend\" : \"%v\",\n" \
+ " \"prod\" : \"%p\",\n" \
+ " \"rev\" : \"%e\",\n" \
+ " \"switch_grp\" : %1,\n" \
+ " \"map_loads\" : %2,\n" \
+ " \"total_q_time\" : %3,\n" \
+ " \"q_timeouts\" : %4,"
+
+#define PRINT_JSON_GROUP "{\n" \
+ " \"selector\" : \"%s\",\n" \
+ " \"pri\" : %p,\n" \
+ " \"dm_st\" : \"%t\","
+
+#define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n"
+
+#define PRINT_JSON_PATH "{\n" \
+ " \"dev\" : \"%d\",\n"\
+ " \"dev_t\" : \"%D\",\n" \
+ " \"dm_st\" : \"%t\",\n" \
+ " \"dev_st\" : \"%o\",\n" \
+ " \"chk_st\" : \"%T\",\n" \
+ " \"checker\" : \"%c\",\n" \
+ " \"pri\" : %p,\n" \
+ " \"host_wwnn\" : \"%N\",\n" \
+ " \"target_wwnn\" : \"%n\",\n" \
+ " \"host_wwpn\" : \"%R\",\n" \
+ " \"target_wwpn\" : \"%r\",\n" \
+ " \"host_adapter\" : \"%a\""
+
#define MAX_LINE_LEN 80
#define MAX_LINES 64
#define MAX_FIELD_LEN 64
int snprint_multipath (char *, int, char *, struct multipath *, int);
int snprint_multipath_topology (char *, int, struct multipath * mpp,
int verbosity);
-int snprint_defaults (char *, int);
-int snprint_blacklist (char *, int);
-int snprint_blacklist_except (char *, int);
-int snprint_blacklist_report (char *, int);
+int snprint_multipath_topology_json (char * buff, int len,
+ struct vectors * vecs);
+int snprint_multipath_map_json (char * buff, int len,
+ struct multipath * mpp, int last);
+int snprint_defaults (struct config *, char *, int);
+int snprint_blacklist (struct config *, char *, int);
+int snprint_blacklist_except (struct config *, char *, int);
+int snprint_blacklist_report (struct config *, char *, int);
int snprint_wildcards (char *, int);
int snprint_status (char *, int, struct vectors *);
-int snprint_devices (char *, int, struct vectors *);
-int snprint_hwtable (char *, int, vector);
-int snprint_mptable (char *, int, vector);
-int snprint_overrides (char *, int, struct hwentry *);
+int snprint_devices (struct config *, char *, int, struct vectors *);
+int snprint_hwtable (struct config *, char *, int, vector);
+int snprint_mptable (struct config *, char *, int, vector);
+int snprint_overrides (struct config *, char *, int, struct hwentry *);
int snprint_host_wwnn (char *, size_t, struct path *);
int snprint_host_wwpn (char *, size_t, struct path *);
int snprint_tgt_wwnn (char *, size_t, struct path *);
void print_all_paths (vector pathvec, int banner);
void print_all_paths_custo (vector pathvec, int banner, char *fmt);
void print_hwtable (vector hwtable);
-
#include "debug.h"
#include "prio.h"
-#include "config.h"
static LIST_HEAD(prioritizers);
-unsigned int get_prio_timeout(unsigned int default_timeout)
+unsigned int get_prio_timeout(unsigned int checker_timeout,
+ unsigned int default_timeout)
{
- if (conf->checker_timeout)
- return conf->checker_timeout * 1000;
+ if (checker_timeout)
+ return checker_timeout * 1000;
return default_timeout;
}
-int init_prio (void)
+int init_prio (char *multipath_dir)
{
- if (!add_prio(DEFAULT_PRIO))
+ if (!add_prio(multipath_dir, DEFAULT_PRIO))
return 1;
return 0;
}
}
}
-struct prio * prio_lookup (char * name)
+static struct prio * prio_lookup (char * name)
{
struct prio * p;
if (!strncmp(name, p->name, PRIO_NAME_LEN))
return p;
}
- return add_prio(name);
+ return NULL;
}
int prio_set_args (struct prio * p, char * args)
return snprintf(p->args, PRIO_ARGS_LEN, "%s", args);
}
-struct prio * add_prio (char * name)
+struct prio * add_prio (char *multipath_dir, char * name)
{
char libname[LIB_PRIO_NAMELEN];
struct stat stbuf;
return NULL;
snprintf(p->name, PRIO_NAME_LEN, "%s", name);
snprintf(libname, LIB_PRIO_NAMELEN, "%s/libprio%s.so",
- conf->multipath_dir, name);
+ multipath_dir, name);
if (stat(libname,&stbuf) < 0) {
condlog(0,"Prioritizer '%s' not found in %s",
- name, conf->multipath_dir);
+ name, multipath_dir);
goto out;
}
condlog(3, "loading %s prioritizer", libname);
errstr);
goto out;
}
- p->getprio = (int (*)(struct path *, char *)) dlsym(p->handle, "getprio");
+ p->getprio = (int (*)(struct path *, char *, unsigned int)) dlsym(p->handle, "getprio");
errstr = dlerror();
if (errstr != NULL)
condlog(0, "A dynamic linking error occurred: (%s)", errstr);
return NULL;
}
-int prio_getprio (struct prio * p, struct path * pp)
+int prio_getprio (struct prio * p, struct path * pp, unsigned int timeout)
{
- return p->getprio(pp, p->args);
+ return p->getprio(pp, p->args, timeout);
}
int prio_selected (struct prio * p)
return p->args;
}
-void prio_get (struct prio * dst, char * name, char * args)
+void prio_get (char *multipath_dir, struct prio * dst, char * name, char * args)
{
- struct prio * src = prio_lookup(name);
+ struct prio * src = NULL;
+
+ if (!dst)
+ return;
+ if (name && strlen(name)) {
+ src = prio_lookup(name);
+ if (!src)
+ src = add_prio(multipath_dir, name);
+ }
if (!src) {
dst->getprio = NULL;
return;
strncpy(dst->name, src->name, PRIO_NAME_LEN);
if (args)
- strncpy(dst->args, args, PRIO_ARGS_LEN);
+ strncpy(dst->args, args, PRIO_ARGS_LEN - 1);
dst->getprio = src->getprio;
dst->handle = NULL;
/*
* Known prioritizers for use in hwtable.c
*/
-#define PRIO_ALUA "alua"
-#define PRIO_CONST "const"
-#define PRIO_EMC "emc"
-#define PRIO_HDS "hds"
-#define PRIO_HP_SW "hp_sw"
-#define PRIO_ONTAP "ontap"
-#define PRIO_RANDOM "random"
-#define PRIO_RDAC "rdac"
-#define PRIO_DATACORE "datacore"
-#define PRIO_WEIGHTED_PATH "weightedpath"
+#define PRIO_ALUA "alua"
+#define PRIO_CONST "const"
+#define PRIO_DATACORE "datacore"
+#define PRIO_EMC "emc"
+#define PRIO_HDS "hds"
+#define PRIO_HP_SW "hp_sw"
+#define PRIO_IET "iet"
+#define PRIO_ONTAP "ontap"
+#define PRIO_RANDOM "random"
+#define PRIO_RDAC "rdac"
+#define PRIO_WEIGHTED_PATH "weightedpath"
+#define PRIO_SYSFS "sysfs"
/*
* Value used to mark the fact prio was not defined
struct list_head node;
char name[PRIO_NAME_LEN];
char args[PRIO_ARGS_LEN];
- int (*getprio)(struct path *, char *);
+ int (*getprio)(struct path *, char *, unsigned int);
};
-unsigned int get_prio_timeout(unsigned int default_timeout);
-int init_prio (void);
+unsigned int get_prio_timeout(unsigned int checker_timeout,
+ unsigned int default_timeout);
+int init_prio (char *);
void cleanup_prio (void);
-struct prio * add_prio (char *);
-struct prio * prio_lookup (char *);
-int prio_getprio (struct prio *, struct path *);
-void prio_get (struct prio *, char *, char *);
+struct prio * add_prio (char *, char *);
+int prio_getprio (struct prio *, struct path *, unsigned int);
+void prio_get (char *, struct prio *, char *, char *);
void prio_put (struct prio *);
int prio_selected (struct prio *);
char * prio_name (struct prio *);
include ../../Makefile.inc
LIBS = \
- libpriorandom.so \
- libprioconst.so \
- libpriohp_sw.so \
- libprioemc.so \
- libpriordac.so \
libprioalua.so \
- libprioontap.so \
+ libprioconst.so \
libpriodatacore.so \
+ libprioemc.so \
libpriohds.so \
+ libpriohp_sw.so \
+ libprioiet.so \
+ libprioontap.so \
+ libpriorandom.so \
+ libpriordac.so \
libprioweightedpath.so \
- libprioiet.so
+ libpriosysfs.so
CFLAGS += -I..
$(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir)
uninstall:
- for file in $(LIBS); do rm -f $(DESTDIR)$(libdir)/$$file; done
+ for file in $(LIBS); do $(RM) $(DESTDIR)$(libdir)/$$file; done
clean:
- rm -f core *.a *.o *.gz *.so
+ $(RM) core *.a *.o *.gz *.so
*
* Author(s): Jan Kunigk
* S. Bader <shbader@de.ibm.com>
- *
+ *
* This file is released under the GPL.
*/
#include <stdio.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#include "alua.h"
}
int
-get_alua_info(struct path * pp)
+get_alua_info(struct path * pp, unsigned int timeout)
{
int rc;
int tpg;
- tpg = get_target_port_group(pp);
+ tpg = get_target_port_group(pp, timeout);
if (tpg < 0) {
- rc = get_target_port_group_support(pp->fd);
+ rc = get_target_port_group_support(pp->fd, timeout);
if (rc < 0)
return -ALUA_PRIO_TPGS_FAILED;
if (rc == TPGS_NONE)
return -ALUA_PRIO_RTPG_FAILED;
}
condlog(3, "reported target port group is %i", tpg);
- rc = get_asymmetric_access_state(pp->fd, tpg);
+ rc = get_asymmetric_access_state(pp->fd, tpg, timeout);
if (rc < 0)
return -ALUA_PRIO_GETAAS_FAILED;
return rc;
}
-int get_exclusive_perf_arg(char *args)
+int get_exclusive_pref_arg(char *args)
{
char *ptr;
return 1;
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
int rc;
int aas;
int priopath;
- int exclusive_perf;
+ int exclusive_pref;
if (pp->fd < 0)
return -ALUA_PRIO_NO_INFORMATION;
- exclusive_perf = get_exclusive_perf_arg(args);
- rc = get_alua_info(pp);
+ exclusive_pref = get_exclusive_pref_arg(args);
+ rc = get_alua_info(pp, timeout);
if (rc >= 0) {
aas = (rc & 0x0f);
priopath = (rc & 0x80);
default:
rc = 0;
}
- if (priopath && (aas != AAS_OPTIMIZED || exclusive_perf))
+ if (priopath && (aas != AAS_OPTIMIZED || exclusive_pref))
rc += 80;
} else {
switch(-rc) {
*
* Author(s): Jan Kunigk
* S. Bader <shbader@de.ibm.com>
- *
+ *
* This file is released under the GPL.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <libudev.h>
* Helper function to setup and run a SCSI inquiry command.
*/
int
-do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
+do_inquiry(int fd, int evpd, unsigned int codepage,
+ void *resp, int resplen, unsigned int timeout)
{
struct inquiry_command cmd;
struct sg_io_hdr hdr;
hdr.dxfer_len = resplen;
hdr.sbp = sense;
hdr.mx_sb_len = sizeof(sense);
- hdr.timeout = get_prio_timeout(SGIO_TIMEOUT);
+ hdr.timeout = get_prio_timeout(timeout, SGIO_TIMEOUT);
if (ioctl(fd, SG_IO, &hdr) < 0) {
PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
* data returned by the standard inquiry command.
*/
int
-get_target_port_group_support(int fd)
+get_target_port_group_support(int fd, unsigned int timeout)
{
struct inquiry_data inq;
int rc;
memset((unsigned char *)&inq, 0, sizeof(inq));
- rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
+ rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq), timeout);
if (!rc) {
rc = inquiry_data_get_tpgs(&inq);
}
}
int
-get_target_port_group(struct path * pp)
+get_target_port_group(struct path * pp, unsigned int timeout)
{
unsigned char *buf;
struct vpd83_data * vpd83;
rc = get_sysfs_pg83(pp, buf, buflen);
if (rc < 0) {
- rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen);
+ rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen, timeout);
if (rc < 0)
goto out;
scsi_buflen = (buf[2] << 8 | buf[3]) + 4;
+ /* Paranoia */
+ if (scsi_buflen >= USHRT_MAX)
+ scsi_buflen = USHRT_MAX;
if (buflen < scsi_buflen) {
free(buf);
buf = (unsigned char *)malloc(scsi_buflen);
}
buflen = scsi_buflen;
memset(buf, 0, buflen);
- rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen);
+ rc = do_inquiry(pp->fd, 1, 0x83, buf, buflen, timeout);
if (rc < 0)
goto out;
}
}
int
-do_rtpg(int fd, void* resp, long resplen)
+do_rtpg(int fd, void* resp, long resplen, unsigned int timeout)
{
struct rtpg_command cmd;
struct sg_io_hdr hdr;
hdr.dxfer_len = resplen;
hdr.mx_sb_len = sizeof(sense);
hdr.sbp = sense;
- hdr.timeout = get_prio_timeout(SGIO_TIMEOUT);
+ hdr.timeout = get_prio_timeout(timeout, SGIO_TIMEOUT);
if (ioctl(fd, SG_IO, &hdr) < 0)
return -RTPG_RTPG_FAILED;
}
int
-get_asymmetric_access_state(int fd, unsigned int tpg)
+get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout)
{
unsigned char *buf;
struct rtpg_data * tpgd;
struct rtpg_tpg_dscr * dscr;
int rc;
int buflen;
- uint32_t scsi_buflen;
+ uint64_t scsi_buflen;
buflen = 4096;
buf = (unsigned char *)malloc(buflen);
return -RTPG_RTPG_FAILED;
}
memset(buf, 0, buflen);
- rc = do_rtpg(fd, buf, buflen);
+ rc = do_rtpg(fd, buf, buflen, timeout);
if (rc < 0)
goto out;
scsi_buflen = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) + 4;
+ if (scsi_buflen > UINT_MAX)
+ scsi_buflen = UINT_MAX;
if (buflen < scsi_buflen) {
free(buf);
buf = (unsigned char *)malloc(scsi_buflen);
}
buflen = scsi_buflen;
memset(buf, 0, buflen);
- rc = do_rtpg(fd, buf, buflen);
+ rc = do_rtpg(fd, buf, buflen, timeout);
if (rc < 0)
goto out;
}
free(buf);
return rc;
}
-
*
* Author(s): Jan Kunigk
* S. Bader <shbader@de.ibm.com>
- *
+ *
* This file is released under the GPL.
*/
#ifndef __RTPG_H__
#define RTPG_RTPG_FAILED 3
#define RTPG_TPG_NOT_FOUND 4
-int get_target_port_group_support(int fd);
-int get_target_port_group(struct path * pp);
-int get_asymmetric_access_state(int fd, unsigned int tpg);
+int get_target_port_group_support(int fd, unsigned int timeout);
+int get_target_port_group(struct path * pp, unsigned int timeout);
+int get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout);
#endif /* __RTPG_H__ */
-
*
* Author(s): Jan Kunigk
* S. Bader <shbader@de.ibm.com>
- *
+ *
* This file is released under the GPL.
*/
#ifndef __SPC3_H__
)
#endif /* __SPC3_H__ */
-
#include <stdio.h>
-#include <prio.h>
+#include "prio.h"
int getprio (struct path * pp, char * args)
{
#include <sys/ioctl.h>
#include <sys/stat.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define INQ_REPLY_LEN 255
#define INQ_CMD_CODE 0x12
unsigned char sense_buffer[32];
sg_io_hdr_t io_hdr;
- int timeout = 2000;
+ int timeout = 2000;
char preferredsds_buff[255] = "";
char * preferredsds = &preferredsds_buff[0];
}
if (sscanf(args, "timeout=%i preferredsds=%s",
- &timeout, preferredsds) == 2) {}
+ &timeout, preferredsds) == 2) {}
else if (sscanf(args, "preferredsds=%s timeout=%i",
preferredsds, &timeout) == 2) {}
else if (sscanf(args, "preferredsds=%s",
int getprio (struct path * pp, char * args)
{
- return datacore_prio(pp->dev, pp->fd, args);
+ return datacore_prio(pp->dev, pp->fd, args);
}
-
#include <string.h>
#include <sys/ioctl.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
#define pp_emc_log(prio, msg) condlog(prio, "%s: emc prio: " msg, dev)
-int emc_clariion_prio(const char *dev, int fd)
+int emc_clariion_prio(const char *dev, int fd, unsigned int timeout)
{
unsigned char sense_buffer[128];
unsigned char sb[128];
io_hdr.dxferp = sense_buffer;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sb;
- io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.timeout = get_prio_timeout(timeout, 60000);
io_hdr.pack_id = 0;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
pp_emc_log(0, "sending query command failed");
return(ret);
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
- return emc_clariion_prio(pp->dev, pp->fd);
+ return emc_clariion_prio(pp->dev, pp->fd, timeout);
}
*
* Prioritizer for Device Mapper Multipath and HDS Storage
*
- * Hitachis Modular Storage contains two controllers for redundancy. The
- * Storage internal LUN (LDEV) will normally allocated via two pathes to the
- * server (one path per controller). For performance reasons should the server
+ * Hitachis Modular Storage contains two controllers for redundancy. The
+ * Storage internal LUN (LDEV) will normally allocated via two pathes to the
+ * server (one path per controller). For performance reasons should the server
* access to a LDEV only via one controller. The other path to the other
- * controller is stand-by. It is also possible to allocate more as one path
- * for a LDEV per controller. Here is active/active access allowed. The other
+ * controller is stand-by. It is also possible to allocate more as one path
+ * for a LDEV per controller. Here is active/active access allowed. The other
* pathes via the other controller are stand-by.
*
- * This prioritizer checks with inquiry command the represented LDEV and
+ * This prioritizer checks with inquiry command the represented LDEV and
* Controller number and gives back a priority followed by this scheme:
*
* CONTROLLER ODD and LDEV ODD: PRIORITY 1
* CONTROLLER EVEN and LDEV ODD: PRIORITY 0
* CONTROLLER EVEN and LDEV EVEN: PRIORITY 1
*
- * In the storage you can define for each LDEV a owner controller. If the
- * server makes IOs via the other controller the storage will switch the
- * ownership automatically. In this case you can see in the storage that the
+ * In the storage you can define for each LDEV a owner controller. If the
+ * server makes IOs via the other controller the storage will switch the
+ * ownership automatically. In this case you can see in the storage that the
* current controller is different from the default controller, but this is
* absolutely no problem.
*
- * With this prioritizer it is possible to establish a static load balancing.
- * Half of the LUNs are accessed via one HBA/storage controller and the other
+ * With this prioritizer it is possible to establish a static load balancing.
+ * Half of the LUNs are accessed via one HBA/storage controller and the other
* half via the other HBA/storage controller.
*
* In cluster environmemnts (RAC) it also guarantees that all cluster nodes have
* access to the LDEVs via the same controller.
- *
+ *
* You can run the prioritizer manually in verbose mode:
* # pp_hds_modular -v 8:224
* VENDOR: HITACHI
* Changes 2006-07-16:
* - Changed to forward declaration of functions
* - The switch-statement was changed to a logical expression
- * - unlinking of the devpath now also occurs at the end of
+ * - unlinking of the devpath now also occurs at the end of
* hds_modular_prio to avoid old /tmp/.pp_balance.%u.%u.devnode
* entries in /tmp-Directory
* - The for-statements for passing variables where changed to
#include <sys/ioctl.h>
#include <stdlib.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define INQ_REPLY_LEN 255
#define INQ_CMD_CODE 0x12
#define INQ_CMD_LEN 6
#define pp_hds_log(prio, fmt, args...) \
- condlog(prio, "%s: hds prio: " fmt, dev, ##args)
+ condlog(prio, "%s: hds prio: " fmt, dev, ##args)
-int hds_modular_prio (const char *dev, int fd)
+int hds_modular_prio (const char *dev, int fd, unsigned int timeout)
{
int k;
char vendor[9];
io_hdr.dxferp = inqBuff;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_buffer;
- io_hdr.timeout = get_prio_timeout(2000); /* TimeOut = 2 seconds */
+ io_hdr.timeout = get_prio_timeout(timeout, 2000); /* TimeOut = 2 seconds */
if (ioctl (fd, SG_IO, &io_hdr) < 0) {
pp_hds_log(0, "SG_IO error");
return 0;
break;
}
+ break;
case '1': case '3': case '5': case '7': case '9':
switch (ldev[3]) {
case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E':
return 1;
break;
}
+ break;
}
return -1;
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
- return hds_modular_prio(pp->dev, pp->fd);
+ return hds_modular_prio(pp->dev, pp->fd, timeout);
}
#include <sys/ioctl.h>
#include <errno.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define TUR_CMD_LEN 6
#define SCSI_CHECK_CONDITION 0x2
#define HP_PATH_FAILED 0x00
#define pp_hp_sw_log(prio, fmt, args...) \
- condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
+ condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
-int hp_sw_prio(const char *dev, int fd)
+int hp_sw_prio(const char *dev, int fd, unsigned int timeout)
{
- unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
unsigned char sb[128];
struct sg_io_hdr io_hdr;
int ret = HP_PATH_FAILED;
io_hdr.dxfer_direction = SG_DXFER_NONE;
io_hdr.cmdp = turCmdBlk;
io_hdr.sbp = sb;
- io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.timeout = get_prio_timeout(timeout, 60000);
io_hdr.pack_id = 0;
retry:
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
pp_hp_sw_log(0, "sending tur command failed");
goto out;
}
- io_hdr.status &= 0x7e;
- if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status)) {
+ io_hdr.status &= 0x7e;
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status)) {
/* Command completed normally, path is active */
- ret = HP_PATH_ACTIVE;
+ ret = HP_PATH_ACTIVE;
}
- if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
- (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
- (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
- if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
- int sense_key, asc, asq;
- unsigned char * sense_buffer = io_hdr.sbp;
- if (sense_buffer[0] & 0x2) {
- sense_key = sense_buffer[1] & 0xf;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key, asc, asq;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2) {
+ sense_key = sense_buffer[1] & 0xf;
asc = sense_buffer[2];
asq = sense_buffer[3];
} else {
- sense_key = sense_buffer[2] & 0xf;
+ sense_key = sense_buffer[2] & 0xf;
asc = sense_buffer[12];
asq = sense_buffer[13];
}
- if(RECOVERED_ERROR == sense_key)
- ret = HP_PATH_ACTIVE;
+ if(RECOVERED_ERROR == sense_key)
+ ret = HP_PATH_ACTIVE;
if(NOT_READY == sense_key) {
if (asc == 0x04 && asq == 0x02) {
/* This is a standby path */
goto retry;
}
}
- }
- }
+ }
+ }
out:
return(ret);
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
- return hp_sw_prio(pp->dev, pp->fd);
+ return hp_sw_prio(pp->dev, pp->fd, timeout);
}
#include <stdio.h>
#include <string.h>
#include <regex.h>
-#include <prio.h>
-#include <debug.h>
+#include "prio.h"
+#include "debug.h"
#include <unistd.h>
-#include <structs.h>
+#include "structs.h"
//
// This prioritizer suits iSCSI needs, makes it possible to prefer one path.
// (It's a bit of a misnomer since supports the client side [eg. open-iscsi]
// instead of just "iet".)
//
-// Usage:
+// Usage:
// prio "iet"
// prio_args "preferredip=10.11.12.13"
//
if (result) {
strncpy(result, &string[start], size);
result[size] = '\0';
+ free(pmatch);
return result;
}
}
- else return NULL;
+ free(pmatch);
}
}
return NULL;
#include <errno.h>
#include <assert.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
#define SG_TIMEOUT 60000
#define pp_ontap_log(prio, fmt, args...) \
- condlog(prio, "%s: ontap prio: " fmt, dev, ##args)
+ condlog(prio, "%s: ontap prio: " fmt, dev, ##args)
static void dump_cdb(unsigned char *cdb, int size)
{
* 0: success
*/
static int send_gva(const char *dev, int fd, unsigned char pg,
- unsigned char *results, int *results_size)
+ unsigned char *results, int *results_size,
+ unsigned int timeout)
{
unsigned char sb[128];
unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
io_hdr.dxferp = results;
io_hdr.cmdp = cdb;
io_hdr.sbp = sb;
- io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
+ io_hdr.timeout = get_prio_timeout(timeout, SG_TIMEOUT);
io_hdr.pack_id = 0;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
pp_ontap_log(0, "SG_IO ioctl failed, errno=%d", errno);
* 0: Device _not_ proxy path
* 1: Device _is_ proxy path
*/
-static int get_proxy(const char *dev, int fd)
+static int get_proxy(const char *dev, int fd, unsigned int timeout)
{
unsigned char results[256];
unsigned char sb[128];
io_hdr.dxferp = results;
io_hdr.cmdp = cdb;
io_hdr.sbp = sb;
- io_hdr.timeout = get_prio_timeout(SG_TIMEOUT);
+ io_hdr.timeout = get_prio_timeout(timeout, SG_TIMEOUT);
io_hdr.pack_id = 0;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
pp_ontap_log(0, "ioctl sending inquiry command failed, "
* 2: iSCSI software
* 1: FCP proxy
*/
-static int ontap_prio(const char *dev, int fd)
+static int ontap_prio(const char *dev, int fd, unsigned int timeout)
{
unsigned char results[RESULTS_MAX];
int results_size=RESULTS_MAX;
is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
memset(&results, 0, sizeof (results));
- rc = send_gva(dev, fd, 0x41, results, &results_size);
+ rc = send_gva(dev, fd, 0x41, results, &results_size, timeout);
if (rc >= 0) {
tot_len = results[0] << 24 | results[1] << 16 |
results[2] << 8 | results[3];
}
try_fcp_proxy:
- rc = get_proxy(dev, fd);
+ rc = get_proxy(dev, fd, timeout);
if (rc >= 0) {
is_proxy = rc;
}
}
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
- return ontap_prio(pp->dev, pp->fd);
+ return ontap_prio(pp->dev, pp->fd, timeout);
}
#include <sys/time.h>
#include <time.h>
-#include <prio.h>
+#include "prio.h"
int getprio (struct path * pp, char * args)
{
#include <string.h>
#include <sys/ioctl.h>
-#include <sg_include.h>
-#include <debug.h>
-#include <prio.h>
-#include <structs.h>
+#include "sg_include.h"
+#include "debug.h"
+#include "prio.h"
+#include "structs.h"
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
#define pp_rdac_log(prio, msg) condlog(prio, "%s: rdac prio: " msg, dev)
-int rdac_prio(const char *dev, int fd)
+int rdac_prio(const char *dev, int fd, unsigned int timeout)
{
unsigned char sense_buffer[128];
unsigned char sb[128];
io_hdr.dxferp = sense_buffer;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sb;
- io_hdr.timeout = get_prio_timeout(60000);
+ io_hdr.timeout = get_prio_timeout(timeout, 60000);
io_hdr.pack_id = 0;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
pp_rdac_log(0, "sending inquiry command failed");
return(ret);
}
-int getprio (struct path * pp, char * args)
+int getprio (struct path * pp, char * args, unsigned int timeout)
{
- return rdac_prio(pp->dev, pp->fd);
+ return rdac_prio(pp->dev, pp->fd, timeout);
}
--- /dev/null
+/*
+ * sysfs.c
+ *
+ * Copyright(c) 2016 Hannes Reinecke, SUSE Linux GmbH
+ */
+
+#include <stdio.h>
+
+#include "structs.h"
+#include "discovery.h"
+#include "prio.h"
+
+static const struct {
+ unsigned char value;
+ char *name;
+} sysfs_access_state_map[] = {
+ { 50, "active/optimized" },
+ { 10, "active/non-optimized" },
+ { 5, "lba-dependent" },
+ { 1, "standby" },
+};
+
+int get_exclusive_pref_arg(char *args)
+{
+ char *ptr;
+
+ if (args == NULL)
+ return 0;
+ ptr = strstr(args, "exclusive_pref_bit");
+ if (!ptr)
+ return 0;
+ if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t')
+ return 0;
+ if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t')
+ return 0;
+ return 1;
+}
+
+int getprio (struct path * pp, char * args, unsigned int timeout)
+{
+ int prio = 0, rc, i;
+ char buff[512];
+ int exclusive_pref;
+
+ exclusive_pref = get_exclusive_pref_arg(args);
+ rc = sysfs_get_asymmetric_access_state(pp, buff, 512);
+ if (rc < 0)
+ return PRIO_UNDEF;
+ prio = 0;
+ for (i = 0; i < 4; i++) {
+ if (!strncmp(buff, sysfs_access_state_map[i].name,
+ strlen(sysfs_access_state_map[i].name))) {
+ prio = sysfs_access_state_map[i].value;
+ break;
+ }
+ }
+ if (rc > 0 && (prio != 50 || exclusive_pref))
+ prio += 80;
+
+ return prio;
+}
#include <stdio.h>
#include <string.h>
-#include <prio.h>
+#include "prio.h"
#include "weightedpath.h"
-#include <config.h>
-#include <structs.h>
-#include <memory.h>
-#include <debug.h>
+#include "config.h"
+#include "structs.h"
+#include "memory.h"
+#include "debug.h"
#include <regex.h>
-#include <structs_vec.h>
-#include <print.h>
+#include "structs_vec.h"
+#include "print.h"
char *get_next_string(char **temp, char *split_char)
{
{
return prio_path_weight(pp, args);
}
-
do_attr_set(var, conf, shift, "(config file default)")
extern int
-select_mode (struct multipath *mp)
+select_mode (struct config *conf, struct multipath *mp)
{
char *origin;
}
extern int
-select_uid (struct multipath *mp)
+select_uid (struct config *conf, struct multipath *mp)
{
char *origin;
}
extern int
-select_gid (struct multipath *mp)
+select_gid (struct config *conf, struct multipath *mp)
{
char *origin;
* stop at first explicit setting found
*/
extern int
-select_rr_weight (struct multipath * mp)
+select_rr_weight (struct config *conf, struct multipath * mp)
{
char *origin, buff[13];
}
extern int
-select_pgfailback (struct multipath * mp)
+select_pgfailback (struct config *conf, struct multipath * mp)
{
char *origin, buff[13];
}
extern int
-select_pgpolicy (struct multipath * mp)
+select_pgpolicy (struct config *conf, struct multipath * mp)
{
char *origin, buff[POLICY_NAME_SIZE];
}
extern int
-select_selector (struct multipath * mp)
+select_selector (struct config *conf, struct multipath * mp)
{
char *origin;
}
static void
-select_alias_prefix (struct multipath * mp)
+select_alias_prefix (struct config *conf, struct multipath * mp)
{
char *origin;
}
static int
-want_user_friendly_names(struct multipath * mp)
+want_user_friendly_names(struct config *conf, struct multipath * mp)
{
char *origin;
}
extern int
-select_alias (struct multipath * mp)
+select_alias (struct config *conf, struct multipath * mp)
{
char *origin = NULL;
}
mp->alias = NULL;
- if (!want_user_friendly_names(mp))
+ if (!want_user_friendly_names(conf, mp))
goto out;
- select_alias_prefix(mp);
+ select_alias_prefix(conf, mp);
if (strlen(mp->alias_old) > 0) {
mp->alias = use_existing_alias(mp->wwid, conf->bindings_file,
}
extern int
-select_features (struct multipath * mp)
+select_features (struct config *conf, struct multipath * mp)
{
char *origin;
}
extern int
-select_hwhandler (struct multipath * mp)
+select_hwhandler (struct config *conf, struct multipath * mp)
{
char *origin;
}
extern int
-select_checker(struct path *pp)
+select_checker(struct config *conf, struct path *pp)
{
char *origin, *checker_name;
struct checker * c = &pp->checker;
do_set(checker_name, conf, checker_name, "(config file setting)");
do_default(checker_name, DEFAULT_CHECKER);
out:
- checker_get(c, checker_name);
+ checker_get(conf->multipath_dir, c, checker_name);
condlog(3, "%s: path_checker = %s %s", pp->dev, c->name, origin);
if (conf->checker_timeout) {
c->timeout = conf->checker_timeout;
}
extern int
-select_getuid (struct path * pp)
+select_getuid (struct config *conf, struct path * pp)
{
char *origin;
}
void
-detect_prio(struct path * pp)
+detect_prio(struct config *conf, struct path * pp)
{
int ret;
struct prio *p = &pp->prio;
int tpgs = 0;
+ unsigned int timeout = conf->checker_timeout;
+ char buff[512];
+ char *default_prio = PRIO_ALUA;
- if ((tpgs = get_target_port_group_support(pp->fd)) <= 0)
+ if ((tpgs = get_target_port_group_support(pp->fd, timeout)) <= 0)
return;
pp->tpgs = tpgs;
- ret = get_target_port_group(pp);
+ ret = get_target_port_group(pp, timeout);
if (ret < 0)
return;
- if (get_asymmetric_access_state(pp->fd, ret) < 0)
+ if (get_asymmetric_access_state(pp->fd, ret, timeout) < 0)
return;
- prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
+ if (sysfs_get_asymmetric_access_state(pp, buff, 512) >= 0)
+ default_prio = PRIO_SYSFS;
+ prio_get(conf->multipath_dir, p, default_prio, DEFAULT_PRIO_ARGS);
}
-#define set_prio(src, msg) \
+#define set_prio(dir, src, msg) \
do { \
if (src && src->prio_name) { \
- prio_get(p, src->prio_name, src->prio_args); \
+ prio_get(dir, p, src->prio_name, src->prio_args); \
origin = msg; \
goto out; \
} \
} while(0)
extern int
-select_prio (struct path * pp)
+select_prio (struct config *conf, struct path * pp)
{
char *origin;
struct mpentry * mpe;
struct prio * p = &pp->prio;
if (pp->detect_prio == DETECT_PRIO_ON) {
- detect_prio(pp);
+ detect_prio(conf, pp);
if (prio_selected(p)) {
origin = "(detected setting)";
goto out;
}
}
- mpe = find_mpe(pp->wwid);
- set_prio(mpe, "(LUN setting)");
- set_prio(conf->overrides, "(overrides setting)");
- set_prio(pp->hwe, "controller setting)");
- set_prio(conf, "(config file default)");
- prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
+ mpe = find_mpe(conf->mptable, pp->wwid);
+ set_prio(conf->multipath_dir, mpe, "(LUN setting)");
+ set_prio(conf->multipath_dir, conf->overrides, "(overrides setting)");
+ set_prio(conf->multipath_dir, pp->hwe, "controller setting)");
+ set_prio(conf->multipath_dir, conf, "(config file default)");
+ prio_get(conf->multipath_dir, p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
origin = "(internal default)";
out:
/*
*/
if (!strncmp(prio_name(p), PRIO_ALUA, PRIO_NAME_LEN)) {
int tpgs = 0;
- if(!pp->tpgs &&
- (tpgs = get_target_port_group_support(pp->fd)) >= 0)
+ unsigned int timeout = conf->checker_timeout;
+
+ if(!pp->tpgs &&
+ (tpgs = get_target_port_group_support(pp->fd, timeout)) >= 0)
pp->tpgs = tpgs;
}
condlog(3, "%s: prio = %s %s", pp->dev, prio_name(p), origin);
}
extern int
-select_no_path_retry(struct multipath *mp)
+select_no_path_retry(struct config *conf, struct multipath *mp)
{
char *origin = NULL;
char buff[12];
}
int
-select_minio_rq (struct multipath * mp)
+select_minio_rq (struct config *conf, struct multipath * mp)
{
char *origin;
}
int
-select_minio_bio (struct multipath * mp)
+select_minio_bio (struct config *conf, struct multipath * mp)
{
char *origin;
}
extern int
-select_minio (struct multipath * mp)
+select_minio (struct config *conf, struct multipath * mp)
{
unsigned int minv_dmrq[3] = {1, 1, 0};
if (VERSION_GE(conf->version, minv_dmrq))
- return select_minio_rq(mp);
+ return select_minio_rq(conf, mp);
else
- return select_minio_bio(mp);
+ return select_minio_bio(conf, mp);
}
extern int
-select_fast_io_fail(struct multipath *mp)
+select_fast_io_fail(struct config *conf, struct multipath *mp)
{
char *origin, buff[12];
}
extern int
-select_dev_loss(struct multipath *mp)
+select_dev_loss(struct config *conf, struct multipath *mp)
{
char *origin, buff[12];
}
extern int
-select_flush_on_last_del(struct multipath *mp)
+select_flush_on_last_del(struct config *conf, struct multipath *mp)
{
char *origin;
}
extern int
-select_reservation_key (struct multipath * mp)
+select_reservation_key (struct config *conf, struct multipath * mp)
{
char *origin, buff[12];
}
extern int
-select_retain_hwhandler (struct multipath * mp)
+select_retain_hwhandler (struct config *conf, struct multipath * mp)
{
char *origin;
unsigned int minv_dm_retain[3] = {1, 5, 0};
}
extern int
-select_detect_prio (struct path * pp)
+select_detect_prio (struct config *conf, struct path * pp)
{
char *origin;
}
extern int
-select_deferred_remove (struct multipath *mp)
+select_deferred_remove (struct config *conf, struct multipath *mp)
{
char *origin;
}
extern int
-select_delay_watch_checks(struct multipath *mp)
+select_delay_watch_checks(struct config *conf, struct multipath *mp)
{
char *origin, buff[12];
}
extern int
-select_delay_wait_checks(struct multipath *mp)
+select_delay_wait_checks(struct config *conf, struct multipath *mp)
{
char *origin, buff[12];
-int select_rr_weight (struct multipath * mp);
-int select_pgfailback (struct multipath * mp);
-int select_pgpolicy (struct multipath * mp);
-int select_selector (struct multipath * mp);
-int select_alias (struct multipath * mp);
-int select_features (struct multipath * mp);
-int select_hwhandler (struct multipath * mp);
-int select_checker(struct path *pp);
-int select_getuid (struct path * pp);
-int select_prio (struct path * pp);
-int select_no_path_retry(struct multipath *mp);
-int select_flush_on_last_del(struct multipath *mp);
-int select_minio(struct multipath *mp);
-int select_mode(struct multipath *mp);
-int select_uid(struct multipath *mp);
-int select_gid(struct multipath *mp);
-int select_fast_io_fail(struct multipath *mp);
-int select_dev_loss(struct multipath *mp);
-int select_reservation_key(struct multipath *mp);
-int select_retain_hwhandler (struct multipath * mp);
-int select_detect_prio(struct path * pp);
-int select_deferred_remove(struct multipath *mp);
-int select_delay_watch_checks (struct multipath * mp);
-int select_delay_wait_checks (struct multipath * mp);
+int select_rr_weight (struct config *conf, struct multipath * mp);
+int select_pgfailback (struct config *conf, struct multipath * mp);
+int select_pgpolicy (struct config *conf, struct multipath * mp);
+int select_selector (struct config *conf, struct multipath * mp);
+int select_alias (struct config *conf, struct multipath * mp);
+int select_features (struct config *conf, struct multipath * mp);
+int select_hwhandler (struct config *conf, struct multipath * mp);
+int select_checker(struct config *conf, struct path *pp);
+int select_getuid (struct config *conf, struct path * pp);
+int select_prio (struct config *conf, struct path * pp);
+int select_no_path_retry(struct config *conf, struct multipath *mp);
+int select_flush_on_last_del(struct config *conf, struct multipath *mp);
+int select_minio(struct config *conf, struct multipath *mp);
+int select_mode(struct config *conf, struct multipath *mp);
+int select_uid(struct config *conf, struct multipath *mp);
+int select_gid(struct config *conf, struct multipath *mp);
+int select_fast_io_fail(struct config *conf, struct multipath *mp);
+int select_dev_loss(struct config *conf, struct multipath *mp);
+int select_reservation_key(struct config *conf, struct multipath *mp);
+int select_retain_hwhandler (struct config *conf, struct multipath * mp);
+int select_detect_prio(struct config *conf, struct path * pp);
+int select_deferred_remove(struct config *conf, struct multipath *mp);
+int select_delay_watch_checks (struct config *conf, struct multipath * mp);
+int select_delay_wait_checks (struct config *conf, struct multipath * mp);
* about to be removed
*/
p = strchr(*f, ' ');
- if (!p)
+ if (!p) {
/* Internal error, feature string inconsistent */
+ FREE(n);
return 1;
+ }
while (*p == ' ')
p++;
p--;
return 0;
}
-
/* checkers shared data */
void * mpcontext;
-
+
/* persistent management data*/
unsigned char * reservation_key;
unsigned char prflag;
struct multipath * find_mp_by_wwid (vector mp, char * wwid);
struct multipath * find_mp_by_str (vector mp, char * wwid);
struct multipath * find_mp_by_minor (vector mp, int minor);
-
+
struct path * find_path_by_devt (vector pathvec, char * devt);
struct path * find_path_by_dev (vector pathvec, char * dev);
struct path * first_path (struct multipath * mpp);
#include "vector.h"
#include "defaults.h"
#include "debug.h"
+#include "config.h"
#include "structs.h"
#include "structs_vec.h"
#include "sysfs.h"
#include "waiter.h"
#include "devmapper.h"
#include "dmparser.h"
-#include "config.h"
#include "propsel.h"
#include "discovery.h"
#include "prio.h"
extern int
adopt_paths (vector pathvec, struct multipath * mpp)
{
- int i;
+ int i, ret;
struct path * pp;
+ struct config *conf;
if (!mpp)
return 0;
if (!find_path_by_dev(mpp->paths, pp->dev) &&
store_path(mpp->paths, pp))
return 1;
- if (pathinfo(pp, conf->hwtable,
- DI_PRIO | DI_CHECKER))
+ conf = get_multipath_config();
+ ret = pathinfo(pp, conf,
+ DI_PRIO | DI_CHECKER);
+ put_multipath_config(conf);
+ if (ret)
return 1;
}
}
condlog(3, "%s: product = %s", pp->dev, pp->product_id);
condlog(3, "%s: rev = %s", pp->dev, pp->rev);
if (!pp->hwe) {
+ struct config *conf = get_multipath_config();
+
condlog(3, "searching hwtable");
pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
pp->product_id, pp->rev);
+ put_multipath_config(conf);
}
}
}
static int
-update_multipath_table (struct multipath *mpp, vector pathvec)
+update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
{
char params[PARAMS_SIZE] = {0};
return 1;
}
- if (disassemble_map(pathvec, params, mpp)) {
+ if (disassemble_map(pathvec, params, mpp, is_daemon)) {
condlog(3, "%s: cannot disassemble map", mpp->alias);
return 1;
}
}
extern int
-update_multipath_strings (struct multipath *mpp, vector pathvec)
+update_multipath_strings (struct multipath *mpp, vector pathvec, int is_daemon)
{
if (!mpp)
return 1;
free_pgvec(mpp->pg, KEEP_PATHS);
mpp->pg = NULL;
- if (update_multipath_table(mpp, pathvec))
+ if (update_multipath_table(mpp, pathvec, is_daemon))
return 1;
sync_paths(mpp, pathvec);
}
extern void
-set_no_path_retry(struct multipath *mpp)
+set_no_path_retry(struct config *conf, struct multipath *mpp)
{
mpp->retry_tick = 0;
mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
- select_no_path_retry(mpp);
+ select_no_path_retry(conf, mpp);
switch (mpp->no_path_retry) {
case NO_PATH_RETRY_UNDEF:
default:
dm_queue_if_no_path(mpp->alias, 1);
if (mpp->nr_active == 0) {
+ struct config *conf = get_multipath_config();
/* Enter retry mode */
mpp->retry_tick = mpp->no_path_retry * conf->checkint;
condlog(1, "%s: Entering recovery mode: max_retries=%d",
mpp->alias, mpp->no_path_retry);
+ put_multipath_config(conf);
}
break;
}
}
extern int
-__setup_multipath (struct vectors * vecs, struct multipath * mpp, int reset)
+__setup_multipath (struct vectors * vecs, struct multipath * mpp,
+ int reset, int is_daemon)
{
+ struct config *conf;
+
if (dm_get_info(mpp->alias, &mpp->dmi)) {
/* Error accessing table */
condlog(3, "%s: cannot access table", mpp->alias);
goto out;
}
- if (update_multipath_strings(mpp, vecs->pathvec)) {
+ if (update_multipath_strings(mpp, vecs->pathvec, is_daemon)) {
condlog(0, "%s: failed to setup multipath", mpp->alias);
goto out;
}
set_multipath_wwid(mpp);
- mpp->mpe = find_mpe(mpp->wwid);
+ conf = get_multipath_config();
+ mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
+ put_multipath_config(conf);
condlog(3, "%s: discover", mpp->alias);
if (!mpp->hwe)
mpp->alias);
}
if (reset) {
- select_rr_weight(mpp);
- select_pgfailback(mpp);
- set_no_path_retry(mpp);
- select_flush_on_last_del(mpp);
+ select_rr_weight(conf, mpp);
+ select_pgfailback(conf, mpp);
+ set_no_path_retry(conf, mpp);
+ select_flush_on_last_del(conf, mpp);
if (VECTOR_SIZE(mpp->paths) != 0)
dm_cancel_deferred_remove(mpp);
}
{
struct multipath * mpp = alloc_multipath();
- if (!mpp || !alias)
+ if (!mpp)
+ return NULL;
+ if (!alias) {
+ FREE(mpp);
return NULL;
+ }
mpp->alias = STRDUP(alias);
int i;
vector_foreach_slot (vecs->mpvec, mp, i)
- if (strcmp(mp->wwid, mpp->wwid) == 0) {
- strncpy(mpp->alias_old, mp->alias, WWID_SIZE);
+ if (strncmp(mp->wwid, mpp->wwid, WWID_SIZE - 1) == 0) {
+ strncpy(mpp->alias_old, mp->alias, WWID_SIZE - 1);
return;
}
}
struct path * pp, int add_vec)
{
struct multipath * mpp;
+ struct config *conf = NULL;
if (!strlen(pp->wwid))
return NULL;
if (!(mpp = alloc_multipath()))
return NULL;
- mpp->mpe = find_mpe(pp->wwid);
+ conf = get_multipath_config();
+ mpp->mpe = find_mpe(conf->mptable, pp->wwid);
mpp->hwe = pp->hwe;
+ put_multipath_config(conf);
strcpy(mpp->wwid, pp->wwid);
find_existing_alias(mpp, vecs);
- if (select_alias(mpp))
+ if (select_alias(conf, mpp))
goto out;
mpp->size = pp->size;
return 2;
}
- if (__setup_multipath(vecs, mpp, reset))
+ if (__setup_multipath(vecs, mpp, reset, 1))
return 1; /* mpp freed in setup_multipath */
/*
continue;
if (pp->state != PATH_DOWN) {
+ struct config *conf = get_multipath_config();
int oldstate = pp->state;
condlog(2, "%s: mark as failed", pp->dev);
mpp->stat_path_failures++;
*/
if (pp->tick > conf->checkint)
pp->tick = conf->checkint;
+ put_multipath_config(conf);
}
}
}
void update_queue_mode_del_path(struct multipath *mpp)
{
if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
+ struct config *conf = get_multipath_config();
+
/*
* Enter retry mode.
* meaning of +1: retry_tick may be decremented in
mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
condlog(1, "%s: Entering recovery mode: max_retries=%d",
mpp->alias, mpp->no_path_retry);
+ put_multipath_config(conf);
}
condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
}
}
condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
}
-
#ifndef _STRUCTS_VEC_H
#define _STRUCTS_VEC_H
+#include "vector.h"
+#include "config.h"
#include "lock.h"
/*
struct mutex_lock {
vector mpvec;
};
-void set_no_path_retry(struct multipath *mpp);
+void set_no_path_retry(struct config *conf, struct multipath *mpp);
int adopt_paths (vector pathvec, struct multipath * mpp);
void orphan_paths (vector pathvec, struct multipath * mpp);
int verify_paths(struct multipath * mpp, struct vectors * vecs);
int update_mpp_paths(struct multipath * mpp, vector pathvec);
int __setup_multipath (struct vectors * vecs, struct multipath * mpp,
- int reset);
-#define setup_multipath(vecs, mpp) __setup_multipath(vecs, mpp, 1)
-int update_multipath_strings (struct multipath *mpp, vector pathvec);
-
+ int reset, int is_daemon);
+#define setup_multipath(vecs, mpp) __setup_multipath(vecs, mpp, 1, 1)
+int update_multipath_strings (struct multipath *mpp, vector pathvec,
+ int is_daemon);
+
void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
void remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs, int purge_vec);
void remove_maps (struct vectors * vecs);
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
attr_name);
condlog(4, "open '%s'", devpath);
- if (stat(devpath, &statbuf) != 0) {
+ /* read attribute value */
+ fd = open(devpath, O_RDONLY);
+ if (fd < 0) {
+ condlog(4, "attribute '%s' can not be opened: %s",
+ devpath, strerror(errno));
+ return -errno;
+ }
+ if (fstat(fd, &statbuf) < 0) {
condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
+ close(fd);
return -ENXIO;
}
-
/* skip directories */
if (S_ISDIR(statbuf.st_mode)) {
condlog(4, "%s is a directory", devpath);
+ close(fd);
return -EISDIR;
}
-
/* skip non-writeable files */
if ((statbuf.st_mode & S_IRUSR) == 0) {
condlog(4, "%s is not readable", devpath);
+ close(fd);
return -EPERM;
}
- /* read attribute value */
- fd = open(devpath, O_RDONLY);
- if (fd < 0) {
- condlog(4, "attribute '%s' can not be opened: %s",
- devpath, strerror(errno));
- return -errno;
- }
size = read(fd, value, value_len);
if (size < 0) {
condlog(4, "read from %s failed: %s", devpath, strerror(errno));
size = -errno;
+ value[0] = '\0';
} else if (size == value_len) {
+ value[size - 1] = '\0';
condlog(4, "overflow while reading from %s", devpath);
size = 0;
} else {
value[size] = '\0';
+ size = strchop(value);
}
close(fd);
- if (size > 0)
- size = strchop(value);
return size;
}
snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
attr_name);
condlog(4, "open '%s'", devpath);
- if (stat(devpath, &statbuf) != 0) {
+ /* read attribute value */
+ fd = open(devpath, O_RDONLY);
+ if (fd < 0) {
+ condlog(4, "attribute '%s' can not be opened: %s",
+ devpath, strerror(errno));
+ return -errno;
+ }
+ if (fstat(fd, &statbuf) != 0) {
condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
+ close(fd);
return -ENXIO;
}
/* skip directories */
if (S_ISDIR(statbuf.st_mode)) {
condlog(4, "%s is a directory", devpath);
+ close(fd);
return -EISDIR;
}
/* skip non-writeable files */
if ((statbuf.st_mode & S_IRUSR) == 0) {
condlog(4, "%s is not readable", devpath);
+ close(fd);
return -EPERM;
}
- /* read attribute value */
- fd = open(devpath, O_RDONLY);
- if (fd < 0) {
- condlog(4, "attribute '%s' can not be opened: %s",
- devpath, strerror(errno));
- return -errno;
- }
size = read(fd, value, value_len);
if (size < 0) {
condlog(4, "read from %s failed: %s", devpath, strerror(errno));
snprintf(devpath, PATH_SIZE, "%s/%s", udev_device_get_syspath(dev),
attr_name);
condlog(4, "open '%s'", devpath);
- if (stat(devpath, &statbuf) != 0) {
+ /* write attribute value */
+ fd = open(devpath, O_WRONLY);
+ if (fd < 0) {
+ condlog(4, "attribute '%s' can not be opened: %s",
+ devpath, strerror(errno));
+ return -errno;
+ }
+ if (fstat(fd, &statbuf) != 0) {
condlog(4, "stat '%s' failed: %s", devpath, strerror(errno));
+ close(fd);
return -errno;
}
/* skip directories */
if (S_ISDIR(statbuf.st_mode)) {
condlog(4, "%s is a directory", devpath);
+ close(fd);
return -EISDIR;
}
/* skip non-writeable files */
if ((statbuf.st_mode & S_IWUSR) == 0) {
condlog(4, "%s is not writeable", devpath);
+ close(fd);
return -EPERM;
}
- /* write attribute value */
- fd = open(devpath, O_WRONLY);
- if (fd < 0) {
- condlog(4, "attribute '%s' can not be opened: %s",
- devpath, strerror(errno));
- return -errno;
- }
size = write(fd, value, value_len);
if (size < 0) {
condlog(4, "write to %s failed: %s", devpath, strerror(errno));
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sys/socket.h>
#include <sys/user.h>
#include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <pthread.h>
}
/* enable receiving of the sender credentials */
- setsockopt(sock, SOL_SOCKET, SO_PASSCRED,
- &feature_on, sizeof(feature_on));
+ retval = setsockopt(sock, SOL_SOCKET, SO_PASSCRED,
+ &feature_on, sizeof(feature_on));
+ if (retval < 0) {
+ condlog(0, "failed to enable credential passing, exit");
+ goto exit;
+ }
} else {
/* Fallback to read kernel netlink events */
condlog(3, "receive buffer size for socket is %u.", rcvsz);
/* enable receiving of the sender credentials */
- setsockopt(sock, SOL_SOCKET, SO_PASSCRED,
- &feature_on, sizeof(feature_on));
+ if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED,
+ &feature_on, sizeof(feature_on)) < 0) {
+ condlog(0, "error on enabling credential passing for socket");
+ exit(1);
+ }
retval = bind(sock, (struct sockaddr *) &snl,
sizeof(struct sockaddr_nl));
{
int err = 2;
struct udev_monitor *monitor = NULL;
- int fd, fd_ep = -1, socket_flags, events;
+ int fd, socket_flags, events;
int need_failback = 1;
int timeout = 30;
- sigset_t mask;
LIST_HEAD(uevlisten_tmp);
/*
goto out;
}
- pthread_sigmask(SIG_SETMASK, NULL, &mask);
events = 0;
while (1) {
struct uevent *uev;
struct udev_device *dev;
struct pollfd ev_poll;
- struct timespec poll_timeout;
+ int poll_timeout;
int fdcount;
memset(&ev_poll, 0, sizeof(struct pollfd));
ev_poll.fd = fd;
ev_poll.events = POLLIN;
- memset(&poll_timeout, 0, sizeof(struct timespec));
- poll_timeout.tv_sec = timeout;
+ poll_timeout = timeout * 1000;
errno = 0;
- fdcount = ppoll(&ev_poll, 1, &poll_timeout, &mask);
+ fdcount = poll(&ev_poll, 1, poll_timeout);
if (fdcount && ev_poll.revents & POLLIN) {
timeout = 0;
dev = udev_monitor_receive_device(monitor);
}
need_failback = 0;
out:
- if (fd_ep >= 0)
- close(fd_ep);
if (monitor)
udev_monitor_unref(monitor);
if (need_failback)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <signal.h>
#include <errno.h>
#ifdef USE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
-#include <mpath_cmd.h>
+#include "mpath_cmd.h"
#include "memory.h"
#include "uxsock.h"
-/*
+/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
- *
+ *
* Part: vector.c include file.
- *
+ *
* Version: $Id: vector.h,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
#ifndef _VERSION_H
#define _VERSION_H
-#define VERSION_CODE 0x000601
-#define DATE_CODE 0x050a10
+#define VERSION_CODE 0x000602
+#define DATE_CODE 0x071610
#define PROG "multipath-tools"
#include <sys/mman.h>
#include <pthread.h>
#include <signal.h>
+#include <urcu.h>
#include "vector.h"
#include "memory.h"
#include "checkers.h"
+#include "config.h"
#include "structs.h"
#include "structs_vec.h"
#include "devmapper.h"
if (wp->dmt)
dm_task_destroy(wp->dmt);
+ rcu_unregister_thread();
FREE(wp);
}
waiter = (struct event_thread *)et;
pthread_cleanup_push(free_waiter, et);
+ rcu_register_thread();
while (1) {
r = waiteventloop(waiter);
if (!wp)
goto out;
- strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+ strncpy(wp->mapname, mpp->alias, WWID_SIZE - 1);
wp->vecs = vecs;
if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
condlog(0, "failed to start waiter thread");
return 1;
}
-
struct multipath * mpp;
size_t len;
int ret = -1;
+ struct config *conf;
+ conf = get_multipath_config();
fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
+ put_multipath_config(conf);
if (fd < 0)
goto out;
if (!can_write) {
int fd, len, can_write;
char *str;
int ret = -1;
+ struct config *conf;
len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */
str = malloc(len);
goto out;
}
condlog(3, "removing line '%s' from wwids file", str);
+ conf = get_multipath_config();
fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
+ put_multipath_config(conf);
if (fd < 0)
goto out;
if (!can_write) {
{
int fd, can_write, found, ret;
FILE *f;
+ struct config *conf;
+
+ conf = get_multipath_config();
fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER);
+ put_multipath_config(conf);
if (fd < 0)
return -1;
int
should_multipath(struct path *pp1, vector pathvec)
{
- int i;
+ int i, ignore_new_devs;;
struct path *pp2;
+ struct config *conf;
- if (!conf->find_multipaths && !conf->ignore_new_devs)
+ conf = get_multipath_config();
+ ignore_new_devs = conf->ignore_new_devs;
+ if (!conf->find_multipaths && !ignore_new_devs) {
+ put_multipath_config(conf);
return 1;
+ }
+ put_multipath_config(conf);
condlog(4, "checking if %s should be multipathed", pp1->dev);
- if (!conf->ignore_new_devs) {
+ if (!ignore_new_devs) {
vector_foreach_slot(pathvec, pp2, i) {
if (pp1->dev == pp2->dev)
continue;
#
include ../Makefile.inc
-OBJS = main.o
+OBJS = main.o
-CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
LDFLAGS += -lpthread -ldevmapper -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -L$(mpathcmddir) -lmpathcmd -lmultipath -ludev
EXEC = mpathpersist
$(EXEC): $(OBJS)
$(CC) -g $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
+
install:
- install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
- install -d $(DESTDIR)$(mandir)
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
-
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+ $(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+ $(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+
clean:
- rm -f *.o $(EXEC)
- rm -f mpathpersist.8.gz
+ $(RM) *.o $(EXEC)
+ $(RM) mpathpersist.8.gz
uninstall:
- rm $(DESTDIR)$(bindir)/$(EXEC)
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
+ $(RM) $(DESTDIR)$(bindir)/$(EXEC)
+ $(RM) $(DESTDIR)$(mandir)/$(EXEC).8.gz
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <checkers.h>
-#include <vector.h>
-#include <structs.h>
+#include "checkers.h"
+#include "vector.h"
+#include "config.h"
+#include "structs.h"
#include <getopt.h>
#include <libudev.h>
-#include <mpath_persist.h>
+#include "mpath_persist.h"
#include "main.h"
#include <pthread.h>
#include <ctype.h>
};
int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
-void mpath_print_buf_readcap(struct prin_resp *pr_buff);
+void mpath_print_buf_readcap(struct prin_resp *pr_buff);
void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
void mpath_print_buf_readresv(struct prin_resp *pr_buff);
void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
void dumpHex(const char* str, int len, int no_ascii);
-void * mpath_alloc_prin_response(int prin_sa);
+void * mpath_alloc_prin_response(int prin_sa);
void mpath_print_transport_id(struct prin_fulldescr *fdesc);
int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
int logsink;
unsigned int mpath_mx_alloc_len;
+struct config *multipath_conf;
+
+struct config *get_multipath_config(void)
+{
+ return multipath_conf;
+}
+
+void put_multipath_config(struct config *conf)
+{
+ /* Noop for now */
+}
+
+void rcu_register_thread_memb(void) {}
+
+void rcu_unregister_thread_memb(void) {}
int main (int argc, char * argv[])
{
void *resp = NULL;
struct transportid * tmp;
struct udev *udev = NULL;
+ struct config *conf;
if (optind == argc)
{
}
udev = udev_new();
- mpath_lib_init(udev);
+ conf = mpath_lib_init(udev);
memset(transportids,0,MPATH_MX_TIDS);
+ multipath_conf = conf;
while (1)
{
break;
case 'l':
- if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
- fprintf(stderr, "bad argument to '--alloc-length'\n");
- return MPATH_PR_SYNTAX_ERROR;
- } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
- fprintf(stderr, "'--alloc-length' argument exceeds maximum"
- " limit(%d)\n", MPATH_MAX_PARAM_LEN);
- return MPATH_PR_SYNTAX_ERROR;
- }
- break;
+ if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
+ fprintf(stderr, "bad argument to '--alloc-length'\n");
+ return MPATH_PR_SYNTAX_ERROR;
+ } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
+ fprintf(stderr, "'--alloc-length' argument exceeds maximum"
+ " limit(%d)\n", MPATH_MAX_PARAM_LEN);
+ return MPATH_PR_SYNTAX_ERROR;
+ }
+ break;
default:
- fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
+ fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
usage ();
ret = MPATH_PR_SYNTAX_ERROR;
goto out;
if (ret != MPATH_PR_SUCCESS )
{
fprintf (stderr, "Persistent Reserve IN command failed\n");
- goto out;
+ goto out;
}
switch(prin_sa)
- {
- case MPATH_PRIN_RKEY_SA:
- mpath_print_buf_readkeys(resp);
+ {
+ case MPATH_PRIN_RKEY_SA:
+ mpath_print_buf_readkeys(resp);
break;
- case MPATH_PRIN_RRES_SA:
+ case MPATH_PRIN_RRES_SA:
mpath_print_buf_readresv(resp);
break;
case MPATH_PRIN_RCAP_SA:
- mpath_print_buf_readcap(resp);
+ mpath_print_buf_readcap(resp);
break;
case MPATH_PRIN_RFSTAT_SA:
- mpath_print_buf_readfullstat(resp);
+ mpath_print_buf_readfullstat(resp);
break;
}
free(resp);
}
else if (prout)
{
- int j;
+ int j;
struct prout_param_descriptor *paramp;
paramp= malloc(sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS )));
-
+
memset(paramp, 0, sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS)));
for (j = 7; j >= 0; --j) {
if (param_aptpl)
paramp->sa_flags |= 0x1;
- if (num_transport)
+ if (num_transport)
{
paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
paramp->num_transportid = num_transport;
res = close (fd);
if (res < 0)
{
- mpath_lib_exit();
+ mpath_lib_exit(conf);
udev_unref(udev);
return MPATH_PR_FILE_ERROR;
}
out :
- mpath_lib_exit();
+ mpath_lib_exit(conf);
udev_unref(udev);
return (ret >= 0) ? ret : MPATH_PR_OTHER;
}
{
int j, num, scope=0, type=0;
unsigned char *keyp;
- uint64_t prkey;
+ uint64_t prkey;
num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
if (0 == num)
}
else
printf(" PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
- keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
+ keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
prkey = 0;
for (j = 0; j < 8; ++j) {
if (j > 0)
scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) & 0x0f;
type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
- if (scope == 0)
+ if (scope == 0)
printf(" scope = LU_SCOPE, type = %s", pr_type_strs[type]);
else
printf(" scope = %d, type = %s", scope, pr_type_strs[type]);
uint16_t rel_pt_addr;
unsigned char * keyp;
- num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
+ num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
if (0 == num)
{
printf(" PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
}
printf(" Key = 0x%" PRIx64 "\n", prkey);
- if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
+ if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
printf(" All target ports bit set\n");
else {
printf(" All target ports bit clear\n");
case MPATH_PROTOCOL_ID_FC:
printf(" FCP-2 ");
if (0 != fdesc->trnptid.format_code)
- printf(" [Unexpected format code: %d]\n",
+ printf(" [Unexpected format code: %d]\n",
fdesc->trnptid.format_code);
dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
break;
case MPATH_PROTOCOL_ID_SAS:
printf(" SAS ");
if (0 != fdesc->trnptid.format_code)
- printf(" [Unexpected format code: %d]\n",
- fdesc->trnptid.format_code);
- dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
+ printf(" [Unexpected format code: %d]\n",
+ fdesc->trnptid.format_code);
+ dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
break;
default:
return;
}
return 0;
}
-
{"register", 0, 0, 'G'},
{"register-ignore", 0, 0, 'I'},
{"release", 0, 0, 'L'},
- {"report-capabilities", 0, 0, 'c'},
+ {"report-capabilities", 0, 0, 'c'},
{"reserve", 0, 0, 'R'},
{"transport-id", 1, 0, 'X'},
{"alloc-length", 1, 0, 'l'},
};
static void usage(void);
-
+++ /dev/null
-%define _rpmdir rpms
-%define _builddir .
-
-Summary: Tools to manage multipathed devices with the device-mapper.
-Name: multipath-tools
-Version: __VERSION__
-Release: 1
-License: GPL
-Group: Utilities/System
-URL: http://christophe.varoqui.free.fr
-Source: /dev/null
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
-Packager: Christophe Varoqui <christophe.varoqui@opensvc.com>
-Prefix: /
-Vendor: Starving Linux Artists (tm Brian O'Sullivan)
-ExclusiveOS: linux
-
-%description
-%{name} provides the tools to manage multipathed devices by
-instructing the device-mapper multipath module what to do. The tools
-are :
-* multipath : scan the system for multipathed devices, assembles them
- and update the device-mapper's maps
-* multipathd : wait for maps events, then execs multipath
-* kpartx : maps linear devmaps upon device partitions, which makes
- multipath maps partionable
-
-%prep
-mkdir -p %{buildroot} %{_rpmdir}
-
-%build
-make
-
-%install
-rm -rf %{buildroot}
-make DESTDIR=%{buildroot} install
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root,-)
-%{prefix}/sbin/multipath
-%{prefix}/sbin/kpartx
-%{prefix}/usr/share/man/man8/multipath.8.gz
-%{prefix}/usr/share/man/man8/kpartx.8.gz
-%{prefix}/usr/share/man/man8/multipathd.8.gz
-%{prefix}/usr/share/man/man5/multipath.conf.5.gz
-%{prefix}/sbin/multipathd
-%{prefix}/etc/udev/rules.d/multipath.rules
-%{prefix}/etc/udev/rules.d/kpartx.rules
-%{prefix}/lib/udev/kpartx_id
-%{prefix}/lib/multipath/*.so
-
-
-%changelog
-* Sat May 14 2004 Christophe Varoqui
-- Initial build.
PROGS="/sbin/udev /sbin/udevstart /bin/mountpoint /bin/readlink"
LIBS=`ldd $PROGS | grep -v linux-gate.so | sort -u | \
-awk '{print $3}'`
+awk '{print $3}'`
for i in $LIBS
do
mkdir -p `dirname $INITRDDIR/$i`
PROGS="/lib/udev/scsi_id /bin/mountpoint"
LIBS=`ldd $PROGS | grep -v linux-gate.so | sort -u | \
-awk '{print $3}'`
+awk '{print $3}'`
for i in $LIBS
do
mkdir -p `dirname $INITRDDIR/$i`
then
cp /etc/multipath.conf $INITRDDIR/etc/
fi
-
$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
uninstall:
- rm $(DESTDIR)$(bindir)/$(EXEC)
- rm $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
- rm $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
- rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
- rm $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
+ $(RM) $(DESTDIR)$(bindir)/$(EXEC)
+ $(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules
+ $(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules
+ $(RM) $(DESTDIR)$(mandir)/$(EXEC).8.gz
+ $(RM) $(DESTDIR)$(man5dir)/$(EXEC).conf.5.gz
clean:
- rm -f core *.o $(EXEC) *.gz
+ $(RM) core *.o $(EXEC) *.gz
#include <libudev.h>
#include <syslog.h>
-#include <checkers.h>
-#include <prio.h>
-#include <vector.h>
-#include <memory.h>
+#include "checkers.h"
+#include "prio.h"
+#include "vector.h"
+#include "memory.h"
#include <libdevmapper.h>
-#include <devmapper.h>
-#include <util.h>
-#include <defaults.h>
-#include <structs.h>
-#include <structs_vec.h>
-#include <dmparser.h>
-#include <sysfs.h>
-#include <config.h>
-#include <blacklist.h>
-#include <discovery.h>
-#include <debug.h>
-#include <switchgroup.h>
-#include <print.h>
-#include <alias.h>
-#include <configure.h>
-#include <pgpolicies.h>
-#include <version.h>
+#include "devmapper.h"
+#include "util.h"
+#include "defaults.h"
+#include "config.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "dmparser.h"
+#include "sysfs.h"
+#include "blacklist.h"
+#include "discovery.h"
+#include "debug.h"
+#include "switchgroup.h"
+#include "print.h"
+#include "alias.h"
+#include "configure.h"
+#include "pgpolicies.h"
+#include "version.h"
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
-#include <wwids.h>
-#include <uxsock.h>
-#include <mpath_cmd.h>
+#include "wwids.h"
+#include "uxsock.h"
+#include "mpath_cmd.h"
int logsink;
+struct udev *udev;
+struct config *multipath_conf;
+
+struct config *get_multipath_config(void)
+{
+ return multipath_conf;
+}
+
+void put_multipath_config(struct config *conf)
+{
+ /* Noop for now */
+}
+
+void rcu_register_thread_memb(void) {}
+
+void rcu_unregister_thread_memb(void) {}
static int
filter_pathvec (vector pathvec, char * refwwid)
fprintf (stderr,
"\n"
"Where:\n"
- " -h print this usage text\n" \
- " -l show multipath topology (sysfs and DM info)\n" \
- " -ll show multipath topology (maximum info)\n" \
- " -f flush a multipath device map\n" \
- " -F flush all multipath device maps\n" \
- " -a add a device wwid to the wwids file\n" \
- " -c check if a device should be a path in a multipath device\n" \
- " -q allow queue_if_no_path when multipathd is not running\n"\
- " -d dry run, do not create or update devmaps\n" \
- " -t dump internal hardware table\n" \
- " -r force devmap reload\n" \
- " -i ignore wwids file\n" \
- " -B treat the bindings file as read only\n" \
- " -b fil bindings file location\n" \
- " -w remove a device from the wwids file\n" \
- " -W reset the wwids file include only the current devices\n" \
- " -p pol force all maps to specified path grouping policy :\n" \
- " . failover one path per priority group\n" \
- " . multibus all paths in one priority group\n" \
- " . group_by_serial one priority group per serial\n" \
- " . group_by_prio one priority group per priority lvl\n" \
- " . group_by_node_name one priority group per target node\n" \
- " -v lvl verbosity level\n" \
- " . 0 no output\n" \
- " . 1 print created devmap names only\n" \
- " . 2 default verbosity\n" \
- " . 3 print debug information\n" \
- " dev action limited to:\n" \
- " . multipath named 'dev' (ex: mpath0) or\n" \
- " . multipath whose wwid is 'dev' (ex: 60051..)\n" \
- " . multipath including the path named 'dev' (ex: /dev/sda)\n" \
- " . multipath including the path with maj:min 'dev' (ex: 8:0)\n" \
+ " -h print this usage text\n"
+ " -l show multipath topology (sysfs and DM info)\n"
+ " -ll show multipath topology (maximum info)\n"
+ " -f flush a multipath device map\n"
+ " -F flush all multipath device maps\n"
+ " -a add a device wwid to the wwids file\n"
+ " -c check if a device should be a path in a multipath device\n"
+ " -q allow queue_if_no_path when multipathd is not running\n"
+ " -d dry run, do not create or update devmaps\n"
+ " -t dump internal hardware table\n"
+ " -r force devmap reload\n"
+ " -i ignore wwids file\n"
+ " -B treat the bindings file as read only\n"
+ " -b fil bindings file location\n"
+ " -w remove a device from the wwids file\n"
+ " -W reset the wwids file include only the current devices\n"
+ " -p pol force all maps to specified path grouping policy :\n"
+ " . failover one path per priority group\n"
+ " . multibus all paths in one priority group\n"
+ " . group_by_serial one priority group per serial\n"
+ " . group_by_prio one priority group per priority lvl\n"
+ " . group_by_node_name one priority group per target node\n"
+ " -v lvl verbosity level\n"
+ " . 0 no output\n"
+ " . 1 print created devmap names only\n"
+ " . 2 default verbosity\n"
+ " . 3 print debug information\n"
+ " dev action limited to:\n"
+ " . multipath named 'dev' (ex: mpath0) or\n"
+ " . multipath whose wwid is 'dev' (ex: 60051..)\n"
+ " . multipath including the path named 'dev' (ex: /dev/sda)\n"
+ " . multipath including the path with maj:min 'dev' (ex: 8:0)\n"
);
}
int i, j;
struct pathgroup * pgp;
struct path * pp;
+ struct config *conf;
if (!mpp->pg)
return 0;
continue;
}
pp->mpp = mpp;
- if (pathinfo(pp, conf->hwtable, DI_ALL))
+ conf = get_multipath_config();
+ if (pathinfo(pp, conf, DI_ALL))
pp->state = PATH_UNCHECKED;
+ put_multipath_config(conf);
continue;
}
pp->mpp = mpp;
if (pp->state == PATH_UNCHECKED ||
pp->state == PATH_WILD) {
- if (pathinfo(pp, conf->hwtable, DI_CHECKER))
+ conf = get_multipath_config();
+ if (pathinfo(pp, conf, DI_CHECKER))
pp->state = PATH_UNCHECKED;
+ put_multipath_config(conf);
}
if (pp->priority == PRIO_UNDEF) {
- if (pathinfo(pp, conf->hwtable, DI_PRIO))
+ conf = get_multipath_config();
+ if (pathinfo(pp, conf, DI_PRIO))
pp->priority = PRIO_UNDEF;
+ put_multipath_config(conf);
}
}
}
}
static int
-get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
+get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
{
int i;
struct multipath * mpp;
continue;
}
- if (conf->cmd == CMD_VALID_PATH)
+ if (cmd == CMD_VALID_PATH)
continue;
dm_get_map(mpp->alias, &mpp->size, params);
dm_get_status(mpp->alias, status);
condlog(3, "status = %s", status);
- disassemble_map(pathvec, params, mpp);
+ disassemble_map(pathvec, params, mpp, 0);
/*
* disassemble_map() can add new paths to pathvec.
* If not in "fast list mode", we need to fetch information
* about them
*/
- if (conf->cmd != CMD_LIST_SHORT)
+ if (cmd != CMD_LIST_SHORT)
update_paths(mpp);
- if (conf->cmd == CMD_LIST_LONG)
+ if (cmd == CMD_LIST_LONG)
mpp->bestpg = select_path_group(mpp);
disassemble_status(status, mpp);
- if (conf->cmd == CMD_LIST_SHORT ||
- conf->cmd == CMD_LIST_LONG)
+ if (cmd == CMD_LIST_SHORT ||
+ cmd == CMD_LIST_LONG) {
+ struct config *conf = get_multipath_config();
print_multipath_topology(mpp, conf->verbosity);
+ put_multipath_config(conf);
+ }
- if (conf->cmd == CMD_CREATE)
+ if (cmd == CMD_CREATE)
reinstate_paths(mpp);
}
return 0;
* 1: Failure
*/
static int
-configure (void)
+configure (enum mpath_cmds cmd, enum devtypes dev_type, char *devpath)
{
vector curmp = NULL;
vector pathvec = NULL;
int di_flag = 0;
char * refwwid = NULL;
char * dev = NULL;
+ struct config *conf;
/*
* allocate core vectors to store paths and multipaths
vecs.pathvec = pathvec;
vecs.mpvec = curmp;
- dev = convert_dev(conf->dev, (conf->dev_type == DEV_DEVNODE));
+ dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
/*
* if we have a blacklisted device parameter, exit early
*/
- if (dev && conf->dev_type == DEV_DEVNODE &&
- conf->cmd != CMD_REMOVE_WWID &&
+ conf = get_multipath_config();
+ if (dev && (dev_type == DEV_DEVNODE ||
+ dev_type == DEV_UEVENT) &&
+ cmd != CMD_REMOVE_WWID &&
(filter_devnode(conf->blist_devnode,
conf->elist_devnode, dev) > 0)) {
- if (conf->cmd == CMD_VALID_PATH)
+ if (cmd == CMD_VALID_PATH)
printf("%s is not a valid multipath device path\n",
- conf->dev);
+ devpath);
+ put_multipath_config(conf);
goto out;
}
+ put_multipath_config(conf);
/*
* scope limiting must be translated into a wwid
* failing the translation is fatal (by policy)
*/
- if (conf->dev) {
- int failed = get_refwwid(conf->dev, conf->dev_type, pathvec,
- &refwwid);
+ if (devpath) {
+ int failed = get_refwwid(cmd, devpath, dev_type,
+ pathvec, &refwwid);
if (!refwwid) {
- condlog(4, "%s: failed to get wwid", conf->dev);
- if (failed == 2 && conf->cmd == CMD_VALID_PATH)
- printf("%s is not a valid multipath device path\n", conf->dev);
+ condlog(4, "%s: failed to get wwid", devpath);
+ if (failed == 2 && cmd == CMD_VALID_PATH)
+ printf("%s is not a valid multipath device path\n", devpath);
else
- condlog(3, "scope is nul");
+ condlog(3, "scope is null");
goto out;
}
- if (conf->cmd == CMD_REMOVE_WWID) {
+ if (cmd == CMD_REMOVE_WWID) {
r = remove_wwid(refwwid);
if (r == 0)
printf("wwid '%s' removed\n", refwwid);
}
goto out;
}
- if (conf->cmd == CMD_ADD_WWID) {
+ if (cmd == CMD_ADD_WWID) {
r = remember_wwid(refwwid);
if (r == 0)
printf("wwid '%s' added\n", refwwid);
* paths to determine if this path should be multipathed. To
* do this, we put off the check until after discovering all
* the paths */
- if (conf->cmd == CMD_VALID_PATH &&
+ if (cmd == CMD_VALID_PATH &&
(!conf->find_multipaths || !conf->ignore_wwids)) {
if (conf->ignore_wwids ||
check_wwids_file(refwwid, 0) == 0)
r = 0;
printf("%s %s a valid multipath device path\n",
- conf->dev, r == 0 ? "is" : "is not");
+ devpath, r == 0 ? "is" : "is not");
goto out;
}
}
/*
* get a path list
*/
- if (conf->dev)
+ if (devpath)
di_flag = DI_WWID;
- if (conf->cmd == CMD_LIST_LONG)
+ if (cmd == CMD_LIST_LONG)
/* extended path info '-ll' */
di_flag |= DI_SYSFS | DI_CHECKER;
- else if (conf->cmd == CMD_LIST_SHORT)
+ else if (cmd == CMD_LIST_SHORT)
/* minimum path info '-l' */
di_flag |= DI_SYSFS;
else
/* maximum info */
di_flag = DI_ALL;
- if (path_discovery(pathvec, conf, di_flag) < 0)
+ if (path_discovery(pathvec, di_flag) < 0)
goto out;
if (conf->verbosity > 2)
get_path_layout(pathvec, 0);
- if (get_dm_mpvec(curmp, pathvec, refwwid))
+ if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
goto out;
filter_pathvec(pathvec, refwwid);
- if (conf->cmd == CMD_VALID_PATH) {
- /* This only happens if find_multipaths is and
+ if (cmd == CMD_VALID_PATH) {
+ /* This only happens if find_multipaths and
* ignore_wwids is set.
* If there is currently a multipath device matching
* the refwwid, or there is more than one path matching
if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
r = 0;
printf("%s %s a valid multipath device path\n",
- conf->dev, r == 0 ? "is" : "is not");
+ devpath, r == 0 ? "is" : "is not");
goto out;
}
- if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
+ if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
r = 0;
goto out;
}
/*
* core logic entry point
*/
- r = coalesce_paths(&vecs, NULL, refwwid, conf->force_reload);
+ r = coalesce_paths(&vecs, NULL, refwwid,
+ conf->force_reload, cmd);
out:
if (refwwid)
}
static int
-dump_config (void)
+dump_config (struct config *conf)
{
char * c, * tmp = NULL;
char * reply;
return 1;
}
c = tmp = reply;
- c += snprint_defaults(c, reply + maxlen - c);
+ c += snprint_defaults(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
if (again) {
reply = REALLOC(reply, maxlen *= 2);
continue;
}
- c += snprint_blacklist(c, reply + maxlen - c);
+ c += snprint_blacklist(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
if (again) {
reply = REALLOC(reply, maxlen *= 2);
continue;
}
- c += snprint_blacklist_except(c, reply + maxlen - c);
+ c += snprint_blacklist_except(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
if (again) {
reply = REALLOC(reply, maxlen *= 2);
continue;
}
- c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
+ c += snprint_hwtable(conf, c, reply + maxlen - c, conf->hwtable);
again = ((c - reply) == maxlen);
if (again) {
reply = REALLOC(reply, maxlen *= 2);
continue;
}
- c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
+ c += snprint_overrides(conf, c, reply + maxlen - c,
+ conf->overrides);
again = ((c - reply) == maxlen);
if (again) {
reply = REALLOC(reply, maxlen *= 2);
continue;
}
if (VECTOR_SIZE(conf->mptable) > 0) {
- c += snprint_mptable(c, reply + maxlen - c,
+ c += snprint_mptable(conf, c, reply + maxlen - c,
conf->mptable);
again = ((c - reply) == maxlen);
if (again)
}
else if (sscanf(dev, "%d:%d", &i, &i) == 2)
return DEV_DEVT;
- else
+ else if (valid_alias(dev))
return DEV_DEVMAP;
+ return DEV_NONE;
}
int
main (int argc, char *argv[])
{
- struct udev *udev;
int arg;
extern char *optarg;
extern int optind;
int r = 1;
+ enum mpath_cmds cmd = CMD_CREATE;
+ enum devtypes dev_type;
+ char *dev = NULL;
+ struct config *conf;
udev = udev_new();
logsink = 0;
- if (load_config(DEFAULT_CONFIGFILE, udev))
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
exit(1);
-
+ multipath_conf = conf;
while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BritquwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
conf->allow_queueing = 1;
break;
case 'c':
- conf->cmd = CMD_VALID_PATH;
+ cmd = CMD_VALID_PATH;
break;
case 'd':
- if (conf->cmd == CMD_CREATE)
- conf->cmd = CMD_DRY_RUN;
+ if (cmd == CMD_CREATE)
+ cmd = CMD_DRY_RUN;
break;
case 'f':
conf->remove = FLUSH_ONE;
break;
case 'l':
if (optarg && !strncmp(optarg, "l", 1))
- conf->cmd = CMD_LIST_LONG;
+ cmd = CMD_LIST_LONG;
else
- conf->cmd = CMD_LIST_SHORT;
+ cmd = CMD_LIST_SHORT;
break;
case 'M':
break;
case 'p':
conf->pgpolicy_flag = get_pgpolicy_id(optarg);
- if (conf->pgpolicy_flag == -1) {
+ if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
printf("'%s' is not a valid policy\n", optarg);
usage(argv[0]);
exit(1);
conf->ignore_wwids = 1;
break;
case 't':
- r = dump_config();
+ r = dump_config(conf);
goto out_free_config;
case 'h':
usage(argv[0]);
exit(0);
case 'u':
- conf->cmd = CMD_VALID_PATH;
- conf->dev_type = DEV_UEVENT;
+ cmd = CMD_VALID_PATH;
+ dev_type = DEV_UEVENT;
break;
case 'w':
- conf->cmd = CMD_REMOVE_WWID;
+ cmd = CMD_REMOVE_WWID;
break;
case 'W':
- conf->cmd = CMD_RESET_WWIDS;
+ cmd = CMD_RESET_WWIDS;
break;
case 'a':
- conf->cmd = CMD_ADD_WWID;
+ cmd = CMD_ADD_WWID;
break;
case ':':
fprintf(stderr, "Missing option argument\n");
exit(1);
}
+ dm_init(conf->verbosity);
if (dm_prereq())
exit(1);
dm_drv_version(conf->version, TGT_MPATH);
dm_udev_set_sync_support(1);
if (optind < argc) {
- conf->dev = MALLOC(FILE_NAME_SIZE);
+ dev = MALLOC(FILE_NAME_SIZE);
- if (!conf->dev)
+ if (!dev)
goto out;
- strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
- if (conf->dev_type != DEV_UEVENT)
- conf->dev_type = get_dev_type(conf->dev);
+ strncpy(dev, argv[optind], FILE_NAME_SIZE);
+ if (dev_type != DEV_UEVENT)
+ dev_type = get_dev_type(dev);
+ if (dev_type == DEV_NONE) {
+ condlog(0, "'%s' is not a valid argument\n", dev);
+ goto out;
+ }
}
- conf->daemon = 0;
- if (conf->dev_type == DEV_UEVENT) {
+ if (dev_type == DEV_UEVENT) {
openlog("multipath", 0, LOG_DAEMON);
setlogmask(LOG_UPTO(conf->verbosity + 3));
logsink = 1;
conf->max_fds, strerror(errno));
}
- if (init_checkers()) {
+ if (init_checkers(conf->multipath_dir)) {
condlog(0, "failed to initialize checkers");
goto out;
}
- if (init_prio()) {
+ if (init_prio(conf->multipath_dir)) {
condlog(0, "failed to initialize prioritizers");
goto out;
}
- dm_init();
- if (conf->cmd == CMD_VALID_PATH &&
- (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
+ if (cmd == CMD_VALID_PATH &&
+ (!dev || dev_type == DEV_DEVMAP)) {
condlog(0, "the -c option requires a path to check");
goto out;
}
- if (conf->cmd == CMD_VALID_PATH &&
- conf->dev_type == DEV_UEVENT) {
+ if (cmd == CMD_VALID_PATH &&
+ dev_type == DEV_UEVENT) {
int fd;
fd = mpath_connect();
if (fd == -1) {
printf("%s is not a valid multipath device path\n",
- conf->dev);
+ dev);
goto out;
}
mpath_disconnect(fd);
}
- if (conf->cmd == CMD_REMOVE_WWID && !conf->dev) {
+ if (cmd == CMD_REMOVE_WWID && !dev) {
condlog(0, "the -w option requires a device");
goto out;
}
- if (conf->cmd == CMD_RESET_WWIDS) {
+ if (cmd == CMD_RESET_WWIDS) {
struct multipath * mpp;
int i;
vector curmp;
goto out;
}
if (conf->remove == FLUSH_ONE) {
- if (conf->dev_type == DEV_DEVMAP) {
- r = dm_suspend_and_flush_map(conf->dev);
+ if (dev_type == DEV_DEVMAP) {
+ r = dm_suspend_and_flush_map(dev);
} else
condlog(0, "must provide a map name to remove");
r = dm_flush_maps();
goto out;
}
- while ((r = configure()) < 0)
+ while ((r = configure(cmd, dev_type, dev)) < 0)
condlog(3, "restart multipath configuration process");
out:
cleanup_prio();
cleanup_checkers();
- if (conf->dev_type == DEV_UEVENT)
+ if (dev_type == DEV_UEVENT)
closelog();
out_free_config:
free_config(conf);
conf = NULL;
udev_unref(udev);
+ if (dev)
+ FREE(dev);
#ifdef _DEBUG_
dbg_free_final(NULL);
#endif
-.TH MULTIPATH.CONF 5 "30 November 2006"
+.TH MULTIPATH.CONF 5 2016-07-08 "Linux"
.SH NAME
-multipath.conf \- multipath daemon configuration file
+multipath.conf \- multipath daemon configuration file.
.SH DESCRIPTION
-.B "multipath.conf"
+.B "/etc/multipath.conf"
is the configuration file for the multipath daemon. It is used to
overwrite the built-in configuration table of \fBmultipathd\fP.
Any line whose first non-white-space character is a '#' is considered
<attribute> <value>
.I "..."
.RE
+.ft B
}
.RE
+.ft B
}
.ft R
.fi
.TP
.B multipaths
This section defines the multipath topologies. They are indexed by a
-\fIWorld Wide Identifier\fR(wwid). For details on the wwid generation
-see section \fBWWID generation\fR below.
+\fIWorld Wide Identifier\fR(WWID). For details on the WWID generation
+see section \fIWWID generation\fR below.
.TP
.B devices
This section defines the device-specific settings.
.LP
.SH "defaults section"
The
-.B defaults
+.I defaults
section recognizes the following keywords:
.TP 17
+.B verbosity
+Default verbosity. Higher values increase the verbosity level. Valid
+levels are between 0 and 6.
+.RS
+.TP
+Default value is: \fB2\fR
+.RE
+.TP
.B polling_interval
-interval between two path checks in seconds. For properly functioning paths,
+Interval between two path checks in seconds. For properly functioning paths,
the interval between checks will gradually increase to
-.B max_polling_interval.
+.I max_polling_interval.
This value will be overridden by the
-.B WatchdogSec
+.I WatchdogSec
setting in the multipathd.service definition if systemd is used.
-Default is
-.I 5
-.TP
-.B max_polling_interval
-maximal interval between two path checks in seconds; default is
-.I 4 * polling_interval
+.RS
.TP
-.B multipath_dir
-directory where the dynamic shared objects are stored; default is system
-dependent, commonly
-.I /lib/multipath
+Default value is: \fB5\fR
+.RE
.TP
-.B find_multipaths
-If set to
-.I yes
-, instead of trying to create a multipath device for every non-blacklisted
-path, multipath will only create a device if one of three condidions are
-met.
-.I 1
-There are at least two non-blacklisted paths with the same wwid,
-.I 2
-the user manually forces the creation, by specifying a device with the multipath
-command, or
-.I 3
-a path has the same WWID as a multipath device that was previously created
-while find_multipaths was set (even if that multipath device doesn't currently
-exist).
-Whenever a multipath device is created with find_multipaths set, multipath will
-remeber the WWID of the device, so that it will automatically create the
-device again, as soon as it sees a path with that WWID. This should allow most
-users to have multipath automatically choose the correct paths to make into
-multipath devices, without having to edit the blacklist; Default is
-.I no
+.B max_polling_interval
+Maximal interval between two path checks in seconds.
+.RS
.TP
-.B verbosity
-default verbosity. Higher values increase the verbosity level. Valid
-levels are between 0 and 6; default is
-.I 2
+Default value is: \fB4 * polling_interval\fR
+.RE
.TP
.B reassign_maps
-enable reassigning of device-mapper maps. With this option multipathd
+Enable reassigning of device-mapper maps. With this option multipathd
will remap existing device-mapper maps to always point to multipath
device, not the underlying block devices. Possible values are
-\fIyes\fR and \fIno\fR. Default is
-.I yes
+\fIyes\fR and \fIno\fR.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
+.TP
+.B multipath_dir
+Directory where the dynamic shared objects are stored.
+.RS
+.TP
+Default value is: \fB<system dependent>\fR, commonly \fI/lib64/multipath/\fR
+.RE
.TP
.B path_selector
The default path selector algorithm to use; they are offered by the
-kernel multipath target. There are three selector algorithms.
+kernel multipath target. There are three selector algorithms:
.RS
.TP 12
-.B "round-robin 0"
+.I "round-robin 0"
Loop through every path in the path group, sending the same amount of IO to
each.
.TP
-.B "queue-length 0"
+.I "queue-length 0"
Send the next bunch of IO down the path with the least amount of outstanding IO.
.TP
-.B "service-time 0"
+.I "service-time 0"
Choose the path for the next bunch of IO based on the amount of outstanding IO
to the path and its relative throughput.
+.TP
+Default value is: \fBservice-time 0\fR
.RE
.TP
.B path_grouping_policy
The default path grouping policy to apply to unspecified
-multipaths. Possible values are
+multipaths. Possible values are:
.RS
.TP 12
-.B failover
-1 path per priority group
+.I failover
+One path per priority group.
.TP
-.B multibus
-all paths in 1 priority group
+.I multibus
+All paths in one priority group.
.TP
-.B group_by_serial
-1 priority group per serial number
+.I group_by_serial
+One priority group per serial number.
.TP
-.B group_by_prio
-1 priority group per priority value. Priorities are determined by
+.I group_by_prio
+One priority group per priority value. Priorities are determined by
callout programs specified as a global, per-controller or
per-multipath option in the configuration file.
.TP
-.B group_by_node_name
-1 priority group per target node name. Target node names are fetched
-in /sys/class/fc_transport/target*/node_name.
+.I group_by_node_name
+One priority group per target node name. Target node names are fetched
+in \fI/sys/class/fc_transport/target*/node_name\fR.
.TP
-Default value is \fIfailover\fR.
+Default value is: \fBgroup_by_prio\fR
.RE
.TP
.B uid_attribute
-The udev attribute providing a unique path
-identifier. Default value is
-.I ID_SERIAL
+The udev attribute providing a unique path identifier.
+.RS
+.TP
+Default value is: \fBID_SERIAL\fR for SCSI devices
+.TP
+Default value is: \fBID_UID\fR for DASD devices
+.RE
.TP
.B getuid_callout
-The default program and args to callout to obtain a unique path
+(Deprecated) The default program and args to callout to obtain a unique path
identifier. Should be specified with an absolute path.
-This parameter is deprecated.
.TP
.B prio
The name of the path priority routine. The specified routine
are implemented:
.RS
.TP 12
-.B const
+.I const
Return a constant priority of \fI1\fR.
.TP
-.B emc
-Generate the path priority for EMC arrays.
+.I sysfs
+Use the sysfs attributes \fIaccess_state\fR and \fIpreferred_path\fR to
+generate the path priority. This prioritizer accepts the optional prio_arg
+.I exclusive_pref_bit
.TP
-.B alua
+.I emc
+(Hardware-dependent)
+Generate the path priority for DGC class arrays as CLARiiON CX/AX and
+EMC VNX families.
+.TP
+.I alua
+(Hardware-dependent)
Generate the path priority based on the SCSI-3 ALUA settings. This prioritizer
-accepts the optional prio_arg
-.I exclusive_pref_bit
+accepts the optional prio_arg \fIexclusive_pref_bit\fR.
.TP
-.B ontap
-Generate the path priority for NetApp arrays.
+.I ontap
+(Hardware-dependent)
+Generate the path priority for NetApp ONTAP class and OEM arrays as IBM NSeries.
.TP
-.B rdac
-Generate the path priority for LSI/Engenio/NetApp E-Series RDAC controller.
+.I rdac
+(Hardware-dependent)
+Generate the path priority for LSI/Engenio/NetApp RDAC class as NetApp E/EF
+Series, and OEM arrays from IBM DELL SGI STK and SUN.
.TP
-.B hp_sw
-Generate the path priority for Compaq/HP controller in
-active/standby mode.
+.I hp_sw
+(Hardware-dependent)
+Generate the path priority for HP/COMPAQ/DEC HSG80 and MSA/HSV arrays with
+Active/Standby mode exclusively.
.TP
-.B hds
+.I hds
+(Hardware-dependent)
Generate the path priority for Hitachi HDS Modular storage arrays.
.TP
-.B random
+.I random
Generate a random priority between 1 and 10.
.TP 12
-.B weightedpath
-Generate the path priority based on the regular expression and the
-priority provided as argument. requires prio_args keyword.
+.I weightedpath
+Generate the path priority based on the regular expression and the
+priority provided as argument. Requires prio_args keyword.
+.TP
+.I datacore
+???. Requires prio_args keyword.
.TP
-Default value is \fBnone\fR.
+.I iet
+???. Requires prio_args keyword.
+.TP
+Default value is: \fBconst\fR
.RE
.TP
.B prio_args
Arguments to pass to to the prio function. This only applies to certain
-prioritizers
+prioritizers:
.RS
.TP 12
-.B weighted
+.I weighted
Needs a value of the form
.I "<hbtl|devname|wwn> <regex1> <prio1> <regex2> <prio2> ..."
.I hbtl
these values can be looked up through sysfs or by running
.I mulitpathd show paths format "%N:%R:%n:%r" Ex: 0x200100e08ba0aea0:0x210100e08ba0aea0:.*:.* , .*:.*:iqn.2009-10.com.redhat.msp.lab.ask-06:.*
.TP
-.B alua
+.I alua
If
.I exclusive_pref_bit
-is set, paths with the TPGS pref bit set will always be in their own path
-group.
+is set, paths with the \fIpreferred path\fR bit set will always
+be in their own path group.
+.TP
+.I datacore
+.I preferredsds
+???.
+.TP
+.I iet
+.I preferredip
+???.
+.TP
+Default value is: \fB<unset>\fR
.RE
.TP
.B features
.I num list
where
.I num
-is the number of features in
+is the number, between 0 and 6, of features in
.I list.
-Possible values for the feature list are
+Possible values for the feature list are:
.RS
.TP 12
-.B queue_if_no_path
+.I queue_if_no_path
Queue IO if no path is active; identical to the
.I no_path_retry
keyword.
.TP
-.B no_partitions
+.I no_partitions
Disable automatic partitions generation via kpartx.
+.TP
+.I pg_init_retries
+Number of times to retry pg_init, it must be between 1 and 50.
+.TP
+.I pg_init_delay_msecs
+Number of msecs before pg_init retry, it must be between 0 and 60000.
+.TP
+Default value is: \fB0\fR
.RE
.TP
.B path_checker
The default method used to determine the paths state. Possible values
-are
+are:
.RS
.TP 12
-.B readsector0
+.I readsector0
(Deprecated) Read the first sector of the device. This checker is being
-deprecated, please use \fIdirectio\fR instead
+deprecated, please use \fItur\fR instead.
.TP
-.B tur
+.I tur
Issue a
.I TEST UNIT READY
command to the device.
.TP
-.B emc_clariion
-Query the EMC Clariion specific EVPD page 0xC0 to determine the path
-state.
+.I emc_clariion
+(Hardware-dependent)
+Query the DGC/EMC specific EVPD page 0xC0 to determine the path state
+for CLARiiON CX/AX and EMC VNX arrays families.
+.TP
+.I hp_sw
+(Hardware-dependent)
+Check the path state for HP/COMPAQ/DEC HSG80 and MSA/HSV arrays with
+Active/Standby mode exclusively.
.TP
-.B hp_sw
-Check the path state for HP storage arrays with Active/Standby firmware.
+.I rdac
+(Hardware-dependent)
+Check the path state for LSI/Engenio/NetApp RDAC class as NetApp E/EF
+Series, and OEM arrays from IBM DELL SGI STK and SUN.
.TP
-.B rdac
-Check the path state for LSI/Engenio/NetApp E-Series RDAC storage controller.
+.I directio
+(Deprecated) Read the first sector with direct I/O. This checker is being
+deprecated, it could cause spurious path failures under high load.
+Please use \fItur\fR instead.
.TP
-.B directio
-Read the first sector with direct I/O.
+.I cciss_tur
+(Hardware-dependent)
+Check the path state for HP/COMPAQ Smart Array(CCISS) controllers.
.TP
-Default value is \fIdirectio\fR.
+Default value is: \fBtur\fR
+.RE
+.TP
+.B alias_prefix
+The \fIuser_friendly_names\fR prefix.
+.RS
+.TP
+Default value is: \fBmpath\fR
.RE
.TP
.B failback
Tell multipathd how to manage path group failback.
.RS
.TP 12
-.B immediate
+.I immediate
Immediately failback to the highest priority pathgroup that contains
active paths.
.TP
-.B manual
+.I manual
Do not perform automatic failback.
.TP
-.B followover
+.I followover
Only perform automatic failback when the first path of a pathgroup
becomes active. This keeps a node from automatically failing back when
another node requested the failover.
.TP
-.B values > 0
-deferred failback (time to defer in seconds)
+.I values > 0
+Deferred failback (time to defer in seconds).
.TP
-Default value is \fImanual\fR.
+Default value is: \fBimmediate\fR
.RE
.TP
.B rr_min_io
The number of IO to route to a path before switching to the next in
-the same path group. This is only for BIO based multipath. Default is
-.I 1000
+the same path group. This is only for BIO based multipath.
+.RS
+.TP
+Default value is: \fB1000\fR
+.RE
.TP
.B rr_min_io_rq
The number of IO requests to route to a path before switching to the
next in the same path group. This is only for request based multipath.
-Default is
-.I 1
+.RS
+.TP
+Default value is: \fB1\fR
+.RE
+.TP
+.B max_fds
+Specify the maximum number of file descriptors that can be opened by multipath
+and multipathd. This is equivalent to ulimit \-n. A value of \fImax\fR will set
+this to the system limit from \fI/proc/sys/fs/nr_open\fR. If this is not set, the
+maximum number of open fds is taken from the calling process. It is usually
+1024. To be safe, this should be set to the maximum number of paths plus 32,
+if that number is greated than 1024.
+.RS
+.TP
+Default value is: \fBmax\fR
+.RE
.TP
.B rr_weight
If set to \fIpriorities\fR the multipath configurator will assign
.I priorities
or
.IR uniform .
-Default is
-.IR uniform .
+.RS
+.TP
+Default value is: \fBuniform\fR
+.RE
.TP
.B no_path_retry
Specify the number of retries until disable queueing, or
for immediate failure (no queueing),
.I queue
for never stop queueing. If unset no queueing is attempted.
-Default is unset.
+.RS
.TP
-.B user_friendly_names
-If set to
-.I yes
-, using the bindings file
-.I /etc/multipath/bindings
-to assign a persistent and unique alias to the multipath, in the form of mpath<n>.
-If set to
+Default value is: \fB<unset>\fR
+.RE
+.TP
+.B queue_without_daemon
+If set to
.I no
-use the WWID as the alias. In either case this be will
-be overridden by any specific aliases in the \fImultipaths\fR section.
-Default is
+, when multipathd stops, queueing will be turned off for all devices.
+This is useful for devices that set no_path_retry. If a machine is
+shut down while all paths to a device are down, it is possible to hang waiting
+for IO to return from the device after multipathd has been stopped. Without
+multipathd running, access to the paths cannot be restored, and the kernel
+cannot be told to stop queueing IO. Setting queue_without_daemon to
.I no
+, avoids this problem.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
+.TP
+.B checker_timeout
+Specify the timeout to use for path checkers and prioritizers that issue SCSI
+commands with an explicit timeout, in seconds.
+.RS
+.TP
+Default value is: in \fB/sys/block/sd<x>/device/timeout\fR
+.RE
.TP
.B flush_on_last_del
If set to
.I yes
, multipathd will disable queueing when the last path to a device has been
-deleted. Default is
-.I no
+deleted.
+.RS
.TP
-.B max_fds
-Specify the maximum number of file descriptors that can be opened by multipath
-and multipathd. This is equivalent to ulimit \-n. A value of \fImax\fR will set
-this to the system limit from /proc/sys/fs/nr_open. If this is not set, the
-maximum number of open fds is taken from the calling process. It is usually
-1024. To be safe, this should be set to the maximum number of paths plus 32,
-if that number is greated than 1024.
+Default value is: \fBno\fR
+.RE
.TP
-.B checker_timeout
-Specify the timeout to use for path checkers and prioritizers that issue scsi
-commands with an explicit timeout, in seconds; default taken from
-.I /sys/block/sd<x>/device/timeout
+.B user_friendly_names
+If set to
+.I yes
+, using the bindings file
+.I /etc/multipath/bindings
+to assign a persistent and unique alias to the multipath, in the form of mpath<n>.
+If set to
+.I no
+use the WWID as the alias. In either case this be will
+be overridden by any specific aliases in the \fImultipaths\fR section.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
.TP
.B fast_io_fail_tmo
-Specify the number of seconds the scsi layer will wait after a problem has been
+Specify the number of seconds the SCSI layer will wait after a problem has been
detected on a FC remote port before failing IO to devices on that remote port.
This should be smaller than dev_loss_tmo. Setting this to
.I off
will disable the timeout.
+.RS
+.TP
+Default value is: in \fB5\fR
+.RE
.TP
.B dev_loss_tmo
-Specify the number of seconds the scsi layer will wait after a problem has
+Specify the number of seconds the SCSI layer will wait after a problem has
been detected on a FC remote port before removing it from the system. This
can be set to "infinity" which sets it to the max value of 2147483647
seconds, or 68 years. It will be automatically adjusted to the overall
\fIno_path_retry\fR * \fIpolling_interval\fR
if a number of retries is given with \fIno_path_retry\fR and the
overall retry interval is longer than the specified \fIdev_loss_tmo\fR value.
-The linux kernel will cap this value to \fI300\fR if \fBfast_io_fail_tmo\fR
-is not set. Default is 600.
+The Linux kernel will cap this value to \fI300\fR if \fIfast_io_fail_tmo\fR
+is not set.
+.RS
.TP
-.B queue_without_daemon
-If set to
-.I no
-, when multipathd stops, queueing will be turned off for all devices.
-This is useful for devices that set no_path_retry. If a machine is
-shut down while all paths to a device are down, it is possible to hang waiting
-for IO to return from the device after multipathd has been stopped. Without
-multipathd running, access to the paths cannot be restored, and the kernel
-cannot be told to stop queueing IO. Setting queue_without_daemon to
-.I no
-, avoids this problem. Default is
-.I no
+Default value is: \fB600\fR
+.RE
.TP
.B bindings_file
-The full pathname of the binding file to be used when the user_friendly_names option is set. Defaults to
-.I /etc/multipath/bindings
+The full pathname of the binding file to be used when the user_friendly_names option is set.
+.RS
+.TP
+Default value is: \fB/etc/multipath/bindings\fR
+.RE
.TP
.B wwids_file
-The full pathname of the wwids file, which is used by multipath to keep track
-of the wwids for LUNs it has created multipath devices on in the past.
-Defaults to
-.I /etc/multipath/wwids
+The full pathname of the WWIDs file, which is used by multipath to keep track
+of the WWIDs for LUNs it has created multipath devices on in the past.
+.RS
+.TP
+Default value is: \fB/etc/multipath/wwids\fR
+.RE
.TP
.B log_checker_err
If set to
, multipathd logs the first path checker error at logging level 2. Any later
errors are logged at level 3 until the device is restored. If set to
.I always
-, multipathd always logs the path checker error at logging level 2. Default is
-.I always
+, multipathd always logs the path checker error at logging level 2.
+.RS
+.TP
+Default value is: \fBalways\fR
+.RE
.TP
.B reservation_key
This is the service action reservation key used by mpathpersist. It must be
set for all multipath devices using persistent reservations, and it must be
the same as the RESERVATION KEY field of the PERSISTENT RESERVE OUT parameter
list which contains an 8-byte value provided by the application client to the
-device server to identify the I_T nexus. It is unset by default.
+device server to identify the I_T nexus.
+.RS
+.TP
+Default value is: \fB<unset>\fR
+.RE
.TP
.B retain_attached_hw_handler
If set to
.I yes
-and the scsi layer has already attached a hardware_handler to the device,
+and the SCSI layer has already attached a hardware_handler to the device,
multipath will not force the device to use the hardware_handler specified by
-mutipath.conf. If the scsi layer has not attached a hardware handler,
-multipath will continue to use its configured hardware handler. Default is
-.I no
+mutipath.conf. If the SCSI layer has not attached a hardware handler,
+multipath will continue to use its configured hardware handler.
+.RS
+.TP
+Default value is: \fByes\fR
+.RE
.TP
.B detect_prio
If set to
.I yes
-, multipath will try to detect if the device supports ALUA. If so, the device
-will automatically use the
+, multipath will try to detect if the device supports SCSI-3 ALUA. If so, the
+device will automatically use the
+.I sysfs
+prioritizer if the required sysfs attributes
+.I access_state
+and
+.I preferred_path
+are supported, or the
.I alua
-prioritizer. If not, the prioritizer will be selected as usual. Default is
+prioritizer if not. If set to
.I no
+, the prioritizer will be selected as usual.
+.RS
+.TP
+Default value is: \fByes\fR
+.RE
.TP
.B force_sync
If set to
.I yes
, multipathd will call the path checkers in sync mode only. This means that
only one checker will run at a time. This is useful in the case where many
-multipathd checkers running in parallel causes significant CPU pressure. The
-Default is
-.I no
+multipathd checkers running in parallel causes significant CPU pressure.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
+.TP
+.B strict_timinig
+If set to
+.I yes
+, multipathd will start a new path checker loop after exactly one second,
+so that each path check will occur at exactly
+.I polling_interval
+seconds. On busy systems path checks might take longer than one second;
+here the missing ticks will be accounted for on the next round.
+A warning will be printed if path checks take longer than
+.I polling_interval
+seconds.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
.TP
.B deferred_remove
If set to
last path device has been deleted. This means that if the multipath device is
still in use, it will be freed when the last user closes it. If path is added
to the multipath device before the last user closes it, the deferred remove
-will be canceled. Default is
-.I no
+will be canceled.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
+.TP
+.B partition_delimiter
+If this value is not set, when multipath renames a device, it will act just
+like the kpartx default does, only adding a \fI"p"\fR to names ending in a
+number. If this parameter is set, multipath will act like kpartx does with
+the \fI-p\fR option is used, and always add delimiter.
+.RS
+.TP
+Default value is: \fB<unset>\fR
+.RE
.TP
.B config_dir
If set to anything other than "", multipath will search this directory
alphabetically for file ending in ".conf" and it will read configuration
-information from them, just as if it was in /etc/multipath.conf. config_dir
-must either be "" or a fully qualified directory name. Default is
-.I "/etc/multipath/conf.d"
+information from them, just as if it was in \fI/etc/multipath.conf\fR.
+config_dir must either be "" or a fully qualified directory name.
+.RS
+.TP
+Default value is: \fB/etc/multipath/conf.d/\fR
+.RE
.TP
.B delay_watch_checks
If set to a value greater than 0, multipathd will watch paths that have
being watched, when they next become valid, they will not be used until they
have stayed up for
.I delay_wait_checks
-checks. Default is
-.I no
+checks.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
.TP
.B delay_wait_checks
If set to a value greater than 0, when a device that has recently come back
checks, the next time it comes back online, it will marked and delayed, and not
used until it has passed
.I delay_wait_checks
-checks. Default is
-.I no
+checks.
+.RS
.TP
-.B strict_timinig
+Default value is: \fBno\fR
+.RE
+.TP
+.B find_multipaths
If set to
.I yes
-, multipathd will start a new path checker loop after exactly one second,
-so that each path check will occur at exactly
-.I polling_interval
-seconds. On busy systems path checks might take longer than one second;
-here the missing ticks will be accounted for on the next round.
-A warning will be printed if path checks take longer than
-.I polling_interval
-seconds.
-Default is
-.I no
+, instead of trying to create a multipath device for every non-blacklisted
+path, multipath will only create a device if one of three condidions are
+met.
+.I 1
+There are at least two non-blacklisted paths with the same WWID,
+.I 2
+the user manually forces the creation, by specifying a device with the multipath
+command, or
+.I 3
+a path has the same WWID as a multipath device that was previously created
+while find_multipaths was set (even if that multipath device doesn't currently
+exist).
+Whenever a multipath device is created with find_multipaths set, multipath will
+remeber the WWID of the device, so that it will automatically create the
+device again, as soon as it sees a path with that WWID. This should allow most
+users to have multipath automatically choose the correct paths to make into
+multipath devices, without having to edit the blacklist.
+.RS
+.TP
+Default value is: \fBno\fR
+.RE
.TP
.B uxsock_timeout
CLI receive timeout in milliseconds. For larger systems CLI commands
might timeout before the multipathd lock is released and the CLI command
can be processed. This will result in errors like
-'timeout receiving packet' to be returned from CLI commands.
+"timeout receiving packet" to be returned from CLI commands.
In these cases it is recommended to increase the CLI timeout to avoid
-those issues. The default is
-.I 1000
+those issues.
+.RS
+.TP
+Default value is: \fB1000\fR
+.RE
+.TP
+.B retrigger_tries
+Sets the number of times multipathd will try to retrigger a uevent to get the
+WWID.
+.RS
+.TP
+Default value is: \fB3\fR
+.RE
+.TP
+.B retrigger_delay
+Sets the amount of time, in seconds, to wait between retriggers.
+.RS
+.TP
+Default value is: \fB10\fR
+.RE
.TP
.B missing_uev_wait_timeout
Controls how many seconds multipathd will wait, after a new multipath device
is created, to receive a change event from udev for the device, before
automatically enabling device reloads. Usually multipathd will delay reloads
-on a device until it receives a change uevent from the initial table load. The
-default is
-.I 30
+on a device until it receives a change uevent from the initial table load.
+.RS
+.TP
+Default value is: \fB30\fR
+.RE
.
.SH "blacklist section"
The
.LP
The following keywords are recognized:
.TP 17
-.B wwid
-The \fIWorld Wide Identification\fR of a device.
-.TP
.B devnode
Regular expression of the device nodes to be excluded.
.TP
+.B wwid
+The \fIWorld Wide Identification\fR of a device.
+.TP
.B property
Regular expression of the udev property to be excluded.
.TP
.B device
Subsection for the device description. This subsection recognizes the
-.I vendor
+.B vendor
and
-.I product
+.B product
keywords. For a full description of these keywords please see the
.I devices
section description.
.I blacklist_exceptions
section is used to revert the actions of the
.I blacklist
-section, ie to include specific device in the
+section, for example to include specific device in the
multipath topology. This allows one to selectively include devices which
would normally be excluded via the
.I blacklist
.LP
The following keywords are recognized:
.TP 17
+.B devnode
+Regular expression of the device nodes to be whitelisted.
+.TP
.B wwid
The \fIWorld Wide Identification\fR of a device.
.TP
.B property
-Regular expression of the udev property to be whitelisted. Defaults to
-.I (ID_WWN|SCSI_IDENT_.*)
+Regular expression of the udev property to be whitelisted.
+.RS
.TP
-.B devnode
-Regular expression of the device nodes to be whitelisted.
+Default value is: \fB(ID_WWN|SCSI_IDENT_.*)\fR
+.RE
.TP
.B device
Subsection for the device description. This subsection recognizes the
-.I vendor
+.B vendor
and
-.I product
+.B product
keywords. For a full description of these keywords please see the
.I devices
section description.
.I property
blacklist and whitelist handling is different from the usual handling
in the sense that the whitelist
-.B has
+.I has
to be set, otherwise the device will be blacklisted.
In these cases the message
.I blacklisted, udev property missing
will be displayed.
.SH "multipaths section"
The only recognized attribute for the
-.B multipaths
+.I multipaths
section is the
.I multipath
subsection.
.LP
The
-.B multipath
+.I multipath
subsection recognizes the following attributes:
.TP 17
.B wwid
-Index of the container. Mandatory for this subsection.
+(Mandatory) Index of the container.
.TP
.B alias
-(Optional) symbolic name for the multipath map.
+(Optional) Symbolic name for the multipath map.
.LP
The following attributes are optional; if not set the default values
are taken from the
.TP
.B rr_weight
.TP
-.B flush_on_last_del
-.TP
.B no_path_retry
.TP
.B rr_min_io
.TP
.B rr_min_io_rq
.TP
+.B flush_on_last_del
+.TP
.B features
.TP
.B reservation_key
.TP
+.B user_friendly_names
+.TP
.B deferred_remove
.TP
.B delay_watch_checks
.LP
.SH "devices section"
The only recognized attribute for the
-.B devices
+.I devices
section is the
.I device
subsection.
subsection recognizes the following attributes:
.TP 17
.B vendor
-(Mandatory) Vendor identifier
+(Mandatory) Vendor identifier.
.TP
.B product
-(Mandatory) Product identifier
+(Mandatory) Product identifier.
.TP
.B revision
-(Optional) Revision identfier
+(Optional) Revision identfier.
.TP
.B product_blacklist
-(Optional) Product strings to blacklist for this vendor
+(Optional) Product strings to blacklist for this vendor.
.TP
.B alias_prefix
(Optional) The user_friendly_names prefix to use for this
-device type, instead of the default "mpath"
+device type, instead of the default "mpath".
.TP
.B hardware_handler
(Optional) The hardware handler to use for this device type.
The following hardware handler are implemented:
.RS
.TP 12
-.B 1 emc
-Hardware handler for EMC storage arrays.
-.TP
-.B 1 rdac
-Hardware handler for LSI/Engenio/NetApp E-Series RDAC storage controller.
-.TP
-.B 1 hp_sw
-Hardware handler for Compaq/HP storage arrays in active/standby
-mode.
-.TP
-.B 1 alua
+.I 1 emc
+(Hardware-dependent)
+Hardware handler for DGC class arrays as CLARiiON CX/AX and EMC VNX families.
+.TP
+.I 1 rdac
+(Hardware-dependent)
+Hardware handler for LSI/Engenio/NetApp RDAC class as NetApp E/EF
+Series, and OEM arrays from IBM DELL SGI STK and SUN.
+.TP
+.I 1 hp_sw
+(Hardware-dependent)
+Hardware handler for HP/COMPAQ/DEC HSG80 and MSA/HSV arrays with
+Active/Standby mode exclusively.
+.TP
+.I 1 alua
+(Hardware-dependent)
Hardware handler for SCSI-3 ALUA compatible arrays.
+.TP
+Default value is: \fB<unset>\fR
.RE
.LP
The following attributes are optional; if not set the default values
.PD
.LP
.SH "WWID generation"
-Multipath uses a \fIWorld Wide Identification\fR (wwid) to determine
+Multipath uses a \fIWorld Wide Identification\fR (WWID) to determine
which paths belong to the same device. Each path presenting the same
-wwid is assumed to point to the same device.
+WWID is assumed to point to the same device.
.LP
-The wwid is generated by three methods (in the order of preference):
+The WWID is generated by three methods (in the order of preference):
.TP 17
.B getuid_callout
Use the specified external program; cf \fIgetuid_callout\fR above.
.B vpd_pg83
If none of the \fIgetuid_callout\fR or \fIuid_attribute\fR parameters
are present multipath will try to use the sysfs attribute
-\fIvpd_pg83\fR to generate the wwid.
+\fIvpd_pg83\fR to generate the WWID.
.SH "KNOWN ISSUES"
The usage of
-.B queue_if_no_path
+.I queue_if_no_path
option can lead to
-.B D state
+.I D state
processes being hung and not killable in situations where all the paths to the LUN go offline.
It is advisable to use the
-.B no_path_retry
+.I no_path_retry
option instead.
.P
The use of
-.B queue_if_no_path
+.I queue_if_no_path
or
-.B no_path_retry
+.I no_path_retry
might lead to a deadlock if the
-.B dev_loss_tmo
+.I dev_loss_tmo
setting results in a device being removed while I/O is still queued.
The multipath daemon will update the
-.B dev_loss_tmo
+.I dev_loss_tmo
setting accordingly to avoid this deadlock. Hence if both values are
specified the order of precedence is
-.I no_path_retry, queue_if_no_path, dev_loss_tmo
+.I no_path_retry, queue_if_no_path, dev_loss_tmo.
.SH "SEE ALSO"
.BR udev (8),
-.BR dmsetup (8)
-.BR multipath (8)
-.BR multipathd (8)
+.BR dmsetup (8),
+.BR multipath (8),
+.BR multipathd (8).
+
.SH AUTHORS
-.B multipath
+.I multipath-tools
was developed by Christophe Varoqui, <christophe.varoqui@opensvc.com> and others.
+++ /dev/null
-#! /bin/sh
-# Copyright (c) 2005 SuSE GmbH Nuernberg, Germany.
-#
-# Author: Hannes Reinecke <feedback@suse.de>
-#
-# init.d/boot.multipath
-#
-### BEGIN INIT INFO
-# Provides: boot.multipath
-# Required-Start: boot.device-mapper boot.udev
-# Required-Stop: boot.device-mapper boot.udev
-# Should-Start: boot.xdrsetsite
-# Should-Stop: boot.xdrsetsite
-# Default-Start: B
-# Default-Stop:
-# Short-Description: Create multipath device targets
-# Description: Setup initial multipath device-mapper targets
-### END INIT INFO
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-PROGRAM=/sbin/multipath
-
-# Set the maximum number of open files
-MAX_OPEN_FDS=4096
-
-# Number of seconds to wait for disks and partitions
-MPATH_DEVICE_TIMEOUT=30
-
-test -x $PROGRAM || exit 5
-
-# Shell functions sourced from /etc/rc.status:
-# rc_check check and set local and overall rc status
-# rc_status check and set local and overall rc status
-# rc_status -v ditto but be verbose in local rc status
-# rc_status -v -r ditto and clear the local rc status
-# rc_failed set local and overall rc status to failed
-# rc_reset clear local rc status (overall remains)
-# rc_exit exit appropriate to overall rc status
-. /etc/rc.status
-
-# First reset status of this service
-rc_reset
-
-# Return values acc. to LSB for all commands but status:
-# 0 - success
-# 1 - misc error
-# 2 - invalid or excess args
-# 3 - unimplemented feature (e.g. reload)
-# 4 - insufficient privilege
-# 5 - program not installed
-# 6 - program not configured
-# 7 - program is not running
-#
-# Note that starting an already running service, stopping
-# or restarting a not-running service as well as the restart
-# with force-reload (in case signalling is not supported) are
-# considered a success.
-
-case "$1" in
- start)
- # Check for existing multipath mappings
- if dmsetup table --target multipath | grep -q multipath ; then
- # Multipath active, start daemon
- exec /etc/init.d/multipathd $1
- fi
-
- echo -n "Creating multipath targets:"
- # Check whether multipath daemon is already running
- if /sbin/multipathd -k"list paths" > /dev/null 2>&1 ; then
- echo -n " (multipathd running)"
- rc_status -v
- rc_exit
- fi
- # Load prerequisite module
- modprobe dm-multipath
-
- # Set the maximum number of open files
- if [ -n "$MAX_OPEN_FDS" ] ; then
- ulimit -n $MAX_OPEN_FDS
- fi
-
- # Start the program directly as checkproc doesn't work here
- $PROGRAM -v 0
- echo -n " (waiting for udev)"
- # Wait for all multipathed devices to appear
- maplist=$(/sbin/dmsetup ls --target multipath | sed '/No devices/d' | sed -n 's/\(^[^ ()]*\)[\t ]*.*/\1/p')
- wait=$MPATH_DEVICE_TIMEOUT
- while [ $wait -gt 0 ] ; do
- num=0
- for map in $maplist; do
- [ -e /dev/disk/by-id/dm-name-$map ] && continue
- num=$((num + 1))
- done
- [ $num -eq 0 ] && break
- wait=$((wait - 1))
- sleep 1;
- done
- if [ $wait -le 0 ] ; then
- echo -n " timeout: $num devices left"
- rc_failed 1
- else
- # Reset to wait for partitions
- wait=$MPATH_DEVICE_TIMEOUT
- fi
- # Wait for all partitions on multipathed devices
- while [ $wait -gt 0 ] ; do
- num=0
- for map in $maplist ; do
- [ -e /dev/disk/by-id/dm-name-$map ] || continue
- partlist=$(/sbin/kpartx -l -p _part /dev/disk/by-id/dm-name-$map | sed 's/\([^ ]*\) :.*/\1/p')
- for part in $partlist; do
- [ -e /dev/disk/by-id/dm-name-$part ] && continue
- num=$((num + 1))
- done
- done
- [ $num -eq 0 ] && break
- wait=$((wait - 1))
- sleep 1;
- done
- if [ $wait -le 0 ] ; then
- echo -n "timeout: $num partitions left"
- rc_failed 1
- fi
-
- # Remember status and be verbose
- rc_status -v
- ;;
- stop)
- echo -n "Removing multipath targets:"
-
- # Flush all existing maps
- $PROGRAM -F
-
- rc_failed 0
- rc_status -v
- ;;
- status)
- echo -n "Checking multipath targets: "
- # Display active multipath tables
- tblnum=$(/sbin/dmsetup ls --target multipath | sed '/No devices/d' | wc --lines)
- if [ "$tblnum" ] && [ $tblnum -gt 0 ] ; then
- echo -n "($tblnum multipath devices) "
- rc_failed 0
- else
- rc_failed 3
- fi
- rc_status -v
- ;;
- restart)
- $0 stop
- $0 start
- ;;
- *)
- echo "Usage: $0 {start|stop|status|restart}"
- exit 1
- ;;
-esac
-rc_exit
ifdef SYSTEMD
CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
endif
-LDFLAGS += -lpthread -ldevmapper -lreadline
+LDFLAGS += -lurcu -lpthread -ldevmapper -lreadline
ifdef SYSTEMD
ifeq ($(shell test $(SYSTEMD) -gt 209 && echo 1), 1)
LDFLAGS += -lsystemd
install:
$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
- $(INSTALL_PROGRAM) -d $(DESTDIR)$(rcdir)
ifdef SYSTEMD
$(INSTALL_PROGRAM) -d $(DESTDIR)$(unitdir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).service $(DESTDIR)$(unitdir)
$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
uninstall:
- rm -f $(DESTDIR)$(bindir)/$(EXEC)
- rm -f $(DESTDIR)$(rcdir)/$(EXEC)
- rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
- rm -f $(DESTDIR)$(unitdir)/$(EXEC).service
- rm -f $(DESTDIR)$(unitdir)/$(EXEC).socket
+ $(RM) $(DESTDIR)$(bindir)/$(EXEC)
+ $(RM) $(DESTDIR)$(mandir)/$(EXEC).8.gz
+ $(RM) $(DESTDIR)$(unitdir)/$(EXEC).service
+ $(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
clean:
- rm -f core *.o $(EXEC) *.gz
-
+ $(RM) core *.o $(EXEC) *.gz
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
-#include <memory.h>
-#include <vector.h>
-#include <structs.h>
-#include <structs_vec.h>
-#include <parser.h>
-#include <util.h>
-#include <version.h>
+#include "memory.h"
+#include "vector.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "parser.h"
+#include "util.h"
+#include "version.h"
#include <readline/readline.h>
#include "cli.h"
}
int
-set_unlocked_handler_callback (unsigned long fp,int (*fn)(void *, char **, int *, void *))
+set_unlocked_handler_callback (uint64_t fp,int (*fn)(void *, char **, int *, void *))
{
struct handler * h = find_handler(fp);
r += add_key(keys, "setprstatus", SETPRSTATUS, 0);
r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0);
r += add_key(keys, "format", FMT, 1);
+ r += add_key(keys, "json", JSON, 0);
if (r) {
free_keys(keys);
pthread_testcancel();
r = h->fn(cmdvec, reply, len, data);
}
- lock_cleanup_pop(vecs->lock);
+ pthread_cleanup_pop(!r);
} else
r = h->fn(cmdvec, reply, len, data);
free_keys(cmdvec);
add_handler(LIST+MAPS+FMT, NULL);
add_handler(LIST+MAPS+RAW+FMT, NULL);
add_handler(LIST+MAPS+TOPOLOGY, NULL);
+ add_handler(LIST+MAPS+JSON, NULL);
add_handler(LIST+TOPOLOGY, NULL);
add_handler(LIST+MAP+TOPOLOGY, NULL);
+ add_handler(LIST+MAP+JSON, NULL);
add_handler(LIST+MAP+FMT, NULL);
add_handler(LIST+MAP+RAW+FMT, NULL);
add_handler(LIST+CONFIG, NULL);
*/
return ((char *)NULL);
}
-
__SETPRSTATUS,
__UNSETPRSTATUS,
__FMT,
+ __JSON,
};
#define LIST (1 << __LIST)
#define SETPRSTATUS (1ULL << __SETPRSTATUS)
#define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS)
#define FMT (1ULL << __FMT)
+#define JSON (1ULL << __JSON)
#define INITIAL_REPLY_LEN 1200
/*
* Copyright (c) 2005 Christophe Varoqui
*/
-#include <checkers.h>
-#include <memory.h>
-#include <vector.h>
-#include <structs.h>
-#include <structs_vec.h>
+#include "checkers.h"
+#include "memory.h"
+#include "vector.h"
+#include "structs.h"
+#include "structs_vec.h"
#include <libdevmapper.h>
-#include <devmapper.h>
-#include <discovery.h>
-#include <config.h>
-#include <configure.h>
-#include <blacklist.h>
-#include <debug.h>
-#include <print.h>
-#include <sysfs.h>
+#include "devmapper.h"
+#include "discovery.h"
+#include "config.h"
+#include "configure.h"
+#include "blacklist.h"
+#include "debug.h"
+#include "print.h"
+#include "sysfs.h"
#include <errno.h>
#include <libudev.h>
-#include <util.h>
+#include "util.h"
#include "main.h"
#include "cli.h"
char * reply;
unsigned int maxlen = INITIAL_REPLY_LEN;
int again = 1;
-
+
get_path_layout(vecs->pathvec, 0);
reply = MALLOC(maxlen);
return 0;
}
+int
+show_maps_json (char ** r, int * len, struct vectors * vecs)
+{
+ int i;
+ struct multipath * mpp;
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN *
+ PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec);
+ int again = 1;
+
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (update_multipath(vecs, mpp->alias, 0)) {
+ return 1;
+ }
+ }
+
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+
+ c += snprint_multipath_topology_json(c, maxlen, vecs);
+ again = ((c - reply) == maxlen);
+
+ REALLOC_REPLY(reply, again, maxlen);
+ }
+ *r = reply;
+ *len = (int)(c - reply);
+ return 0;
+}
+
+int
+show_map_json (char ** r, int * len, struct multipath * mpp,
+ struct vectors * vecs)
+{
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ if (update_multipath(vecs, mpp->alias, 0))
+ return 1;
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+
+ c += snprint_multipath_map_json(c, maxlen, mpp, 1);
+ again = ((c - reply) == maxlen);
+
+ REALLOC_REPLY(reply, again, maxlen);
+ }
+ *r = reply;
+ *len = (int)(c - reply);
+ return 0;
+}
+
int
show_config (char ** r, int * len)
{
char * reply;
unsigned int maxlen = INITIAL_REPLY_LEN;
int again = 1;
+ struct config *conf;
c = reply = MALLOC(maxlen);
+ conf = get_multipath_config();
while (again) {
- if (!reply)
+ if (!reply) {
+ put_multipath_config(conf);
return 1;
+ }
c = reply;
- c += snprint_defaults(c, reply + maxlen - c);
+ c += snprint_defaults(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
if (again)
continue;
- c += snprint_blacklist(c, reply + maxlen - c);
+ c += snprint_blacklist(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
if (again)
continue;
- c += snprint_blacklist_except(c, reply + maxlen - c);
+ c += snprint_blacklist_except(conf, c, reply + maxlen - c);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
if (again)
continue;
- c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
+ c += snprint_hwtable(conf, c, reply + maxlen - c,
+ conf->hwtable);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
if (again)
continue;
- c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
+ c += snprint_overrides(conf, c, reply + maxlen - c,
+ conf->overrides);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
if (again)
continue;
if (VECTOR_SIZE(conf->mptable) > 0) {
- c += snprint_mptable(c, reply + maxlen - c,
+ c += snprint_mptable(conf, c, reply + maxlen - c,
conf->mptable);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
}
+ put_multipath_config(conf);
*r = reply;
*len = (int)(c - reply + 1);
return 0;
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
-
+
param = convert_dev(param, 0);
get_path_layout(vecs->pathvec, 0);
mpp = find_mp_by_str(vecs->mpvec, param);
return show_maps_topology(reply, len, vecs);
}
+int
+cli_list_map_json (void * v, char ** reply, int * len, void * data)
+{
+ struct multipath * mpp;
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
+ param = convert_dev(param, 0);
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ condlog(3, "list multipath json %s (operator)", param);
+
+ return show_map_json(reply, len, mpp, vecs);
+}
+
+int
+cli_list_maps_json (void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+
+ condlog(3, "list multipaths json (operator)");
+
+ return show_maps_json(reply, len, vecs);
+}
+
int
cli_list_wildcards (void * v, char ** reply, int * len, void * data)
{
char * param = get_keyparam(v, PATH);
struct path *pp;
int r;
+ struct config *conf;
param = convert_dev(param, 1);
condlog(2, "%s: add path (operator)", param);
-
+ conf = get_multipath_config();
if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
- param) > 0)
+ param) > 0) {
+ put_multipath_config(conf);
goto blacklisted;
+ }
pp = find_path_by_dev(vecs->pathvec, param);
if (pp) {
condlog(2, "%s: path already in pathvec", param);
- if (pp->mpp)
+ if (pp->mpp) {
+ put_multipath_config(conf);
return 0;
+ }
} else {
struct udev_device *udevice;
- udevice = udev_device_new_from_subsystem_sysname(conf->udev,
+ udevice = udev_device_new_from_subsystem_sysname(udev,
"block",
param);
- r = store_pathinfo(vecs->pathvec, conf->hwtable,
+ r = store_pathinfo(vecs->pathvec, conf,
udevice, DI_ALL, &pp);
udev_device_unref(udevice);
if (!pp) {
+ put_multipath_config(conf);
if (r == 2)
goto blacklisted;
condlog(0, "%s: failed to store path info", param);
}
pp->checkint = conf->checkint;
}
+ put_multipath_config(conf);
return ev_add_path(pp, vecs);
blacklisted:
*reply = strdup("blacklisted\n");
char dev_path[PATH_SIZE];
char *alias, *refwwid;
int rc, count = 0;
+ struct config *conf;
param = convert_dev(param, 0);
condlog(2, "%s: add map (operator)", param);
+ conf = get_multipath_config();
if (filter_wwid(conf->blist_wwid, conf->elist_wwid, param, NULL) > 0) {
+ put_multipath_config(conf);
*reply = strdup("blacklisted\n");
*len = strlen(*reply) + 1;
condlog(2, "%s: map blacklisted", param);
return 1;
}
+ put_multipath_config(conf);
do {
minor = dm_get_minor(param);
if (minor < 0)
if (!alias && !count) {
condlog(2, "%s: mapname not found for %d:%d",
param, major, minor);
- rc = get_refwwid(param, DEV_DEVMAP, vecs->pathvec,
- &refwwid);
+ rc = get_refwwid(CMD_NONE, param, DEV_DEVMAP,
+ vecs->pathvec, &refwwid);
if (refwwid) {
- if (coalesce_paths(vecs, NULL, refwwid, 0))
+ if (coalesce_paths(vecs, NULL, refwwid, 0, 1))
condlog(2, "%s: coalesce_paths failed",
param);
dm_lib_release();
+ FREE(refwwid);
}
} /*we attempt to create device only once*/
count++;
}
rc = ev_add_map(dev_path, alias, vecs);
FREE(alias);
- FREE(refwwid);
return rc;
}
return 1;
}
- return reload_map(vecs, mpp, 0);
+ return reload_map(vecs, mpp, 0, 1);
}
int resize_map(struct multipath *mpp, unsigned long long size,
update_mpp_paths(mpp, vecs->pathvec);
setup_map(mpp, params, PARAMS_SIZE);
mpp->action = ACT_RESIZE;
- if (domap(mpp, params) <= 0) {
+ if (domap(mpp, params, 1) <= 0) {
condlog(0, "%s: failed to resize map : %s", mpp->alias,
strerror(errno));
mpp->size = orig_size;
int
cli_force_no_daemon_q(void * v, char ** reply, int * len, void * data)
{
+ struct config *conf = get_multipath_config();
+
condlog(2, "force queue_without_daemon (operator)");
if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
conf->queue_without_daemon = QUE_NO_DAEMON_FORCE;
+ put_multipath_config(conf);
return 0;
}
int
cli_restore_no_daemon_q(void * v, char ** reply, int * len, void * data)
{
+ struct config *conf = get_multipath_config();
+
condlog(2, "restore queue_without_daemon (operator)");
if (conf->queue_without_daemon == QUE_NO_DAEMON_FORCE)
conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
+ put_multipath_config(conf);
return 0;
}
dm_queue_if_no_path(mpp->alias, 1);
if (mpp->nr_active > 0)
mpp->retry_tick = 0;
- else
+ else {
+ struct config *conf = get_multipath_config();
mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+ put_multipath_config(conf);
+ }
}
return 0;
}
dm_queue_if_no_path(mpp->alias, 1);
if (mpp->nr_active > 0)
mpp->retry_tick = 0;
- else
+ else {
+ struct config *conf = get_multipath_config();
mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+ put_multipath_config(conf);
+ }
}
}
return 0;
char *reply = NULL;
unsigned int maxlen = INITIAL_REPLY_LEN;
int again = 1;
+ struct config *conf = get_multipath_config();
reply = MALLOC(maxlen);
while (again) {
- if (!reply)
+ if (!reply) {
+ put_multipath_config(conf);
return 1;
+ }
c = reply;
- c += snprint_blacklist_report(c, maxlen);
+ c += snprint_blacklist_report(conf, c, maxlen);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
*r = reply;
*len = (int)(c - reply + 1);
+ put_multipath_config(conf);
return 0;
}
char *reply = NULL;
unsigned int maxlen = INITIAL_REPLY_LEN;
int again = 1;
+ struct config *conf = get_multipath_config();
reply = MALLOC(maxlen);
while (again) {
- if (!reply)
+ if (!reply) {
+ put_multipath_config(conf);
return 1;
+ }
c = reply;
- c += snprint_devices(c, maxlen, vecs);
+ c += snprint_devices(conf, c, maxlen, vecs);
again = ((c - reply) == maxlen);
REALLOC_REPLY(reply, again, maxlen);
}
*r = reply;
*len = (int)(c - reply + 1);
+ put_multipath_config(conf);
return 0;
}
int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
int cli_list_map_topology (void * v, char ** reply, int * len, void * data);
int cli_list_maps_topology (void * v, char ** reply, int * len, void * data);
+int cli_list_map_json (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_json (void * v, char ** reply, int * len, void * data);
int cli_list_config (void * v, char ** reply, int * len, void * data);
int cli_list_blacklist (void * v, char ** reply, int * len, void * data);
int cli_list_devices (void * v, char ** reply, int * len, void * data);
int cli_getprstatus(void * v, char ** reply, int * len, void * data);
int cli_setprstatus(void * v, char ** reply, int * len, void * data);
int cli_unsetprstatus(void * v, char ** reply, int * len, void * data);
-
#include <unistd.h>
#include <sys/stat.h>
#include <libdevmapper.h>
-#include <wait.h>
+#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/oom.h>
#include <libudev.h>
+#include <urcu.h>
#ifdef USE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
#include <semaphore.h>
-#include <mpath_cmd.h>
-#include <mpath_persist.h>
#include <time.h>
/*
* libcheckers
*/
-#include <checkers.h>
+#include "checkers.h"
#ifdef USE_SYSTEMD
static int use_watchdog;
/*
* libmultipath
*/
-#include <parser.h>
-#include <vector.h>
-#include <memory.h>
-#include <config.h>
-#include <util.h>
-#include <hwtable.h>
-#include <defaults.h>
-#include <structs.h>
-#include <blacklist.h>
-#include <structs_vec.h>
-#include <dmparser.h>
-#include <devmapper.h>
-#include <sysfs.h>
-#include <dict.h>
-#include <discovery.h>
-#include <debug.h>
-#include <propsel.h>
-#include <uevent.h>
-#include <switchgroup.h>
-#include <print.h>
-#include <configure.h>
-#include <prio.h>
-#include <wwids.h>
-#include <pgpolicies.h>
-#include <uevent.h>
-#include <log.h>
+#include "parser.h"
+#include "vector.h"
+#include "memory.h"
+#include "config.h"
+#include "util.h"
+#include "hwtable.h"
+#include "defaults.h"
+#include "structs.h"
+#include "blacklist.h"
+#include "structs_vec.h"
+#include "dmparser.h"
+#include "devmapper.h"
+#include "sysfs.h"
+#include "dict.h"
+#include "discovery.h"
+#include "debug.h"
+#include "propsel.h"
+#include "uevent.h"
+#include "switchgroup.h"
+#include "print.h"
+#include "configure.h"
+#include "prio.h"
+#include "wwids.h"
+#include "pgpolicies.h"
+#include "uevent.h"
+#include "log.h"
+
+#include "mpath_cmd.h"
+#include "mpath_persist.h"
+
#include "prioritizers/alua_rtpg.h"
#include "main.h"
unsigned int mpath_mx_alloc_len;
int logsink;
+int verbosity;
+int bindings_read_only;
+int ignore_new_devs;
enum daemon_status running_state = DAEMON_INIT;
pid_t daemon_pid;
pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
struct udev * udev;
+struct config *multipath_conf;
+
const char *
daemon_status(void)
{
return rc;
}
+struct config *get_multipath_config(void)
+{
+ rcu_read_lock();
+ return rcu_dereference(multipath_conf);
+}
+
+void put_multipath_config(struct config *conf)
+{
+ rcu_read_unlock();
+}
+
static int
need_switch_pathgroup (struct multipath * mpp, int refresh)
{
struct pathgroup * pgp;
struct path * pp;
unsigned int i, j;
+ struct config *conf;
if (!mpp || mpp->pgfailback == -FAILBACK_MANUAL)
return 0;
/*
* Refresh path priority values
*/
- if (refresh)
- vector_foreach_slot (mpp->pg, pgp, i)
- vector_foreach_slot (pgp->paths, pp, j)
- pathinfo(pp, conf->hwtable, DI_PRIO);
+ if (refresh) {
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ conf = get_multipath_config();
+ pathinfo(pp, conf, DI_PRIO);
+ put_multipath_config(conf);
+ }
+ }
+ }
if (!mpp->pg || VECTOR_SIZE(mpp->paths) == 0)
return 0;
{
struct multipath * ompp;
vector ompv = vecs->mpvec;
- unsigned int i;
+ unsigned int i, reassign_maps;
+ struct config *conf;
+ conf = get_multipath_config();
+ reassign_maps = conf->reassign_maps;
+ put_multipath_config(conf);
vector_foreach_slot (ompv, ompp, i) {
condlog(3, "%s: coalesce map", ompp->alias);
if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
dm_lib_release();
condlog(2, "%s devmap removed", ompp->alias);
}
- } else if (conf->reassign_maps) {
+ } else if (reassign_maps) {
condlog(3, "%s: Reassign existing device-mapper"
" devices", ompp->alias);
dm_reassign(ompp->alias);
vector_foreach_slot (mpp->pg, pgp, i){
vector_foreach_slot (pgp->paths, pp, j){
- if (pp->state == PATH_UNCHECKED ||
+ if (pp->state == PATH_UNCHECKED ||
pp->state == PATH_WILD ||
pp->state == PATH_DELAYED)
continue;
retries = -1;
goto fail;
}
- if (domap(mpp, params) <= 0 && retries-- > 0) {
+ if (domap(mpp, params, 1) <= 0 && retries-- > 0) {
condlog(0, "%s: map_udate sleep", mpp->alias);
sleep(1);
goto retry;
char * refwwid;
struct multipath * mpp;
int map_present;
- int r = 1;
+ int r = 1, delayed_reconfig, reassign_maps;
+ struct config *conf;
map_present = dm_map_present(alias);
/* setup multipathd removed the map */
return 1;
}
+ conf = get_multipath_config();
+ delayed_reconfig = conf->delayed_reconfig;
+ reassign_maps = conf->reassign_maps;
+ put_multipath_config(conf);
if (mpp->wait_for_udev) {
mpp->wait_for_udev = 0;
- if (conf->delayed_reconfig &&
+ if (delayed_reconfig &&
!need_to_delay_reconfig(vecs)) {
condlog(2, "reconfigure (delayed)");
set_config_state(DAEMON_CONFIGURE);
* if we create a multipath mapped device as a result
* of uev_add_path
*/
- if (conf->reassign_maps) {
+ if (reassign_maps) {
condlog(3, "%s: Reassign existing device-mapper devices",
alias);
dm_reassign(alias);
return 1;
}
}
- r = get_refwwid(dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
+ r = get_refwwid(CMD_NONE, dev, DEV_DEVMAP, vecs->pathvec, &refwwid);
if (refwwid) {
- r = coalesce_paths(vecs, NULL, refwwid, 0);
+ r = coalesce_paths(vecs, NULL, refwwid, 0, CMD_NONE);
dm_lib_release();
}
{
struct path *pp;
int ret = 0, i;
+ struct config *conf;
condlog(2, "%s: add path (uevent)", uev->kernel);
if (strstr(uev->kernel, "..") != NULL) {
condlog(3, "%s: reinitialize path", uev->kernel);
udev_device_unref(pp->udev);
pp->udev = udev_device_ref(uev->udev);
- r = pathinfo(pp, conf->hwtable,
+ conf = get_multipath_config();
+ r = pathinfo(pp, conf,
DI_ALL | DI_BLACKLIST);
+ put_multipath_config(conf);
if (r == PATHINFO_OK)
ret = ev_add_path(pp, vecs);
else if (r == PATHINFO_SKIPPED) {
/*
* get path vital state
*/
- ret = alloc_path_with_pathinfo(conf->hwtable, uev->udev,
+ conf = get_multipath_config();
+ ret = alloc_path_with_pathinfo(conf, uev->udev,
DI_ALL, &pp);
+ put_multipath_config(conf);
if (!pp) {
if (ret == PATHINFO_SKIPPED)
return 0;
pthread_testcancel();
ret = store_path(vecs->pathvec, pp);
if (!ret) {
+ conf = get_multipath_config();
pp->checkint = conf->checkint;
+ put_multipath_config(conf);
ret = ev_add_path(pp, vecs);
} else {
condlog(0, "%s: failed to store path info, "
* reload the map for the multipath mapped device
*/
retry:
- ret = domap(mpp, params);
+ ret = domap(mpp, params, 1);
if (ret <= 0) {
if (ret < 0 && retries-- > 0) {
condlog(0, "%s: retry domap for addition of new "
* reload the map
*/
mpp->action = ACT_RELOAD;
- if (domap(mpp, params) <= 0) {
+ if (domap(mpp, params, 1) <= 0) {
condlog(0, "%s: failed in domap for "
"removal of path %s",
mpp->alias, pp->dev);
}
}
if (mpp) {
- retval = reload_map(vecs, mpp, 0);
+ retval = reload_map(vecs, mpp, 0, 1);
condlog(2, "%s: map %s reloaded (retval %d)",
uev->kernel, mpp->alias, retval);
{
int r = 0;
struct vectors * vecs;
+ struct config *conf;
vecs = (struct vectors *)trigger_data;
/*
* path add/remove event
*/
+ conf = get_multipath_config();
if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
- uev->kernel) > 0)
+ uev->kernel) > 0) {
+ put_multipath_config(conf);
goto out;
+ }
+ put_multipath_config(conf);
if (!strncmp(uev->action, "add", 3)) {
r = uev_add_path(uev, vecs);
return r;
}
+static void *rcu_unregister(void *param)
+{
+ rcu_unregister_thread();
+ return NULL;
+}
+
static void *
ueventloop (void * ap)
{
struct udev *udev = ap;
+ pthread_cleanup_push(rcu_unregister, NULL);
+ rcu_register_thread();
if (uevent_listen(udev))
condlog(0, "error starting uevent listener");
-
+ pthread_cleanup_pop(1);
return NULL;
}
static void *
uevqloop (void * ap)
{
+ pthread_cleanup_push(rcu_unregister, NULL);
+ rcu_register_thread();
if (uevent_dispatch(&uev_trigger, ap))
condlog(0, "error starting uevent dispatcher");
-
+ pthread_cleanup_pop(1);
return NULL;
}
static void *
condlog(1, "Failed to init uxsock listener");
return NULL;
}
-
+ pthread_cleanup_push(rcu_unregister, NULL);
+ rcu_register_thread();
set_handler_callback(LIST+PATHS, cli_list_paths);
set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);
set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);
+ set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json);
set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);
set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);
set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);
- set_unlocked_handler_callback(LIST+CONFIG, cli_list_config);
- set_unlocked_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
+ set_handler_callback(LIST+MAP+JSON, cli_list_map_json);
+ set_handler_callback(LIST+CONFIG, cli_list_config);
+ set_handler_callback(LIST+BLACKLIST, cli_list_blacklist);
set_handler_callback(LIST+DEVICES, cli_list_devices);
set_handler_callback(LIST+WILDCARDS, cli_list_wildcards);
set_handler_callback(ADD+PATH, cli_add_path);
umask(077);
uxsock_listen(&uxsock_trigger, ap);
-
+ pthread_cleanup_pop(1);
return NULL;
}
{
struct multipath * mpp;
unsigned int i;
- int timed_out = 0;
+ int timed_out = 0, delayed_reconfig;
+ struct config *conf;
vector_foreach_slot (vecs->mpvec, mpp, i) {
if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
}
}
- if (timed_out && conf->delayed_reconfig &&
+ conf = get_multipath_config();
+ delayed_reconfig = conf->delayed_reconfig;
+ put_multipath_config(conf);
+ if (timed_out && delayed_reconfig &&
!need_to_delay_reconfig(vecs)) {
condlog(2, "reconfigure (delayed)");
set_config_state(DAEMON_CONFIGURE);
struct path *pp1;
struct pathgroup * pgp;
int i, j, changed = 0;
+ struct config *conf;
if (refresh_all) {
vector_foreach_slot (pp->mpp->pg, pgp, i) {
vector_foreach_slot (pgp->paths, pp1, j) {
oldpriority = pp1->priority;
- pathinfo(pp1, conf->hwtable, DI_PRIO);
+ conf = get_multipath_config();
+ pathinfo(pp1, conf, DI_PRIO);
+ put_multipath_config(conf);
if (pp1->priority != oldpriority)
changed = 1;
}
return changed;
}
oldpriority = pp->priority;
- pathinfo(pp, conf->hwtable, DI_PRIO);
+ conf = get_multipath_config();
+ pathinfo(pp, conf, DI_PRIO);
+ put_multipath_config(conf);
if (pp->priority == oldpriority)
return 0;
int update_path_groups(struct multipath *mpp, struct vectors *vecs, int refresh)
{
- if (reload_map(vecs, mpp, refresh))
+ if (reload_map(vecs, mpp, refresh, 1))
return 1;
dm_lib_release();
}
/*
- * Returns '1' if the path has been checked, '0' otherwise
+ * Returns '1' if the path has been checked, '-1' if it was blacklisted
+ * and '0' otherwise
*/
int
check_path (struct vectors * vecs, struct path * pp, int ticks)
int add_active;
int disable_reinstate = 0;
int oldchkrstate = pp->chkrstate;
+ int retrigger_tries, checkint;
+ struct config *conf;
+ int ret;
if ((pp->initialized == INIT_OK ||
pp->initialized == INIT_REQUESTED_UDEV) && !pp->mpp)
if (pp->tick)
return 0; /* don't check this path yet */
+ conf = get_multipath_config();
+ retrigger_tries = conf->retrigger_tries;
+ checkint = conf->checkint;
+ put_multipath_config(conf);
if (!pp->mpp && pp->initialized == INIT_MISSING_UDEV &&
- pp->retriggers < conf->retrigger_tries) {
+ pp->retriggers < retrigger_tries) {
condlog(2, "%s: triggering change event to reinitialize",
pp->dev);
pp->initialized = INIT_REQUESTED_UDEV;
* provision a next check soonest,
* in case we exit abnormaly from here
*/
- pp->tick = conf->checkint;
+ pp->tick = checkint;
newstate = path_offline(pp);
/*
if (newstate == PATH_REMOVED)
newstate = PATH_DOWN;
- if (newstate == PATH_UP)
- newstate = get_state(pp, 1);
- else
+ if (newstate == PATH_UP) {
+ conf = get_multipath_config();
+ newstate = get_state(pp, conf, 1);
+ put_multipath_config(conf);
+ } else
checker_clear_message(&pp->checker);
if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) {
condlog(2, "%s: unusable path", pp->dev);
- pathinfo(pp, conf->hwtable, 0);
+ conf = get_multipath_config();
+ pathinfo(pp, conf, 0);
+ put_multipath_config(conf);
return 1;
}
if (!pp->mpp) {
if (!strlen(pp->wwid) && pp->initialized != INIT_MISSING_UDEV &&
(newstate == PATH_UP || newstate == PATH_GHOST)) {
condlog(2, "%s: add missing path", pp->dev);
- if (pathinfo(pp, conf->hwtable, DI_ALL) == 0) {
+ conf = get_multipath_config();
+ ret = pathinfo(pp, conf, DI_ALL | DI_BLACKLIST);
+ if (ret == PATHINFO_OK) {
ev_add_path(pp, vecs);
pp->tick = 1;
+ } else if (ret == PATHINFO_SKIPPED) {
+ put_multipath_config(conf);
+ return -1;
}
+ put_multipath_config(conf);
}
return 0;
}
/*
* Synchronize with kernel state
*/
- if (update_multipath_strings(pp->mpp, vecs->pathvec)) {
+ if (update_multipath_strings(pp->mpp, vecs->pathvec, 1)) {
condlog(1, "%s: Could not synchronize with kernel state",
pp->dev);
pp->dmstate = PSTATE_UNDEF;
* upon state change, reset the checkint
* to the shortest delay
*/
+ conf = get_multipath_config();
pp->checkint = conf->checkint;
+ put_multipath_config(conf);
if (newstate == PATH_DOWN || newstate == PATH_SHAKY) {
/*
return 0;
}
} else {
+ unsigned int max_checkint;
LOG_MSG(4, checker_message(&pp->checker));
- if (pp->checkint != conf->max_checkint) {
+ conf = get_multipath_config();
+ max_checkint = conf->max_checkint;
+ put_multipath_config(conf);
+ if (pp->checkint != max_checkint) {
/*
* double the next check delay.
* max at conf->max_checkint
*/
- if (pp->checkint < (conf->max_checkint / 2))
+ if (pp->checkint < (max_checkint / 2))
pp->checkint = 2 * pp->checkint;
else
- pp->checkint = conf->max_checkint;
+ pp->checkint = max_checkint;
condlog(4, "%s: delay next check %is",
pp->dev_t, pp->checkint);
}
else if (newstate == PATH_DOWN &&
strlen(checker_message(&pp->checker))) {
- if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
+ int log_checker_err;
+
+ conf = get_multipath_config();
+ log_checker_err = conf->log_checker_err;
+ put_multipath_config(conf);
+ if (log_checker_err == LOG_CHKR_ERR_ONCE)
LOG_MSG(3, checker_message(&pp->checker));
else
LOG_MSG(2, checker_message(&pp->checker));
unsigned int i;
struct itimerval timer_tick_it;
struct timeval last_time;
+ struct config *conf;
+ pthread_cleanup_push(rcu_unregister, NULL);
+ rcu_register_thread();
mlockall(MCL_CURRENT | MCL_FUTURE);
vecs = (struct vectors *)ap;
condlog(2, "path checkers start up");
* init the path check interval
*/
vector_foreach_slot (vecs->pathvec, pp, i) {
+ conf = get_multipath_config();
pp->checkint = conf->checkint;
+ put_multipath_config(conf);
}
/* Tweak start time for initial path check */
condlog(4, "timeout waiting for DAEMON_IDLE");
continue;
}
- strict_timing = conf->strict_timing;
if (vecs->pathvec) {
pthread_cleanup_push(cleanup_lock, &vecs->lock);
lock(vecs->lock);
pthread_testcancel();
vector_foreach_slot (vecs->pathvec, pp, i) {
- num_paths += check_path(vecs, pp, ticks);
+ rc = check_path(vecs, pp, ticks);
+ if (rc < 0) {
+ vector_del_slot(vecs->pathvec, i);
+ free_path(pp);
+ i--;
+ } else
+ num_paths += rc;
}
lock_cleanup_pop(vecs->lock);
}
gettimeofday(&end_time, NULL) == 0) {
timersub(&end_time, &start_time, &diff_time);
if (num_paths) {
+ unsigned int max_checkint;
+
condlog(3, "checked %d path%s in %lu.%06lu secs",
num_paths, num_paths > 1 ? "s" : "",
diff_time.tv_sec, diff_time.tv_usec);
- if (diff_time.tv_sec > conf->max_checkint)
+ conf = get_multipath_config();
+ max_checkint = conf->max_checkint;
+ put_multipath_config(conf);
+ if (diff_time.tv_sec > max_checkint)
condlog(1, "path checkers took longer "
"than %lu seconds, consider "
"increasing max_polling_interval",
}
post_config_state(DAEMON_IDLE);
+ conf = get_multipath_config();
+ strict_timing = conf->strict_timing;
+ put_multipath_config(conf);
if (!strict_timing)
sleep(1);
else {
if (sigwait(&mask, &signo) != 0) {
condlog(3, "sigwait failed with error %d",
errno);
+ conf = get_multipath_config();
conf->strict_timing = 0;
+ put_multipath_config(conf);
break;
}
}
}
+ pthread_cleanup_pop(1);
return NULL;
}
struct path * pp;
vector mpvec;
int i, ret;
+ struct config *conf;
if (!vecs->pathvec && !(vecs->pathvec = vector_alloc()))
return 1;
/*
* probe for current path (from sysfs) and map (from dm) sets
*/
- ret = path_discovery(vecs->pathvec, conf, DI_ALL);
+ ret = path_discovery(vecs->pathvec, DI_ALL);
if (ret < 0)
return 1;
vector_foreach_slot (vecs->pathvec, pp, i){
+ conf = get_multipath_config();
if (filter_path(conf, pp) > 0){
vector_del_slot(vecs->pathvec, i);
free_path(pp);
}
else
pp->checkint = conf->checkint;
+ put_multipath_config(conf);
}
if (map_discovery(vecs))
return 1;
/*
* create new set of maps & push changed ones into dm
*/
- if (coalesce_paths(vecs, mpvec, NULL, 1))
+ if (coalesce_paths(vecs, mpvec, NULL, 1, CMD_NONE))
return 1;
/*
return 0;
}
+void rcu_free_config(struct rcu_head *head)
+{
+ struct config *conf = container_of(head, struct config, rcu);
+
+ free_config(conf);
+}
+
int
reconfigure (struct vectors * vecs)
{
- struct config * old = conf;
- int retval = 1;
+ struct config * old, *conf;
+
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
+ return 1;
/*
* free old map and path vectors ... they use old conf state
if (VECTOR_SIZE(vecs->mpvec))
remove_maps_and_stop_waiters(vecs);
- if (VECTOR_SIZE(vecs->pathvec))
- free_pathvec(vecs->pathvec, FREE_PATHS);
-
+ free_pathvec(vecs->pathvec, FREE_PATHS);
vecs->pathvec = NULL;
- conf = NULL;
/* Re-read any timezone changes */
tzset();
- if (!load_config(DEFAULT_CONFIGFILE, udev)) {
- dm_drv_version(conf->version, TGT_MPATH);
- conf->verbosity = old->verbosity;
- conf->bindings_read_only = old->bindings_read_only;
- conf->ignore_new_devs = old->ignore_new_devs;
- conf->daemon = 1;
- configure(vecs, 1);
- free_config(old);
- retval = 0;
- } else {
- conf = old;
- }
+ dm_drv_version(conf->version, TGT_MPATH);
+ if (verbosity)
+ conf->verbosity = verbosity;
+ if (bindings_read_only)
+ conf->bindings_read_only = bindings_read_only;
+ if (ignore_new_devs)
+ conf->ignore_new_devs = ignore_new_devs;
uxsock_timeout = conf->uxsock_timeout;
- return retval;
+ old = rcu_dereference(multipath_conf);
+ rcu_assign_pointer(multipath_conf, conf);
+ call_rcu(&old->rcu, rcu_free_config);
+
+ configure(vecs, 1);
+
+
+ return 0;
}
static struct vectors *
unsigned long checkint;
#endif
int rc;
+ int pid_fd = -1;
+ struct config *conf;
char *envp;
mlockall(MCL_CURRENT | MCL_FUTURE);
signal_init();
-
- udev = udev_new();
+ rcu_init();
setup_thread_attr(&misc_attr, 64 * 1024, 1);
setup_thread_attr(&uevent_attr, DEFAULT_UEVENT_STACKSIZE * 1024, 1);
log_thread_start(&log_attr);
pthread_attr_destroy(&log_attr);
}
- if (pidfile_create(DEFAULT_PIDFILE, daemon_pid)) {
+ pid_fd = pidfile_create(DEFAULT_PIDFILE, daemon_pid);
+ if (pid_fd < 0) {
condlog(1, "failed to create pidfile");
if (logsink == 1)
log_thread_stop();
condlog(2, "--------start up--------");
condlog(2, "read " DEFAULT_CONFIGFILE);
- if (load_config(DEFAULT_CONFIGFILE, udev))
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
goto failed;
+ if (verbosity)
+ conf->verbosity = verbosity;
+ if (bindings_read_only)
+ conf->bindings_read_only = bindings_read_only;
+ if (ignore_new_devs)
+ conf->ignore_new_devs = ignore_new_devs;
uxsock_timeout = conf->uxsock_timeout;
-
+ multipath_conf = conf;
+ dm_init(conf->verbosity);
dm_drv_version(conf->version, TGT_MPATH);
- if (init_checkers()) {
+ if (init_checkers(conf->multipath_dir)) {
condlog(0, "failed to initialize checkers");
goto failed;
}
- if (init_prio()) {
+ if (init_prio(conf->multipath_dir)) {
condlog(0, "failed to initialize prioritizers");
goto failed;
}
setscheduler();
set_oom_adj();
- conf->daemon = 1;
dm_udev_set_sync_support(0);
#ifdef USE_SYSTEMD
envp = getenv("WATCHDOG_USEC");
conf = NULL;
udev_unref(udev);
udev = NULL;
+ pthread_attr_destroy(&waiter_attr);
#ifdef _DEBUG_
dbg_free_final(NULL);
#endif
#ifdef USE_SYSTEMD
sd_notify(0, "ERRNO=1");
#endif
+ if (pid_fd >= 0)
+ close(pid_fd);
exit(1);
}
int arg;
int err;
int foreground = 0;
+ struct config *conf;
logsink = 1;
- dm_init();
if (getuid() != 0) {
fprintf(stderr, "need to be root\n");
strerror(errno));
umask(umask(077) | 022);
- conf = alloc_config();
-
- if (!conf)
- exit(1);
+ udev = udev_new();
while ((arg = getopt(argc, argv, ":dsv:k::Bn")) != EOF ) {
switch(arg) {
!isdigit(optarg[0]))
exit(1);
- conf->verbosity = atoi(optarg);
+ verbosity = atoi(optarg);
break;
case 's':
logsink = -1;
break;
case 'k':
- if (load_config(DEFAULT_CONFIGFILE, udev_new()))
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
exit(1);
+ if (verbosity)
+ conf->verbosity = verbosity;
uxclnt(optarg, uxsock_timeout + 100);
exit(0);
case 'B':
- conf->bindings_read_only = 1;
+ bindings_read_only = 1;
break;
case 'n':
- conf->ignore_new_devs = 1;
+ ignore_new_devs = 1;
break;
default:
fprintf(stderr, "Invalid argument '-%c'\n",
char * s = cmd;
char * c = s;
- if (load_config(DEFAULT_CONFIGFILE, udev_new()))
+ conf = load_config(DEFAULT_CONFIGFILE);
+ if (!conf)
exit(1);
+ if (verbosity)
+ conf->verbosity = verbosity;
memset(cmd, 0x0, CMDSIZE);
while (optind < argc) {
if (strchr(argv[optind], ' '))
rc = pthread_join(thread, NULL);
return 0;
}
-
.RB [\| options \|]
.SH DESCRIPTION
-The
-.B multipathd
+The
+.B multipathd
daemon is in charge of checking for failed paths. When this happens,
-it will reconfigure the multipath map the path belongs to, so that this map
+it will reconfigure the multipath map the path belongs to, so that this map
regains its maximum performance and redundancy.
-This daemon executes the external multipath config tool when events occur.
-In turn, the multipath tool signals the multipathd daemon when it is done with
+This daemon executes the external multipath config tool when events occur.
+In turn, the multipath tool signals the multipathd daemon when it is done with
devmap reconfiguration, so that it can refresh its failed path list.
.SH OPTIONS
Suppress timestamps. Do not prefix logging messages with a timestamp.
.TP
.B -v "level"
-Verbosity level. Print additional information while running multipathd. A level of 0 means only print errors. A level of 3 or greater prints debugging information as well.
+Verbosity level. Print additional information while running multipathd. A level of 0 means only print errors. A level of 3 or greater prints debugging information as well.
.TP
.B -B
Read-only bindings file. Multipathd will not write to the user_friendly_names
bindings file. If a user_friendly_name doesn't already exist for a device, it
will use its WWID as its alias.
.TP
-.B -k
+.B -k
multipathd will enter interactive mode. From this mode, the available commands can be viewed by entering "help". When you are finished entering commands, press CTRL-D to quit.
.TP
.B -n
The following commands can be used in interactive mode:
.TP
.B list|show paths
-Show the paths that multipathd is monitoring, and their state.
+Show the paths that multipathd is monitoring, and their state.
.TP
.B list|show paths format $format
Show the paths that multipathd is monitoring, using a format string with path
format wildcards.
.TP
.B list|show maps|multipaths
-Show the multipath devices that the multipathd is monitoring.
+Show the multipath devices that the multipathd is monitoring.
.TP
.B list|show maps|multipaths format $format
Show the status of all multipath devices that the multipathd is monitoring,
.TP
.B add path $path
Add a path to the list of monitored paths. $path is as listed in /sys/block (e.g. sda).
-.TP
+.TP
.B remove|del path $path
Stop monitoring a path. $path is as listed in /sys/block (e.g. sda).
.TP
.B add map|multipath $map
-Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa).
+Add a multipath device to the list of monitored devices. $map can either be a device-mapper device as listed in /sys/block (e.g. dm-0) or it can be the alias for the multipath device (e.g. mpath1) or the uid of the multipath device (e.g. 36005076303ffc56200000000000010aa).
.TP
.B remove|del map|multipath $map
Stop monitoring a multipath device.
.TP
.B resize map|multipath $map
Resizes map $map to the given size
-.TP
+.TP
.B switch|switchgroup map|multipath $map group $group
Force a multipath device to switch to a specific path group. $group is the path group index, starting with 1.
.TP
+++ /dev/null
-#!/bin/sh
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-DAEMON=/usr/bin/multipathd
-
-test -x $DAEMON || exit 0
-
-case "$1" in
- start)
- echo -n "Starting multipath daemon: multipathd"
- $DAEMON
- echo "."
- ;;
- stop)
- echo -n "Stopping multipath daemon: multipathd"
- echo "."
- $DAEMON shutdown
- ;;
- force-reload|restart)
- $0 stop
- $0 start
- ;;
- *)
- echo "Usage: /etc/init.d/multipathd {start|stop|restart|force-reload}"
- exit 1
- ;;
-esac
-
-exit 0
+++ /dev/null
-#!/bin/bash
-#
-# multipathd Starts the multipath daemon
-#
-# chkconfig: - 06 87
-# description: Manages device-mapper multipath devices
-
-### BEGIN INIT INFO
-# Provides: multipathd
-# Required-Start:
-# Required-Stop:
-# Default-Start:
-# Default-Stop:
-# Short-Description: Control multipathd
-# Description: This service monitors and manages
-# device-mapper multipath devices
-### END INIT INFO
-
-DAEMON=/sbin/multipathd
-prog=`basename $DAEMON`
-initdir=/etc/rc.d/init.d
-lockdir=/var/lock/subsys
-sysconfig=/etc/sysconfig
-syspath=/sys/block
-
-
-. $initdir/functions
-
-test -r $sysconfig/$prog && . $sysconfig/$prog
-
-RETVAL=0
-
-teardown_slaves()
-{
-pushd $1 > /dev/null
-if [ -d "slaves" ]; then
-for slave in slaves/*;
-do
- if [ "$slave" = "slaves/*" ]; then
- read dev < $1/dev
- tablename=`dmsetup table --target multipath | sed -n "s/\(.*\): .* $dev .*/\1/p"`
- if ! [ -z $tablename ]; then
- echo "Root is on a multipathed device, multipathd can not be stopped"
- exit 1
- fi
- else
- local_slave=`readlink -f $slave`;
- teardown_slaves $local_slave;
- fi
- done
-
-else
- read dev < $1/dev
- tablename=`dmsetup table --target multipath | sed -n "s/\(.*\): .* $dev .*/\1/p"`
- if ! [ -z $tablename ]; then
- echo "Root is on a multipathed device, multipathd can not be stopped"
- exit 1
- fi
-fi
-popd > /dev/null
-}
-
-#
-# See how we were called.
-#
-
-start() {
- test -x $DAEMON || exit 5
- echo -n $"Starting $prog daemon: "
- daemon $DAEMON
- RETVAL=$?
- [ $RETVAL -eq 0 ] && touch $lockdir/$prog
- echo
-}
-
-force_stop() {
- echo -n $"Stopping $prog daemon: "
- killproc $DAEMON
- RETVAL=$?
- [ $RETVAL -eq 0 ] && rm -f $lockdir/$prog
- echo
-}
-
-check_root() {
- root_dev=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $1; }}' /etc/mtab)
- dm_num=`dmsetup info -c --noheadings -o minor $root_dev 2> /dev/null`
- if [ $? -eq 0 ]; then
- root_dm_device="dm-$dm_num"
- [ -d $syspath/$root_dm_device ] && teardown_slaves $syspath/$root_dm_device
- fi
-}
-
-force_queue_without_daemon() {
- $DAEMON forcequeueing daemon
-}
-
-restart() {
- force_queue_without_daemon
- check_root
- force_stop
- start
-}
-
-force_restart() {
- force_queue_without_daemon
- force_stop
- start
-}
-
-reload() {
- echo -n "Reloading $prog: "
- trap "" SIGHUP
- killproc $DAEMON -HUP
- RETVAL=$?
- echo
-}
-
-case "$1" in
-start)
- start
- ;;
-stop)
- check_root
- force_stop
- ;;
-force-stop)
- force_stop
- ;;
-force-reload|reload)
- reload
- ;;
-restart)
- restart
- ;;
-force-restart)
- force_restart
- ;;
-condrestart|try-restart)
- if [ -f $lockdir/$prog ]; then
- restart
- fi
- ;;
-status)
- status $prog
- RETVAL=$?
- ;;
-*)
- echo $"Usage: $0 {start|stop|force-stop|status|restart|force-restart|condrestart|reload}"
- RETVAL=2
-esac
-
-exit $RETVAL
+++ /dev/null
-#! /bin/sh
-# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany.
-#
-# Author: Hannes Reinecke <feedback@suse.de>
-#
-# init.d/multipathd
-#
-### BEGIN INIT INFO
-# Provides: multipathd
-# Required-Start: $syslog
-# Required-Stop: $syslog
-# Default-Start: 3 5
-# Default-Stop: 0 1 2 4 6
-# Short-Description: Starts multipath daemon
-# Description: Starts the multipath daemon
-### END INIT INFO
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-DAEMON=/sbin/multipathd
-PIDFILE=/run/multipathd.pid
-MPATH_INIT_TIMEOUT=10
-ARGS=""
-
-# Set the maximum number of open files
-MAX_OPEN_FDS=4096
-
-# Set to enable asynchronous daemon startup
-DAEMON_ASYNC_STARTUP=
-
-test -x $DAEMON || exit 5
-
-. /etc/rc.status
-
-# First reset status of this service
-rc_reset
-
-case "$1" in
- start)
- echo -n "Starting multipathd"
- ulimit -c unlimited
- if $DAEMON -k"reconfigure" > /dev/null 2>&1 ; then
- echo -n " (multipathd running)"
- rc_status -v
- rc_exit
- fi
-
- modprobe dm-multipath
-
- # Set the maximum number of open files
- if [ -n "$MAX_OPEN_FDS" ] ; then
- ulimit -n $MAX_OPEN_FDS
- fi
-
- $DAEMON $ARGS
-
- if [ -n "$DAEMON_ASYNC_STARTUP" ] ; then
- rc_status -v
- rc_exit
- fi
- # Wait for the daemon to start up
- status=$($DAEMON -k'show daemon' 2> /dev/null)
- timeout=$MPATH_INIT_TIMEOUT
- while [ $timeout -gt 0 ] ; do
- if [ -n "$status" ] ; then
- PID=${status##pid }
- STATUS=${PID##* }
- # Configuration might be taking some time,
- # so don't increase the timeout here
- [ "$STATUS" != "configure" ] && timeout=$(( $timeout - 1 ))
-
- [ "$STATUS" == "running" ] && break
- else
- timeout=$(( $timeout - 1 ))
- fi
- sleep 1
- status=$($DAEMON -k'show daemon' 2> /dev/null)
- done
- if [ -z "$status" ] ; then
- rc_failed 7
- fi
- if [ $timeout -le 0 ] ; then
- rc_failed 1
- fi
- # Remember status and be verbose
- rc_status -v
- ;;
- stop)
- echo -n "Shutting down multipathd"
- STATUS="unknown"
- # Try to get PID from daemon
- status=$($DAEMON -k'show daemon' 2> /dev/null)
- if [ -n "$status" ] ; then
- PID=${status##pid }
- STATUS=${PID##* }
- PID=${PID%% *}
- fi
- # Fallback to PID file for older versions
- if [ -z "$PID" ] || [ "$PID" == "multipath-tools" ] ; then
- if [ -f $PIDFILE ]; then
- PID="$(cat $PIDFILE)"
- STATUS="running"
- else
- rc_failed 7
- rc_status -v
- rc_exit
- fi
- fi
- # Shutdown the daemon via CLI
- if [ "$STATUS" = "running" ] ; then
- status=$($DAEMON -k'shutdown' 2> /dev/null)
- if [ "$status" = "ok" ] ; then
- timeout=$MPATH_INIT_TIMEOUT
- while [ $timeout -gt 0 ] ; do
- PROCNAME="$(ps -p $PID -o comm=)"
- if [ "$PROCNAME" != "multipathd" ] &&
- [ "$PROCNAME" != "multipathd <defunct>" ] ; then
- STATUS="shutdown"
- break
- fi
- sleep 1
- timeout=$(( $timeout - 1 ))
- done
- fi
- fi
- # Kill the daemon if the above failed
- if [ -n "$PID" -a "$STATUS" != "shutdown" ] ; then
- kill -TERM $PID
- timeout=$MPATH_INIT_TIMEOUT
- while [ $timeout -gt 0 ] ; do
- PROCNAME="$(ps -p $PID -o comm=)"
- if [ "$PROCNAME" != "multipathd" ] &&
- [ "$PROCNAME" != "multipathd <defunct>" ] ; then
- STATUS="shutdown"
- break
- fi
- sleep 1
- timeout=$(( $timeout - 1 ))
- done
- fi
- if [ $STATUS != "shutdown" ] ; then
- echo -n " (still running)"
- rc_failed 1
- fi
-
- # Remember status and be verbose
- rc_status -v
- ;;
- try-restart)
- ## Stop the service and if this succeeds (i.e. the
- ## service was running before), start it again.
- $0 status >/dev/null && $0 restart
-
- # Remember status and be quiet
- rc_status
- ;;
- restart|force-reload)
- ## Stop the service and regardless of whether it was
- ## running or not, start it again.
- $0 stop
- $0 start
-
- # Remember status and be quiet
- rc_status
- ;;
- reload)
- ## Like force-reload, but if daemon does not support
- ## signalling, do nothing (!)
-
- $DAEMON -k"reconfigure" > /dev/null 2>&1
-
- # Remember status and be quiet
- rc_status
- ;;
- status)
- echo -n "Checking for multipathd: "
-
- # Status has a slightly different for the status command:
- # 0 - service running
- # 1 - service dead, but /var/run/ pid file exists
- # 2 - service dead, but /var/lock/ lock file exists
- # 3 - service not running
-
- status=$($DAEMON -k'show daemon' 2> /dev/null)
- if [ -n "$status" ]; then
- (exit 0)
- else
- (exit 3)
- fi
- rc_status -v
- ;;
- probe)
- ## Optional: Probe for the necessity of a reload,
- ## give out the argument which is required for a reload.
- ;;
- *)
- echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
- exit 1
- ;;
-esac
-rc_exit
#include <unistd.h> /* for unlink() */
#include <fcntl.h> /* for fcntl() */
-#include <debug.h>
+#include "debug.h"
#include "pidfile.h"
(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
condlog(0, "Cannot open pidfile [%s], error was [%s]",
pidFile, strerror(errno));
- return 1;
+ return -errno;
}
lock.l_type = F_WRLCK;
lock.l_start = 0;
"error was [%s]", pidFile, strerror(errno));
goto fail;
}
- return 0;
+ return fd;
fail:
close(fd);
- return 1;
+ return -errno;
}
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <readline/readline.h>
#include <readline/history.h>
-#include <mpath_cmd.h>
-#include <uxsock.h>
-#include <memory.h>
-#include <defaults.h>
+#include "mpath_cmd.h"
+#include "uxsock.h"
+#include "memory.h"
+#include "defaults.h"
-#include <vector.h>
+#include "vector.h"
#include "cli.h"
static void print_reply(char *s)
process_req(fd, inbuf, timeout);
else
process(fd, timeout);
-
+ mpath_disconnect(fd);
return 0;
}
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <sys/time.h>
#include <signal.h>
-#include <checkers.h>
-#include <memory.h>
-#include <debug.h>
-#include <vector.h>
-#include <structs.h>
-#include <structs_vec.h>
-#include <uxsock.h>
-#include <defaults.h>
-#include <config.h>
-#include <mpath_cmd.h>
+#include "checkers.h"
+#include "memory.h"
+#include "debug.h"
+#include "vector.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "uxsock.h"
+#include "defaults.h"
+#include "config.h"
+#include "mpath_cmd.h"
#include "main.h"
#include "cli.h"
return NULL;
}
- if (!conf) {
- condlog(1, "uxsock: configuration changed");
- return NULL;
- }
-
pthread_cleanup_push(uxsock_cleanup, NULL);
condlog(3, "uxsock: startup listener");
extern volatile sig_atomic_t log_reset_sig;
#endif
-