r291 - in multipath-tools/trunk: . devmap_name kpartx libcheckers
libmultipath multipath multipathd path_priority/pp_alua
path_priority/pp_balance_units path_priority/pp_emc
path_priority/pp_netapp path_priority/pp_random path_priority/pp_tpc
Bastian Blank
waldi at costa.debian.org
Mon Mar 13 15:16:47 UTC 2006
Author: waldi
Date: Mon Mar 13 15:16:41 2006
New Revision: 291
Added:
multipath-tools/trunk/kpartx/dasd.c
multipath-tools/trunk/kpartx/dasd.h
multipath-tools/trunk/kpartx/mac.c
multipath-tools/trunk/kpartx/mac.h
multipath-tools/trunk/libcheckers/checkers.c
multipath-tools/trunk/libcheckers/directio.h
multipath-tools/trunk/libcheckers/emc_clariion.h
multipath-tools/trunk/libcheckers/hp_sw.h
multipath-tools/trunk/libcheckers/readsector0.h
multipath-tools/trunk/libcheckers/tur.h
multipath-tools/trunk/libmultipath/configure.c
multipath-tools/trunk/libmultipath/configure.h
multipath-tools/trunk/libmultipath/structs_vec.c
multipath-tools/trunk/libmultipath/structs_vec.h
multipath-tools/trunk/path_priority/pp_netapp/
multipath-tools/trunk/path_priority/pp_netapp/Makefile
multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c
multipath-tools/trunk/path_priority/pp_tpc/
multipath-tools/trunk/path_priority/pp_tpc/Makefile
multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c
Removed:
multipath-tools/trunk/libcheckers/path_state.h
multipath-tools/trunk/libcheckers/selector.c
multipath-tools/trunk/libmultipath/cache.c
multipath-tools/trunk/libmultipath/cache.h
Modified:
multipath-tools/trunk/ (props changed)
multipath-tools/trunk/ChangeLog
multipath-tools/trunk/FAQ
multipath-tools/trunk/Makefile.inc
multipath-tools/trunk/README
multipath-tools/trunk/TODO
multipath-tools/trunk/devmap_name/Makefile
multipath-tools/trunk/devmap_name/devmap_name.c
multipath-tools/trunk/kpartx/Makefile
multipath-tools/trunk/kpartx/byteorder.h
multipath-tools/trunk/kpartx/devmapper.c
multipath-tools/trunk/kpartx/devmapper.h
multipath-tools/trunk/kpartx/dos.c
multipath-tools/trunk/kpartx/kpartx.c
multipath-tools/trunk/kpartx/kpartx.h
multipath-tools/trunk/libcheckers/Makefile
multipath-tools/trunk/libcheckers/checkers.h
multipath-tools/trunk/libcheckers/directio.c
multipath-tools/trunk/libcheckers/emc_clariion.c
multipath-tools/trunk/libcheckers/hp_sw.c
multipath-tools/trunk/libcheckers/readsector0.c
multipath-tools/trunk/libcheckers/tur.c
multipath-tools/trunk/libmultipath/Makefile
multipath-tools/trunk/libmultipath/alias.c
multipath-tools/trunk/libmultipath/blacklist.c
multipath-tools/trunk/libmultipath/blacklist.h
multipath-tools/trunk/libmultipath/callout.c
multipath-tools/trunk/libmultipath/callout.h
multipath-tools/trunk/libmultipath/config.c
multipath-tools/trunk/libmultipath/config.h
multipath-tools/trunk/libmultipath/debug.c
multipath-tools/trunk/libmultipath/debug.h
multipath-tools/trunk/libmultipath/defaults.c
multipath-tools/trunk/libmultipath/defaults.h
multipath-tools/trunk/libmultipath/devmapper.c
multipath-tools/trunk/libmultipath/devmapper.h
multipath-tools/trunk/libmultipath/dict.c
multipath-tools/trunk/libmultipath/dict.h
multipath-tools/trunk/libmultipath/discovery.c
multipath-tools/trunk/libmultipath/discovery.h
multipath-tools/trunk/libmultipath/dmparser.c
multipath-tools/trunk/libmultipath/dmparser.h
multipath-tools/trunk/libmultipath/hwtable.c
multipath-tools/trunk/libmultipath/log.c
multipath-tools/trunk/libmultipath/log_pthread.c
multipath-tools/trunk/libmultipath/parser.c
multipath-tools/trunk/libmultipath/parser.h
multipath-tools/trunk/libmultipath/pgpolicies.c
multipath-tools/trunk/libmultipath/pgpolicies.h
multipath-tools/trunk/libmultipath/print.c
multipath-tools/trunk/libmultipath/print.h
multipath-tools/trunk/libmultipath/propsel.c
multipath-tools/trunk/libmultipath/propsel.h
multipath-tools/trunk/libmultipath/structs.c
multipath-tools/trunk/libmultipath/structs.h
multipath-tools/trunk/libmultipath/switchgroup.c
multipath-tools/trunk/libmultipath/uevent.c
multipath-tools/trunk/libmultipath/uevent.h
multipath-tools/trunk/libmultipath/uxsock.c
multipath-tools/trunk/libmultipath/vector.c
multipath-tools/trunk/multipath-tools.spec.in
multipath-tools/trunk/multipath.conf.annotated
multipath-tools/trunk/multipath.conf.synthetic
multipath-tools/trunk/multipath/Makefile
multipath-tools/trunk/multipath/main.c
multipath-tools/trunk/multipath/main.h
multipath-tools/trunk/multipath/multipath.rules
multipath-tools/trunk/multipathd/Makefile
multipath-tools/trunk/multipathd/cli.c
multipath-tools/trunk/multipathd/cli.h
multipath-tools/trunk/multipathd/cli_handlers.c
multipath-tools/trunk/multipathd/cli_handlers.h
multipath-tools/trunk/multipathd/main.c
multipath-tools/trunk/multipathd/main.h
multipath-tools/trunk/multipathd/uxclnt.c
multipath-tools/trunk/multipathd/uxlsnr.c
multipath-tools/trunk/path_priority/pp_alua/Makefile
multipath-tools/trunk/path_priority/pp_balance_units/Makefile
multipath-tools/trunk/path_priority/pp_emc/Makefile
multipath-tools/trunk/path_priority/pp_random/Makefile
Log:
Merge /multipath-tools/upstream/current (0.4.7).
Modified: multipath-tools/trunk/ChangeLog
==============================================================================
--- multipath-tools/trunk/ChangeLog (original)
+++ multipath-tools/trunk/ChangeLog Mon Mar 13 15:16:41 2006
@@ -1,1068 +1,6 @@
-2005-05-23 multipath-tools-0.4.5
+Change logs are at :
- * [libmultipath] default_prio and prio_callout keyword can be
- explicitly set to "none". Suggested by Kiyoshi Ueda, NEC
- * [path_prio] don't exit pp_balance_units with error when
- find_controler() is not successful. It just means no other
- path is currently active on this controler.
- * [path_prio] move balance_units in its own dir
- * [multipathd] proactively fail_path upon checker up->down
- transitions. Suggested by Edward Goggin, EMC
- * [libmultipath] .priority is clearly an int, not an unsigned
- int. /bin/false is now personna non grata as a prio callout.
- Kiyoshi Ueda, NEC
- * [libmultipath] callout.c argv parsing fix. Kiyoshi Ueda,
- NEC
- * [multipathd] check return codes in init_paths(), split out
- init_event().
- * [libmultipath] add find_slot(vec, addr) to vector lib.
- * [multipath] remove signal sending
- * [multipathd] use uevent to do paths list housekeeping for
- checkers. Remove signal handling.
- * [libmultipath] add uevent.[ch]
-
-2005-04-23 multipath-tools-0.4.4
-
- * [path_prio] clarify pp_alua licensing. Stefan Bader, IBM.
- * [devmap_name] add a target_type filter (suggested by Hannes)
- and set DM task device by major:minor rather than parsing
- the full map list.
- * [libmultipath] propagate an error on getprio callout
- failures, so that multipath can mark the map as immutable.
- Reported by Lars Marowsky-Brée, Suse.
- * [libmultipath] move push_callout() from dict.c to config.c
- Use it in store_hwe() to get in multipathd's ramfs the
- callout defined in hwtable.c when no config file is used.
- Reported by Lars Marowsky-Brée, Suse.
- * [checkers] zero sense buffers before use in EMC checker.
- Lars Marowsky-Brée, Suse.
- * [all] pre-release bugfixing effort from Alasdair, Hannes,
- Lars, Benjamin Marzinski
- * [multipathd] set oom_adj to -17 when kernel permits.
- Immune to OOM killer ? agk says : watch out for mem
- leaks :/
- * [multipathd] safety nets from udevd : exit early if
- not root, chdir to / to avoid pining a mount.
- * [multipathd] multipathd could loose events coming from
- sighup or DM waitev. Add a pending_event counter to
- track that.
- * [path_prio] add pp_emc from Lars M Bree, Suse.
- * [path_prio] add pp_alua from Stefan Bader, IBM.
- * [libmultipath] add config.c:load_config(), which sucks
- a big chunk of code out of multipath/main.c.
- * [libmultipath] don't allocate memory in :
- * devmapper.c:dm_get_map()
- * devmapper.c:dm_get_status()
- * [libmultipath] devinfo() a la carte fetching
- * [libmultipath] merge keepalived memory audit framework
- (Thanks again, M. Cassen). Already found and fixed a
- couple of leaks.
- * [libmultipath] flatten/optimize dm_map_present() and
- dm_mapname(). Inspired by Alasdair Kergon, RedHat.
- * [kpartx] dm_map_name() free before use bugfix. Kiyoshi
- Ueda, NEC
- * [kpartx] add hotplug mode. To enable name the binary
- "kpartx.dev". Kiyoshi Ueda, NEC
- * [multipathd] don't loose events in event waiter thread.
- Suggested and prototyped by Edward Goggin, EMC
- * [libmultipath] add return values to vector manipulation
- fonctions. Mem alloc return code audit.
- * [libmultipath] Use "config->udev_dir + path->dev" as
- a path devnode to open instead of mknod'ing for each
- one. Fix some DoS issues regarding usage of /tmp in
- libmultipath/discovery.c:opennode(). Kill unlinknode()
- * [multipathd] merged the redhat init script and stop
- installing one on "make install"
- * [libmultipath] fold safe_sprintf.h into util.h
- * [libmultipath] move blacklist to a real regex matcher
- Example config files updated : check yours !!
- * [multipath] fix path group compare logic to not stop
- comparing at first path in each PG.
- * [multipathd] check if pidfile is a dead remnent of a
- crashed daemon. If so, overwrite it. Suggested by
- Alasdair Kergon, RedHat. Code heavily based on work
- by Andrew Tridgell, Samba Fame.
- * [build] dropped libdevmapper/ and libsysfs/ from the
- package. klibc build is now broken until distributors
- provide klibc compiled static libraries in their
- respective packages.
- * [libmultipath] dm_task_no_open_count() before each DM
- ioctl. Not doing that is reported to cause deadlocks
- in kernel-space. Reported by Edward Goggin, EMC, fix
- suggested by Alasdair Kergon, RedHat
- Note minimal libdevmapper version bumped up to 1.01.
- * [multipath] switched to condlog(). "make DEBUG=N" is
- deprecated. Debug is spat with "-v3" or more.
- * [multipathd] "multipathd -vN" cmdline arg to control
- daemon verbosity. 0 < N < 4. "make LOGLEVEL=N" is
- deprecated.
- * [libmultipath] provide a common condlog() primitive to
- switch lib messages to syslog or stdout depending on
- who uses the lib (daemon or tool).
- * [kpartx] give kpartx a private, slim copy of devmap.[ch]
- * [multipath] allow wwid in blacklist{} config section.
- Kiyoshi Ueda, NEC.
- * [multipathd] set mode value before use (S_IRWXU). Fixes
- RedHat Bugzilla Bug 150665.
- * [all] add ->fd to "struct path *". remove fd from all
- checker context declaration. remove lots of duplicate
- logic. Now a fd is opened only once for path. It should
- also bring a bit safety in contended memory scenarii
- * [libcheckers] remove redundant sg_include.h
- * [libmultipath] merge multipath:dict.[ch] with
- multipathd:dict.[ch] into libmultipath/. move config.h
- there too, add some helper functions to alloc/free
- "struct config *" in a new config.c. Start using a
- config in the daemon.
- * [libmultipath] move dm_geteventnr(), dm_get_maps() and
- dm_switchgroup() in devmapper.[ch]
- * [libmultipath] move path discovery logic in
- libmultipath. merge devinfo.[ch] and sysfs_devinfo.[ch]
- into discovery.[ch]
- * [libmultipath] move config.h in libmultipath. Move
- find_[mp|hw]e in a new config.c. Move "struct hwtable"
- declaration in config.h. Move propsel.[ch] in the
- lib too.
- * [multipathd] use libmultipath:dm_type() instead of
- duplacate and bogus devmap discovery code.
- * [multipathd] asynchronous & non-blocking logger
- thread. Implementation split into a generic log
- lib and a pthread wrapper for locking and events.
- An ipc wrapper could be easily created by
- interested parties.
- * [multipath] add "multipath -l -v2 [devname|devt]"
- support in complement to [mapname|wwid]
- * [kpartx] suppress loop.h private copy. Should fix
- the reported build problems
- * [multipath] do sysfs_get_mnt_path() only one time
- and store in a global var.
- * [multipath] further path discovery optimzation
- * [multipath] purge superfluous includes in main.c
- * [libmultipath] introduce a cache file. expiry set
- to 5 secondes to covert the hotplug event storms.
- * [multipath] split get_pathvec_sysfs(). Introduce
- get_refwwid() and filter_pathvec()
-
-2005-03-19 multipath-tools-0.4.3
-
- * [libmultipath] rename find_[mp|hw] to find_[mp|hw]e and
- introduce a real find_mp().
- * [priority] provison for recursive compilation of prio
- subdirs, in preparation of merging more signicant
- prioritizers. Stephan Bader, IBM
- * [libmultipath] add a netapp controler to the hwtable
- * [libmultipath] blacklist() not to discard sda[0-9]*
- when sda is blacklisted
- * [multipath] add a rr_min_io keyword in config file.
- Suggested by Igor Feoktistov, NetApp
- * [multipath] stop trying to avoid running in parallel
- * [multipath] bump up params size to 1024
- * [multipathd] put prio callouts in to ramfs. Stephan
- Bader, IBM
- * [multipath] simplify multibus pgpolicy : no need to
- copy mp->paths into mp->pg->paths then free source :
- just copy the ptr and set source to NULL.
- * [multipath] sort PG by descending prio value in
- group_by_prio. Stephan Bader, IBM
- * [multipath] fix a bug in group_by_prio that lead to
- creation of multiple PG for a single prio value
- * [multipath] don't store multipaths in a vector anymore :
- free the "struct multipath" after usage.
- * [multipath] multiple optimizations in the exec plan
- * [multipath] allow "multipath -l -v2 [mapname|wwid]"
- * [build] rip off klibc and move to klcc, at last.
- Good job hpa. multipath-tools now depend on klibc
- > 1.0 to build with BUILD=klibc flag.
- * [multipath] never reload a map if no path is up in the
- computed new map
- * [multipath] don't flush maps with open count != 0
- * [libmultipath] add "int *dm_get_opencount(char *map)"
- to devmapper.c
- * [multipath] plug leaks and optimize devinfo.c. From
- Edward Goggin, EMC
- * [multipath] fix the multipath.dev hotplug script to not
- do kpartx stuff in the same run as multipath stuff.
- Igor Feoktistov, NetApp, noted the devmap symlink was
- not yet present for kpartx to use.
- * [devmap_name] accept major:minor synthax
- * [libmultipath] add "char *dm_mapname(int maj, int min)",
- needed to fail paths from checker thread
- * [libmultipath] move dm_reinstate() in the lib, and add
- dm_fail_path()
- * [multipathd] mark failed path as failed upon DM
- event. This should fix the design bug noticed by
- Ramesh Caushik, Intel, where the daemon didn't run
- multipath when a path went down and up in between 2
- checks.
- * [libmultipath] allow NULL as a pathvec in disassemble_map
- as is passed only for memory optimization
- * [libmultipath] add structs.c to store alloc_*() and
- free_*()
- * [libmultipath] move dmparser.[ch] to the lib.
- remove devinfo.[ch] dependency.
- * [build] fix compilation glitch with BUILD=klibc,
- flags to force use of local libs, remove the link
- dependency in klibc, try to guess kernel sources
- and build dirs. Stefan Bader, IBM
- * [libmultipath] find_hw matching logic to take str
- lengths in account. Noticed by Ramesh Caushik, Intel
- * [multipath] select_action matching logic to take str
- length in account.
- * [multipath] lookup mp alias name earlier (in coalesce)
- Edward Goggin, EMC, noticed we tried to use it before
- it was set up.
-
-2005-01-23 multipath-tools-0.4.2
-
- * [libmultipath] add symmetrix controler family to the
- hwtable. Edward Goggin, EMC
- * [libmultipath] factorize core structs (path, ...)
- and defaults (pidfile, configfile, ...). Convert
- callers.
- * [multipath] fix dmparser to properly fetch non-default
- hwhandler. Edward Goggin, EMC
- * [multipath] fix devt2devname matching 8:1 with 8:10
- for example. Edward Goggin, EMC
- * [multipath] switch_pg upon devmap create or reload
- Noticed by Ake.
- * [libmultipath] move find_hw() the library. Convert
- users. Now multipathd understand '*' as a product
- string
- * [multipath] dissaemble_map() fix to avoid to
- interpret 'D' as a disable PG (not 'F'). Edward
- Goggin, EMC
- * [multipath] find_path() fix to avoid matching 8:1
- with 8:10 for example. Edward Goggin, EMC
- * [libmultipath] move some sysfs fetching routines
- to library, under sysfs_devinfo.[ch]. Convert
- callers.
- * [multipath] fix -v0 : avoids the daemon waiting
- for the initial multipath run to complete, which
- will never happen because of a flooded pipe
- * [multipathd] add scsi_id to default binvec
- * [libmultipath] move hwtable related logic to the
- library. Convert multipath and multipathd
- * [multipath] move first blacklist call down after
- setup_default_blist()
- * [libmultipath] move basename() to the lib. Convert
- multipath and multipathd.
- * [libmultipath] move blacklist related logic to the
- library. Convert multipath and multipathd
- * [multipath] fix bug in the default hardware table
- matching logic (Lars M-B, Suse)
- * [multipath] allow "*" as scsi model string wildcard
- (Lars M-B, Suse)
- * [multipath] provide a macro to fill all hwe fields,
- use it to declare Clariion models (Lars M-B, Suse)
- * [multipath] use DEFAULT_GETUID instead of hardcoded
- *and* incorrect "/bin/scsi_id -g -s" (Lars M-B, Suse)
- * [multipath] kill superfluous suspend before table
- reload. The code was unsafe, as spotted by Edward
- Goggin (EMC)
- * [multipath] exit early if device parameter is
- blacklisted
- * [multipath] don't check for prefix in initrd's
- multipath.dev : this is the tool responsability to
- exit early based on its blacklist.
- * [multipath] don't signal the daemon in initrd
- (Guido Guenther, Debian tracker)
- * [multipath] better fail to run kpartx in initrd
- than crashing the whole system. So don't sleep
- waiting for udev to create the DM node. Maybe udev
- has made progress I this regard ... (noticed by
- Paul Wagland, Debian tracker)
- * [multipath] don't reinstate when listing, ie list
- implies dry_run
- * [checkers] fix the emc checker (Hergen Lange)
- * [multipath] node_name fetching shouldn't exit on
- error. FC SAN are not the only multipathed context
- (noticed by Ramesh Caushik)
-
-2004-12-20 multipath-tools-0.4.1
-
- * [multipath] bump SERIAL_SIZE to 19
- * [multipath] add a new group_by_node_name pgpolicy
- * [multipath] move getopt policy parser to
- get_policy_id()
- * [multipath] remove get_evpd_wwid()
- * [checkers] fix the wwn_set test in emc checker
- (Hergen Lange)
- * [checkers] treat the emc checker in the name to
- index translator function (Hergen Lange)
- * [multipath] print to stderr DM unmet requirement
- (Guido Guenther)
- * [multipath] fix realloc return value store not
- propagated to caller by merge_word() (Nicola Ranaldo)
-
-2004-12-10 multipath-tools-0.4.0
-
- * [checkers] forgot to return back to caller the newly
- allocated context. Lead to fd leak notably.
- * [checkers] heavy check logic fix
- * [checkers] really malloc the checker context size,
- not the pointer size (stupidy may kill)
- * [multipathd] check more sysfs calls return values
- * [multipathd] search for sysfs mount point only once,
- not on each updatepaths() iteration
- * [multipathd] plug (char *) leak in the daemon
- * [multipath] change pgcmp logic : we want to reload a
- map only if a path is in computed map but not in cur
- map (ie accept to load a map if it brings more paths)
- * [multipath] undust coalesce_paths()
- * [multipath] don't print unchanged multipath
- * [multipath] store the action to take in the multipath
- struct
- * [multipath] print mp size with kB, MB, GB or TB units
- * [multipath] compilation fix for merge_words() (Andy)
- * [multipath] don't feed the kernel DM maps with paths of
- different sizes : DM fails and we end up with an empty
- map ... not fun
- * [multipath] cover a new corner case : path listed in
- status string but disappeared from sysfs
- * [multipath] remove the "-D" command line flag : now
- we can pass major:minor directly as last argument, like
- device names or device map names. Update multipathd
- accordingly.
- * [multipath] try reinstate again paths after a switchpg
- * [multipath] reinstate condition change :
-
-2004-12-05 multipath-tools-0.3.9
-
- * [multipath] add a "-l" flag to list the current
- multipath maps and their status info
- * [priority] zalloc controler to avoid random path_count
- at allocation time
- * [multipath] add configlet pointers in struct multipath
- to avoid searching for an entry over and over again
- * [multipath] new reinstate policy : on multipath exec,
- reinstate all failed paths the checkers report as ready
- if they belong to enabled path groups (not disabled, not
- active path group)
- * [multipath] fork a print_mp() out of print_all_mp()
- * [multipath] introduce PG priority, which is the sum of
- its path priorities. Set first_pg in the map string to
- the highest prio PG index.
- * [multipath] assemble maps scaning PG top down now that
- PG vector is unsorted
- * [multipath] move select_*() to propsel.c
- * [multipath] move devinfo() to devinfo.c
- * [multipath] move h/b/t/l fetching to sysfs_devinfo()
- * [multipath] move devt2devname() to devinfo.c so we can
- use it from dmparser.c too
- * [multipath] introduce select_alias() and clarify a bit
- of code
- * [multipath] don't sort PG anymore. We want the map as
- static as possible.
- * [multipath] fix a segfault in apply_format() triggered
- when no config file found.
- * [multipath] kill unused vars all over the place
- * [multipath] add a struct pathgroup in struct multipath
- Store the pathvec in it. We now have a place to store
- PG status, etc ...
- * [multipath] new dmparser.c, with disassemble_map(),
- disassemble_status()
- * [multipath] suppress *selector_args keywords. Merge
- in the selector string. Update config file templates.
-
-2004-11-26 multipath-tools-0.3.8
-
- * [priority] teach multipath to read callout keywords
- formatted as /sbin/scsi_id -g -u -s /block/%n
- Apply one substitutions out of :
- * %n : blockdev basename (ie sdb)
- * %d : blockdev major:minor string (ie 8:16)
- update sample config files
- * [priority] fix find_controler(). Now works, verified
- on IBM T200 at OSDL (thanks again, Dave). Add to the
- main build process
- * [multipath] add a controler specific "prio_callout"
- keyword. Noticed by Ake
- * [multipath] normalize the debug ouput
- * [multipath] add select_getuid(). De-spaghetti
- devinfo() thanks to that helper.
- * [libmultipath] add VECTOR_LAST_SLOT macro.
- multipath/dict.h now use it heavily.
- * [multipath] policies selectors speedup and cleanup
- (pgpolicy, features, hwhandler, selector)
- * [multipath] new "flush" command flag
- * [libmultipath] add dm_type() and dm_flush_maps()
- * [multipath] move dm_get_map() to libmultipath
- * [multipath] rename iopolicy to pgpolicy everywhere.
- Dual terminology was getting confusing.
- * [multipath] assemble_map() to always set next_pg to 1
- for now.
- * [multipath] update config file to show new keywords.
- Add an IBM array tested at OSDL.
- * [multipath] fork select_iopolicy() from setup_map()
- * [multipath] introduce select_features() and
- select_hwhandler(). Should merge select_* one day ...
- * [multipath] add features and hardware_handler keywords
- and use them in the map setup
- * [build] make clean really clean. Noticed by Dave Olien,
- OSDL
- * [multipath] group_by_serial bugfix
- * [multipath] dm_addmap() return value fix. Now multipath
- really creates the maps
- * [multipath] try dm_log_init_verbose() instead of dup()
- + close() to silence libdevmapper (Ake at umu)
- * [libcheckers] remove checkpath() wrapper, obsoleted by
- the "fd in context" changes
- * [multipathd] let pathcheckers allocate their context.
- No more over or unneeded allocation. Suggested by Lars,
- Suse
- * [multipathd] store the pathcheckers fd in their context.
- No more open / close on each check. Suggested by Lars,
- Suse
-
-2004-11-05 multipath-tools-0.3.7
-
- * [multipathd] fix off by one memory allocation (Hannes,
- Suse)
- * [multipathd] introduce a default callout handler that
- just remembers to put the callout in ramfs, even if the
- daemon has no direct use of them. multipath need some
- that where forgotten, so parse them and use that default
- handler.
- * [libcheckers] emc_clariion checker update (Lars, Suse)
- * [build] exit build process on failure (Lars, Suse)
- * [kpartx] exit early if DM prereq not met
- * [multipath] exit early if DM prereq not met
- * [libmultipath] new dm_prereq() fn to check out if all DM
- prerequisites are met
- * [libmultipath] move callout.[ch] function in there.
- multipath and multipathd impacted
- * [libmultipath] move dm_* function in there. kpartx,
- multipath are impacted
- * [priority] pp_balance_lun should use DM_DEVICE_TABLE ioctl
- instead of DM_DEVICE_STATUS to find out paths from the
- primary path groups.
- * [klibc] drop in "Stable" version 0.190
- * [build] add manpages for kpartx and multipathd (Patrick
- Caulfield)
- * [build] use system's sysfs for multipathd linking
- * [build] make glibc the default build
- * [build] "make BUILD=klibc" is enough, deprecate the
- "make BUILD=klibc klibc" synthax
-
-2004-10-30 multipath-tools-0.3.6
-
- * Patrick Caulfield took over debian packaging. Showing
- evident expertise, his first wish is to see debian/
- disappear. :) So be it.
- * [libmultipath] add a vector_foreach_slot macro. Still
- needs an iterator but saves 1 line per loop occurence and
- tame this UPPERCASE MACROS bad taste.
- * [multipathd] don't load sg anymore on multipathd startup
- * [multipathd] change killall for kill `cat $PIDFILE` in
- init script (Jaime Peñalba & Cesar Solera)
- * [multipathd] the fork fallback was borked (just exiting)
- noticed by Jaime Peñalba & Cesar Solera
- * [multipathd] try without the FLOATING_STACKS flag. Does
- it matter anyway ?
- * [multipathd] merge clone_platform.h from LTP and cover
- the hppa special case.
- * [multipath] since we will be able to create a devmap with
- paths too small, don't rely anymore on the first path's
- size blindly : verify the path is up, before assigning its
- size to the multipath
- * [priority] add a path priority fetcher to balance LU accross
- controlers based on the controler serial detection. Untested
- but provides a good example of what can be done with the
- priority framework.
- * [priority] create subdir and drop a test pp_random
- * [multipath] add dev_t reporting to print_path() to ease
- devmap decoding by humans
- * [multipath] change default path priority to 1
- * [multipath] add wits to the sort_by_prio policy, so that
- sort_pathvec_by_prio() is now useless. Remove it.
- * [multipath] invert sort_pg_by_summed_prio sort order :
- highest prio leftmost
- * [libmultipath] add vector_del_slot
- * revert multipath.rules change : devmap_name still takes
- "major minor" and not "major:minor" as argument
- * Makefile refinement : you can now enter any tool directory
- and build from here, deps are solved
-
-2004-10-26 multipath-tools-0.3.5
-
- * [multipathd] fix broken test for path going up or shaky
- that kept executing multipath when it shouldn't
- * change multipath.dev to exit early when udev' DEVNAME is
- a devmap (/dev/dm-*). This avoids a recursion case when
- the kernel devmapper keeps removing a map after multipath
- configures it.
- * change multipath.rules to follow the new -D synthax
- * [multipath] "-D major minor" synthax changed to
- "-D major:minor" to match the sysfs attribute value.
- This change removes a few translations in multipath and
- multipathd.
- * [multipath] fix segfault in test if conf->dev is a devmap
- (the one forwarded by MikeAnd)
- * SG_IO ioctl seem to work in lk 2.6.10+, so remove all sg
- device knowledge and advertise (here) the new dependency.
- * [multipath] remove unused do_tur()
- * [multipath] fix sort_pg_by_summed_prio(), and don't add up
- failed path priority
-
-2004-10-26 multipath-tools-0.3.4
-
- * [multipathd] exec multipath precisely : pass in the path
- or the devmap to update. No more full reconfiguration, and
- really use the reinstate feature of multipath.
- * [multipathd] check all paths, not only failed ones. Path
- checker now trigger on state change (formerly triggred on
- state == UP condition)
- * [multipathd] incremental updatepaths() instead of scrap /
- refresh all logic.
- * [multipathd] path checkers now take *msg and *context
- params. consensus w/ lmb at suse. tur.c modified as example
- * [multipath] assemble maps in PG vector descending order to
- fit the layered policies design
- * [multipath] stop playing with strings in pgpolicies, as it
- uses more memory and looses info for no gain
- * [multipath] remove lk2.4 scsi ioctl scsi_type remnant
- * [multipath] layered pgpolicies : (see pgpolicies.c)
- * group_by_status
- * group_by_serial | multibus | failover | group_by_prio
- * sort_pg_by_summed_prio
- thus remove duplicated failedpath logic in pgpolicies
- * [libmultipath] add vector_insert_slot
- * [checkers] framework for arbitrate checkers return values
- * [multipathd] scrap yet another reinvented wheel in the
- name of the LOG macro : learn the existance of setloglevel
- and LOG_UPTO macro
- * glibc make with "make BUILD=glibc", asked by lmb at suse
-
-2004-10-20 multipath-tools-0.3.3
-
- * [checkers] add the emc_clariion path checker (lmb at Suse)
- * [multipath] introduce safe_snprintf macro to complement the
- safe_sprintf. Needed to cover the sizeof(pointer) cases
- pointed by Dave Olien at OSDL
- * [multipath] move to the common libchecker framework and
- activate the selector
- * [multipath] fix an iopolicy selector bug (initialized lun
- iopolicy overrode controler-wide iopolicy)
- * [multipathd] cleanly separate out the checker selector, as
- done with iopolicy selector
- * [multipathd] move out the checkers into a common libcheckers
- * [multipath] fix the anti-parallel-exec logic : use a write
- lease for the task. From Dave Olien at osdl.
- * [multipath] fix reinstate : pass a devt, not a devname
-
-2004-10-16 multipath-tools-0.3.2
-
- * [multipath] add path reinstate logic :
- * if a path is given as multipath arg
- * if the map containing that path already exists
- * if this map is the same as the that would be
- created by this multipath run
- * THEN reinstate the path
- multipathd is is thus unchanged, while now supporting
- reinstate
- * audit and ensafe all sprintf usage
- * [multipath] fix the annoying \n after each dev_t in
- params string reporting
- * [multipath] print out devmaps in "-v2 -d" mode
- * [kpartx] bump up the params string size (lmb at suse)
- * [kpartx] replace sprintf by snprintf (lmb at suse)
- * [kpartx] initialize some more vars (lmb at suse)
- * [multipath] mp->pg == NULL safety net before calling
- assemble_map() (for Andy who happen to hit the bug)
- * [multipath] last rampant bug in map CREATE or UPDATE switch
- logic due to the device alias feature
- * [kpartx] zeroe "struct slice all" (lmb at suse)
-
-2004-10-11 multipath-tools-0.3.1
-
- * [kpartx] move back to getopt, originaly removed from the
- original partx because of lack of implementation in klibc
- * [kpartx] don't map extended partitions
- * [kpartx] add a -p command flag to allow admin to force a
- delimiting string between disk name and part number. When
- specified always use it, when unspecified use 'p' as a delim
- when last char of disk name is a digit, NUL otherwise.
- * [kpartx] clean up
- * bump klibc to 0.182
- * one step further : use klibc MCONFIG for all klibc specific
- FLAGS definitions, ie massive Makefile.inc cleanup
- * follow the klibc compilation rules by appending its OPTFLAGS
- to multipath-tools' CFLAGS. This corrects the segfaults seen
- on i386 where klibc is built with regparm=3 and tools are not
- * [multipathd] fall back to fork when clone not available
- like in Debian Woody
- * [kpartx] move .start and .size from uint to ulong (Ake)
- * briefly document system-disk-on-multipath in the FAQ file
-
-2004-10-06 multipath-tools-0.3.0
-
- * first cut at making scripts to create multipath-aware initrds
- those scripts are tested on Debian SID, and must be copied into
- /etc/mkinitrd/scripts. it works here.
- * [multipath] verify presence of the /sys/block/... node before
- reading sysfs attributes. Avoids libsysfs and scsi_id stderr
- garbage
- * [multipath] move down the stderr close (Ake Sandgren at umu.se)
- * [multipath] don't care about 0-sized mp (Ake Sandgren at umu.se)
- * [multipath] bump mp size field to ulong (Ake Sandgren at umu.se)
- * [multipath] replace quiet/verbose flags by a verbosity one.
- introduce a new verbosity level : 1 == print only devmap names
- thus we can feed kpartx with that output
- * [multipath] update man page to reflect the hotplug.d -> dev.d
- transition and replace the obsolete group_by_tur policy by the
- forgotten group_by_prio
- * [multipath] provide a /etc/udev/rules.d/multipath.rules for
- multipath devices naming. Cleaner than the previously suggested
- rule addition in the main udev.rules
- * [multipath] move out of hotplug.d to dev.d : kill synchronisation
- problems between device node creation and multipath execution.
- Incidentally the unfriendly $DEVPATH param become a friendly
- $DEVNAME (simply /dev/sdb)
- * [multipath] rework the iopolicies name-to-id & id-to-name
- translations. kills the last compilation warning here too
- * [kpartx] kill last compilation warnings
- * bump klibc to 0.181
- * add the debian/ packaging dir (make deb)
- * prototype __clone & __clone2
-
-2004-09-24 multipath-tools-0.2.9
-
- * [multipathd] finally tame the clone compilation glitch on IA64
- move from sys_clone to __clone / __clone2
- * [kpartx] rework from Stephan Bader, IBM :
- * handle s390x arch
- * endianness fixes
- * push the partname string size to handle wwwids
- * quieten implicit cast warnings
- * [multipath] add an 'alias' multipath keyword for friendlier device
- names. This was "asked" by OSDL' CGL board of secret reviewers
- * [multipath] last pass with JBOD and parallel SCSI support :
- hard-code scsi_id as a fallback when disk strings doesn't match
- any hwtable entry
- * [multipath & multipathd] change the parser to not coalesce
- consecutive spaces (Patrick Mansfield)
- * [multipath] remove the [UN]: output prefix, so that stdout can be
- easily fed to a tool like dmsetup
- * [multipathd] DEBUG=3 logs more readable/usefull
- * [multipathd] add a multipath_tool config keyword
- * [multipathd] move to execute_program() like multipath already did
- * [multipath] don't print the "no path" msg in quiet mode
- * [multipathd] include linux/unistd.h for _syscall2
- definition on RedHat systems. Remove superfluous
- asm/unistd.h include
- * [libsysfs] forked : last version uses mntent, which
- klibc doesn't provide. That, plus the fact we use
- only 1/3 of the lib, pushed me to freeze the version
- and strip all unused stuff.
- * [multipathd] prepare_namespace() cleanup : no more "multipath"
- special casing since we push it to binvec vector, like the other
- callouts detected in the config file.
-
-2004-08-13 multipath-tools-0.2.8
-
- * [multipathd] setsched prio to RT
- * [multipath] massive include cleanup
- * [multipath] add a "prio_callout" keyword
- first user will be SPC-3 ALUA priority field fetcher
- from IBM
- * [multipath] reenable stdout on some error paths
- * [build] spilt KERNEL_DIR into KERNEL_SOURCE &
- KERNEL_BUILD as per 2.6 and SuSe convention
- * [klibc] kill warnings due to awk parsing wrong locale in
- arch/i386/MCONFIG
- * [multipath] implement a generic group_by_prio pgpolicy
- * [multipath] fix the broken failover pgpolicy
-
-2004-07-24 multipath-tools-0.2.7
-
- * [multipath] args parser moved to getopt
- <genanr at emsphone.com>
- * [multipath] zero conf->hotplugdev at allocation
- <genanr at emsphone.com>
- * [multipath] clean up failed devmap creation attempt
- * [libs] update to libdevmapper 1.00.19
- * [multipath] framework for claimed device skipping
- still lacks a reliable way to know if the device is
- claimed and by who (fs, swap, md, dm, ...). If you
- think it is valid to let libdevmapper hit the wall,
- please speak up and tell so.
- * [multipath] shut down stderr when calling into libdm
- * [multipath] reformat the verbose output
- * [multipath] framework for path priority handling (ALUA)
- * [multipath] kill all reference to group_by_tur
- * [multipath] integrate path state logic into multibus &
- failover pgpolicies. This obsoletes the group_by_tur one
- which is now the same as multibus.
- * [multipath] zalloc mp structs to avoid garbage in ->size
- * bump version requisite for scsi_id to 0.6 to support the new
- '-u' flag (s/ /_/ for proper JBOD device map naming)
- * [multipath] correct the for(;;) limits to accept 1-slot
- pathvecs
- * [multipath] push WWID_SIZE to 64 char (scsi_id w/ JBODs)
- * [multipath] add a exit_tool() wrapper fn for runfile unlink
- * [multipath] add a "path_grouping_policy" keyword in the
- "defaults" block.
- * [multipath] add a "getuid_callout" keyword in the
- "defaults" block. Now multipath is going to work with JBODs
- * [multipath] fix segfault when pathvec is empty after
- get_pathvec()
- * move to template based specfile to avoid regular version skew
-
-2004-07-16 multipath-tools-0.2.6
-
- * [multipathd] implement the system-disk-on-SAN safety net
- * [multipathd] add exit_daemon() wrapper function
- * [multipathd] mlockall() all daemon threads
- * [multipath] fix a bug in the mp_iopolicy_handler that kept
- the iopolicy per LUN override from working
- * [multipath] display the tur bit value in print_path
- as requested by SUN
- * try to open /$udev/reverse/$major:$minor before falling back
- to mknod
- * add "udev_dir" to the defaults block in the config file
- * merge "daemon" & "device_maps" config blocks into a new
- "defaults" block
- * [multipath] properly comment the config file
- * [multipath] generalize the dbg() macro usage
- Makefile now has a DEBUG flag
- * [multipath] move to callout based WWID fetching. Default to
- scsi_id callout. I merged execute_program from udev for that
- (so credit goes to GregKH)
- * [multipath] get rid of "devnodes in /dev" assumption
- ie move to "maj:min" device mapper target synthax
-
-2004-07-10 multipath-tools-0.2.5
-
- * [multipathd] fix misbehaviour noted by <genanr at emsphone.com>
- improper tar directive in Makefile on some systems
- * [multipathd] fix bug noted by <genanr at emsphone.com>
- get_devmaps fills a private vector and forget to pass its
- address to caller
- * [multipath] extend EVPD 0x83 id fetching logic.
- Code borrowed from scsi_id (thanks goes to Patrick
- Mansfield @IBM) and merged by Hannes Reinecke @SUSE
- * [multipathd] fix regression noted by <genanr at emsphone.com>
- (segfault when no config file)
-
-2004-06-20 multipath-tools-0.2.4
-
- * [multipathd] break free from system's libsysfs for now
- as it is not that common these days
- * [multipath] introduce per LUN policies in the config
- file : path_grouping_policy, path_selector and
- path_selector_args are supported.
- See updated sample config file.
- * [multipath] move ->iopolicy to multipath struct (from
- path struct)
- * [multipath] fill the voids left in the config file with
- defaults
- * [multipath] group config & flags in a global struct *
- * [multipath] fix segfault when no config file (was a
- regression since hwtable vectorisation in 0.2.2)
- * [multipath] default path selector override in config file
- * [multipath] don't play with strings in pgpolicies, leave
- that to a new assemble_map fn. policies now use vector
- * [multipathd] compilation fix for gentoo (Franck Denis)
- * [multipath] strcmp fix (Franck Denis)
-
-2004-06-14 multipath-tools-0.2.3
-
- * [multipath] group_by_serial try to be smart with LUN
- balancing across controlers (for STK / LSI) :
- 1st multipath : 1st pg made of path through 1st controler
- 2nd multipath : 1st pg made of path through 2nd controler
- 3rd multipath : 1st pg made of path through 1st controler
- ...
- * [multipath] drop .pindex[] in struct multipath in favor
- of a *paths vector : much cleaner
- * [multipath] fix group_by_serial pgpolicy broken by
- vectorisation in 0.2.2
- * add a StorageTek array in the sample multipath.conf
- * [multipathd] strcmp fix from Franck Denis
- * [multipathd] convert to vector api
- * [multipathd] add a configfile option for path checking
- interval. See sample configfile for synthax.
-
-2004-06-07 multipath-tools-0.2.2
-
- * [multipath] leave out 2.4 compat code. Is there
- interest anyway ?
- * [multipath] convert all_paths table to vector api.
- Rename to pathvec. Get rid of max_devs
- * [multipath] convert mp table to vector api
- * convert blacklist to vector api
- * 2.6.7-rc? adds _user annotations to scsi/sg.h, causing
- compilation breakage. Add a "#define _user" in all
- sg_include.h (and remove cruft)
- * merge a real parser (from keepalived) courtesy of
- Alexandre Cassen. Now multipath and multipathd share a
- config file. This comes with a nice vector lib.
- * devnode blacklist moved from hardcoded to config file
- * Guy Coates noted -O2 CFLAGS lead to multipathd crashes
- on IA64. Remove the needless optimisation for now.
-
-2004-06-05 multipath-tools-0.2.1
-
- * [multipath] add a flag to inihibit the final SIGHUP to
- multipathd. Needed to avoid recursion with the correction
- below
- * [multipathd] devmap event now triggers a multipath exec
- in addition to the usual updatepaths()
- * [multipathd] move checkers from sg_io on BLK onto CHR
- readsector0 goes from read to sg_read
- * [multipathd] rely on sysfs for failedpaths enum and no
- longer on the device mapper
- * [multipathd] convert get_lun_strings from ioctl to sysfs
- so we can benefit from strings persistency for failed
- paths
- * [multipath] readconfig() to take only 8 char from vendor
- string (ake)
- * [multipath] remove unecessery and wrong getuid == NULL
- check from devinfo() (ake)
- * [multipathd] make readsector0 open path O_DIRECT
- * [multipathd] sizeof(path) -> sizeof(struct path) (MikeC)
- * [Makefile] don't try to install and uninstall libs
- * [devmap_name] kill the wrong trailing '\n'
- (Mike Christie)
- * [kpartx] works with device nodes outside /dev
- * [kpartx] correctly display the delimiter in partition
- name outputs
-
-2004-05-17 multipath-tools-0.2.0
-
- * change the default klibc by greg's :
- corrects the segfaults reported by Ling Hwa Hing
-
-2004-05-16 multipath-tools-0.1.9
-
- * break free from udev : package klibc and libsysfs
- * add a spec file and a "make rpm" rule
- * pensum on klibc changes needed :
- * mmap.c & fork.c : invert includes
- * make clean wipes .*.d
- * auto create the linux symlink
- * remove tools and specfiles (files and Makefile
- targets)
-
-2004-05-15 multipath-tools-0.1.8
-
- * Makefiles cleanup and factorisation
- * Compilation fixes for non-ix86 archs, tested on x86_64
- * strip execs harder for a 10% size reduction
- * blacklist /dev/fd* and /dev/loop*
- * dmadm works with sysfs nodes with '!' (cciss for ex)
-
-2004-05-10 multipath-tools-0.1.7
-
- * bugfixes from Andy <genanr at emsphone.com> :
- * read the last line of the config file
- * add an entry for the 3PARData storage ctlrs
- * read the last char of vendor and model strings
-
-2004-04-25 multipath-tools-0.1.6
-
- * add the dmadm WIP tool (read MD superblocks and create
- corresponding devmaps when possible)
- * plug fd leak in TUR path checker
-
-2004-03-25 multipath-tools-0.1.5
-
- * kpartx to manage the nested bdevs as /dev/cciss/c0d0.
- parts are named sysfs style : cciss!c0d0p*
- * kpartx loop support
- * kpartx do DM updates if part maps already present
- * merge kpartx for partitioned multipath support
- * add get_null_uid to getuid methods. assign it the "0" index
- devices with this getuid are thus ignored by multipath.
- warning : change /etc/multipath.conf (get_evpd_wwid == 1)
- * mv all_scsi_ids out of the 2.6 code path, into the 2.4 one
- * unlink runfile on malloc exit path
- * update multipath manpage (MikeC)
-
-2004-03-17 multipath-tools-0.1.4
-
- * multipath clean up
- * split default hw table in hwtable.h
- * split grouping policies in pgpolocies.c
- * pass *mp to setup_map instead of mp[]+index
- * ensure defhwtable is used if /etc/multipath.conf is buggy
- * hwtable is not global anymore
- * unlink the runfile in various error paths
-
-2004-03-13 multipath-tools-0.1.3
-
- * multipath config tool now has a config file parser
- (did I say I make the ugliest parsers ?)
- * example multipath.conf to put in /etc (manualy)
-
-2004-03-12 multipath-tools-0.1.2
-
- * detach the per devmap waiter threads
- * set the thread stack size to lower limits
- (VSZ down to 4MB from 85 MB here)
-
-2004-03-06 multipath-tools-0.1.1
-
- * include dlist.h in multipath main.c (PM Hahn)
- * typo in hotplug script (PM Hahn)
- * pass -9 opt to gzip for manpages (PM Hahn)
-
-2004-03-05 multipath-tools-0.1.0
-
- * add the group_by_tur policy
- * add the multipathd daemon for pathchecking & DM hot-reconfig
- * multipath doesn't run twice
- * massive cleanups, and code restructuring
- * Avoid Kernel Bug when passing too small a buffer in do_inq()
- * Sync with 2.6.3-udm4 target synthax (no more PG prio)
-
-2004-02-21 multipath-018
-
- * From the Debian SID inclusion review (Philipp Matthias Hahn)
- * use DESTDIR install prefix in the Makefile
- * add man pages for devmap_name & multipath
- * correct libsysfs.h includes
- * fork the hotplug script in its own shell
- * Sync with the kernel device mapper code as of 2.6.3-udm3
- ie. Remove the test interval parameter and its uses
- * Remove superfluous scsi parameter passed from hotplug
- * Add the man pages to the [un]install targets
-
-2004-02-17 multipath-017
-
- * remove the restrictive -f flag.
- Introduce a more generic "-m iopolicy" one.
- * remove useless "int with_sysfs" in env struct
-
-2004-02-04 multipath-016
-
- * add a GROUP_BY_SERIAL flag. This should be useful for
- controlers that activate they spare paths on simple IO
- submition with a penalty. The StorageWorks HW defaults to
- this mode, even if the MULTIBUS mode is OK.
- * remove unused sg_err.c
- * big restructuring : split devinfo.c from main.c. Export :
- * void basename (char *, char *);
- * int get_serial (int, char *);
- * int get_lun_strings (char *, char *, char *, char *);
- * int get_evpd_wwid(char *, char *);
- * long get_disk_size (char *);
- * stop passing struct env as param
- * add devmap_name proggy for udev to name devmaps as per their
- internal DM name and not only by their sysfs enum name (dm-*)
- The corresponding udev.rules line is :
- KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \
- NAME="%k", SYMLINK="%c"
- * remove make_dm_node fn & call. Rely on udev for this.
- * don't rely on the linux symlink in the udev/klibc dir since
- udev build doesn't use it anymore. This corrects build breakage
-
-2004-01-19 multipath-013
-
- * update the DM target synthax to the 2.6.0-udm5 style
-
-2003-12-29 multipath-012
-
- * check hotplug event refers to a block device; if not exit early
- * refresh doc
- * add the uninstall target in Makefile
-
-2003-12-22 multipath-010
-
- * tweak the install target in Makefile
- * stop passing fds as argument : this change enable a strict
- segregation of ugly 2.4 code
- * sysfs version of get_lun_strings()
- * be careful about the return of get_unique_id() since errors
- formerly caught up by if(open()) in the caller fn are now returned
- by get_unique_id()
- * send get_serial() in unused.c
- * introduce dm-simplecmd for RESUME & SUSPEND requests
- * split add_map() in setup_map() & dm-addmap()
- * setup_map() correctly submits "SUSPEND-RELOAD-RESUME or CREATE"
- sequences instead of the bogus "RELOAD or CREATE"
- * don't print .sg_dev if equal to .dev (2.6) in print_path()
- * since the kernel code handles defective paths, remove all
- code to cope with them :
- * move do_tur() to unused.c
- * remove .state from path struct
- * remove .state settings & conditionals
- * add a cmdline switch to force maps to failover mode,
- ie 1 path per priority group
- * add default policies to the whitelist array (spread io ==
- MULTIBUS / io forced to 1 path == FAILOVER)
- * move get_disk_size() call out of add_map() to coalesce()
- * comment tricky coalesce() fn
- * bogus unsused.c file renamed to unused.c
-
-2003-12-20 multipath-010
-
- * big ChangeLog update
- * start to give a little control over target params :
- introduce cmdline arg -i to control polling interval
- * cope with hotplug-style calling convention :
- ie "multipath scsi $DEVPATH" ... to avoid messing with
- online maps not concerned by an event
- * example hotplug agent to drop in /etc/hotplug.d/scsi
- * revert the run & resched patch : unless someone proves me
- wrong, this was overdesigned
- * move commented out functions in unused.c
- * update multipath target params to "udm[23] style"
- * mp target now supports nr_path == 1, so do we
- * add gratuitous free()
- * push version forward
-
-2003-12-15 multipath-009
-
- * Make the HW-specific get_unique_id switch pretty
- * Prepare to field-test by whitelisting all known fibre array,
- try to fetch WWID from the standard EVPD 0x83 off 8 for everyone
- * configure the multipath target with round-robin path selector and
- conservative default for a start (udm1 style) :
- yes it makes this release the firstreally useful one.
- * temporarily disable map creation for single path device
- due to current restrictive defaults in the kernel target.
- Sistina should work it out.
- * correct the strncmp logic in blacklist function.
- * update the Makefiles to autodetect libgcc.a & gcc includes
- "ulibc-style". Factorisation of udevdirs & others niceties
- * drop a hint about absent /dev/sd? on failed open()
- * implement a reschedule flag in /var/run.
- Last thing the prog do before exit is check if a call to multipath
- was done (but canceled by /var/run/multipath.run check) during its
- execution. If so restart themain loop.
- * implement a blacklist of sysfs bdev to not bother with for now
- (hd,md, dm, sr, scd, ram, raw).
- This avoid sending SG_IO to unappropiate devices.
- * Adds a /var/run/multipath.run handling to avoid simultaneous runs.
- * Remove a commented-out "printf"
- * drop a libdevmapper copy in extras/multipath;
- maybe discussions w/Sistina folks will bring a better solution
- in the future.
- * drop a putchar usage in libdevmapper to compile cleanly with klibc
- * drop another such usage of my own in main.c
- * massage the Makefile to compile libdevmapper against klibc
- * use "ld" to produce the binary rather than "gcc -static"
- * stop being stupid w/ uneeded major, minor & dev in main.c:dm_mk_node()
- * reverse to creating striped target for now because the multipath
- target is more hairy than expected initialy
- * push the version code to 009 to be in synch w/ udev
-
-2003-11-27 multipath-007
-
- * removes sg_err.[ch] deps
- * makes sure the core code play nice with klibc
- * port the sysfs calls to dlist helpers
- * links against udev's sysfs (need libsysfs.a & dlist.a)
- * finally define DM_TARGET as "multipath" as Joe posted the code today
- (not tested yet)
- * push version forward (do you want it in sync with udev version?)
-
-2003-11-19 multipath-006
-
- * merged in udev-006 tree
-
-2003-09-18 multipath-0.0.1
-
- * multipath 0.0.1 released.
- * Initial release.
+- pre-0.4.5
+ http://christophe.varoqui.free.fr/wiki/wakka.php?wiki=ChangeLog
+- post-0.4.5
+ http://www.kernel.org/git/gitweb.cgi?p=linux/storage/multipath-tools/.git;a=log
Modified: multipath-tools/trunk/FAQ
==============================================================================
--- multipath-tools/trunk/FAQ (original)
+++ multipath-tools/trunk/FAQ Mon Mar 13 15:16:41 2006
@@ -1,3 +1,5 @@
+More at http://christophe.varoqui.free.fr/wiki/wakka.php?wiki=FAQ
+
1. How to set up System-on-multipath ?
======================================
Modified: multipath-tools/trunk/Makefile.inc
==============================================================================
--- multipath-tools/trunk/Makefile.inc (original)
+++ multipath-tools/trunk/Makefile.inc Mon Mar 13 15:16:41 2006
@@ -25,9 +25,17 @@
bindir = $(exec_prefix)/sbin
checkersdir = $(TOPDIR)/libcheckers
multipathdir = $(TOPDIR)/libmultipath
-mandir = /usr/share/man/man8
+mandir = $(prefix)/usr/share/man/man8
+rcdir = $(prefix)/etc/init.d
GZIP = /bin/gzip -9 -c
CHECKERSLIB = $(checkersdir)/libcheckers
MULTIPATHLIB = $(multipathdir)/libmultipath
+
+OPTFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
+CFLAGS = $(OPTFLAGS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
Modified: multipath-tools/trunk/README
==============================================================================
--- multipath-tools/trunk/README (original)
+++ multipath-tools/trunk/README Mon Mar 13 15:16:41 2006
@@ -1,52 +1 @@
-Dependancies :
-==============
-
-These libs have been dropped in the multipath tree :
-
-o libdevmapper : comes with device-mapper-XXXX.tar.gz
- See www.sistina.com
-o libsysfs : comes with sysutils or udev
- See ftp.kernel.org/pub/linux/utils/kernel/hotplug/
-o klibc
- See ftp.kernel.org/pub/linux/libs/klibc/
-
-External :
-
-o Linux kernel 2.6.10-rc with udm2 patchset (or greater)
- ftp://sources.redhat.com/pub/dm/
-
-How it works :
-==============
-
-Get a path list in sysfs.
-
-For each path, a wwid is retrieved by a callout program.
-Only White Listed HW can retrieve this info.
-
-Coalesce the paths according to pluggable policies and store
- the result in mp array.
-
-Feed the maps to the kernel device mapper.
-
-The naming of the corresponding block device is handeld
-by udev with the help of the devmap_name proggy. It is
-called by the following rule in /etc/udev/udev.rules :
-
-KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \
-NAME="%k", SYMLINK="%c"
-
-Notes :
-=======
-
-o 2.4.21 version of DM does not like even segment size.
- if you enconter pbs with this, upgrade DM.
-
-Credits :
-=========
-
-o Heavy cut'n paste from sg_utils. Thanks goes to D.
- Gilbert.
-o Light cut'n paste from dmsetup. Thanks Joe Thornber.
-o Greg KH for the nice sysfs API.
-o The klibc guys (Starving Linux Artists :), espacially
- for their nice Makefiles and specfile
+Things to read
Modified: multipath-tools/trunk/TODO
==============================================================================
--- multipath-tools/trunk/TODO (original)
+++ multipath-tools/trunk/TODO Mon Mar 13 15:16:41 2006
@@ -1,3 +1 @@
Things to do
-
-o activate group dm mesg fn
Modified: multipath-tools/trunk/devmap_name/Makefile
==============================================================================
--- multipath-tools/trunk/devmap_name/Makefile (original)
+++ multipath-tools/trunk/devmap_name/Makefile Mon Mar 13 15:16:41 2006
@@ -6,7 +6,6 @@
include ../Makefile.inc
OBJS = devmap_name.o
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
ifeq ($(strip $(BUILD)),klibc)
OBJS += $(libdm)
@@ -24,7 +23,7 @@
glibc: prepare $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
+
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(OBJS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
Modified: multipath-tools/trunk/devmap_name/devmap_name.c
==============================================================================
--- multipath-tools/trunk/devmap_name/devmap_name.c (original)
+++ multipath-tools/trunk/devmap_name/devmap_name.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Modified: multipath-tools/trunk/kpartx/Makefile
==============================================================================
--- multipath-tools/trunk/kpartx/Makefile (original)
+++ multipath-tools/trunk/kpartx/Makefile Mon Mar 13 15:16:41 2006
@@ -6,16 +6,16 @@
include ../Makefile.inc
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes -I.
+CFLAGS += -I. -D_LARGEFILE64_SOURCE
ifeq ($(strip $(BUILD)),klibc)
OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \
- lopart.o xstrncpy.o devmapper.o \
+ lopart.o xstrncpy.o devmapper.o dasd.o mac.o \
$(MULTIPATHLIB)-$(BUILD).a $(libdm)
else
LDFLAGS = -ldevmapper
- OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o \
- gpt.o crc32.o lopart.o xstrncpy.o devmapper.o
+ OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o \
+ gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
endif
EXEC = kpartx
Modified: multipath-tools/trunk/kpartx/byteorder.h
==============================================================================
--- multipath-tools/trunk/kpartx/byteorder.h (original)
+++ multipath-tools/trunk/kpartx/byteorder.h Mon Mar 13 15:16:41 2006
@@ -9,9 +9,15 @@
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
+# define le16_to_cpu(x) (x)
+# define be16_to_cpu(x) bswap_16(x)
# define le32_to_cpu(x) (x)
+# define be32_to_cpu(x) bswap_32(x)
#elif BYTE_ORDER == BIG_ENDIAN
+# define le16_to_cpu(x) bswap_16(x)
+# define be16_to_cpu(x) (x)
# define le32_to_cpu(x) bswap_32(x)
+# define be32_to_cpu(x) (x)
#else
# error unsupported
#endif
Added: multipath-tools/trunk/kpartx/dasd.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/dasd.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,240 @@
+/*
+ * dasd.c
+ *
+ * IBM DASD partition table handling.
+ *
+ * Mostly taken from drivers/s390/block/dasd.c
+ *
+ * Copyright (c) 2005, Hannes Reinecke, SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libdevmapper.h>
+#include "devmapper.h"
+#include "kpartx.h"
+#include "byteorder.h"
+#include "dasd.h"
+
+/*
+ */
+int
+read_dasd_pt(int fd, struct slice all, struct slice *sp, int ns)
+{
+ int retval = -1;
+ int blocksize, offset, size;
+ long disksize;
+ dasd_information_t info;
+ struct hd_geometry geo;
+ char type[5] = {0,};
+ char name[7] = {0,};
+ unsigned char *label_raw;
+ volume_label_t vlabel;
+ unsigned char *data = NULL;
+ unsigned int blk;
+ int fd_dasd = -1;
+ struct stat sbuf;
+ dev_t dev;
+ char *devname;
+ char pathname[256];
+
+ if (fd < 0) {
+ return -1;
+ }
+
+ if (fstat(fd, &sbuf) == -1) {
+ return -1;
+ }
+
+ devname = dm_mapname(major(sbuf.st_rdev), minor(sbuf.st_rdev));
+
+ if (devname != NULL) {
+ /* We were passed a handle to a dm device.
+ * Get the first target and operate on that instead.
+ */
+ if (!(dev = dm_get_first_dep(devname))) {
+ free(devname);
+ return -1;
+ }
+ free(devname);
+
+ if ((unsigned int)major(dev) != 94) {
+ /* Not a DASD */
+ return -1;
+ }
+
+ /*
+ * Hard to believe, but there's no simple way to translate
+ * 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) {
+ /* Devicenode does not exist. Try to create one */
+ if (mknod(pathname, 0600 | S_IFBLK, dev) == -1) {
+ /* Couldn't create a device node */
+ return -1;
+ }
+ fd_dasd = open(pathname, O_RDONLY);
+ /*
+ * The file will vanish when the last process (we)
+ * has ceased to access it.
+ */
+ unlink(pathname);
+ }
+ if (!fd_dasd) {
+ /* Couldn't open the device */
+ return -1;
+ }
+ } else {
+ fd_dasd = fd;
+ }
+
+ if (ioctl(fd_dasd, BIODASDINFO, (unsigned long)&info) != 0) {
+ goto out;
+ }
+
+ if (ioctl(fd_dasd, HDIO_GETGEO, (unsigned long)&geo) != 0) {
+ goto out;
+ }
+
+ if (ioctl(fd_dasd, BLKGETSIZE, &disksize) != 0)
+ goto out;
+
+ if (ioctl(fd_dasd, BLKSSZGET, &blocksize) != 0)
+ goto out;
+
+ if (blocksize < 512 || blocksize > 4096)
+ goto out;
+
+ /*
+ * Get volume label, extract name and type.
+ */
+
+ if (!(data = (unsigned char *)malloc(blocksize)))
+ goto out;
+
+
+ if (lseek(fd_dasd, info.label_block * blocksize, SEEK_SET) == -1)
+ goto out;
+ if (read(fd_dasd, data, blocksize) == -1) {
+ perror("read");
+ goto out;
+ }
+ vtoc_ebcdic_dec(data, type, 4);
+
+ if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
+ label_raw = &data[8];
+ else
+ label_raw = &data[4];
+
+ name[6] = '\0';
+ vtoc_ebcdic_dec(label_raw, name, 6);
+
+ memcpy (&vlabel, data, sizeof(volume_label_t));
+
+ /*
+ * Three different types: CMS1, VOL1 and LNX1/unlabeled
+ */
+ if (strncmp(type, "CMS1", 4) == 0) {
+ /*
+ * VM style CMS1 labeled disk
+ */
+ int *label = (int *) &vlabel;
+
+ if (label[13] != 0) {
+ /* disk is reserved minidisk */
+ blocksize = label[3];
+ offset = label[13];
+ size = (label[7] - 1)*(blocksize >> 9);
+ } else {
+ offset = (info.label_block + 1) * (blocksize >> 9);
+ size = disksize - offset;
+ }
+ sp[0].start = offset * (blocksize >> 9);
+ sp[0].size = size - offset * (blocksize >> 9);
+ retval = 1;
+ } else if ((strncmp(type, "VOL1", 4) == 0) &&
+ (!info.FBA_layout) && (!strcmp(info.type, "ECKD"))) {
+ /*
+ * New style VOL1 labeled disk
+ */
+ int counter;
+
+ /* get block number and read then go through format1 labels */
+ blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+ counter = 0;
+ if (lseek(fd_dasd, blk * blocksize, SEEK_SET) == -1)
+ goto out;
+
+ while (read(fd_dasd, data, blocksize) != -1) {
+ format1_label_t f1;
+
+ memcpy(&f1, data, sizeof(format1_label_t));
+
+ /* skip FMT4 / FMT5 / FMT7 labels */
+ if (EBCtoASC[f1.DS1FMTID] == '4'
+ || EBCtoASC[f1.DS1FMTID] == '5'
+ || EBCtoASC[f1.DS1FMTID] == '7') {
+ blk++;
+ continue;
+ }
+
+ /* only FMT1 valid at this point */
+ if (EBCtoASC[f1.DS1FMTID] != '1')
+ break;
+
+ /* OK, we got valid partition data */
+ offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+ size = cchh2blk(&f1.DS1EXT1.ulimit, &geo) -
+ offset + geo.sectors;
+ sp[counter].start = offset * (blocksize >> 9);
+ sp[counter].size = size * (blocksize >> 9);
+ counter++;
+ blk++;
+ }
+ retval = counter;
+ } else {
+ /*
+ * Old style LNX1 or unlabeled disk
+ */
+ offset = (info.label_block + 1) * (blocksize >> 9);
+ size = disksize - offset;
+ sp[0].start = offset * (blocksize >> 9);
+ sp[0].size = size - offset * (blocksize >> 9);
+ retval = 1;
+ }
+
+ out:
+ if (data != NULL)
+ free(data);
+ if (fd_dasd != -1 && fd_dasd != fd)
+ close(fd_dasd);
+ return retval;
+}
Added: multipath-tools/trunk/kpartx/dasd.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/dasd.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,272 @@
+/*
+ * dasd.h
+ *
+ * IBM DASD partition table handling.
+ *
+ * Mostly taken from drivers/s390/block/dasd.c
+ *
+ * Copyright (c) 2005, Hannes Reinecke, SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef _DASD_H
+#define _DASD_H
+
+typedef struct ttr
+{
+ uint16_t tt;
+ uint8_t r;
+} __attribute__ ((packed)) ttr_t;
+
+typedef struct cchhb
+{
+ uint16_t cc;
+ uint16_t hh;
+ uint8_t b;
+} __attribute__ ((packed)) cchhb_t;
+
+typedef struct cchh
+{
+ uint16_t cc;
+ uint16_t hh;
+} __attribute__ ((packed)) cchh_t;
+
+typedef struct labeldate
+{
+ uint8_t year;
+ uint16_t day;
+} __attribute__ ((packed)) labeldate_t;
+
+
+typedef struct 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 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 */
+ char lvtoc[14]; /* owner code for LVTOC */
+ char res3[29]; /* reserved */
+} __attribute__ ((packed)) volume_label_t;
+
+
+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 */
+} __attribute__ ((packed)) extent_t;
+
+
+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 */
+} __attribute__ ((packed)) dev_const_t;
+
+
+typedef struct format1_label
+{
+ char DS1DSNAM[44]; /* data set name */
+ uint8_t DS1FMTID; /* format identifier */
+ char DS1DSSN[6]; /* data set serial number */
+ uint16_t DS1VOLSQ; /* volume sequence number */
+ 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 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 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 */
+ ttr_t DS1LSTAR; /* last used track and block on track */
+ uint16_t DS1TRBAL; /* space remaining on last used track */
+ uint16_t res1; /* reserved */
+ extent_t DS1EXT1; /* first extent description */
+ extent_t DS1EXT2; /* second extent description */
+ extent_t DS1EXT3; /* third extent description */
+ cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */
+} __attribute__ ((packed)) format1_label_t;
+
+
+/*
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
+ */
+typedef struct dasd_information_t {
+ unsigned int devno; /* S/390 devno */
+ unsigned int real_devno; /* for aliases */
+ unsigned int schid; /* S/390 subchannel identifier */
+ unsigned int cu_type : 16; /* from SenseID */
+ unsigned int cu_model : 8; /* from SenseID */
+ unsigned int dev_type : 16; /* from SenseID */
+ unsigned int dev_model : 8; /* from SenseID */
+ unsigned int open_count;
+ unsigned int req_queue_len;
+ unsigned int chanq_len; /* length of chanq */
+ char type[4]; /* from discipline.name, 'none' for unknown */
+ unsigned int status; /* current device level */
+ unsigned int label_block; /* where to find the VOLSER */
+ unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
+ unsigned int characteristics_size;
+ unsigned int confdata_size;
+ char characteristics[64]; /* from read_device_characteristics */
+ char configuration_data[256]; /* from read_configuration_data */
+} dasd_information_t;
+
+#define DASD_IOCTL_LETTER 'D'
+#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+#define BLKGETSIZE _IO(0x12,96)
+#define BLKSSZGET _IO(0x12,104)
+
+/*
+ * Only compile this on S/390. Doesn't make any sense
+ * for other architectures.
+ */
+
+static unsigned char EBCtoASC[256] =
+{
+/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 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 */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -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 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48 . < ( + | */
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58 Ã ! $ * ) ; */
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60 - / ---- Ã ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70 --- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0 ^ ---- § ---- */
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8 ---- [ ] ---- ---- ---- ---- */
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8 Y Z ---- Ã ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8 8 9 ---- ---- Ã ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+static inline void
+vtoc_ebcdic_dec (const unsigned char *source, char *target, int l)
+{
+ int i;
+
+ for (i = 0; i < l; i++)
+ target[i]=(char)EBCtoASC[(unsigned char)(source[i])];
+}
+
+/*
+ * compute the block number from a
+ * cyl-cyl-head-head structure
+ */
+static inline int
+cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+ return ptr->cc * geo->heads * geo->sectors +
+ ptr->hh * geo->sectors;
+}
+
+
+/*
+ * compute the block number from a
+ * cyl-cyl-head-head-block structure
+ */
+static inline int
+cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+ return ptr->cc * geo->heads * geo->sectors +
+ ptr->hh * geo->sectors +
+ ptr->b;
+}
+
+#endif /* _DASD_H */
Modified: multipath-tools/trunk/kpartx/devmapper.c
==============================================================================
--- multipath-tools/trunk/kpartx/devmapper.c (original)
+++ multipath-tools/trunk/kpartx/devmapper.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -116,11 +119,12 @@
}
-const char *
+char *
dm_mapname(int major, int minor)
{
struct dm_task *dmt;
- const char *mapname;
+ char *mapname = NULL;
+ const char *map;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return NULL;
@@ -132,9 +136,45 @@
if (!dm_task_run(dmt))
goto out;
- mapname = strdup(dm_task_get_name(dmt));
+ map = dm_task_get_name(dmt);
+ if (map && strlen(map))
+ mapname = strdup(map);
+
out:
dm_task_destroy(dmt);
return mapname;
}
+/*
+ * dm_get_first_dep
+ *
+ * Return the device number of the first dependend device
+ * for a given target.
+ */
+dev_t dm_get_first_dep(char *devname)
+{
+ struct dm_task *dmt;
+ struct dm_deps *dm_deps;
+ dev_t ret = 0;
+
+ if ((dmt = dm_task_create(DM_DEVICE_DEPS)) == NULL) {
+ return ret;
+ }
+ if (!dm_task_set_name(dmt, devname)) {
+ goto out;
+ }
+ if (!dm_task_run(dmt)) {
+ goto out;
+ }
+ if ((dm_deps = dm_task_get_deps(dmt)) == NULL) {
+ goto out;
+ }
+ if (dm_deps->count > 0) {
+ ret = dm_deps->device[0];
+ }
+out:
+ dm_task_destroy(dmt);
+
+ return ret;
+}
+
Modified: multipath-tools/trunk/kpartx/devmapper.h
==============================================================================
--- multipath-tools/trunk/kpartx/devmapper.h (original)
+++ multipath-tools/trunk/kpartx/devmapper.h Mon Mar 13 15:16:41 2006
@@ -2,4 +2,5 @@
int dm_simplecmd (int, const char *);
int dm_addmap (int, const char *, const char *, const char *, unsigned long);
int dm_map_present (char *);
-const char * dm_mapname(int major, int minor);
+char * dm_mapname(int major, int minor);
+dev_t dm_get_first_dep(char *devname);
Modified: multipath-tools/trunk/kpartx/dos.c
==============================================================================
--- multipath-tools/trunk/kpartx/dos.c (original)
+++ multipath-tools/trunk/kpartx/dos.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Source: copy of util-linux' partx dos.c
+ *
+ * Copyrights of the original file apply
+ * Copyright (c) 2005 Bastian Blank
+ */
#include "kpartx.h"
#include "byteorder.h"
#include <stdio.h>
@@ -14,15 +20,16 @@
struct slice *sp, int ns)
{
struct partition p;
- unsigned long start, here;
+ unsigned long start, here, next;
unsigned char *bp;
int loopct = 0;
int moretodo = 1;
int i, n=0;
- here = start = le32_to_cpu(ep->start_sect);
+ next = start = le32_to_cpu(ep->start_sect);
while (moretodo) {
+ here = next;
moretodo = 0;
if (++loopct > 100)
return n;
@@ -37,12 +44,11 @@
for (i=0; i<2; i++) {
memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
if (is_extended(p.sys_type)) {
- if (p.nr_sects) {
- here = start + le32_to_cpu(p.start_sect);
+ if (p.nr_sects && !moretodo) {
+ next = start + le32_to_cpu(p.start_sect);
moretodo = 1;
}
- else
- continue;
+ continue;
}
if (n < ns) {
sp[n].start = here + le32_to_cpu(p.start_sect);
@@ -80,9 +86,6 @@
for (i=0; i<4; i++) {
memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
- }
- for (i=0; i<4; i++) {
- memcpy(&p, bp + 0x1be + i * sizeof (p), sizeof (p));
if (is_gpt(p.sys_type))
return 0;
if (i < ns) {
@@ -93,8 +96,11 @@
"dos_partition: too many slices\n");
break;
}
- if (is_extended(p.sys_type))
+ if (is_extended(p.sys_type)) {
n += read_extended_partition(fd, &p, sp+n, ns-n);
+ /* hide the extended partition itself */
+ sp[i].size = 0;
+ }
}
return n;
}
Modified: multipath-tools/trunk/kpartx/kpartx.c
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.c (original)
+++ multipath-tools/trunk/kpartx/kpartx.c Mon Mar 13 15:16:41 2006
@@ -1,4 +1,13 @@
/*
+ * Source: copy of util-linux' partx partx.c
+ *
+ * Copyrights of the original file applies
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda
+ * Copyright (c) 2005 Lars Soltau
+ */
+
+/*
* Given a block device and a partition table type,
* try to parse the partition table, and list the
* contents. Optionally add or remove partitions.
@@ -68,6 +77,8 @@
addpts("bsd", read_bsd_pt);
addpts("solaris", read_solaris_pt);
addpts("unixware", read_unixware_pt);
+ addpts("dasd", read_dasd_pt);
+ addpts("mac", read_mac_pt);
}
static char short_opts[] = "ladgvnp:t:";
@@ -455,27 +466,14 @@
/*
* sseek: seek to specified sector
*/
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
- && !defined (__s390x__)
-#include <linux/unistd.h> /* _syscall */
-static
-_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
- long long *, res, uint, wh);
-#endif
static int
sseek(int fd, unsigned int secnr) {
- long long in, out;
- in = ((long long) secnr << 9);
+ off64_t in, out;
+ in = ((off64_t) secnr << 9);
out = 1;
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
- && !defined (__s390x__)
- if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0
- || out != in)
-#else
- if ((out = lseek(fd, in, SEEK_SET)) != in)
-#endif
+ if ((out = lseek64(fd, in, SEEK_SET)) != in)
{
fprintf(stderr, "llseek error\n");
return -1;
Modified: multipath-tools/trunk/kpartx/kpartx.h
==============================================================================
--- multipath-tools/trunk/kpartx/kpartx.h (original)
+++ multipath-tools/trunk/kpartx/kpartx.h Mon Mar 13 15:16:41 2006
@@ -31,6 +31,8 @@
extern ptreader read_solaris_pt;
extern ptreader read_unixware_pt;
extern ptreader read_gpt_pt;
+extern ptreader read_dasd_pt;
+extern ptreader read_mac_pt;
char *getblock(int fd, unsigned int secnr);
Added: multipath-tools/trunk/kpartx/mac.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/mac.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,47 @@
+#include "kpartx.h"
+#include "byteorder.h"
+#include <stdio.h>
+#include <string.h>
+#include "mac.h"
+
+int
+read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
+ struct mac_driver_desc *md;
+ struct mac_partition *part;
+ unsigned secsize;
+ char *data;
+ int blk, blocks_in_map;
+ int n = 0;
+
+ md = (struct mac_driver_desc *) getblock(fd, 0);
+ if (md == NULL)
+ return -1;
+
+ if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
+ return -1;
+
+ secsize = be16_to_cpu(md->block_size);
+ data = getblock(fd, secsize/512);
+ if (!data)
+ return -1;
+ part = (struct mac_partition *) (data + secsize%512);
+
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+ return -1;
+
+ blocks_in_map = be32_to_cpu(part->map_count);
+ for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) {
+ int pos = blk * secsize;
+ data = getblock(fd, pos/512);
+ if (!data)
+ return -1;
+
+ part = (struct mac_partition *) (data + pos%512);
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+ break;
+
+ sp[n].start = be32_to_cpu(part->start_block) * (secsize/512);
+ sp[n].size = be32_to_cpu(part->block_count) * (secsize/512);
+ }
+ return n;
+}
Added: multipath-tools/trunk/kpartx/mac.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/kpartx/mac.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,30 @@
+#ifndef MAC_H
+#define MAC_H
+
+#include <stdint.h>
+
+#define MAC_PARTITION_MAGIC 0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#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 */
+};
+
+#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;
+ /* ... more stuff */
+};
+
+#endif
Modified: multipath-tools/trunk/libcheckers/Makefile
==============================================================================
--- multipath-tools/trunk/libcheckers/Makefile (original)
+++ multipath-tools/trunk/libcheckers/Makefile Mon Mar 13 15:16:41 2006
@@ -6,7 +6,7 @@
include ../Makefile.inc
-OBJS = readsector0.o tur.o selector.o directio.o emc_clariion.o hp_sw.o
+OBJS = checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o
all: $(BUILD)
Added: multipath-tools/trunk/libcheckers/checkers.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/checkers.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "checkers.h"
+
+#include "directio.h"
+#include "tur.h"
+#include "hp_sw.h"
+#include "emc_clariion.h"
+#include "readsector0.h"
+
+static struct checker checkers[] = {
+ {
+ .fd = 0,
+ .name = DIRECTIO,
+ .message = "",
+ .context = NULL,
+ .check = directio,
+ .init = directio_init,
+ .free = directio_free
+ },
+ {
+ .fd = 0,
+ .name = TUR,
+ .message = "",
+ .context = NULL,
+ .check = tur,
+ .init = tur_init,
+ .free = tur_free
+ },
+ {
+ .fd = 0,
+ .name = HP_SW,
+ .message = "",
+ .context = NULL,
+ .check = hp_sw,
+ .init = hp_sw_init,
+ .free = hp_sw_free
+ },
+ {
+ .fd = 0,
+ .name = EMC_CLARIION,
+ .message = "",
+ .context = NULL,
+ .check = emc_clariion,
+ .init = emc_clariion_init,
+ .free = emc_clariion_free
+ },
+ {
+ .fd = 0,
+ .name = READSECTOR0,
+ .message = "",
+ .context = NULL,
+ .check = readsector0,
+ .init = readsector0_init,
+ .free = readsector0_free
+ },
+ {0, "", "", NULL, NULL, NULL, NULL},
+};
+
+void checker_set_fd (struct checker * c, int fd)
+{
+ c->fd = fd;
+}
+
+struct checker * checker_lookup (char * name)
+{
+ struct checker * c = &checkers[0];
+
+ while (c->check) {
+ if (!strncmp(name, c->name, CHECKER_NAME_LEN))
+ return c;
+ c++;
+ }
+ return NULL;
+}
+
+int checker_init (struct checker * c)
+{
+ return c->init(c);
+}
+
+void checker_put (struct checker * c)
+{
+ if (c->free)
+ c->free(c);
+ memset(c, 0x0, sizeof(struct checker));
+}
+
+int checker_check (struct checker * c)
+{
+ int r;
+
+ if (c->fd <= 0) {
+ MSG(c, "no usable fd");
+ return PATH_WILD;
+ }
+ r = c->check(c);
+
+ return r;
+}
+
+int checker_selected (struct checker * c)
+{
+ return (c->check) ? 1 : 0;
+}
+
+char * checker_name (struct checker * c)
+{
+ return c->name;
+}
+
+char * checker_message (struct checker * c)
+{
+ return c->message;
+}
+
+struct checker * checker_default (void)
+{
+ return checker_lookup(DEFAULT_CHECKER);
+}
+
+void checker_get (struct checker * dst, struct checker * src)
+{
+ dst->fd = src->fd;
+ strncpy(dst->name, src->name, CHECKER_NAME_LEN);
+ strncpy(dst->message, src->message, CHECKER_MSG_LEN);
+ dst->check = src->check;
+ dst->init = src->init;
+ dst->free = src->free;
+}
Modified: multipath-tools/trunk/libcheckers/checkers.h
==============================================================================
--- multipath-tools/trunk/libcheckers/checkers.h (original)
+++ multipath-tools/trunk/libcheckers/checkers.h Mon Mar 13 15:16:41 2006
@@ -1,30 +1,53 @@
#ifndef _CHECKERS_H
#define _CHECKERS_H
-#define CHECKER_NAME_SIZE 16
-#define DEVNODE_SIZE 256
-#define MAX_CHECKER_MSG_SIZE 256
-
-enum checkers {
- CHECKER_UNDEF,
- TUR,
- READSECTOR0,
- DIRECTIO,
- EMC_CLARIION,
- HP_SW
+/*
+ * path states
+ */
+#define PATH_WILD -1
+#define PATH_UNCHECKED 0
+#define PATH_DOWN 1
+#define PATH_UP 2
+#define PATH_SHAKY 3
+#define PATH_GHOST 4
+
+#define DIRECTIO "directio"
+#define TUR "tur"
+#define HP_SW "hp_sw"
+#define EMC_CLARIION "emc_clariion"
+#define READSECTOR0 "readsector0"
+
+#define DEFAULT_CHECKER READSECTOR0
+
+/*
+ * strings lengths
+ */
+#define CHECKER_NAME_LEN 16
+#define CHECKER_MSG_LEN 256
+#define CHECKER_DEV_LEN 256
+
+struct checker {
+ int fd;
+ char name[CHECKER_NAME_LEN];
+ char message[CHECKER_MSG_LEN]; /* comm with callers */
+ void * context; /* store for persistent data */
+ int (*check)(struct checker *);
+ int (*init)(struct checker *); /* to allocate the context */
+ void (*free)(struct checker *); /* to free the context */
};
-#define MSG(a) if (msg != NULL) \
- snprintf(msg, MAX_CHECKER_MSG_SIZE, "%s", a);
+#define MSG(c, a) snprintf((c)->message, CHECKER_MSG_LEN, a);
-int get_checker_id (char *);
-void *get_checker_addr (int);
-int get_checker_name (char *, int);
-
-int emc_clariion (int fd, char * msg, void ** ctxt);
-int directio (int fd, char * msg, void ** ctxt);
-int readsector0 (int fd, char * msg, void ** ctxt);
-int tur (int fd, char * msg, void ** ctxt);
-int hp_sw (int fd, char * msg, void ** ctxt);
+int checker_init (struct checker *);
+void checker_put (struct checker *);
+void checker_reset (struct checker * c);
+void checker_set_fd (struct checker *, int);
+struct checker * checker_lookup (char *);
+int checker_check (struct checker *);
+int checker_selected (struct checker *);
+char * checker_name (struct checker *);
+char * checker_message (struct checker *);
+struct checker * checker_default (void);
+void checker_get (struct checker *, struct checker *);
#endif /* _CHECKERS_H */
Modified: multipath-tools/trunk/libcheckers/directio.c
==============================================================================
--- multipath-tools/trunk/libcheckers/directio.c (original)
+++ multipath-tools/trunk/libcheckers/directio.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Hannes Reinecke, Suse
+ */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
@@ -10,17 +13,63 @@
#include <linux/fs.h>
#include <errno.h>
-#include "path_state.h"
#include "checkers.h"
#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
#define MSG_DIRECTIO_UP "directio checker reports path is up"
#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
-struct readsector0_checker_context {
- void * dummy;
+struct directio_context {
+ int blksize;
+ unsigned char *buf;
+ unsigned char *ptr;
};
+int directio_init (struct checker * c)
+{
+ unsigned long pgsize = getpagesize();
+ struct directio_context * ct;
+
+ ct = malloc(sizeof(struct directio_context));
+ if (!ct)
+ return 1;
+ c->context = (void *)ct;
+
+ if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
+ MSG(c, "cannot get blocksize, set default");
+ ct->blksize = 512;
+ }
+ if (ct->blksize > 4096) {
+ /*
+ * Sanity check for DASD; BSZGET is broken
+ */
+ ct->blksize = 4096;
+ }
+ if (!ct->blksize)
+ goto out;
+ ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
+ if (!ct->buf)
+ goto out;
+ ct->ptr = (unsigned char *)(((unsigned long)ct->buf + pgsize - 1) &
+ (~(pgsize - 1)));
+
+ return 0;
+out:
+ free(ct);
+ return 1;
+}
+
+void directio_free (struct checker * c)
+{
+ struct directio_context * ct = (struct directio_context *)c->context;
+
+ if (!ct)
+ return;
+ if (ct->buf)
+ free(ct->buf);
+ free(ct);
+}
+
static int
direct_read (int fd, unsigned char * buff, int size)
{
@@ -65,101 +114,26 @@
return retval;
}
-extern int
-directio (int fd, char *msg, void **context)
+int directio (struct checker * c)
{
- unsigned char *buf, *ptr;
- struct readsector0_checker_context * ctxt = NULL;
- unsigned long pgsize, numsect;
- int ret, blksize;
-
- pgsize = getpagesize();
-
- /*
- * caller passed in a context : use its address
- */
- if (context)
- ctxt = (struct readsector0_checker_context *) (*context);
-
- /*
- * passed in context is uninitialized or volatile context :
- * initialize it
- */
- if (!ctxt) {
- ctxt = malloc(sizeof(struct readsector0_checker_context));
- memset(ctxt, 0, sizeof(struct readsector0_checker_context));
-
- if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
- }
- if (context)
- *context = ctxt;
- }
- if (fd <= 0) {
- MSG("no usable fd");
- ret = -1;
- goto out;
- }
-
- if (ioctl(fd, BLKGETSIZE, &numsect) < 0) {
- MSG("cannot get number of sectors, set default");
- numsect = 0;
- }
+ int ret;
+ struct directio_context * ct = (struct directio_context *)c->context;
- if (ioctl(fd, BLKBSZGET, &blksize) < 0) {
- MSG("cannot get blocksize, set default");
- blksize = 512;
- }
-
- if (blksize > 4096) {
- /*
- * Sanity check for DASD; BSZGET is broken
- */
- blksize = 4096;
- }
-
- if (!blksize) {
- /*
- * Blocksize is 0, assume we can't write
- * to this device.
- */
- MSG(MSG_DIRECTIO_DOWN);
- ret = PATH_DOWN;
- goto out;
- }
-
- buf = (unsigned char *)malloc(blksize + pgsize);
- if (!buf){
- goto out;
- }
- ptr = (unsigned char *)(((unsigned long)buf + pgsize - 1) &
- (~(pgsize - 1)));
- ret = direct_read(fd, ptr, blksize);
+ ret = direct_read(c->fd, ct->ptr, ct->blksize);
switch (ret)
{
case PATH_UNCHECKED:
- MSG(MSG_DIRECTIO_UNKNOWN);
+ MSG(c, MSG_DIRECTIO_UNKNOWN);
break;
case PATH_DOWN:
- MSG(MSG_DIRECTIO_DOWN);
+ MSG(c, MSG_DIRECTIO_DOWN);
break;
case PATH_UP:
- MSG(MSG_DIRECTIO_UP);
+ MSG(c, MSG_DIRECTIO_UP);
break;
default:
break;
}
- free(buf);
-
-out:
- /*
- * caller told us he doesn't want to keep the context :
- * free it
- */
- if (!context)
- free(ctxt);
-
return ret;
}
Added: multipath-tools/trunk/libcheckers/directio.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/directio.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _DIRECTIO_H
+#define _DIRECTIO_H
+
+int directio (struct checker *);
+int directio_init (struct checker *);
+void directio_free (struct checker *);
+
+#endif /* _DIRECTIO_H */
Modified: multipath-tools/trunk/libcheckers/emc_clariion.c
==============================================================================
--- multipath-tools/trunk/libcheckers/emc_clariion.c (original)
+++ multipath-tools/trunk/libcheckers/emc_clariion.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Lars Marowsky-Bree
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -8,7 +11,6 @@
#include <sys/ioctl.h>
#include <errno.h>
-#include "path_state.h"
#include "checkers.h"
#include "../libmultipath/sg_include.h"
@@ -18,54 +20,34 @@
#define HEAVY_CHECK_COUNT 10
struct emc_clariion_checker_context {
- int run_count;
char wwn[16];
unsigned wwn_set;
};
-int emc_clariion(int fd, char *msg, void **context)
+int emc_clariion_init (struct checker * c)
+{
+ c->context = malloc(sizeof(struct emc_clariion_checker_context));
+ if (!c->context)
+ return 1;
+ ((struct emc_clariion_checker_context *)c->context)->wwn_set = 0;
+ return 0;
+}
+
+void emc_clariion_free (struct checker * c)
+{
+ free(c->context);
+}
+
+int emc_clariion(struct checker * c)
{
unsigned char sense_buffer[256] = { 0, };
unsigned char sb[128] = { 0, };
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
sizeof(sb), 0};
struct sg_io_hdr io_hdr;
- struct emc_clariion_checker_context * ctxt = NULL;
- int ret;
-
- /*
- * caller passed in a context : use its address
- */
- if (context)
- ctxt = (struct emc_clariion_checker_context *) (*context);
-
- /*
- * passed in context is uninitialized or volatile context :
- * initialize it
- */
- if (!ctxt) {
- ctxt = malloc(sizeof(struct emc_clariion_checker_context));
- memset(ctxt, 0, sizeof(struct emc_clariion_checker_context));
-
- if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
- }
- if (context)
- *context = ctxt;
- }
- ctxt->run_count++;
-
- if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
- ctxt->run_count = 0;
- /* do stuff */
- }
+ struct emc_clariion_checker_context * ct =
+ (struct emc_clariion_checker_context *)c->context;
- if (fd <= 0) {
- MSG("no usable fd");
- ret = -1;
- goto out;
- }
memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof (inqCmdBlk);
@@ -77,21 +59,18 @@
io_hdr.sbp = sb;
io_hdr.timeout = 60000;
io_hdr.pack_id = 0;
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
- MSG("emc_clariion_checker: sending query command failed");
- ret = PATH_DOWN;
- goto out;
+ if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ MSG(c, "emc_clariion_checker: sending query command failed");
+ return PATH_DOWN;
}
if (io_hdr.info & SG_INFO_OK_MASK) {
- MSG("emc_clariion_checker: query command indicates error");
- ret = PATH_DOWN;
- goto out;
+ MSG(c, "emc_clariion_checker: query command indicates error");
+ return PATH_DOWN;
}
if (/* Verify the code page - right page & revision */
sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
- MSG("emc_clariion_checker: Path unit report page in unknown format");
- ret = PATH_DOWN;
- goto out;
+ MSG(c, "emc_clariion_checker: Path unit report page in unknown format");
+ return PATH_DOWN;
}
if ( /* Effective initiator type */
@@ -100,16 +79,14 @@
|| (sense_buffer[28] & 0x07) != 0x04
/* Arraycommpath should be set to 1 */
|| (sense_buffer[30] & 0x04) != 0x04) {
- MSG("emc_clariion_checker: Path not correctly configured for failover");
- ret = PATH_DOWN;
- goto out;
+ MSG(c, "emc_clariion_checker: Path not correctly configured for failover");
+ return PATH_DOWN;
}
if ( /* LUN operations should indicate normal operations */
sense_buffer[48] != 0x00) {
- MSG("emc_clariion_checker: Path not available for normal operations");
- ret = PATH_SHAKY;
- goto out;
+ MSG(c, "emc_clariion_checker: Path not available for normal operations");
+ return PATH_SHAKY;
}
#if 0
@@ -117,8 +94,7 @@
* _would_ bind the path */
if ( /* LUN should at least be bound somewhere */
sense_buffer[4] != 0x00) {
- ret = PATH_UP;
- goto out;
+ return PATH_UP;
}
#endif
@@ -127,27 +103,17 @@
* change in between, to protect against the path suddenly
* pointing somewhere else.
*/
- if (context && ctxt->wwn_set) {
- if (memcmp(ctxt->wwn, &sense_buffer[10], 16) != 0) {
- MSG("emc_clariion_checker: Logical Unit WWN has changed!");
- ret = PATH_DOWN;
- goto out;
+ if (ct->wwn_set) {
+ if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
+ MSG(c, "emc_clariion_checker: Logical Unit WWN has changed!");
+ return PATH_DOWN;
}
} else {
- memcpy(ctxt->wwn, &sense_buffer[10], 16);
- ctxt->wwn_set = 1;
+ memcpy(ct->wwn, &sense_buffer[10], 16);
+ ct->wwn_set = 1;
}
- MSG("emc_clariion_checker: Path healthy");
- ret = PATH_UP;
-out:
- /*
- * caller told us he doesn't want to keep the context :
- * free it
- */
- if (!context)
- free(ctxt);
-
- return(ret);
+ MSG(c, "emc_clariion_checker: Path healthy");
+ return PATH_UP;
}
Added: multipath-tools/trunk/libcheckers/emc_clariion.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/emc_clariion.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _EMC_CLARIION_H
+#define _EMC_CLARIION_H
+
+int emc_clariion (struct checker *);
+int emc_clariion_init (struct checker *);
+void emc_clariion_free (struct checker *);
+
+#endif /* _EMC_CLARIION_H */
Modified: multipath-tools/trunk/libcheckers/hp_sw.c
==============================================================================
--- multipath-tools/trunk/libcheckers/hp_sw.c (original)
+++ multipath-tools/trunk/libcheckers/hp_sw.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -8,7 +11,6 @@
#include <sys/ioctl.h>
#include <errno.h>
-#include "path_state.h"
#include "checkers.h"
#include "../libmultipath/sg_include.h"
@@ -30,9 +32,19 @@
#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
struct sw_checker_context {
- int run_count;
+ void * dummy;
};
+int hp_sw_init (struct checker * c)
+{
+ return 0;
+}
+
+void hp_sw_free (struct checker * c)
+{
+ return;
+}
+
static int
do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
void *resp, int mx_resp_len, int noisy)
@@ -112,66 +124,19 @@
}
extern int
-hp_sw (int fd, char *msg, void **context)
+hp_sw (struct checker * c)
{
char buff[MX_ALLOC_LEN];
- struct sw_checker_context * ctxt = NULL;
- int ret;
- /*
- * caller passed in a context : use its address
- */
- if (context)
- ctxt = (struct sw_checker_context *) (*context);
-
- /*
- * passed in context is uninitialized or volatile context :
- * initialize it
- */
- if (!ctxt) {
- ctxt = malloc(sizeof(struct sw_checker_context));
- memset(ctxt, 0, sizeof(struct sw_checker_context));
-
- if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
- }
- if (context)
- *context = ctxt;
+ if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ MSG(c, MSG_HP_SW_DOWN);
+ return PATH_DOWN;
}
- ctxt->run_count++;
- if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
- ctxt->run_count = 0;
- /* do stuff */
- }
- if (fd <= 0) {
- MSG("no usable fd");
- ret = -1;
- goto out;
- }
-
- if (0 != do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
- MSG(MSG_HP_SW_DOWN);
- ret = PATH_DOWN;
- goto out;
- }
-
- if (do_tur(fd)) {
- MSG(MSG_HP_SW_GHOST);
- ret = PATH_GHOST;
- } else {
- MSG(MSG_HP_SW_UP);
- ret = PATH_UP;
- }
-
-out:
- /*
- * caller told us he doesn't want to keep the context :
- * free it
- */
- if (!context)
- free(ctxt);
-
- return(ret);
+ if (do_tur(c->fd)) {
+ MSG(c, MSG_HP_SW_GHOST);
+ return PATH_GHOST;
+ }
+ MSG(c, MSG_HP_SW_UP);
+ return PATH_UP;
}
Added: multipath-tools/trunk/libcheckers/hp_sw.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/hp_sw.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _HP_SW_H
+#define _HP_SW_H
+
+int hp_sw (struct checker *);
+int hp_sw_init (struct checker *);
+void hp_sw_free (struct checker *);
+
+#endif /* _HP_SW_H */
Modified: multipath-tools/trunk/libcheckers/readsector0.c
==============================================================================
--- multipath-tools/trunk/libcheckers/readsector0.c (original)
+++ multipath-tools/trunk/libcheckers/readsector0.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -8,7 +11,6 @@
#include <sys/ioctl.h>
#include <errno.h>
-#include "path_state.h"
#include "checkers.h"
#include "../libmultipath/sg_include.h"
@@ -23,6 +25,16 @@
void * dummy;
};
+int readsector0_init (struct checker * c)
+{
+ return 0;
+}
+
+void readsector0_free (struct checker * c)
+{
+ return;
+}
+
static int
sg_read (int sg_fd, unsigned char * buff)
{
@@ -83,58 +95,23 @@
}
extern int
-readsector0 (int fd, char *msg, void **context)
+readsector0 (struct checker * c)
{
unsigned char buf[512];
- struct readsector0_checker_context * ctxt = NULL;
int ret;
- /*
- * caller passed in a context : use its address
- */
- if (context)
- ctxt = (struct readsector0_checker_context *) (*context);
-
- /*
- * passed in context is uninitialized or volatile context :
- * initialize it
- */
- if (!ctxt) {
- ctxt = malloc(sizeof(struct readsector0_checker_context));
- memset(ctxt, 0, sizeof(struct readsector0_checker_context));
-
- if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
- }
- if (context)
- *context = ctxt;
- }
- if (fd <= 0) {
- MSG("no usable fd");
- ret = -1;
- goto out;
- }
- ret = sg_read(fd, &buf[0]);
+ ret = sg_read(c->fd, &buf[0]);
switch (ret)
{
case PATH_DOWN:
- MSG(MSG_READSECTOR0_DOWN);
+ MSG(c, MSG_READSECTOR0_DOWN);
break;
case PATH_UP:
- MSG(MSG_READSECTOR0_UP);
+ MSG(c, MSG_READSECTOR0_UP);
break;
default:
break;
}
-out:
- /*
- * caller told us he doesn't want to keep the context :
- * free it
- */
- if (!context)
- free(ctxt);
-
return ret;
}
Added: multipath-tools/trunk/libcheckers/readsector0.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/readsector0.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _READSECTOR0_H
+#define _READSECTOR0_H
+
+int readsector0 (struct checker *);
+int readsector0_init (struct checker *);
+void readsector0_free (struct checker *);
+
+#endif /* _READSECTOR0_H */
Modified: multipath-tools/trunk/libcheckers/tur.c
==============================================================================
--- multipath-tools/trunk/libcheckers/tur.c (original)
+++ multipath-tools/trunk/libcheckers/tur.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,8 @@
+/*
+ * Some code borrowed from sg-utils.
+ *
+ * Copyright (c) 2004 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -8,7 +13,6 @@
#include <sys/ioctl.h>
#include <errno.h>
-#include "path_state.h"
#include "checkers.h"
#include "../libmultipath/sg_include.h"
@@ -20,52 +24,26 @@
#define MSG_TUR_DOWN "tur checker reports path is down"
struct tur_checker_context {
- int run_count;
+ void * dummy;
};
+int tur_init (struct checker * c)
+{
+ return 0;
+}
+
+void tur_free (struct checker * c)
+{
+ return;
+}
extern int
-tur (int fd, char *msg, void **context)
+tur (struct checker * c)
{
+ struct sg_io_hdr io_hdr;
unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
- struct sg_io_hdr io_hdr;
unsigned char sense_buffer[32];
- struct tur_checker_context * ctxt = NULL;
- int ret;
- /*
- * caller passed in a context : use its address
- */
- if (context)
- ctxt = (struct tur_checker_context *) (*context);
-
- /*
- * passed in context is uninitialized or volatile context :
- * initialize it
- */
- if (!ctxt) {
- ctxt = malloc(sizeof(struct tur_checker_context));
- memset(ctxt, 0, sizeof(struct tur_checker_context));
-
- if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
- }
- if (context)
- *context = ctxt;
- }
- ctxt->run_count++;
-
- if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
- ctxt->run_count = 0;
- /* do stuff */
- }
- if (fd <= 0) {
- MSG("no usable fd");
- ret = -1;
- goto out;
- }
-
memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof (turCmdBlk);
@@ -75,26 +53,14 @@
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 20000;
io_hdr.pack_id = 0;
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
- MSG(MSG_TUR_DOWN);
- ret = PATH_DOWN;
- goto out;
+ if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ MSG(c, MSG_TUR_DOWN);
+ return PATH_DOWN;
}
if (io_hdr.info & SG_INFO_OK_MASK) {
- MSG(MSG_TUR_DOWN);
- ret = PATH_DOWN;
- goto out;
+ MSG(c, MSG_TUR_DOWN);
+ return PATH_DOWN;
}
- MSG(MSG_TUR_UP);
- ret = PATH_UP;
-
-out:
- /*
- * caller told us he doesn't want to keep the context :
- * free it
- */
- if (!context)
- free(ctxt);
-
- return(ret);
+ MSG(c, MSG_TUR_UP);
+ return PATH_UP;
}
Added: multipath-tools/trunk/libcheckers/tur.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libcheckers/tur.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,8 @@
+#ifndef _TUR_H
+#define _TUR_H
+
+int tur (struct checker *);
+int tur_init (struct checker *);
+void tur_free (struct checker *);
+
+#endif /* _TUR_H */
Modified: multipath-tools/trunk/libmultipath/Makefile
==============================================================================
--- multipath-tools/trunk/libmultipath/Makefile (original)
+++ multipath-tools/trunk/libmultipath/Makefile Mon Mar 13 15:16:41 2006
@@ -6,16 +6,16 @@
include ../Makefile.inc
+CFLAGS = -I$(checkersdir)
+
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
- structs.o cache.o discovery.o propsel.o dict.o \
+ structs.o discovery.o propsel.o dict.o \
pgpolicies.o debug.o regex.o defaults.o uevent.o \
switchgroup.o uxsock.o print.o alias.o log_pthread.o \
- log.o
-
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes
+ log.o configure.o structs_vec.o
-PREVBUILD = $(shell nm debug.o|grep log_safe)
+PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
ifeq ($(strip $(DAEMON)),1)
CFLAGS += -DDAEMON
Modified: multipath-tools/trunk/libmultipath/alias.c
==============================================================================
--- multipath-tools/trunk/libmultipath/alias.c (original)
+++ multipath-tools/trunk/libmultipath/alias.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,7 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -102,7 +106,8 @@
if (err) {
if (errno != EINTR)
- condlog(0, "Cannot lock bindings file : %s");
+ condlog(0, "Cannot lock bindings file : %s",
+ strerror(errno));
else
condlog(0, "Bindings file is locked. Giving up.");
}
Modified: multipath-tools/trunk/libmultipath/blacklist.c
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.c (original)
+++ multipath-tools/trunk/libmultipath/blacklist.c Mon Mar 13 15:16:41 2006
@@ -1,60 +1,152 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
#include <stdio.h>
+#include <checkers.h>
+
#include "memory.h"
#include "vector.h"
#include "util.h"
#include "debug.h"
-#include "regex.h"
+#include "structs.h"
+#include "config.h"
#include "blacklist.h"
-static int
+extern int
store_ble (vector blist, char * str)
{
- regex_t * ble;
+ struct blentry * ble;
if (!str)
return 0;
- ble = MALLOC(sizeof(regex_t));
+ if (!blist)
+ goto out;
+
+ ble = MALLOC(sizeof(struct blentry));
if (!ble)
goto out;
- if (regcomp(ble, str, REG_EXTENDED|REG_NOSUB))
+ if (regcomp(&ble->regex, str, REG_EXTENDED|REG_NOSUB))
goto out1;
if (!vector_alloc_slot(blist))
goto out1;
+ ble->str = str;
vector_set_slot(blist, ble);
return 0;
out1:
FREE(ble);
out:
+ FREE(str);
return 1;
}
+
+extern int
+alloc_ble_device (vector blist)
+{
+ struct blentry_device * ble = MALLOC(sizeof(struct blentry_device));
+
+ if (!ble || !blist)
+ return 1;
+
+ if (!vector_alloc_slot(blist)) {
+ FREE(ble);
+ return 1;
+ }
+ vector_set_slot(blist, ble);
+ return 0;
+}
+
+extern int
+set_ble_device (vector blist, char * vendor, char * product)
+{
+ struct blentry_device * ble;
+
+ if (!blist)
+ return 1;
+
+ ble = VECTOR_SLOT(blist, VECTOR_SIZE(blist) - 1);
+
+ if (!ble)
+ return 1;
+
+ if (vendor) {
+ if (regcomp(&ble->vendor_reg, vendor,
+ REG_EXTENDED|REG_NOSUB)) {
+ FREE(vendor);
+ return 1;
+ }
+ ble->vendor = vendor;
+ }
+ if (product) {
+ if (regcomp(&ble->product_reg, product,
+ REG_EXTENDED|REG_NOSUB)) {
+ FREE(product);
+ return 1;
+ }
+ ble->product = product;
+ }
+ return 0;
+}
+
int
-setup_default_blist (vector blist)
+setup_default_blist (struct config * conf)
{
- int r = 0;
+ struct blentry * ble;
+ struct hwentry *hwe;
+ char * str;
+ int i;
- r += store_ble(blist, "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
- r += store_ble(blist, "^hd[a-z]");
- r += store_ble(blist, "^cciss!c[0-9]d[0-9]*");
+ str = STRDUP("^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*");
+ if (!str)
+ return 1;
+ if (store_ble(conf->blist_devnode, str))
+ return 1;
- return r;
+ str = STRDUP("^hd[a-z]");
+ if (!str)
+ return 1;
+ if (store_ble(conf->blist_devnode, str))
+ return 1;
+
+ str = STRDUP("^cciss!c[0-9]d[0-9]*");
+ if (!str)
+ return 1;
+ if (store_ble(conf->blist_devnode, str))
+ return 1;
+
+ vector_foreach_slot (conf->hwtable, hwe, i) {
+ if (hwe->bl_product) {
+ if (alloc_ble_device(conf->blist_device))
+ return 1;
+ ble = VECTOR_SLOT(conf->blist_device,
+ VECTOR_SIZE(conf->blist_device) -1);
+ if (set_ble_device(conf->blist_device,
+ STRDUP(hwe->vendor),
+ STRDUP(hwe->bl_product))) {
+ FREE(ble);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
int
-blacklist (vector blist, char * dev)
+blacklist (vector blist, char * str)
{
int i;
- regex_t * ble;
+ struct blentry * ble;
vector_foreach_slot (blist, ble, i) {
- if (!regexec(ble, dev, 0, NULL, 0)) {
- condlog(3, "%s blacklisted", dev);
+ if (!regexec(&ble->regex, str, 0, NULL, 0)) {
+ condlog(3, "%s: blacklisted", str);
return 1;
}
}
@@ -62,21 +154,41 @@
}
int
-store_regex (vector blist, char * regex)
+blacklist_device (vector blist, char * vendor, char * product)
{
- if (!blist)
+ int i;
+ struct blentry_device * ble;
+
+ vector_foreach_slot (blist, ble, i) {
+ if (!regexec(&ble->vendor_reg, vendor, 0, NULL, 0) &&
+ !regexec(&ble->product_reg, product, 0, NULL, 0)) {
+ condlog(3, "%s:%s: blacklisted", vendor, product);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+blacklist_path (struct config * conf, struct path * pp)
+{
+ if (blacklist(conf->blist_devnode, pp->dev))
+ return 1;
+
+ if (blacklist(conf->blist_wwid, pp->wwid))
return 1;
- if (!regex)
+ if (pp->vendor_id && pp->product_id &&
+ blacklist_device(conf->blist_device, pp->vendor_id, pp->product_id))
return 1;
- return store_ble(blist, regex);
-}
+ return 0;
+}
void
free_blacklist (vector blist)
{
- regex_t * ble;
+ struct blentry * ble;
int i;
if (!blist)
@@ -84,10 +196,31 @@
vector_foreach_slot (blist, ble, i) {
if (ble) {
- regfree(ble);
+ regfree(&ble->regex);
+ FREE(ble->str);
FREE(ble);
}
}
+ vector_free(blist);
+}
+void
+free_blacklist_device (vector blist)
+{
+ struct blentry_device * ble;
+ int i;
+
+ if (!blist)
+ return;
+
+ vector_foreach_slot (blist, ble, i) {
+ if (ble) {
+ regfree(&ble->vendor_reg);
+ regfree(&ble->product_reg);
+ FREE(ble->vendor);
+ FREE(ble->product);
+ FREE(ble);
+ }
+ }
vector_free(blist);
}
Modified: multipath-tools/trunk/libmultipath/blacklist.h
==============================================================================
--- multipath-tools/trunk/libmultipath/blacklist.h (original)
+++ multipath-tools/trunk/libmultipath/blacklist.h Mon Mar 13 15:16:41 2006
@@ -1,11 +1,28 @@
#ifndef _BLACKLIST_H
#define _BLACKLIST_H
-#define BLIST_ENTRY_SIZE 255
+#include "regex.h"
-int setup_default_blist (vector blist);
-int blacklist (vector blist, char * dev);
-int store_regex (vector blist, char * regex);
-void free_blacklist (vector blist);
+struct blentry {
+ char * str;
+ regex_t regex;
+};
+
+struct blentry_device {
+ char * vendor;
+ char * product;
+ regex_t vendor_reg;
+ regex_t product_reg;
+};
+
+int setup_default_blist (struct config *);
+int alloc_ble_device (vector);
+int blacklist (vector, char *);
+int blacklist_device (vector, char *, char *);
+int blacklist_path (struct config *, struct path *);
+int store_ble (vector, char *);
+int set_ble_device (vector, char *, char *);
+void free_blacklist (vector);
+void free_blacklist_device (vector);
#endif /* _BLACKLIST_H */
Modified: multipath-tools/trunk/libmultipath/callout.c
==============================================================================
--- multipath-tools/trunk/libmultipath/callout.c (original)
+++ multipath-tools/trunk/libmultipath/callout.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Source: copy of the udev package source file
+ *
+ * Copyrights of the source file apply
+ * Copyright (c) 2004 Christophe Varoqui
+ */
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
@@ -7,6 +13,12 @@
#include <sys/wait.h>
#include <errno.h>
+#include <checkers.h>
+
+#include "vector.h"
+#include "structs.h"
+#include "debug.h"
+
#define PROGRAM_SIZE 100
#define FIELD_PROGRAM
@@ -103,3 +115,79 @@
}
return retval;
}
+
+extern int
+apply_format (char * string, char * cmd, struct path * pp)
+{
+ char * pos;
+ char * dst;
+ char * p;
+ int len;
+ int myfree;
+
+ if (!string)
+ return 1;
+
+ if (!cmd)
+ return 1;
+
+ dst = cmd;
+ p = dst;
+ pos = strchr(string, '%');
+ myfree = CALLOUT_MAX_SIZE;
+
+ if (!pos) {
+ strcpy(dst, string);
+ return 0;
+ }
+
+ len = (int) (pos - string) + 1;
+ myfree -= len;
+
+ if (myfree < 2)
+ return 1;
+
+ snprintf(p, len, "%s", string);
+ p += len - 1;
+ pos++;
+
+ switch (*pos) {
+ case 'n':
+ len = strlen(pp->dev) + 1;
+ myfree -= len;
+
+ if (myfree < 2)
+ return 1;
+
+ snprintf(p, len, "%s", pp->dev);
+ p += len - 1;
+ break;
+ case 'd':
+ len = strlen(pp->dev_t) + 1;
+ myfree -= len;
+
+ if (myfree < 2)
+ return 1;
+
+ snprintf(p, len, "%s", pp->dev_t);
+ p += len - 1;
+ break;
+ default:
+ break;
+ }
+ pos++;
+
+ if (!*pos)
+ return 0;
+
+ len = strlen(pos) + 1;
+ myfree -= len;
+
+ if (myfree < 2)
+ return 1;
+
+ snprintf(p, len, "%s", pos);
+ condlog(3, "reformated callout = %s", dst);
+ return 0;
+}
+
Modified: multipath-tools/trunk/libmultipath/callout.h
==============================================================================
--- multipath-tools/trunk/libmultipath/callout.h (original)
+++ multipath-tools/trunk/libmultipath/callout.h Mon Mar 13 15:16:41 2006
@@ -1 +1,7 @@
+#ifndef _CALLOUT_H
+#define _CALLOUT_H
+
int execute_program(char *, char *, int);
+int apply_format (char *, char *, struct path *);
+
+#endif /* _CALLOUT_H */
Modified: multipath-tools/trunk/libmultipath/config.c
==============================================================================
--- multipath-tools/trunk/libmultipath/config.c (original)
+++ multipath-tools/trunk/libmultipath/config.c Mon Mar 13 15:16:41 2006
@@ -1,7 +1,13 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
#include <stdio.h>
#include <string.h>
-#include "regex.h"
+#include <checkers.h>
+
#include "memory.h"
#include "util.h"
#include "debug.h"
@@ -9,11 +15,10 @@
#include "dict.h"
#include "hwtable.h"
#include "vector.h"
+#include "structs.h"
+#include "config.h"
#include "blacklist.h"
#include "defaults.h"
-#include "config.h"
-
-#include "../libcheckers/checkers.h"
struct hwentry *
find_hwe (vector hwtable, char * vendor, char * product)
@@ -101,6 +106,9 @@
if (hwe->hwhandler)
FREE(hwe->hwhandler);
+ if (hwe->bl_product)
+ FREE(hwe->bl_product);
+
FREE(hwe);
}
@@ -208,114 +216,47 @@
}
int
-store_hwe (vector hwtable, char * vendor, char * product, int pgp,
- char * getuid)
+store_hwe (vector hwtable, struct hwentry * dhwe)
{
struct hwentry * hwe;
- if (dup_hwe(hwtable, vendor, product))
+ if (dup_hwe(hwtable, dhwe->vendor, dhwe->product))
return 0;
-
- hwe = alloc_hwe();
-
- if (!hwe)
+
+ if (!(hwe = alloc_hwe()))
return 1;
- hwe->vendor = set_param_str(vendor);
-
- if (!hwe->vendor)
+ if (!dhwe->vendor || !(hwe->vendor = set_param_str(dhwe->vendor)))
goto out;
- hwe->product = set_param_str(product);
-
- if (!hwe->product)
+ if (!dhwe->product || !(hwe->product = set_param_str(dhwe->product)))
goto out;
- if (pgp)
- hwe->pgpolicy = pgp;
-
- if (getuid)
- hwe->getuid = set_param_str(getuid);
- else
- hwe->getuid = set_default(DEFAULT_GETUID);
-
- if (!hwe->getuid)
+ if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
goto out;
-
- if (!vector_alloc_slot(hwtable))
- goto out;
-
- vector_set_slot(hwtable, hwe);
- return 0;
-out:
- free_hwe(hwe);
- return 1;
-}
-int
-store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
- char * getuid, char * getprio, char * hwhandler,
- char * features, char * checker, int pgfailback)
-{
- struct hwentry * hwe;
-
- if (dup_hwe(hwtable, vendor, product))
- return 0;
-
- hwe = alloc_hwe();
-
- if (!hwe)
- return 1;
-
- hwe->vendor = set_param_str(vendor);
-
- if (!hwe->vendor)
+ if (dhwe->getprio && !(hwe->getprio = set_param_str(dhwe->getprio)))
goto out;
-
- hwe->product = set_param_str(product);
-
- if (!hwe->product)
+
+ if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
goto out;
- if (pgp)
- hwe->pgpolicy = pgp;
-
- if (getuid)
- hwe->getuid = set_param_str(getuid);
- else
- hwe->getuid = set_default(DEFAULT_GETUID);
-
- if (!hwe->getuid)
+ if (dhwe->hwhandler && !(hwe->hwhandler = set_param_str(dhwe->hwhandler)))
goto out;
-
- if (getprio)
- hwe->getprio = set_param_str(getprio);
- else
- hwe->getprio = NULL;
-
- if (hwhandler)
- hwe->hwhandler = set_param_str(hwhandler);
- else
- hwe->hwhandler = set_default(DEFAULT_HWHANDLER);
- if (!hwe->hwhandler)
+ if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
goto out;
+
+ hwe->pgpolicy = dhwe->pgpolicy;
+ hwe->pgfailback = dhwe->pgfailback;
+ hwe->rr_weight = dhwe->rr_weight;
+ hwe->no_path_retry = dhwe->no_path_retry;
+ hwe->minio = dhwe->minio;
+ hwe->checker = dhwe->checker;
- if (features)
- hwe->features = set_param_str(features);
- else
- hwe->features = set_default(DEFAULT_FEATURES);
-
- if (!hwe->features)
+ if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
goto out;
- if (checker)
- hwe->checker_index = get_checker_id(checker);
- else
- hwe->checker_index = get_checker_id(DEFAULT_CHECKER);
-
- hwe->pgfailback = pgfailback;
-
if (!vector_alloc_slot(hwtable))
goto out;
@@ -347,19 +288,21 @@
if (conf->selector)
FREE(conf->selector);
- if (conf->default_getuid)
- FREE(conf->default_getuid);
+ if (conf->getuid)
+ FREE(conf->getuid);
- if (conf->default_getprio)
- FREE(conf->default_getprio);
+ if (conf->getprio)
+ FREE(conf->getprio);
if (conf->features)
FREE(conf->features);
- if (conf->default_hwhandler)
- FREE(conf->default_hwhandler);
+ if (conf->hwhandler)
+ FREE(conf->hwhandler);
- free_blacklist(conf->blist);
+ free_blacklist(conf->blist_devnode);
+ free_blacklist(conf->blist_wwid);
+ free_blacklist_device(conf->blist_device);
free_mptable(conf->mptable);
free_hwtable(conf->hwtable);
@@ -408,15 +351,27 @@
if (setup_default_hwtable(conf->hwtable))
goto out;
- if (conf->blist == NULL) {
- conf->blist = vector_alloc();
+ if (conf->blist_devnode == NULL) {
+ conf->blist_devnode = vector_alloc();
- if (!conf->blist)
+ if (!conf->blist_devnode)
goto out;
+ }
+ if (conf->blist_wwid == NULL) {
+ conf->blist_wwid = vector_alloc();
+
+ if (!conf->blist_wwid)
+ goto out;
+ }
+ if (conf->blist_device == NULL) {
+ conf->blist_device = vector_alloc();
- if (setup_default_blist(conf->blist))
+ if (!conf->blist_device)
goto out;
}
+ if (setup_default_blist(conf))
+ goto out;
+
if (conf->mptable == NULL) {
conf->mptable = vector_alloc();
@@ -429,22 +384,22 @@
if (conf->udev_dir == NULL)
conf->udev_dir = set_default(DEFAULT_UDEVDIR);
- if (conf->default_getuid == NULL)
- conf->default_getuid = set_default(DEFAULT_GETUID);
+ if (conf->getuid == NULL)
+ conf->getuid = set_default(DEFAULT_GETUID);
if (conf->features == NULL)
conf->features = set_default(DEFAULT_FEATURES);
- if (conf->default_hwhandler == NULL)
- conf->default_hwhandler = set_default(DEFAULT_HWHANDLER);
+ if (conf->hwhandler == NULL)
+ conf->hwhandler = set_default(DEFAULT_HWHANDLER);
if (!conf->selector || !conf->udev_dir ||
- !conf->default_getuid || !conf->features ||
- !conf->default_hwhandler)
+ !conf->getuid || !conf->features ||
+ !conf->hwhandler)
goto out;
- if (!conf->default_checker_index)
- conf->default_checker_index = READSECTOR0;
+ if (!conf->checker)
+ conf->checker = checker_lookup(DEFAULT_CHECKER);
return 0;
out:
Modified: multipath-tools/trunk/libmultipath/config.h
==============================================================================
--- multipath-tools/trunk/libmultipath/config.h (original)
+++ multipath-tools/trunk/libmultipath/config.h Mon Mar 13 15:16:41 2006
@@ -1,10 +1,6 @@
#ifndef _CONFIG_H
#define _CONFIG_H
-#ifndef _VECTOR_H
-#include "vector.h"
-#endif
-
enum devtypes {
DEV_NONE,
DEV_DEVT,
@@ -13,33 +9,35 @@
};
struct hwentry {
- int selector_args;
- int pgpolicy;
- int checker_index;
- int pgfailback;
- int rr_weight;
- int no_path_retry;
-
char * vendor;
char * product;
- char * selector;
char * getuid;
char * getprio;
char * features;
char * hwhandler;
-};
+ char * selector;
+ char * checker_name;
-struct mpentry {
- int selector_args;
int pgpolicy;
int pgfailback;
int rr_weight;
int no_path_retry;
+ int minio;
+ struct checker * checker;
+ char * bl_product;
+};
+struct mpentry {
char * wwid;
- char * selector;
- char * getuid;
char * alias;
+ char * getuid;
+ char * selector;
+
+ int pgpolicy;
+ int pgfailback;
+ int rr_weight;
+ int no_path_retry;
+ int minio;
};
struct config {
@@ -48,9 +46,8 @@
int list;
int pgpolicy_flag;
int with_sysfs;
- int selector_args;
- int default_pgpolicy;
- int default_checker_index;
+ int pgpolicy;
+ struct checker * checker;
int dev_type;
int minio;
int checkint;
@@ -64,15 +61,18 @@
char * dev;
char * udev_dir;
char * selector;
- char * default_getuid;
- char * default_getprio;
+ char * getuid;
+ char * getprio;
char * features;
- char * default_hwhandler;
+ char * hwhandler;
char * bindings_file;
vector mptable;
vector hwtable;
- vector blist;
+
+ vector blist_devnode;
+ vector blist_wwid;
+ vector blist_device;
};
struct config * conf;
@@ -88,11 +88,7 @@
void free_mpe (struct mpentry * mpe);
void free_mptable (vector mptable);
-int store_hwe (vector hwtable, char * vendor, char * product, int pgp,
- char * getuid);
-int store_hwe_ext (vector hwtable, char * vendor, char * product, int pgp,
- char * getuid, char * getprio, char * hwhandler,
- char * features, char * checker, int pgfailback);
+int store_hwe (vector hwtable, struct hwentry *);
int load_config (char * file);
struct config * alloc_config (void);
Added: multipath-tools/trunk/libmultipath/configure.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/configure.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <libdevmapper.h>
+
+#include <checkers.h>
+
+#include "vector.h"
+#include "memory.h"
+#include "devmapper.h"
+#include "defaults.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "dmparser.h"
+#include "config.h"
+#include "blacklist.h"
+#include "propsel.h"
+#include "discovery.h"
+#include "debug.h"
+#include "switchgroup.h"
+#include "print.h"
+#include "configure.h"
+#include "pgpolicies.h"
+#include "dict.h"
+#include "alias.h"
+
+extern int
+setup_map (struct multipath * mpp)
+{
+ struct pathgroup * pgp;
+ int i;
+
+ /*
+ * don't bother if devmap size is unknown
+ */
+ if (mpp->size <= 0) {
+ condlog(3, "%s: devmap size is unknown", mpp->alias);
+ return 1;
+ }
+
+ /*
+ * 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);
+
+ /*
+ * assign paths to path groups -- start with no groups and all paths
+ * in mpp->paths
+ */
+ if (mpp->pg) {
+ vector_foreach_slot (mpp->pg, pgp, i)
+ free_pathgroup(pgp, KEEP_PATHS);
+
+ vector_free(mpp->pg);
+ mpp->pg = NULL;
+ }
+ if (mpp->pgpolicyfn && mpp->pgpolicyfn(mpp))
+ return 1;
+
+ mpp->nr_active = pathcount(mpp, PATH_UP);
+
+ /*
+ * ponders each path group and determine highest prio pg
+ * to switch over (default to first)
+ */
+ mpp->bestpg = select_path_group(mpp);
+
+ /*
+ * transform the mp->pg vector of vectors of paths
+ * into a mp->params strings to feed the device-mapper
+ */
+ if (assemble_map(mpp)) {
+ condlog(0, "%s: problem assembing map", mpp->alias);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+compute_pgid(struct pathgroup * pgp)
+{
+ struct path * pp;
+ int i;
+
+ vector_foreach_slot (pgp->paths, pp, i)
+ pgp->id ^= (long)pp;
+}
+
+static int
+pgcmp (struct multipath * mpp, struct multipath * cmpp)
+{
+ int i, j;
+ struct pathgroup * pgp;
+ struct pathgroup * cpgp;
+ int r = 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ compute_pgid(pgp);
+
+ vector_foreach_slot (cmpp->pg, cpgp, j) {
+ if (pgp->id == cpgp->id) {
+ r = 0;
+ break;
+ }
+ r++;
+ }
+ if (r)
+ return r;
+ }
+ return r;
+}
+
+static void
+select_action (struct multipath * mpp, vector curmp)
+{
+ struct multipath * cmpp;
+
+ cmpp = find_mp_by_alias(curmp, mpp->alias);
+
+ if (!cmpp) {
+ cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+
+ if (cmpp && !conf->dry_run) {
+ condlog(2, "%s: rename %s to %s", mpp->wwid,
+ cmpp->alias, mpp->alias);
+ strncpy(mpp->alias_old, cmpp->alias, WWID_SIZE);
+ mpp->action = ACT_RENAME;
+ return;
+ }
+ else {
+ condlog(3, "%s: set ACT_CREATE (map does not exist)",
+ mpp->alias);
+ mpp->action = ACT_CREATE;
+ }
+ mpp->action = ACT_CREATE;
+ condlog(3, "%s: set ACT_CREATE (map does not exist)",
+ mpp->alias);
+ return;
+ }
+
+ if (!find_mp_by_wwid(curmp, mpp->wwid)) {
+ condlog(2, "%s: remove (wwid changed)", cmpp->alias);
+ dm_flush_map(mpp->alias, DEFAULT_TARGET);
+ strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
+ drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
+ mpp->action = ACT_CREATE;
+ condlog(3, "%s: set ACT_CREATE (map wwid change)",
+ mpp->alias);
+ return;
+ }
+
+ if (pathcount(mpp, PATH_UP) == 0) {
+ mpp->action = ACT_NOTHING;
+ condlog(3, "%s: set ACT_NOTHING (no usable path)",
+ mpp->alias);
+ return;
+ }
+ if (cmpp->size != mpp->size) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (size change)",
+ mpp->alias);
+ return;
+ }
+ if (!mpp->no_path_retry && /* let features be handled by the daemon */
+ strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (features change)",
+ mpp->alias);
+ return;
+ }
+ if (strncmp(cmpp->hwhandler, mpp->hwhandler,
+ strlen(mpp->hwhandler))) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (hwhandler change)",
+ mpp->alias);
+ return;
+ }
+ if (strncmp(cmpp->selector, mpp->selector,
+ strlen(mpp->selector))) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (selector change)",
+ mpp->alias);
+ return;
+ }
+ if (cmpp->minio != mpp->minio) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (minio change, %u->%u)",
+ mpp->alias, cmpp->minio, mpp->minio);
+ return;
+ }
+ if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (path group number change)",
+ mpp->alias);
+ return;
+ }
+ if (pgcmp(mpp, cmpp)) {
+ mpp->action = ACT_RELOAD;
+ condlog(3, "%s: set ACT_RELOAD (path group topology change)",
+ mpp->alias);
+ return;
+ }
+ if (cmpp->nextpg != mpp->bestpg) {
+ mpp->action = ACT_SWITCHPG;
+ condlog(3, "%s: set ACT_SWITCHPG (next path group change)",
+ mpp->alias);
+ return;
+ }
+ mpp->action = ACT_NOTHING;
+ condlog(3, "%s: set ACT_NOTHING (map unchanged)",
+ mpp->alias);
+ return;
+}
+
+extern int
+reinstate_paths (struct multipath * mpp)
+{
+ int i, j;
+ struct pathgroup * pgp;
+ struct path * pp;
+
+ if (!mpp->pg)
+ return 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (pp->state != PATH_UP &&
+ (pgp->status == PGSTATE_DISABLED ||
+ pgp->status == PGSTATE_ACTIVE))
+ continue;
+
+ if (pp->dmstate == PSTATE_FAILED) {
+ if (dm_reinstate_path(mpp->alias, pp->dev_t))
+ condlog(0, "%s: error reinstating",
+ pp->dev);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+lock_multipath (struct multipath * mpp, int lock)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i, j;
+
+ if (!mpp || !mpp->pg)
+ return 0;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+ vector_foreach_slot(pgp->paths, pp, j) {
+ if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
+ errno == EWOULDBLOCK)
+ return 1;
+ else if (!lock)
+ flock(pp->fd, LOCK_UN);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Return value:
+ * -1: Retry
+ * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
+ * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
+ * 2: Map is already existing.
+ */
+extern int
+domap (struct multipath * mpp)
+{
+ int r = 0;
+
+ /*
+ * last chance to quit before touching the devmaps
+ */
+ if (conf->dry_run) {
+ print_multipath_topology(mpp, conf->verbosity);
+ return 0;
+ }
+
+ switch (mpp->action) {
+ case ACT_REJECT:
+ case ACT_NOTHING:
+ return 2;
+
+ case ACT_SWITCHPG:
+ dm_switchgroup(mpp->alias, mpp->bestpg);
+ /*
+ * we may have avoided reinstating paths because there where in
+ * active or disabled PG. Now that the topology has changed,
+ * retry.
+ */
+ reinstate_paths(mpp);
+ return 2;
+
+ case ACT_CREATE:
+ if (lock_multipath(mpp, 1)) {
+ condlog(3, "%s: failed to create map (in use)",
+ mpp->alias);
+ return -1;
+ }
+ dm_shut_log();
+
+ if (dm_map_present(mpp->alias))
+ break;
+
+ r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
+ mpp->params, mpp->size, mpp->wwid);
+
+ /*
+ * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
+ * DM_TABLE_LOAD. Failing the second part leaves an
+ * empty map. Clean it up.
+ */
+ if (!r && dm_map_present(mpp->alias)) {
+ condlog(3, "%s: failed to load map "
+ "(a path might be in use)",
+ mpp->alias);
+ dm_flush_map(mpp->alias, DEFAULT_TARGET);
+ }
+
+ lock_multipath(mpp, 0);
+ dm_restore_log();
+ break;
+
+ case ACT_RELOAD:
+ r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
+ mpp->params, mpp->size, NULL) &&
+ dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
+ break;
+
+ case ACT_RENAME:
+ r = dm_rename(mpp->alias_old, mpp->alias);
+ break;
+
+ default:
+ break;
+ }
+
+ if (r) {
+ /*
+ * DM_DEVICE_CREATE, DM_DEIVCE_RENAME, or DM_DEVICE_RELOAD
+ * succeeded
+ */
+#ifndef DAEMON
+ dm_switchgroup(mpp->alias, mpp->bestpg);
+ if (mpp->action != ACT_NOTHING)
+ print_multipath_topology(mpp, conf->verbosity);
+#else
+ mpp->stat_map_loads++;
+ condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
+ mpp->size, DEFAULT_TARGET, mpp->params);
+#endif
+ }
+
+ return r;
+}
+
+static int
+deadmap (struct multipath * mpp)
+{
+ int i, j;
+ struct pathgroup * pgp;
+ struct path * pp;
+
+ if (!mpp->pg)
+ return 1;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ if (!pgp->paths)
+ continue;
+
+ vector_foreach_slot (pgp->paths, pp, j)
+ if (strlen(pp->dev))
+ return 0; /* alive */
+ }
+
+ return 1; /* dead */
+}
+
+extern int
+coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
+{
+ int r = 1;
+ int k, i;
+ char empty_buff[WWID_SIZE];
+ struct multipath * mpp;
+ struct path * pp1;
+ struct path * pp2;
+ vector curmp = vecs->mpvec;
+ vector pathvec = vecs->pathvec;
+
+ memset(empty_buff, 0, WWID_SIZE);
+
+ vector_foreach_slot (pathvec, pp1, k) {
+ /* skip this path for some reason */
+
+ /* 1. if path has no unique id or wwid blacklisted */
+ if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
+ blacklist_path(conf, pp1))
+ continue;
+
+ /* 2. if path already coalesced */
+ if (pp1->mpp)
+ continue;
+
+ /* 3. if path has disappeared */
+ if (!pp1->size)
+ continue;
+
+ /* 4. path is out of scope */
+ if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
+ continue;
+
+ /*
+ * at this point, we know we really got a new mp
+ */
+ if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL)
+ return 1;
+
+ if (pp1->priority < 0)
+ mpp->action = ACT_REJECT;
+
+ if (!mpp->paths) {
+ condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
+ remove_map(mpp, vecs, NULL, 0);
+ continue;
+ }
+
+ for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
+ pp2 = VECTOR_SLOT(pathvec, i);
+
+ if (strcmp(pp1->wwid, pp2->wwid))
+ continue;
+
+ if (!pp2->size)
+ continue;
+
+ if (pp2->size != mpp->size) {
+ /*
+ * ouch, avoid feeding that to the DM
+ */
+ condlog(0, "%s: size %llu, expected %llu. "
+ "Discard", pp2->dev_t, pp2->size,
+ mpp->size);
+ mpp->action = ACT_REJECT;
+ }
+ if (pp2->priority < 0)
+ mpp->action = ACT_REJECT;
+ }
+ verify_paths(mpp, vecs, NULL);
+
+ if (setup_map(mpp)) {
+ remove_map(mpp, vecs, NULL, 0);
+ continue;
+ }
+
+ if (mpp->action == ACT_UNDEF)
+ select_action(mpp, curmp);
+
+ r = domap(mpp);
+
+ if (!r) {
+ condlog(3, "%s: domap (%u) failure "
+ "for create/reload map",
+ mpp->alias, r);
+ remove_map(mpp, vecs, NULL, 0);
+ continue;
+ }
+ else if (r < 0) {
+ condlog(3, "%s: domap (%u) failure "
+ "for create/reload map",
+ mpp->alias, r);
+ return r;
+ }
+
+ if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+ if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+ dm_queue_if_no_path(mpp->alias, 0);
+ else
+ dm_queue_if_no_path(mpp->alias, 1);
+ }
+
+ if (newmp) {
+ if (mpp->action != ACT_REJECT) {
+ if (!vector_alloc_slot(newmp))
+ return 1;
+ vector_set_slot(newmp, mpp);
+ }
+ else
+ remove_map(mpp, vecs, NULL, 0);
+ }
+ }
+ /*
+ * Flush maps with only dead paths (ie not in sysfs)
+ * Keep maps with only failed paths
+ */
+ 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);
+
+ remove_map(mpp, vecs, NULL, 0);
+
+ if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
+ condlog(2, "%s: remove failed (dead)",
+ mpp->alias);
+ else
+ condlog(2, "%s: remove (dead)", mpp->alias);
+ }
+ }
+ return 0;
+}
+
+extern char *
+get_refwwid (char * dev, int dev_type, vector pathvec)
+{
+ struct path * pp;
+ char buff[FILE_NAME_SIZE];
+ char * refwwid;
+
+ if (dev_type == DEV_NONE)
+ return NULL;
+
+ if (dev_type == DEV_DEVNODE) {
+ basename(dev, buff);
+ pp = find_path_by_dev(pathvec, buff);
+
+ if (!pp) {
+ pp = alloc_path();
+
+ if (!pp)
+ return NULL;
+
+ strncpy(pp->dev, buff, FILE_NAME_SIZE);
+
+ if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+ return NULL;
+
+ if (store_path(pathvec, pp)) {
+ free_path(pp);
+ return NULL;
+ }
+ }
+ refwwid = pp->wwid;
+ goto out;
+ }
+
+ if (dev_type == DEV_DEVT) {
+ pp = find_path_by_devt(pathvec, dev);
+
+ if (!pp) {
+ if (devt2devname(buff, dev))
+ return NULL;
+
+ pp = alloc_path();
+
+ if (!pp)
+ return NULL;
+
+ strncpy(pp->dev, buff, FILE_NAME_SIZE);
+
+ if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
+ return NULL;
+
+ if (store_path(pathvec, pp)) {
+ free_path(pp);
+ return NULL;
+ }
+ }
+ refwwid = pp->wwid;
+ goto out;
+ }
+ if (dev_type == DEV_DEVMAP) {
+ /*
+ * may be a binding
+ */
+ refwwid = get_user_friendly_wwid(dev,
+ conf->bindings_file);
+
+ if (refwwid)
+ return refwwid;
+
+ /*
+ * or may be an alias
+ */
+ refwwid = get_mpe_wwid(dev);
+
+ /*
+ * or directly a wwid
+ */
+ if (!refwwid)
+ refwwid = dev;
+ }
+out:
+ if (refwwid && strlen(refwwid))
+ return STRDUP(refwwid);
+
+ return NULL;
+}
+
Added: multipath-tools/trunk/libmultipath/configure.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/configure.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,29 @@
+/*
+ * configurator actions
+ */
+#define ACT_NOTHING_STR "unchanged"
+#define ACT_REJECT_STR "reject"
+#define ACT_RELOAD_STR "reload"
+#define ACT_SWITCHPG_STR "switchpg"
+#define ACT_RENAME_STR "rename"
+#define ACT_CREATE_STR "create"
+
+enum actions {
+ ACT_UNDEF,
+ ACT_NOTHING,
+ ACT_REJECT,
+ ACT_RELOAD,
+ ACT_SWITCHPG,
+ ACT_RENAME,
+ ACT_CREATE
+};
+
+#define FLUSH_ONE 1
+#define FLUSH_ALL 2
+
+int setup_map (struct multipath * mpp);
+int domap (struct multipath * mpp);
+int reinstate_paths (struct multipath *mpp);
+int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid);
+char * get_refwwid (char * dev, int dev_type, vector pathvec);
+
Modified: multipath-tools/trunk/libmultipath/debug.c
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.c (original)
+++ multipath-tools/trunk/libmultipath/debug.c Mon Mar 13 15:16:41 2006
@@ -1,11 +1,17 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#if DAEMON
#include "log_pthread.h"
+#include <sys/types.h>
+#include <time.h>
#endif
+#include "vector.h"
#include "config.h"
void dlog (int sink, int prio, char * fmt, ...)
@@ -17,13 +23,23 @@
thres = (conf) ? conf->verbosity : 0;
if (prio <= thres) {
+#if DAEMON
if (!sink) {
+ time_t t = time(NULL);
+ struct tm *tb = localtime(&t);
+ char buff[16];
+
+ strftime(buff, 16, "%b %d %H:%M:%S", tb);
+
+ fprintf(stdout, "%s | ", buff);
vfprintf(stdout, fmt, ap);
fprintf(stdout, "\n");
}
-#if DAEMON
else
log_safe(prio + 3, fmt, ap);
+#else
+ vfprintf(stdout, fmt, ap);
+ fprintf(stdout, "\n");
#endif
}
va_end(ap);
Modified: multipath-tools/trunk/libmultipath/debug.h
==============================================================================
--- multipath-tools/trunk/libmultipath/debug.h (original)
+++ multipath-tools/trunk/libmultipath/debug.h Mon Mar 13 15:16:41 2006
@@ -1,4 +1,5 @@
-void dlog (int sink, int prio, char * fmt, ...);
+void dlog (int sink, int prio, char * fmt, ...)
+ __attribute__((format(printf, 3, 4)));
#if DAEMON
Modified: multipath-tools/trunk/libmultipath/defaults.c
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.c (original)
+++ multipath-tools/trunk/libmultipath/defaults.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <string.h>
#include "memory.h"
Modified: multipath-tools/trunk/libmultipath/defaults.h
==============================================================================
--- multipath-tools/trunk/libmultipath/defaults.h (original)
+++ multipath-tools/trunk/libmultipath/defaults.h Mon Mar 13 15:16:41 2006
@@ -3,12 +3,21 @@
#define DEFAULT_SELECTOR "round-robin 0"
#define DEFAULT_FEATURES "0"
#define DEFAULT_HWHANDLER "0"
-#define DEFAULT_CHECKER "readsector0"
+#define DEFAULT_MINIO 1000
+#define DEFAULT_GETPRIO NULL
+#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_USER_FRIENDLY_NAMES 0
+
+#define DEFAULT_CHECKINT 5
+#define MAX_CHECKINT(a) (a << 2)
#define DEFAULT_TARGET "multipath"
#define DEFAULT_PIDFILE "/var/run/multipathd.pid"
#define DEFAULT_SOCKET "/var/run/multipathd.sock"
#define DEFAULT_CONFIGFILE "/etc/multipath.conf"
-#define DEFAULT_BINDINGS_FILE "/var/lib/multipath/bindings"
+#define DEFAULT_BINDINGS_FILE "/var/lib/multipath/bindings"
char * set_default (char * str);
Modified: multipath-tools/trunk/libmultipath/devmapper.c
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.c (original)
+++ multipath-tools/trunk/libmultipath/devmapper.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * snippets copied from device-mapper dmsetup.c
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -6,6 +12,8 @@
#include <linux/kdev_t.h>
#include <unistd.h>
+#include <checkers.h>
+
#include "vector.h"
#include "structs.h"
#include "debug.h"
@@ -381,7 +389,7 @@
if (!dm_map_present(mapname))
return 0;
- if (!dm_type(mapname, type))
+ if (dm_type(mapname, type) <= 0)
return 1;
if (dm_remove_partmaps(mapname))
@@ -562,7 +570,7 @@
do {
info = dm_type(names->name, type);
- if (!info)
+ if (info <= 0)
goto next;
mpp = alloc_multipath();
@@ -604,6 +612,35 @@
return r;
}
+extern int
+dm_get_name(char *uuid, char *type, char *name)
+{
+ vector vec;
+ struct multipath *mpp;
+ int i;
+
+ vec = vector_alloc();
+
+ if (!vec)
+ return 0;
+
+ if (dm_get_maps(vec, type)) {
+ vector_free(vec);
+ return 0;
+ }
+
+ vector_foreach_slot(vec, mpp, i) {
+ if (!strcmp(uuid, mpp->wwid)) {
+ vector_free(vec);
+ strcpy(name, mpp->alias);
+ return 1;
+ }
+ }
+
+ vector_free(vec);
+ return 0;
+}
+
int
dm_geteventnr (char *name)
{
@@ -640,7 +677,8 @@
char *
dm_mapname(int major, int minor)
{
- char * response;
+ char * response = NULL;
+ const char *map;
struct dm_task *dmt;
int r;
int loop = MAX_WAIT * LOOPS_PER_SEC;
@@ -674,7 +712,10 @@
goto bad;
}
- response = STRDUP((char *)dm_task_get_name(dmt));
+ map = dm_task_get_name(dmt);
+ if (map && strlen(map))
+ response = STRDUP((char *)dm_task_get_name(dmt));
+
dm_task_destroy(dmt);
return response;
bad:
@@ -718,7 +759,7 @@
/*
* if devmap target is "linear"
*/
- dm_type(names->name, "linear") &&
+ (dm_type(names->name, "linear") > 0) &&
/*
* and the multipath mapname and the part mapname start
@@ -806,15 +847,91 @@
return r;
}
-#if 0
int
-dm_rename (char * old, char * new)
+dm_rename_partmaps (char * old, char * new)
{
+ struct dm_task *dmt;
+ struct dm_names *names;
+ unsigned next = 0;
+ char buff[PARAMS_SIZE];
+ unsigned long long size;
+ char dev_t[32];
int r = 1;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ return 1;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!(names = dm_task_get_names(dmt)))
+ goto out;
+
+ if (!names->dev) {
+ r = 0; /* this is perfectly valid */
+ goto out;
+ }
+
+ if (dm_dev_t(old, &dev_t[0], 32))
+ goto out;
+
+ do {
+ if (
+ /*
+ * if devmap target is "linear"
+ */
+ (dm_type(names->name, "linear") > 0) &&
+
+ /*
+ * and the multipath mapname and the part mapname start
+ * the same
+ */
+ !strncmp(names->name, old, strlen(old)) &&
+
+ /*
+ * and we can fetch the map table from the kernel
+ */
+ !dm_get_map(names->name, &size, &buff[0]) &&
+
+ /*
+ * and the table maps over the multipath map
+ */
+ strstr(buff, dev_t)
+ ) {
+ /*
+ * then it's a kpartx generated partition.
+ * Rename it.
+ */
+ snprintf(buff, PARAMS_SIZE, "%s%s",
+ new, names->name + strlen(old));
+ dm_rename(names->name, buff);
+ condlog(4, "partition map %s renamed",
+ names->name);
+ }
+
+ next = names->next;
+ names = (void *) names + next;
+ } while (next);
+
+ r = 0;
+out:
+ dm_task_destroy (dmt);
+ return r;
+}
+
+int
+dm_rename (char * old, char * new)
+{
+ int r = 0;
struct dm_task *dmt;
+ if (dm_rename_partmaps(old, new))
+ return r;
+
if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
- return 0;
+ return r;
if (!dm_task_set_name(dmt, old))
goto out;
@@ -827,9 +944,8 @@
if (!dm_task_run(dmt))
goto out;
- r = 0;
+ r = 1;
out:
dm_task_destroy(dmt);
return r;
}
-#endif
Modified: multipath-tools/trunk/libmultipath/devmapper.h
==============================================================================
--- multipath-tools/trunk/libmultipath/devmapper.h (original)
+++ multipath-tools/trunk/libmultipath/devmapper.h Mon Mar 13 15:16:41 2006
@@ -23,7 +23,5 @@
int dm_remove_partmaps (char * mapname);
int dm_get_uuid(char *name, char *uuid);
int dm_get_info (char * mapname, struct dm_info ** dmi);
-
-#if 0
int dm_rename (char * old, char * new);
-#endif
+int dm_get_name(char * uuid, char * type, char * name);
Modified: multipath-tools/trunk/libmultipath/dict.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.c (original)
+++ multipath-tools/trunk/libmultipath/dict.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,11 @@
+/*
+ * Based on Alexandre Cassen template for keepalived
+ * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ */
+#include <checkers.h>
+
#include "vector.h"
#include "hwtable.h"
#include "structs.h"
@@ -7,8 +15,7 @@
#include "memory.h"
#include "pgpolicies.h"
#include "blacklist.h"
-
-#include "../libcheckers/checkers.h"
+#include "defaults.h"
/*
* default block handlers
@@ -20,7 +27,7 @@
buff = VECTOR_SLOT(strvec, 1);
conf->checkint = atoi(buff);
- conf->max_checkint = conf->checkint << 2;
+ conf->max_checkint = MAX_CHECKINT(conf->checkint);
return 0;
}
@@ -57,7 +64,7 @@
if (!buff)
return 1;
- conf->default_pgpolicy = get_pgpolicy_id(buff);
+ conf->pgpolicy = get_pgpolicy_id(buff);
FREE(buff);
return 0;
@@ -66,9 +73,9 @@
static int
def_getuid_callout_handler(vector strvec)
{
- conf->default_getuid = set_value(strvec);
+ conf->getuid = set_value(strvec);
- if (!conf->default_getuid)
+ if (!conf->getuid)
return 1;
return 0;
@@ -77,14 +84,15 @@
static int
def_prio_callout_handler(vector strvec)
{
- conf->default_getprio = set_value(strvec);
+ conf->getprio = set_value(strvec);
- if (!conf->default_getprio)
+ if (!conf->getprio)
return 1;
- if (!strncmp(conf->default_getprio, "none", 4)) {
- FREE(conf->default_getprio);
- conf->default_getprio = NULL;
+ if (strlen(conf->getprio) == 4 &&
+ !strcmp(conf->getprio, "none")) {
+ FREE(conf->getprio);
+ conf->getprio = NULL;
}
return 0;
@@ -111,7 +119,7 @@
if (!buff)
return 1;
- conf->default_checker_index = get_checker_id(buff);
+ conf->checker = checker_lookup(buff);
FREE(buff);
return 0;
@@ -159,9 +167,9 @@
buff = set_value(strvec);
- if (!strncmp(buff, "manual", 6))
+ if (strlen(buff) == 6 && !strcmp(buff, "manual"))
conf->pgfailback = -FAILBACK_MANUAL;
- else if (!strncmp(buff, "immediate", 9))
+ else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
conf->pgfailback = -FAILBACK_IMMEDIATE;
else
conf->pgfailback = atoi(buff);
@@ -180,9 +188,10 @@
if (!buff)
return 1;
- if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+ (strlen(buff) == 1 && !strcmp(buff, "0")))
conf->no_path_retry = NO_PATH_RETRY_FAIL;
- else if (!strncmp(buff, "queue", 5))
+ else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
conf->no_path_retry = NO_PATH_RETRY_QUEUE;
else if ((conf->no_path_retry = atoi(buff)) < 1)
conf->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -201,9 +210,11 @@
if (!buff)
return 1;
- if (!strncmp(buff, "no", 2) || !strncmp(buff, "0", 1))
+ if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
+ (strlen(buff) == 1 && !strcmp(buff, "0")))
conf->user_friendly_names = 0;
- else if (!strncmp(buff, "yes", 2) || !strncmp(buff, "1", 1))
+ else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
+ (strlen(buff) == 1 && !strcmp(buff, "1")))
conf->user_friendly_names = 1;
FREE(buff);
@@ -216,29 +227,72 @@
static int
blacklist_handler(vector strvec)
{
- conf->blist = vector_alloc();
+ conf->blist_devnode = vector_alloc();
+ conf->blist_wwid = vector_alloc();
+ conf->blist_device = vector_alloc();
- if (!conf->blist)
+ if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
return 1;
return 0;
}
static int
-ble_handler(vector strvec)
+ble_devnode_handler(vector strvec)
{
char * buff;
- int ret;
buff = set_value(strvec);
if (!buff)
return 1;
- ret = store_regex(conf->blist, buff);
- FREE(buff);
+ return store_ble(conf->blist_devnode, buff);
+}
+
+static int
+ble_wwid_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
- return ret;
+ return store_ble(conf->blist_wwid, buff);
+}
+
+static int
+ble_device_handler(vector strvec)
+{
+ return alloc_ble_device(conf->blist_device);
+}
+
+static int
+ble_vendor_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return set_ble_device(conf->blist_device, buff, NULL);
+}
+
+static int
+ble_product_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ return set_ble_device(conf->blist_device, NULL, buff);
}
/*
@@ -307,6 +361,21 @@
}
static int
+bl_product_handler(vector strvec)
+{
+ struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+
+ if (!hwe)
+ return 1;
+
+ hwe->bl_product = set_value(strvec);
+ if (!hwe->bl_product)
+ return 1;
+
+ return 0;
+}
+
+static int
hw_pgpolicy_handler(vector strvec)
{
char * buff;
@@ -366,7 +435,7 @@
if (!buff)
return 1;
- hwe->checker_index = get_checker_id(buff);
+ hwe->checker = checker_lookup(buff);
FREE(buff);
return 0;
@@ -417,7 +486,7 @@
if (!hwe->getprio)
return 1;
- if (!strncmp(hwe->getprio, "none", 4)) {
+ if (strlen(hwe->getprio) == 4 && !strcmp(hwe->getprio, "none")) {
FREE(hwe->getprio);
hwe->getprio = NULL;
}
@@ -436,9 +505,9 @@
buff = set_value(strvec);
- if (!strncmp(buff, "manual", 6))
+ if (strlen(buff) == 6 && !strcmp(buff, "manual"))
hwe->pgfailback = -FAILBACK_MANUAL;
- else if (!strncmp(buff, "immediate", 9))
+ else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
hwe->pgfailback = -FAILBACK_IMMEDIATE;
else
hwe->pgfailback = atoi(buff);
@@ -484,9 +553,10 @@
if (!buff)
return 1;
- if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+ (strlen(buff) == 1 && !strcmp(buff, "0")))
hwe->no_path_retry = NO_PATH_RETRY_FAIL;
- else if (!strncmp(buff, "queue", 5))
+ else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
else if ((hwe->no_path_retry = atoi(buff)) < 1)
hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -495,6 +565,26 @@
return 0;
}
+static int
+hw_minio_handler(vector strvec)
+{
+ struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
+ char * buff;
+
+ if (!hwe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ hwe->minio = atoi(buff);
+ FREE(buff);
+
+ return 0;
+}
+
/*
* multipaths block handlers
*/
@@ -607,9 +697,9 @@
buff = set_value(strvec);
- if (!strncmp(buff, "manual", 6))
+ if (strlen(buff) == 6 && !strcmp(buff, "manual"))
mpe->pgfailback = -FAILBACK_MANUAL;
- else if (!strncmp(buff, "immediate", 9))
+ else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
mpe->pgfailback = -FAILBACK_IMMEDIATE;
else
mpe->pgfailback = atoi(buff);
@@ -655,9 +745,10 @@
if (!buff)
return 1;
- if (!strncmp(buff, "fail", 4) || !strncmp(buff, "0", 1))
+ if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
+ (strlen(buff) == 1 && !strcmp(buff, "0")))
mpe->no_path_retry = NO_PATH_RETRY_FAIL;
- else if (!strncmp(buff, "queue", 5))
+ else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
else if ((mpe->no_path_retry = atoi(buff)) < 1)
mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
@@ -666,68 +757,626 @@
return 0;
}
-vector
-init_keywords(void)
+static int
+mp_minio_handler(vector strvec)
+{
+ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+ char * buff;
+
+ if (!mpe)
+ return 1;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ mpe->minio = atoi(buff);
+ FREE(buff);
+
+ return 0;
+}
+
+/*
+ * config file keywords printing
+ */
+static int
+snprint_mp_wwid (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ return snprintf(buff, len, "%s", mpe->wwid);
+}
+
+static int
+snprint_mp_alias (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->alias)
+ return 0;
+
+ if (conf->user_friendly_names &&
+ (strlen(mpe->alias) == strlen("mpath")) &&
+ !strcmp(mpe->alias, "mpath"))
+ return 0;
+
+ return snprintf(buff, len, "%s", mpe->alias);
+}
+
+static int
+snprint_mp_path_grouping_policy (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+ char str[POLICY_NAME_SIZE];
+
+ if (!mpe->pgpolicy)
+ return 0;
+ get_pgpolicy_name(str, POLICY_NAME_SIZE, mpe->pgpolicy);
+
+ return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_mp_selector (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->selector)
+ return 0;
+
+ return snprintf(buff, len, "%s", mpe->selector);
+}
+
+static int
+snprint_mp_failback (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->pgfailback)
+ return 0;
+
+ switch(mpe->pgfailback) {
+ case FAILBACK_UNDEF:
+ break;
+ case -FAILBACK_MANUAL:
+ return snprintf(buff, len, "manual");
+ case -FAILBACK_IMMEDIATE:
+ return snprintf(buff, len, "immediate");
+ default:
+ return snprintf(buff, len, "%i", mpe->pgfailback);
+ }
+ return 0;
+}
+
+static int
+snprint_mp_rr_weight (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->rr_weight)
+ return 0;
+ if (mpe->rr_weight == RR_WEIGHT_PRIO)
+ return snprintf(buff, len, "priorities");
+
+ return 0;
+}
+
+static int
+snprint_mp_no_path_retry (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->no_path_retry)
+ return 0;
+
+ switch(mpe->no_path_retry) {
+ case NO_PATH_RETRY_UNDEF:
+ break;
+ case NO_PATH_RETRY_FAIL:
+ return snprintf(buff, len, "fail");
+ case NO_PATH_RETRY_QUEUE:
+ return snprintf(buff, len, "queue");
+ default:
+ return snprintf(buff, len, "%i",
+ mpe->no_path_retry);
+ }
+ return 0;
+}
+
+static int
+snprint_mp_rr_min_io (char * buff, int len, void * data)
+{
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ if (!mpe->minio)
+ return 0;
+
+ return snprintf(buff, len, "%u", mpe->minio);
+}
+
+static int
+snprint_hw_vendor (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->vendor)
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->vendor);
+}
+
+static int
+snprint_hw_product (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->product)
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->product);
+}
+
+static int
+snprint_hw_bl_product (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->bl_product)
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->bl_product);
+}
+
+static int
+snprint_hw_getuid_callout (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->getuid)
+ return 0;
+ if (strlen(hwe->getuid) == strlen(conf->getuid) &&
+ !strcmp(hwe->getuid, conf->getuid))
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->getuid);
+}
+
+static int
+snprint_hw_prio_callout (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!conf->getprio && !hwe->getprio)
+ return 0;
+ if (!conf->getprio && hwe->getprio)
+ return snprintf(buff, len, "%s", hwe->getprio);
+ if (conf->getprio && !hwe->getprio)
+ return snprintf(buff, len, "none");
+
+ /* conf->getprio && hwe->getprio */
+ if (strlen(hwe->getprio) == strlen(conf->getprio) &&
+ !strcmp(hwe->getprio, conf->getprio))
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->getprio);
+}
+
+static int
+snprint_hw_features (char * buff, int len, void * data)
{
- keywords = vector_alloc();
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->features)
+ return 0;
+ if (strlen(hwe->features) == strlen(conf->features) &&
+ !strcmp(hwe->features, conf->features))
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->features);
+}
+
+static int
+snprint_hw_hardware_handler (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->hwhandler)
+ return 0;
+ if (strlen(hwe->hwhandler) == strlen(conf->hwhandler) &&
+ !strcmp(hwe->hwhandler, conf->hwhandler))
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->hwhandler);
+}
+
+static int
+snprint_hw_selector (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->selector)
+ return 0;
+ if (strlen(hwe->selector) == strlen(conf->selector) &&
+ !strcmp(hwe->selector, conf->selector))
+ return 0;
+
+ return snprintf(buff, len, "%s", hwe->selector);
+}
+
+static int
+snprint_hw_path_grouping_policy (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ char str[POLICY_NAME_SIZE];
+
+ if (!hwe->pgpolicy)
+ return 0;
+ if (hwe->pgpolicy == conf->pgpolicy)
+ return 0;
+
+ get_pgpolicy_name(str, POLICY_NAME_SIZE, hwe->pgpolicy);
+
+ return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_hw_failback (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->pgfailback)
+ return 0;
+ if (hwe->pgfailback == conf->pgfailback)
+ return 0;
+ switch(hwe->pgfailback) {
+ case FAILBACK_UNDEF:
+ break;
+ case -FAILBACK_MANUAL:
+ return snprintf(buff, len, "manual");
+ case -FAILBACK_IMMEDIATE:
+ return snprintf(buff, len, "immediate");
+ default:
+ return snprintf(buff, len, "%i", hwe->pgfailback);
+ }
+ return 0;
+}
+
+static int
+snprint_hw_rr_weight (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->rr_weight)
+ return 0;
+ if (hwe->rr_weight == conf->rr_weight)
+ return 0;
+ if (hwe->rr_weight == RR_WEIGHT_PRIO)
+ return snprintf(buff, len, "priorities");
+
+ return 0;
+}
+
+static int
+snprint_hw_no_path_retry (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->no_path_retry)
+ return 0;
+ if (hwe->no_path_retry == conf->no_path_retry)
+ return 0;
+
+ switch(hwe->no_path_retry) {
+ case NO_PATH_RETRY_UNDEF:
+ break;
+ case NO_PATH_RETRY_FAIL:
+ return snprintf(buff, len, "fail");
+ case NO_PATH_RETRY_QUEUE:
+ return snprintf(buff, len, "queue");
+ default:
+ return snprintf(buff, len, "%i",
+ hwe->no_path_retry);
+ }
+ return 0;
+}
+
+static int
+snprint_hw_rr_min_io (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->minio)
+ return 0;
+ if (hwe->minio == conf->minio)
+ return 0;
+
+ return snprintf(buff, len, "%u", hwe->minio);
+}
+
+static int
+snprint_hw_path_checker (char * buff, int len, void * data)
+{
+ struct hwentry * hwe = (struct hwentry *)data;
+
+ if (!hwe->checker)
+ return 0;
+ if (!checker_selected(hwe->checker))
+ return 0;
+ if (hwe->checker == conf->checker)
+ return 0;
+
+ return snprintf(buff, len, "%s", checker_name(hwe->checker));
+}
+
+static int
+snprint_def_polling_interval (char * buff, int len, void * data)
+{
+ if (conf->checkint == DEFAULT_CHECKINT)
+ return 0;
+ return snprintf(buff, len, "%i", conf->checkint);
+}
+
+static int
+snprint_def_udev_dir (char * buff, int len, void * data)
+{
+ if (!conf->udev_dir)
+ return 0;
+ if (strlen(DEFAULT_UDEVDIR) == strlen(conf->udev_dir) &&
+ !strcmp(conf->udev_dir, DEFAULT_UDEVDIR))
+ return 0;
+
+ return snprintf(buff, len, "%s", conf->udev_dir);
+}
+
+static int
+snprint_def_selector (char * buff, int len, void * data)
+{
+ if (!conf->selector)
+ return 0;
+ if (strlen(conf->selector) == strlen(DEFAULT_SELECTOR) &&
+ !strcmp(conf->selector, DEFAULT_SELECTOR))
+ return 0;
+
+ return snprintf(buff, len, "%s", conf->selector);
+}
+
+static int
+snprint_def_path_grouping_policy (char * buff, int len, void * data)
+{
+ char str[POLICY_NAME_SIZE];
+
+ if (!conf->pgpolicy)
+ return 0;
+ if (conf->pgpolicy == DEFAULT_PGPOLICY)
+ return 0;
+
+ get_pgpolicy_name(str, POLICY_NAME_SIZE, conf->pgpolicy);
+
+ return snprintf(buff, len, "%s", str);
+}
+
+static int
+snprint_def_getuid_callout (char * buff, int len, void * data)
+{
+ if (!conf->getuid)
+ return 0;
+ if (strlen(conf->getuid) == strlen(DEFAULT_GETUID) &&
+ !strcmp(conf->getuid, DEFAULT_GETUID))
+ return 0;
+
+ return snprintf(buff, len, "%s", conf->getuid);
+}
+
+static int
+snprint_def_getprio_callout (char * buff, int len, void * data)
+{
+ if (!conf->getprio)
+ return 0;
+
+ return snprintf(buff, len, "%s", conf->getprio);
+}
+
+static int
+snprint_def_features (char * buff, int len, void * data)
+{
+ if (!conf->features)
+ return 0;
+ if (strlen(conf->features) == strlen(DEFAULT_FEATURES) &&
+ !strcmp(conf->features, DEFAULT_FEATURES))
+ return 0;
+
+ return snprintf(buff, len, "%s", conf->features);
+}
+
+static int
+snprint_def_path_checker (char * buff, int len, void * data)
+{
+ if (!conf->checker)
+ return 0;
+ if (conf->checker == checker_default())
+ return 0;
+
+ return snprintf(buff, len, "%s", checker_name(conf->checker));
+}
+
+static int
+snprint_def_failback (char * buff, int len, void * data)
+{
+ if (!conf->pgfailback)
+ return 0;
+ if (conf->pgfailback == DEFAULT_FAILBACK)
+ return 0;
+
+ switch(conf->pgfailback) {
+ case FAILBACK_UNDEF:
+ break;
+ case -FAILBACK_MANUAL:
+ return snprintf(buff, len, "manual");
+ case -FAILBACK_IMMEDIATE:
+ return snprintf(buff, len, "immediate");
+ default:
+ return snprintf(buff, len, "%i", conf->pgfailback);
+ }
+ return 0;
+}
+
+static int
+snprint_def_rr_min_io (char * buff, int len, void * data)
+{
+ if (!conf->minio)
+ return 0;
+ if (conf->minio == DEFAULT_MINIO)
+ return 0;
+
+ return snprintf(buff, len, "%u", conf->minio);
+}
+
+static int
+snprint_def_rr_weight (char * buff, int len, void * data)
+{
+ if (!conf->rr_weight)
+ return 0;
+ if (conf->rr_weight == DEFAULT_RR_WEIGHT)
+ return 0;
+ if (conf->rr_weight == RR_WEIGHT_PRIO)
+ return snprintf(buff, len, "priorities");
+
+ return 0;
+}
+
+static int
+snprint_def_no_path_retry (char * buff, int len, void * data)
+{
+ if (conf->no_path_retry == DEFAULT_NO_PATH_RETRY)
+ return 0;
+
+ switch(conf->no_path_retry) {
+ case NO_PATH_RETRY_UNDEF:
+ break;
+ case NO_PATH_RETRY_FAIL:
+ return snprintf(buff, len, "fail");
+ case NO_PATH_RETRY_QUEUE:
+ return snprintf(buff, len, "queue");
+ default:
+ return snprintf(buff, len, "%i",
+ conf->no_path_retry);
+ }
+ return 0;
+}
+
+static int
+snprint_def_user_friendly_names (char * buff, int len, void * data)
+{
+ if (conf->user_friendly_names == DEFAULT_USER_FRIENDLY_NAMES)
+ return 0;
+ if (!conf->user_friendly_names)
+ return snprintf(buff, len, "no");
+
+ return snprintf(buff, len, "yes");
+}
+
+static int
+snprint_ble_simple (char * buff, int len, void * data)
+{
+ struct blentry * ble = (struct blentry *)data;
+
+ return snprintf(buff, len, "%s", ble->str);
+}
+
+static int
+snprint_bled_vendor (char * buff, int len, void * data)
+{
+ struct blentry_device * bled = (struct blentry_device *)data;
+
+ return snprintf(buff, len, "%s", bled->vendor);
+}
+
+static int
+snprint_bled_product (char * buff, int len, void * data)
+{
+ struct blentry_device * bled = (struct blentry_device *)data;
+
+ return snprintf(buff, len, "%s", bled->product);
+}
+
+#define __deprecated
+
+void
+init_keywords(void)
+{
install_keyword_root("defaults", NULL);
- install_keyword("polling_interval", &polling_interval_handler);
- install_keyword("udev_dir", &udev_dir_handler);
- install_keyword("selector", &def_selector_handler);
- install_keyword("path_grouping_policy", &def_pgpolicy_handler);
- install_keyword("getuid_callout", &def_getuid_callout_handler);
- install_keyword("prio_callout", &def_prio_callout_handler);
- install_keyword("features", &def_features_handler);
- install_keyword("path_checker", &def_path_checker_handler);
- install_keyword("failback", &default_failback_handler);
- install_keyword("rr_min_io", &def_minio_handler);
- install_keyword("rr_weight", &def_weight_handler);
- install_keyword("no_path_retry", &def_no_path_retry_handler);
- install_keyword("user_friendly_names", &names_handler);
-
- /*
- * deprecated synonyms
- */
- install_keyword("default_selector", &def_selector_handler);
- install_keyword("default_path_grouping_policy", &def_pgpolicy_handler);
- install_keyword("default_getuid_callout", &def_getuid_callout_handler);
- install_keyword("default_prio_callout", &def_prio_callout_handler);
- install_keyword("default_features", &def_features_handler);
- install_keyword("default_path_checker", &def_path_checker_handler);
-
- install_keyword_root("devnode_blacklist", &blacklist_handler);
- install_keyword("devnode", &ble_handler);
- install_keyword("wwid", &ble_handler);
+ install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
+ install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir);
+ install_keyword("selector", &def_selector_handler, &snprint_def_selector);
+ install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
+ install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
+ install_keyword("prio_callout", &def_prio_callout_handler, &snprint_def_getprio_callout);
+ install_keyword("features", &def_features_handler, &snprint_def_features);
+ install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
+ install_keyword("failback", &default_failback_handler, &snprint_def_failback);
+ install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
+ install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
+ install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
+ install_keyword("user_friendly_names", &names_handler, &snprint_def_user_friendly_names);
+ __deprecated install_keyword("default_selector", &def_selector_handler, NULL);
+ __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
+ __deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
+ __deprecated install_keyword("default_prio_callout", &def_prio_callout_handler, NULL);
+ __deprecated install_keyword("default_features", &def_features_handler, NULL);
+ __deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
+
+ install_keyword_root("blacklist", &blacklist_handler);
+ install_keyword("devnode", &ble_devnode_handler, &snprint_ble_simple);
+ install_keyword("wwid", &ble_wwid_handler, &snprint_ble_simple);
+ install_keyword("device", &ble_device_handler, NULL);
+ install_sublevel();
+ install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
+ install_keyword("product", &ble_product_handler, &snprint_bled_product);
+ install_sublevel_end();
+
+#if 0
+ __deprecated install_keyword_root("devnode_blacklist", &blacklist_handler);
+ __deprecated install_keyword("devnode", &ble_devnode_handler, &snprint_ble_simple);
+ __deprecated install_keyword("wwid", &ble_wwid_handler, &snprint_ble_simple);
+ __deprecated install_keyword("device", &ble_device_handler, NULL);
+ __deprecated install_sublevel();
+ __deprecated install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
+ __deprecated install_keyword("product", &ble_product_handler, &snprint_bled_product);
+ __deprecated install_sublevel_end();
+#endif
install_keyword_root("devices", &devices_handler);
- install_keyword("device", &device_handler);
+ install_keyword("device", &device_handler, NULL);
install_sublevel();
- install_keyword("vendor", &vendor_handler);
- install_keyword("product", &product_handler);
- install_keyword("path_grouping_policy", &hw_pgpolicy_handler);
- install_keyword("getuid_callout", &hw_getuid_callout_handler);
- install_keyword("path_selector", &hw_selector_handler);
- install_keyword("path_checker", &hw_path_checker_handler);
- install_keyword("features", &hw_features_handler);
- install_keyword("hardware_handler", &hw_handler_handler);
- install_keyword("prio_callout", &prio_callout_handler);
- install_keyword("failback", &hw_failback_handler);
- install_keyword("rr_weight", &hw_weight_handler);
- install_keyword("no_path_retry", &hw_no_path_retry_handler);
+ install_keyword("vendor", &vendor_handler, &snprint_hw_vendor);
+ install_keyword("product", &product_handler, &snprint_hw_product);
+ install_keyword("product_blacklist", &bl_product_handler, &snprint_hw_bl_product);
+ install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_path_grouping_policy);
+ install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
+ install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
+ install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
+ install_keyword("features", &hw_features_handler, &snprint_hw_features);
+ install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
+ install_keyword("prio_callout", &prio_callout_handler, &snprint_hw_prio_callout);
+ install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
+ install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
+ install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
+ install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
install_sublevel_end();
install_keyword_root("multipaths", &multipaths_handler);
- install_keyword("multipath", &multipath_handler);
+ install_keyword("multipath", &multipath_handler, NULL);
install_sublevel();
- install_keyword("wwid", &wwid_handler);
- install_keyword("alias", &alias_handler);
- install_keyword("path_grouping_policy", &mp_pgpolicy_handler);
- install_keyword("path_selector", &mp_selector_handler);
- install_keyword("failback", &mp_failback_handler);
- install_keyword("rr_weight", &mp_weight_handler);
- install_keyword("no_path_retry", &mp_no_path_retry_handler);
+ install_keyword("wwid", &wwid_handler, &snprint_mp_wwid);
+ install_keyword("alias", &alias_handler, &snprint_mp_alias);
+ install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_path_grouping_policy);
+ install_keyword("path_selector", &mp_selector_handler, &snprint_mp_selector);
+ install_keyword("failback", &mp_failback_handler, &snprint_mp_failback);
+ install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
+ install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
+ install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_rr_min_io);
install_sublevel_end();
-
- return keywords;
}
Modified: multipath-tools/trunk/libmultipath/dict.h
==============================================================================
--- multipath-tools/trunk/libmultipath/dict.h (original)
+++ multipath-tools/trunk/libmultipath/dict.h Mon Mar 13 15:16:41 2006
@@ -5,6 +5,6 @@
#include "vector.h"
#endif
-vector init_keywords(void);
+void init_keywords(void);
#endif /* _DICT_H */
Modified: multipath-tools/trunk/libmultipath/discovery.c
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.c (original)
+++ multipath-tools/trunk/libmultipath/discovery.c Mon Mar 13 15:16:41 2006
@@ -1,30 +1,31 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Christophe Varoqui
+ * Copyright (c) 2005 Stefan Bader, IBM
+ * Copyright (c) 2005 Mike Anderson
+ */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <errno.h>
-
#include <sysfs/dlist.h>
#include <sysfs/libsysfs.h>
+#include <checkers.h>
+
#include "vector.h"
#include "memory.h"
-#include "blacklist.h"
#include "util.h"
#include "structs.h"
-#include "callout.h"
#include "config.h"
+#include "blacklist.h"
+#include "callout.h"
#include "debug.h"
#include "propsel.h"
#include "sg_include.h"
#include "discovery.h"
-#include "../libcheckers/path_state.h"
-
-#define readattr(a,b) \
- sysfs_read_attribute_value(a, b, sizeof(b))
-
struct path *
store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
{
@@ -51,67 +52,58 @@
return NULL;
}
-int
-path_discovery (vector pathvec, struct config * conf, int flag)
+static int
+path_discover (vector pathvec, struct config * conf, char * devname, int flag)
{
- struct sysfs_directory * sdir;
- struct sysfs_directory * devp;
char path[FILE_NAME_SIZE];
struct path * pp;
- int r = 0;
- if(safe_sprintf(path, "%s/block", sysfs_path)) {
+ if (!devname)
+ return 0;
+
+ if (blacklist(conf->blist_devnode, devname))
+ return 0;
+
+ if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
+ devname)) {
condlog(0, "path too small");
return 1;
}
- sdir = sysfs_open_directory(path);
+
+ if (!filepresent(path))
+ return 0;
+
+ pp = find_path_by_dev(pathvec, devname);
+
+ if (!pp) {
+ pp = store_pathinfo(pathvec, conf->hwtable,
+ devname, flag);
+ return (pp ? 0 : 1);
+ }
+ return pathinfo(pp, conf->hwtable, flag);
+}
- if (!sdir)
+int
+path_discovery (vector pathvec, struct config * conf, int flag)
+{
+ struct dlist * ls;
+ struct sysfs_class * class;
+ struct sysfs_class_device * dev;
+ int r = 1;
+
+ if (!(class = sysfs_open_class("block")))
return 1;
- sysfs_read_directory(sdir);
+ if (!(ls = sysfs_get_class_devices(class)))
+ goto out;
- dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
- if (!devp)
- continue;
+ r = 0;
- if (blacklist(conf->blist, devp->name))
- continue;
+ dlist_for_each_data(ls, dev, struct sysfs_class_device)
+ r += path_discover(pathvec, conf, dev->name, flag);
- if(safe_sprintf(path, "%s/block/%s/device", sysfs_path,
- devp->name)) {
- condlog(0, "path too small");
- sysfs_close_directory(sdir);
- return 1;
- }
-
- if (!filepresent(path))
- continue;
-
- pp = find_path_by_dev(pathvec, devp->name);
-
- if (!pp) {
- /*
- * new path : alloc, store and fetch info
- * the caller wants
- */
- if (!store_pathinfo(pathvec, conf->hwtable,
- devp->name, flag)) {
- r++;
- continue;
- }
- } else {
- /*
- * path already known :
- * refresh only what the caller wants
- */
- if (pathinfo(pp, conf->hwtable, flag)) {
- r++;
- continue;
- }
- }
- }
- sysfs_close_directory(sdir);
+out:
+ sysfs_close_class(class);
return r;
}
@@ -149,14 +141,13 @@
return 0;
}
#endif
-
+
#define declare_sysfs_get_str(fname, fmt) \
extern int \
sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
{ \
+ struct sysfs_attribute * attr; \
char attr_path[SYSFS_PATH_SIZE]; \
- char attr_buff[SYSFS_PATH_SIZE]; \
- int attr_len; \
\
if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
return 1; \
@@ -164,51 +155,61 @@
if (wait_for_file(attr_path)) \
return 1; \
\
- if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
+ if (!(attr = sysfs_open_attribute(attr_path))) \
return 1; \
\
- attr_len = strlen(attr_buff); \
- if (attr_len < 2 || attr_len - 1 > len) \
- return 1; \
+ if (0 > sysfs_read_attribute(attr)) \
+ goto out; \
\
- strncpy(buff, attr_buff, attr_len - 1); \
- buff[attr_len - 1] = '\0'; \
+ if (attr->len < 2 || attr->len - 1 > len) \
+ goto out; \
+\
+ strncpy(buff, attr->value, attr->len - 1); \
+ buff[attr->len - 1] = '\0'; \
+ sysfs_close_attribute(attr); \
return 0; \
+out: \
+ sysfs_close_attribute(attr); \
+ return 1; \
}
+declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
+declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
declare_sysfs_get_str(model, "%s/block/%s/device/model");
declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
declare_sysfs_get_str(dev, "%s/block/%s/dev");
-#define declare_sysfs_get_val(fname, fmt) \
-extern unsigned long long \
-sysfs_get_##fname (char * sysfs_path, char * dev) \
-{ \
- char attr_path[SYSFS_PATH_SIZE]; \
- char attr_buff[SYSFS_PATH_SIZE]; \
- int r; \
- unsigned long long val; \
-\
- if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
- return 0; \
-\
- if (wait_for_file(attr_path)) \
- return 0; \
-\
- if (0 > sysfs_read_attribute_value(attr_path, attr_buff, sizeof(attr_buff))) \
- return 0; \
-\
- r = sscanf(attr_buff, "%llu\n", &val); \
-\
- if (r != 1) \
- return 0; \
- else \
- return (val); \
-}
+int
+sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
+{
+ struct sysfs_attribute * attr;
+ char attr_path[SYSFS_PATH_SIZE];
+ int r;
+
+ if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
+ return 1;
+
+ attr = sysfs_open_attribute(attr_path);
+
+ if (!attr)
+ return 1;
+
+ if (0 > sysfs_read_attribute(attr))
+ goto out;
-declare_sysfs_get_val(size, "%s/block/%s/size");
+ r = sscanf(attr->value, "%llu\n", size);
+ sysfs_close_attribute(attr);
+ if (r != 1)
+ return 1;
+
+ return 0;
+out:
+ sysfs_close_attribute(attr);
+ return 1;
+}
+
/*
* udev might be slow creating node files : wait
*/
@@ -233,49 +234,56 @@
extern int
devt2devname (char *devname, char *devt)
{
- struct sysfs_directory * sdir;
- struct sysfs_directory * devp;
- char block_path[FILE_NAME_SIZE];
+ struct dlist * ls;
char attr_path[FILE_NAME_SIZE];
- char attr_value[16];
- int len;
+ char block_path[FILE_NAME_SIZE];
+ struct sysfs_attribute * attr;
+ struct sysfs_class * class;
+ struct sysfs_class_device * dev;
if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
condlog(0, "block_path too small");
return 1;
}
- sdir = sysfs_open_directory(block_path);
- sysfs_read_directory(sdir);
+ if (!(class = sysfs_open_class("block")))
+ return 1;
+
+ if (!(ls = sysfs_get_class_devices(class)))
+ goto err;
- dlist_for_each_data (sdir->subdirs, devp, struct sysfs_directory) {
+ dlist_for_each_data(ls, dev, struct sysfs_class_device) {
if(safe_sprintf(attr_path, "%s/%s/dev",
- block_path, devp->name)) {
+ block_path, dev->name)) {
condlog(0, "attr_path too small");
goto err;
}
- sysfs_read_attribute_value(attr_path, attr_value,
- sizeof(attr_value));
+ if (!(attr = sysfs_open_attribute(attr_path)))
+ goto err;
- len = strlen(attr_value);
+ if (sysfs_read_attribute(attr))
+ goto err1;
/* discard newline */
- if (len > 1) len--;
+ if (attr->len > 1) attr->len--;
- if (strlen(devt) == len &&
- strncmp(attr_value, devt, len) == 0) {
+ if (strlen(devt) == attr->len &&
+ strncmp(attr->value, devt, attr->len) == 0) {
if(safe_sprintf(attr_path, "%s/%s",
- block_path, devp->name)) {
+ block_path, dev->name)) {
condlog(0, "attr_path too small");
- goto err;
+ goto err1;
}
sysfs_get_name_from_path(attr_path, devname,
FILE_NAME_SIZE);
- sysfs_close_directory(sdir);
+ sysfs_close_attribute(attr);
+ sysfs_close_class(class);
return 0;
}
}
+err1:
+ sysfs_close_attribute(attr);
err:
- sysfs_close_directory(sdir);
+ sysfs_close_class(class);
return 1;
}
@@ -334,8 +342,8 @@
int
get_serial (char * str, int fd)
{
- int len;
- char buff[MX_ALLOC_LEN + 1];
+ int len = 0;
+ char buff[MX_ALLOC_LEN + 1] = {0};
if (fd < 0)
return 0;
@@ -351,14 +359,14 @@
return 0;
}
-static void
-sysfs_get_bus (char * sysfs_path, struct path * curpath)
+static int
+sysfs_get_bus (char * sysfs_path, struct path * pp)
{
struct sysfs_device *sdev;
char attr_path[FILE_NAME_SIZE];
char attr_buff[FILE_NAME_SIZE];
- curpath->bus = SYSFS_BUS_UNDEF;
+ pp->bus = SYSFS_BUS_UNDEF;
/*
* This is ugly : we should be able to do a simple
@@ -366,55 +374,79 @@
* won't work
*/
if(safe_sprintf(attr_path, "%s/block/%s/device",
- sysfs_path, curpath->dev)) {
+ sysfs_path, pp->dev)) {
condlog(0, "attr_path too small");
- return;
+ return 1;
}
if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
- return;
+ return 1;
+
+#if DAEMON
+ int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
+ while (loop--) {
+ sdev = sysfs_open_device_path(attr_buff);
+
+ if (strlen(sdev->bus))
+ break;
+
+ sysfs_close_device(sdev);
+ usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+ }
+#else
sdev = sysfs_open_device_path(attr_buff);
+#endif
if (!strncmp(sdev->bus, "scsi", 4))
- curpath->bus = SYSFS_BUS_SCSI;
+ pp->bus = SYSFS_BUS_SCSI;
else if (!strncmp(sdev->bus, "ide", 3))
- curpath->bus = SYSFS_BUS_IDE;
+ pp->bus = SYSFS_BUS_IDE;
+ else if (!strncmp(sdev->bus, "ccw", 3))
+ pp->bus = SYSFS_BUS_CCW;
+ else
+ return 1;
sysfs_close_device(sdev);
- return;
+ return 0;
}
static int
-scsi_sysfs_pathinfo (struct path * curpath)
+scsi_sysfs_pathinfo (struct path * pp)
{
char attr_path[FILE_NAME_SIZE];
char attr_buff[FILE_NAME_SIZE];
+ struct sysfs_attribute * attr;
- if (sysfs_get_vendor(sysfs_path, curpath->dev,
- curpath->vendor_id, SCSI_VENDOR_SIZE))
+ if (sysfs_get_vendor(sysfs_path, pp->dev,
+ pp->vendor_id, SCSI_VENDOR_SIZE))
return 1;
- condlog(3, "vendor = %s", curpath->vendor_id);
+ condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
- if (sysfs_get_model(sysfs_path, curpath->dev,
- curpath->product_id, SCSI_PRODUCT_SIZE))
+ if (sysfs_get_model(sysfs_path, pp->dev,
+ pp->product_id, SCSI_PRODUCT_SIZE))
return 1;
- condlog(3, "product = %s", curpath->product_id);
+ condlog(3, "%s: product = %s", pp->dev, pp->product_id);
- if (sysfs_get_rev(sysfs_path, curpath->dev,
- curpath->rev, SCSI_REV_SIZE))
+ if (sysfs_get_rev(sysfs_path, pp->dev,
+ pp->rev, SCSI_REV_SIZE))
return 1;
- condlog(3, "rev = %s", curpath->rev);
+ condlog(3, "%s: rev = %s", pp->dev, pp->rev);
+
+ /*
+ * set the hwe configlet pointer
+ */
+ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
/*
* host / bus / target / lun
*/
if(safe_sprintf(attr_path, "%s/block/%s/device",
- sysfs_path, curpath->dev)) {
+ sysfs_path, pp->dev)) {
condlog(0, "attr_path too small");
return 1;
}
@@ -424,15 +456,16 @@
basename(attr_buff, attr_path);
sscanf(attr_path, "%i:%i:%i:%i",
- &curpath->sg_id.host_no,
- &curpath->sg_id.channel,
- &curpath->sg_id.scsi_id,
- &curpath->sg_id.lun);
- condlog(3, "h:b:t:l = %i:%i:%i:%i",
- curpath->sg_id.host_no,
- curpath->sg_id.channel,
- curpath->sg_id.scsi_id,
- curpath->sg_id.lun);
+ &pp->sg_id.host_no,
+ &pp->sg_id.channel,
+ &pp->sg_id.scsi_id,
+ &pp->sg_id.lun);
+ 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);
/*
* target node name
@@ -440,150 +473,209 @@
if(safe_sprintf(attr_path,
"%s/class/fc_transport/target%i:%i:%i/node_name",
sysfs_path,
- curpath->sg_id.host_no,
- curpath->sg_id.channel,
- curpath->sg_id.scsi_id)) {
+ pp->sg_id.host_no,
+ pp->sg_id.channel,
+ pp->sg_id.scsi_id)) {
condlog(0, "attr_path too small");
return 1;
}
- if (0 <= readattr(attr_path, attr_buff) && strlen(attr_buff) > 0)
- strncpy(curpath->tgt_node_name, attr_buff,
- strlen(attr_buff) - 1);
- condlog(3, "tgt_node_name = %s", curpath->tgt_node_name);
+ if (!(attr = sysfs_open_attribute(attr_path)))
+ return 0;
+
+ if (sysfs_read_attribute(attr))
+ goto err;
+
+ if (attr->len > 0)
+ strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
+
+ condlog(3, "%s: tgt_node_name = %s",
+ pp->dev, pp->tgt_node_name);
return 0;
+err:
+ sysfs_close_attribute(attr);
+ return 1;
}
static int
-common_sysfs_pathinfo (struct path * curpath)
+ccw_sysfs_pathinfo (struct path * pp)
{
- sysfs_get_bus(sysfs_path, curpath);
- condlog(3, "bus = %i", curpath->bus);
-
- if (sysfs_get_dev(sysfs_path, curpath->dev,
- curpath->dev_t, BLK_DEV_SIZE))
- return 1;
+ char attr_path[FILE_NAME_SIZE];
+ char attr_buff[FILE_NAME_SIZE];
- condlog(3, "dev_t = %s", curpath->dev_t);
+ sprintf(pp->vendor_id, "IBM");
- curpath->size = sysfs_get_size(sysfs_path, curpath->dev);
+ condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
- if (curpath->size == 0)
+ if (sysfs_get_devtype(sysfs_path, pp->dev,
+ attr_buff, FILE_NAME_SIZE))
return 1;
- condlog(3, "size = %llu", curpath->size);
+ if (!strncmp(attr_buff, "3370", 4)) {
+ sprintf(pp->product_id,"S/390 DASD FBA");
+ } else if (!strncmp(attr_buff, "9336", 4)) {
+ sprintf(pp->product_id,"S/390 DASD FBA");
+ } else {
+ sprintf(pp->product_id,"S/390 DASD ECKD");
+ }
- return 0;
-}
+ condlog(3, "%s: product = %s", pp->dev, pp->product_id);
-extern int
-sysfs_pathinfo(struct path * curpath)
-{
- if (common_sysfs_pathinfo(curpath))
- return 1;
+ /*
+ * set the hwe configlet pointer
+ */
+ pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, pp->product_id);
- if (curpath->bus == SYSFS_BUS_UNDEF)
- return 0;
- else if (curpath->bus == SYSFS_BUS_SCSI)
- if (scsi_sysfs_pathinfo(curpath))
- return 1;
+ /*
+ * host / bus / target / lun
+ */
+ if(safe_sprintf(attr_path, "%s/block/%s/device",
+ sysfs_path, pp->dev)) {
+ condlog(0, "attr_path too small");
+ return 1;
+ }
+ if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
+ return 1;
+
+ basename(attr_buff, attr_path);
+ 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",
+ pp->dev,
+ pp->sg_id.host_no,
+ pp->sg_id.channel,
+ pp->sg_id.scsi_id,
+ pp->sg_id.lun);
return 0;
}
static int
-apply_format (char * string, char * cmd, struct path * pp)
+common_sysfs_pathinfo (struct path * pp)
{
- char * pos;
- char * dst;
- char * p;
- int len;
- int myfree;
-
- if (!string)
+ if (sysfs_get_bus(sysfs_path, pp))
return 1;
- if (!cmd)
+ condlog(3, "%s: bus = %i", pp->dev, pp->bus);
+
+ if (sysfs_get_dev(sysfs_path, pp->dev,
+ pp->dev_t, BLK_DEV_SIZE))
return 1;
- dst = cmd;
- p = dst;
- pos = strchr(string, '%');
- myfree = CALLOUT_MAX_SIZE;
+ condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
- if (!pos) {
- strcpy(dst, string);
- return 0;
- }
+ if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
+ return 1;
+
+ condlog(3, "%s: size = %llu", pp->dev, pp->size);
- len = (int) (pos - string) + 1;
- myfree -= len;
+ return 0;
+}
- if (myfree < 2)
+extern int
+sysfs_pathinfo(struct path * pp)
+{
+ if (common_sysfs_pathinfo(pp))
return 1;
- snprintf(p, len, "%s", string);
- p += len - 1;
- pos++;
+ if (pp->bus == SYSFS_BUS_UNDEF)
+ return 0;
+ else if (pp->bus == SYSFS_BUS_SCSI) {
+ if (scsi_sysfs_pathinfo(pp))
+ return 1;
+ } else if (pp->bus == SYSFS_BUS_CCW) {
+ if (ccw_sysfs_pathinfo(pp))
+ return 1;
+ }
+ return 0;
+}
- switch (*pos) {
- case 'n':
- len = strlen(pp->dev) + 1;
- myfree -= len;
+static int
+scsi_ioctl_pathinfo (struct path * pp, int mask)
+{
+ if (mask & DI_SERIAL) {
+ get_serial(pp->serial, pp->fd);
+ condlog(3, "%s: serial = %s", pp->dev, pp->serial);
+ }
- if (myfree < 2)
- return 1;
+ return 0;
+}
- snprintf(p, len, "%s", pp->dev);
- p += len - 1;
- break;
- case 'd':
- len = strlen(pp->dev_t) + 1;
- myfree -= len;
+static int
+get_state (struct path * pp)
+{
+ struct checker * c = &pp->checker;
- if (myfree < 2)
+ if (!checker_selected(c)) {
+ select_checker(pp);
+ if (!checker_selected(c))
+ return 1;
+ checker_set_fd(c, pp->fd);
+ if (checker_init(c))
return 1;
-
- snprintf(p, len, "%s", pp->dev_t);
- p += len - 1;
- break;
- default:
- break;
}
- pos++;
-
- if (!*pos)
- return 0;
+ pp->state = checker_check(c);
+ condlog(3, "%s: state = %i", pp->dev, pp->state);
+ if (pp->state == PATH_DOWN)
+ condlog(2, "%s: checker msg is \"%s\"",
+ pp->dev, checker_message(c));
+ return 0;
+}
- len = strlen(pos) + 1;
- myfree -= len;
+static int
+get_prio (struct path * pp)
+{
+ char buff[CALLOUT_MAX_SIZE];
+ char prio[16];
- if (myfree < 2)
+ if (!pp->getprio_selected) {
+ select_getprio(pp);
+ pp->getprio_selected = 1;
+ }
+ if (!pp->getprio) {
+ pp->priority = 1;
+ } else if (apply_format(pp->getprio, &buff[0], pp)) {
+ condlog(0, "error formatting prio callout command");
+ pp->priority = -1;
+ return 1;
+ } else if (execute_program(buff, prio, 16)) {
+ condlog(0, "error calling out %s", buff);
+ pp->priority = -1;
return 1;
+ } else
+ pp->priority = atoi(prio);
- snprintf(p, len, "%s", pos);
- condlog(3, "reformated callout = %s", dst);
+ condlog(3, "%s: prio = %u", pp->dev, pp->priority);
return 0;
}
static int
-scsi_ioctl_pathinfo (struct path * pp, int mask)
+get_uid (struct path * pp)
{
- if (mask & DI_SERIAL) {
- get_serial(pp->serial, pp->fd);
- condlog(3, "serial = %s", pp->serial);
- }
+ char buff[CALLOUT_MAX_SIZE];
+ if (!pp->getuid)
+ select_getuid(pp);
+
+ if (apply_format(pp->getuid, &buff[0], pp)) {
+ condlog(0, "error formatting uid callout command");
+ memset(pp->wwid, 0, WWID_SIZE);
+ } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
+ condlog(0, "error calling out %s", buff);
+ memset(pp->wwid, 0, WWID_SIZE);
+ return 1;
+ }
+ condlog(3, "%s: uid = %s (callout)", pp->dev ,pp->wwid);
return 0;
}
extern int
pathinfo (struct path *pp, vector hwtable, int mask)
{
- char buff[CALLOUT_MAX_SIZE];
- char prio[16];
-
- condlog(3, "===== path info %s (mask 0x%x) =====", pp->dev, mask);
+ condlog(3, "%s: mask = 0x%x", pp->dev, mask);
/*
* fetch info available in sysfs
@@ -598,72 +690,26 @@
pp->fd = opennode(pp->dev, O_RDONLY);
if (pp->fd < 0)
- goto out;
+ goto blank;
if (pp->bus == SYSFS_BUS_SCSI &&
scsi_ioctl_pathinfo(pp, mask))
- goto out;
-
- /* get and store hwe pointer */
- pp->hwe = find_hwe(hwtable, pp->vendor_id, pp->product_id);
-
- /*
- * get path state, no message collection, no context
- */
- if (mask & DI_CHECKER) {
- if (!pp->checkfn)
- select_checkfn(pp);
+ goto blank;
- pp->state = pp->checkfn(pp->fd, NULL, NULL);
- condlog(3, "state = %i", pp->state);
- }
+ if (mask & DI_CHECKER && get_state(pp))
+ goto blank;
- /*
- * get path prio
- */
- if (mask & DI_PRIO) {
- if (!pp->getprio)
- select_getprio(pp);
-
- if (!pp->getprio) {
- pp->priority = 1;
- } else if (apply_format(pp->getprio, &buff[0], pp)) {
- condlog(0, "error formatting prio callout command");
- pp->priority = -1;
- } else if (execute_program(buff, prio, 16)) {
- condlog(0, "error calling out %s", buff);
- pp->priority = -1;
- } else
- pp->priority = atoi(prio);
+ if (mask & DI_PRIO && pp->state != PATH_DOWN)
+ get_prio(pp);
- condlog(3, "prio = %u", pp->priority);
- }
-
- /*
- * get path uid
- */
- if (mask & DI_WWID && !strlen(pp->wwid)) {
- if (!pp->getuid)
- select_getuid(pp);
-
- if (apply_format(pp->getuid, &buff[0], pp)) {
- condlog(0, "error formatting uid callout command");
- memset(pp->wwid, 0, WWID_SIZE);
- } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
- condlog(0, "error calling out %s", buff);
- memset(pp->wwid, 0, WWID_SIZE);
- }
- condlog(3, "uid = %s (callout)", pp->wwid);
- }
- else if (strlen(pp->wwid))
- condlog(3, "uid = %s (cache)", pp->wwid);
+ if (mask & DI_WWID && !strlen(pp->wwid))
+ get_uid(pp);
return 0;
-out:
+blank:
/*
* Recoverable error, for example faulty or offline path
- * Set up safe defaults, don't trust the cache
*/
memset(pp->wwid, 0, WWID_SIZE);
pp->state = PATH_DOWN;
Modified: multipath-tools/trunk/libmultipath/discovery.h
==============================================================================
--- multipath-tools/trunk/libmultipath/discovery.h (original)
+++ multipath-tools/trunk/libmultipath/discovery.h Mon Mar 13 15:16:41 2006
@@ -26,7 +26,7 @@
int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len);
int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len);
-unsigned long long sysfs_get_size (char * sysfs_path, char * dev);
+int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *);
int path_discovery (vector pathvec, struct config * conf, int flag);
void basename (char *, char *);
Modified: multipath-tools/trunk/libmultipath/dmparser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.c (original)
+++ multipath-tools/trunk/libmultipath/dmparser.c Mon Mar 13 15:16:41 2006
@@ -1,12 +1,14 @@
/*
- * Christophe Varoqui (2004)
- * This code is GPLv2, see license file
- *
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Stefan Bader, IBM
+ * Copyright (c) 2005 Edward Goggin, EMC
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <checkers.h>
+
#include "vector.h"
#include "memory.h"
#include "structs.h"
@@ -42,6 +44,67 @@
return 0;
}
+/*
+ * Transforms the path group vector into a proper device map string
+ */
+int
+assemble_map (struct multipath * mp)
+{
+ int i, j;
+ int shift, freechar;
+ int minio;
+ char * p;
+ struct pathgroup * pgp;
+ struct path * pp;
+
+ minio = mp->minio;
+ p = mp->params;
+ freechar = sizeof(mp->params);
+
+ shift = snprintf(p, freechar, "%s %s %i %i",
+ mp->features, mp->hwhandler,
+ VECTOR_SIZE(mp->pg), mp->bestpg);
+
+ if (shift >= freechar) {
+ fprintf(stderr, "mp->params too small\n");
+ return 1;
+ }
+ p += shift;
+ freechar -= shift;
+
+ vector_foreach_slot (mp->pg, pgp, i) {
+ pgp = VECTOR_SLOT(mp->pg, i);
+ shift = snprintf(p, freechar, " %s %i 1", mp->selector,
+ VECTOR_SIZE(pgp->paths));
+ if (shift >= freechar) {
+ fprintf(stderr, "mp->params too small\n");
+ return 1;
+ }
+ p += shift;
+ freechar -= shift;
+
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
+ minio *= pp->priority;
+
+ shift = snprintf(p, freechar, " %s %d",
+ pp->dev_t, minio);
+ if (shift >= freechar) {
+ fprintf(stderr, "mp->params too small\n");
+ return 1;
+ }
+ p += shift;
+ freechar -= shift;
+ }
+ }
+ if (freechar < 1) {
+ fprintf(stderr, "mp->params too small\n");
+ return 1;
+ }
+ snprintf(p, 1, "\n");
+ return 0;
+}
+
extern int
disassemble_map (vector pathvec, char * params, struct multipath * mpp)
{
@@ -210,6 +273,11 @@
goto out1;
strncpy(pp->dev_t, word, BLK_DEV_SIZE);
+
+#ifndef DAEMON
+ if (store_path(pathvec, pp))
+ goto out;
+#endif
}
FREE(word);
@@ -234,7 +302,19 @@
pp->pgindex = i + 1;
for (k = 0; k < num_paths_args; k++)
- p += get_word(p, NULL);
+ if (k == 0 && !strncmp(mpp->selector,
+ "round-robin", 11)) {
+ p += get_word(p, &word);
+ mpp->minio = atoi(word);
+
+ if (mpp->rr_weight)
+ mpp->minio /= mpp->rr_weight;
+
+ FREE(word);
+ }
+ else
+ p += get_word(p, NULL);
+
}
}
return 0;
Modified: multipath-tools/trunk/libmultipath/dmparser.h
==============================================================================
--- multipath-tools/trunk/libmultipath/dmparser.h (original)
+++ multipath-tools/trunk/libmultipath/dmparser.h Mon Mar 13 15:16:41 2006
@@ -1,2 +1,3 @@
+int assemble_map (struct multipath *);
int disassemble_map (vector, char *, struct multipath *);
int disassemble_status (char *, struct multipath *);
Modified: multipath-tools/trunk/libmultipath/hwtable.c
==============================================================================
--- multipath-tools/trunk/libmultipath/hwtable.c (original)
+++ multipath-tools/trunk/libmultipath/hwtable.c Mon Mar 13 15:16:41 2006
@@ -1,50 +1,470 @@
#include <stdio.h>
+#include <checkers.h>
+
#include "vector.h"
#include "defaults.h"
#include "structs.h"
#include "config.h"
#include "pgpolicies.h"
+/*
+ * Tuning suggestions on these parameters should go to
+ * dm-devel at redhat.com
+ *
+ * You are welcome to claim maintainership over a controler
+ * family. Please mail the currently enlisted maintainer and
+ * the upstream package maintainer.
+ */
+static struct hwentry default_hw[] = {
+ /*
+ * StorageWorks controler family
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "3PARdata",
+ .product = "VV",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = DEFAULT_CHECKER,
+ },
+ {
+ .vendor = "DEC",
+ .product = "HSG80",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = "1 hp_sw",
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = HP_SW,
+ },
+ {
+ .vendor = "{COMPAQ,HP}",
+ .product = "{MSA,HSV}1*",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = "1 hp_sw",
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = HP_SW,
+ },
+ {
+ .vendor = "HP",
+ .product = "HSV2*",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ {
+ .vendor = "HP",
+ .product = "DF[456]00",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * DDN controler family
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "DDN",
+ .product = "SAN DataDirector",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * EMC / Clariion controler family
+ *
+ * Maintainer : Edward Goggin, EMC
+ * Mail : egoggin at emc.com
+ */
+ {
+ .vendor = "EMC",
+ .product = "SYMMETRIX",
+ .getuid = "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n",
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ {
+ .vendor = "DGC",
+ .product = "*",
+ .bl_product = "LUNZ",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_emc /dev/%n",
+ .features = "1 queue_if_no_path",
+ .hwhandler = "1 emc",
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = (300 / DEFAULT_CHECKINT),
+ .minio = DEFAULT_MINIO,
+ .checker_name = EMC_CLARIION,
+ },
+ /*
+ * Fujitsu controler family
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "FSC",
+ .product = "CentricStor",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * Hitachi controler family
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "HITACHI",
+ .product = "{A6189A,OPEN-}",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * IBM controler family
+ *
+ * Maintainer : Hannes Reinecke, Suse
+ * Mail : hare at suse.de
+ */
+ {
+ .vendor = "IBM",
+ .product = "ProFibre 4000R",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ {
+ /* IBM DS4100 / FAStT100 */
+ .vendor = "IBM",
+ .product = "1742",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_tpc /dev/%n",
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ {
+ /* IBM DS4200 / FAStT200 */
+ .vendor = "IBM",
+ .product = "3542",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ {
+ /* IBM ESS F20 aka Shark */
+ .vendor = "IBM",
+ .product = "2105F20",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = "1 queue_if_no_path",
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ {
+ /* IBM DS6000 / SAN Volume Controller */
+ .vendor = "IBM",
+ .product = "{1750500,2145}",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_alua /dev/%n",
+ .features = "1 queue_if_no_path",
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ {
+ /* IBM DS8000 */
+ .vendor = "IBM",
+ .product = "2107900",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = "1 queue_if_no_path",
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_SERIAL,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ {
+ /* IBM S/390 ECKD DASD */
+ .vendor = "IBM",
+ .product = "S/390 DASD ECKD",
+ .getuid = "/sbin/dasdview -j /dev/%n",
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = DIRECTIO,
+ },
+ /*
+ * NETAPP controler family
+ *
+ * Maintainer : Igor Feoktistov
+ * Mail : igorf at netapp.com
+ */
+ {
+ .vendor = "NETAPP",
+ .product = "LUN",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_netapp /dev/%n",
+ .features = "1 queue_if_no_path",
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * Pillar Data controler family
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "Pillar",
+ .product = "Axiom 500",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_alua %d",
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ /*
+ * SGI arrays
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "SGI",
+ .product = "TP9[13]00",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ {
+ .vendor = "SGI",
+ .product = "TP9[45]00",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_tpc /dev/%n",
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ /*
+ * STK arrays
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "STK",
+ .product = "OPENstorage D280",
+ .getuid = DEFAULT_GETUID,
+ .getprio = "/sbin/mpath_prio_tpc /dev/%n",
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = GROUP_BY_PRIO,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = TUR,
+ },
+ /*
+ * SUN arrays
+ *
+ * Maintainer : Christophe Varoqui
+ * Mail : christophe.varoqui at free.fr
+ */
+ {
+ .vendor = "SUN",
+ .product = "{StorEdge 3510,T4}",
+ .getuid = DEFAULT_GETUID,
+ .getprio = NULL,
+ .features = DEFAULT_FEATURES,
+ .hwhandler = DEFAULT_HWHANDLER,
+ .selector = DEFAULT_SELECTOR,
+ .pgpolicy = MULTIBUS,
+ .pgfailback = FAILBACK_UNDEF,
+ .rr_weight = RR_WEIGHT_NONE,
+ .no_path_retry = NO_PATH_RETRY_UNDEF,
+ .minio = DEFAULT_MINIO,
+ .checker_name = READSECTOR0,
+ },
+ /*
+ * EOL
+ */
+ {
+ .vendor = NULL,
+ .product = NULL,
+ .getuid = NULL,
+ .getprio = NULL,
+ .features = NULL,
+ .hwhandler = NULL,
+ .selector = NULL,
+ .pgpolicy = 0,
+ .pgfailback = 0,
+ .rr_weight = 0,
+ .no_path_retry = 0,
+ .minio = 0,
+ .checker_name = NULL,
+ },
+};
+
extern int
setup_default_hwtable (vector hw)
{
int r = 0;
+ struct hwentry * hwe = default_hw;
- r += store_hwe(hw, "3PARdata", "VV", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "HSV110 (C)COMPAQ", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "MSA1000", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "COMPAQ", "MSA1000 VOLUME", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "DDN", "SAN DataDirector", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "DEC", "HSG80", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "EMC", "SYMMETRIX", MULTIBUS,
- "/sbin/scsi_id -g -u -ppre-spc3-83 -s /block/%n");
- r += store_hwe(hw, "FSC", "CentricStor", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "HITACHI", "DF400", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HITACHI", "DF500", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HITACHI", "DF600", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HP", "HSV110", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "HP", "HSV210", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HP", "A6189A", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "HP", "OPEN-", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "IBM", "ProFibre 4000R", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "NETAPP", "LUN", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "SGI", "TP9100", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "SGI", "TP9300", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "STK", "OPENstorage D280", GROUP_BY_SERIAL, DEFAULT_GETUID);
- r += store_hwe(hw, "SUN", "StorEdge 3510", MULTIBUS, DEFAULT_GETUID);
- r += store_hwe(hw, "SUN", "T4", MULTIBUS, DEFAULT_GETUID);
-
- r += store_hwe_ext(hw, "DGC", "*", GROUP_BY_PRIO, DEFAULT_GETUID,
- "/sbin/mpath_prio_emc /dev/%n", "1 emc",
- "1 queue_if_no_path", "emc_clariion", FAILBACK_IMMEDIATE);
- r += store_hwe_ext(hw, "IBM", "3542", GROUP_BY_SERIAL, DEFAULT_GETUID,
- NULL, "0", "0", "tur", FAILBACK_UNDEF);
- r += store_hwe_ext(hw, "SGI", "TP9400", MULTIBUS, DEFAULT_GETUID,
- NULL, "0", "0", "tur", FAILBACK_UNDEF);
- r += store_hwe_ext(hw, "SGI", "TP9500", FAILOVER, DEFAULT_GETUID,
- NULL, "0", "0", "tur", FAILBACK_UNDEF);
-
+ while (hwe->vendor) {
+ hwe->checker = checker_lookup(hwe->checker_name);
+ r += store_hwe(hw, hwe);
+ hwe++;
+ }
return r;
}
-
Modified: multipath-tools/trunk/libmultipath/log.c
==============================================================================
--- multipath-tools/trunk/libmultipath/log.c (original)
+++ multipath-tools/trunk/libmultipath/log.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Jun'ichi Nomura, NEC
+ */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
Modified: multipath-tools/trunk/libmultipath/log_pthread.c
==============================================================================
--- multipath-tools/trunk/libmultipath/log_pthread.c (original)
+++ multipath-tools/trunk/libmultipath/log_pthread.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
Modified: multipath-tools/trunk/libmultipath/parser.c
==============================================================================
--- multipath-tools/trunk/libmultipath/parser.c (original)
+++ multipath-tools/trunk/libmultipath/parser.c Mon Mar 13 15:16:41 2006
@@ -24,9 +24,11 @@
/* local vars */
static int sublevel = 0;
+vector keywords = NULL;
int
-keyword_alloc(vector keywords, char *string, int (*handler) (vector))
+keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+ int (*print) (char *, int, void *))
{
struct keyword *keyword;
@@ -41,6 +43,7 @@
}
keyword->string = string;
keyword->handler = handler;
+ keyword->print = print;
vector_set_slot(keywords, keyword);
@@ -50,7 +53,7 @@
int
install_keyword_root(char *string, int (*handler) (vector))
{
- return keyword_alloc(keywords, string, handler);
+ return keyword_alloc(keywords, string, handler, NULL);
}
void
@@ -66,7 +69,8 @@
}
int
-install_keyword(char *string, int (*handler) (vector))
+install_keyword(char *string, int (*handler) (vector),
+ int (*print) (char *, int, void *))
{
int i = 0;
struct keyword *keyword;
@@ -87,7 +91,7 @@
return 1;
/* add new sub keyword */
- return keyword_alloc(keyword->sub, string, handler);
+ return keyword_alloc(keyword->sub, string, handler, print);
}
void
@@ -105,6 +109,73 @@
vector_free(keywords);
}
+struct keyword *
+find_keyword(vector v, char * name)
+{
+ struct keyword *keyword;
+ int i;
+ int len;
+
+ if (!name || !keywords)
+ return NULL;
+
+ if (!v)
+ v = keywords;
+
+ len = strlen(name);
+
+ for (i = 0; i < VECTOR_SIZE(v); i++) {
+ keyword = VECTOR_SLOT(v, i);
+ if ((strlen(keyword->string) == len) &&
+ !strcmp(keyword->string, name))
+ return keyword;
+ if (keyword->sub) {
+ keyword = find_keyword(keyword->sub, name);
+ if (keyword)
+ return keyword;
+ }
+ }
+ return NULL;
+}
+
+int
+snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
+{
+ int r;
+ int fwd = 0;
+ char *f = fmt;
+
+ if (!kw || !kw->print)
+ return 0;
+
+ do {
+ if (fwd == len || *f == '\0')
+ break;
+ if (*f != '%') {
+ *(buff + fwd) = *f;
+ fwd++;
+ continue;
+ }
+ f++;
+ switch(*f) {
+ case 'k':
+ fwd += snprintf(buff + fwd, len - fwd, kw->string);
+ break;
+ case 'v':
+ r = kw->print(buff + fwd, len - fwd, data);
+ if (!r) { /* no output if no value */
+ buff = '\0';
+ return 0;
+ }
+ fwd += r;
+ break;
+ }
+ if (fwd > len)
+ fwd = len;
+ } while (*f++);
+ return fwd;
+}
+
vector
alloc_strvec(char *string)
{
@@ -373,10 +444,14 @@
/* Data initialization */
int
-init_data(char *conf_file, vector (*init_keywords) (void))
+init_data(char *conf_file, void (*init_keywords) (void))
{
int r;
+ if (!keywords)
+ keywords = vector_alloc();
+ if (!keywords)
+ return 1;
stream = fopen(conf_file, "r");
if (!stream) {
syslog(LOG_WARNING, "Configuration file open problem");
@@ -394,7 +469,7 @@
/* Stream handling */
r = process_stream(keywords);
fclose(stream);
- free_keywords(keywords);
+ //free_keywords(keywords);
return r;
}
Modified: multipath-tools/trunk/libmultipath/parser.h
==============================================================================
--- multipath-tools/trunk/libmultipath/parser.h (original)
+++ multipath-tools/trunk/libmultipath/parser.h Mon Mar 13 15:16:41 2006
@@ -42,24 +42,30 @@
struct keyword {
char *string;
int (*handler) (vector);
+ int (*print) (char *, int, void *);
vector sub;
};
+/* global var exported */
+FILE *stream;
+
/* Reloading helpers */
#define SET_RELOAD (reload = 1)
#define UNSET_RELOAD (reload = 0)
#define RELOAD_DELAY 5
-/* global var exported */
-vector keywords;
-FILE *stream;
+/* iterator helper */
+#define iterate_sub_keywords(k,p,i) \
+ 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));
+extern int keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+ int (*print) (char *, int, void *));
extern int install_keyword_root(char *string, int (*handler) (vector));
extern void install_sublevel(void);
extern void install_sublevel_end(void);
-extern int install_keyword(char *string, int (*handler) (vector));
+extern int install_keyword(char *string, int (*handler) (vector),
+ int (*print) (char *, int, void *));
extern void dump_keywords(vector keydump, int level);
extern void free_keywords(vector keywords);
extern vector alloc_strvec(char *string);
@@ -68,6 +74,9 @@
extern int alloc_value_block(vector strvec, void (*alloc_func) (vector));
extern void *set_value(vector strvec);
extern int process_stream(vector keywords);
-extern int init_data(char *conf_file, vector (*init_keywords) (void));
+extern int init_data(char *conf_file, void (*init_keywords) (void));
+extern struct keyword * find_keyword(vector v, char * name);
+int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+ void *data);
#endif
Modified: multipath-tools/trunk/libmultipath/pgpolicies.c
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.c (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.c Mon Mar 13 15:16:41 2006
@@ -1,18 +1,18 @@
/*
- * Here we define the path grouping policies
+ * Copyright (c) 2004, 2005 Christophe Varoqui
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <checkers.h>
+
#include "util.h"
#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "pgpolicies.h"
-#include "../libcheckers/path_state.h"
-
extern int
get_pgpolicy_id (char * str)
{
@@ -31,7 +31,7 @@
}
extern int
-get_pgpolicy_name (char * buff, int id)
+get_pgpolicy_name (char * buff, int len, int id)
{
char * s;
@@ -55,11 +55,7 @@
s = "undefined";
break;
}
- if(safe_snprintf(buff, POLICY_NAME_SIZE, "%s", s)) {
- fprintf(stderr, "get_pgpolicy_name: buff too small\n");
- return 1;
- }
- return 0;
+ return snprintf(buff, POLICY_NAME_SIZE, "%s", s);
}
/*
Modified: multipath-tools/trunk/libmultipath/pgpolicies.h
==============================================================================
--- multipath-tools/trunk/libmultipath/pgpolicies.h (original)
+++ multipath-tools/trunk/libmultipath/pgpolicies.h Mon Mar 13 15:16:41 2006
@@ -20,7 +20,7 @@
};
int get_pgpolicy_id(char *);
-int get_pgpolicy_name (char *, int);
+int get_pgpolicy_name (char *, int, int);
/*
* policies
Modified: multipath-tools/trunk/libmultipath/print.c
==============================================================================
--- multipath-tools/trunk/libmultipath/print.c (original)
+++ multipath-tools/trunk/libmultipath/print.c Mon Mar 13 15:16:41 2006
@@ -1,130 +1,467 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <stdio.h>
#include <string.h>
-#include <math.h>
#include <libdevmapper.h>
+#include <stdarg.h>
+
+#include <checkers.h>
#include "vector.h"
#include "structs.h"
+#include "structs_vec.h"
#include "print.h"
#include "dmparser.h"
+#include "configure.h"
+#include "config.h"
+#include "pgpolicies.h"
+#include "defaults.h"
+#include "parser.h"
-#include "../libcheckers/path_state.h"
+#define MAX(x,y) (x > y) ? x : y
+#define TAIL (line + len - 1 - c)
+#define NOPAD s = c
+#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
+ *c++ = ' '; s = c
+#define PRINT(var, size, format, args...) \
+ fwd = snprintf(var, size, format, ##args); \
+ c += (fwd >= size) ? size : fwd;
-#define MAX_FIELD_LEN 64
+/*
+ * information printing helpers
+ */
+static int
+snprint_str (char * buff, size_t len, char * str)
+{
+ return snprintf(buff, len, "%s", str);
+}
-#define MAX(x,y) (x > y) ? x : y
+static int
+snprint_int (char * buff, size_t len, int val)
+{
+ return snprintf(buff, len, "%i", val);
+}
+
+static int
+snprint_uint (char * buff, size_t len, unsigned int val)
+{
+ return snprintf(buff, len, "%u", val);
+}
+
+static int
+snprint_size (char * buff, size_t len, unsigned long long size)
+{
+ if (size < (1 << 11))
+ return snprintf(buff, len, "%llu kB", size >> 1);
+ else if (size < (1 << 21))
+ return snprintf(buff, len, "%llu MB", size >> 11);
+ else if (size < (1 << 31))
+ return snprintf(buff, len, "%llu GB", size >> 21);
+ else
+ return snprintf(buff, len, "%llu TB", size >> 31);
+}
+
+static int
+snprint_name (char * buff, size_t len, struct multipath * mpp)
+{
+ if (mpp->alias)
+ return snprintf(buff, len, "%s", mpp->alias);
+ else
+ return snprintf(buff, len, "%s", mpp->wwid);
+}
+
+static int
+snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
+{
+ if (mpp->dmi)
+ return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
+
+ return 0;
+}
+
+static int
+snprint_progress (char * buff, size_t len, int cur, int total)
+{
+ int i = PROGRESS_LEN * cur / total;
+ int j = PROGRESS_LEN - i;
+ char * c = buff;
+ char * end = buff + len;
+
+ while (i-- > 0) {
+ c += snprintf(c, len, "X");
+ if ((len = (end - c)) <= 1) goto out;
+ }
+
+ while (j-- > 0) {
+ c += snprintf(c, len, ".");
+ if ((len = (end - c)) <= 1) goto out;
+ }
+
+ c += snprintf(c, len, " %i/%i", cur, total);
+
+out:
+ buff[c - buff + 1] = '\0';
+ return (c - buff + 1);
+}
+
+static int
+snprint_failback (char * buff, size_t len, struct multipath * mpp)
+{
+ if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
+ return snprintf(buff, len, "immediate");
+
+ if (!mpp->failback_tick)
+ return snprintf(buff, len, "-");
+ else
+ return snprint_progress(buff, len, mpp->failback_tick,
+ mpp->pgfailback);
+}
+
+static int
+snprint_queueing (char * buff, size_t len, struct multipath * mpp)
+{
+ if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+ return snprintf(buff, len, "off");
+ else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
+ return snprintf(buff, len, "on");
+ else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
+ return snprintf(buff, len, "-");
+ else if (mpp->no_path_retry > 0) {
+ if (mpp->retry_tick)
+ return snprintf(buff, len, "%i sec",
+ mpp->retry_tick);
+ else
+ return snprintf(buff, len, "%i chk",
+ mpp->no_path_retry);
+ }
+ return 0;
+}
+
+static int
+snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_int(buff, len, mpp->nr_active);
+}
+
+static int
+snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
+{
+ if (mpp->dmi && mpp->dmi->suspended)
+ return snprintf(buff, len, "suspend");
+ else
+ return snprintf(buff, len, "active");
+}
+
+static int
+snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_size(buff, len, mpp->size);
+}
+
+static int
+snprint_features (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_str(buff, len, mpp->features);
+}
+
+static int
+snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_str(buff, len, mpp->hwhandler);
+}
+
+static int
+snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_path_failures);
+}
+
+static int
+snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_switchgroup);
+}
+
+static int
+snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_map_loads);
+}
+
+static int
+snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_total_queueing_time);
+}
+
+static int
+snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
+}
+
+static int
+snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
+{
+ return snprint_str(buff, len, mpp->wwid);
+}
+
+static int
+snprint_action (char * buff, size_t len, struct multipath * mpp)
+{
+ switch (mpp->action) {
+ case ACT_RELOAD:
+ return snprint_str(buff, len, ACT_RELOAD_STR);
+ case ACT_CREATE:
+ return snprint_str(buff, len, ACT_CREATE_STR);
+ case ACT_SWITCHPG:
+ return snprint_str(buff, len, ACT_SWITCHPG_STR);
+ default:
+ return 0;
+ }
+}
+
+static int
+snprint_path_uuid (char * buff, size_t len, struct path * pp)
+{
+ return snprint_str(buff, len, pp->wwid);
+}
+
+static int
+snprint_hcil (char * buff, size_t len, struct path * pp)
+{
+ if (pp->sg_id.host_no < 0)
+ return snprintf(buff, len, "#:#:#:#");
+
+ return snprintf(buff, len, "%i:%i:%i:%i",
+ pp->sg_id.host_no,
+ pp->sg_id.channel,
+ pp->sg_id.scsi_id,
+ pp->sg_id.lun);
+}
+
+static int
+snprint_dev (char * buff, size_t len, struct path * pp)
+{
+ if (!strlen(pp->dev))
+ return snprintf(buff, len, "-");
+ else
+ return snprint_str(buff, len, pp->dev);
+}
+
+static int
+snprint_dev_t (char * buff, size_t len, struct path * pp)
+{
+ if (!strlen(pp->dev))
+ return snprintf(buff, len, "#:#");
+ else
+ return snprint_str(buff, len, pp->dev_t);
+}
+
+static int
+snprint_chk_state (char * buff, size_t len, struct path * pp)
+{
+ switch (pp->state) {
+ case PATH_UP:
+ return snprintf(buff, len, "[ready]");
+ case PATH_DOWN:
+ return snprintf(buff, len, "[faulty]");
+ case PATH_SHAKY:
+ return snprintf(buff, len, "[shaky]");
+ case PATH_GHOST:
+ return snprintf(buff, len, "[ghost]");
+ default:
+ return snprintf(buff, len, "[undef]");
+ }
+}
+
+static int
+snprint_dm_path_state (char * buff, size_t len, struct path * pp)
+{
+ switch (pp->dmstate) {
+ case PSTATE_ACTIVE:
+ return snprintf(buff, len, "[active]");
+ case PSTATE_FAILED:
+ return snprintf(buff, len, "[failed]");
+ default:
+ return snprintf(buff, len, "[undef]");
+ }
+}
+
+static int
+snprint_vpr (char * buff, size_t len, struct path * pp)
+{
+ return snprintf(buff, len, "%s/%s/%s",
+ pp->vendor_id, pp->product_id, pp->rev);
+}
+
+static int
+snprint_next_check (char * buff, size_t len, struct path * pp)
+{
+ if (!pp->mpp)
+ return snprintf(buff, len, "[orphan]");
+
+ return snprint_progress(buff, len, pp->tick, pp->checkint);
+}
+
+static int
+snprint_pri (char * buff, size_t len, struct path * pp)
+{
+ return snprint_int(buff, len, pp->priority);
+}
+
+static int
+snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
+{
+ return snprint_str(buff, len, pgp->selector);
+}
+
+static int
+snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
+{
+ return snprint_int(buff, len, pgp->priority);
+}
+
+static int
+snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
+{
+ switch (pgp->status) {
+ case PGSTATE_ENABLED:
+ return snprintf(buff, len, "[enabled]");
+ case PGSTATE_DISABLED:
+ return snprintf(buff, len, "[disabled]");
+ case PGSTATE_ACTIVE:
+ return snprintf(buff, len, "[active]");
+ default:
+ return snprintf(buff, len, "[undef]");
+ }
+}
+
+static int
+snprint_path_size (char * buff, size_t len, struct path * pp)
+{
+ return snprint_size(buff, len, pp->size);
+}
+
+struct multipath_data mpd[] = {
+ {'n', "name", 0, snprint_name},
+ {'w', "uuid", 0, snprint_multipath_uuid},
+ {'d', "sysfs", 0, snprint_sysfs},
+ {'F', "failback", 0, snprint_failback},
+ {'Q', "queueing", 0, snprint_queueing},
+ {'N', "paths", 0, snprint_nb_paths},
+ {'t', "dm-st", 0, snprint_dm_map_state},
+ {'S', "size", 0, snprint_multipath_size},
+ {'f', "features", 0, snprint_features},
+ {'h', "hwhandler", 0, snprint_hwhandler},
+ {'A', "action", 0, snprint_action},
+ {'0', "path_faults", 0, snprint_path_faults},
+ {'1', "switch_grp", 0, snprint_switch_grp},
+ {'2', "map_loads", 0, snprint_map_loads},
+ {'3', "total_q_time", 0, snprint_total_q_time},
+ {'4', "q_timeouts", 0, snprint_q_timeouts},
+ {0, NULL, 0 , NULL}
+};
+
+struct path_data pd[] = {
+ {'w', "uuid", 0, snprint_path_uuid},
+ {'i', "hcil", 0, snprint_hcil},
+ {'d', "dev", 0, snprint_dev},
+ {'D', "dev_t", 0, snprint_dev_t},
+ {'t', "dm_st", 0, snprint_dm_path_state},
+ {'T', "chk_st", 0, snprint_chk_state},
+ {'s', "vend/prod/rev", 0, snprint_vpr},
+ {'C', "next_check", 0, snprint_next_check},
+ {'p', "pri", 0, snprint_pri},
+ {'S', "size", 0, snprint_path_size},
+ {0, NULL, 0 , NULL}
+};
+
+struct pathgroup_data pgd[] = {
+ {'s', "selector", 0, snprint_pg_selector},
+ {'p', "pri", 0, snprint_pg_pri},
+ {'t', "dm_st", 0, snprint_pg_state},
+};
void
-get_path_layout (struct path_layout * pl, vector pathvec)
+get_path_layout (vector pathvec)
{
- int i;
+ int i, j;
char buff[MAX_FIELD_LEN];
struct path * pp;
- int uuid_len;
- int hbtl_len;
- int dev_len;
- int dev_t_len;
- int prio_len;
-
- /* reset max col lengths */
- pl->uuid_len = 0;
- pl->hbtl_len = 0;
- pl->dev_len = 0;
- pl->dev_t_len = 0;
- pl->prio_len = 0;
-
- vector_foreach_slot (pathvec, pp, i) {
- uuid_len = strlen(pp->wwid);
- hbtl_len = snprintf(buff, MAX_FIELD_LEN, "%i:%i:%i:%i",
- pp->sg_id.host_no,
- pp->sg_id.channel,
- pp->sg_id.scsi_id,
- pp->sg_id.lun);
- dev_len = strlen(pp->dev);
- dev_t_len = strlen(pp->dev_t);
- prio_len = 1 + (int)log10(pp->priority);
-
- pl->uuid_len = MAX(uuid_len, pl->uuid_len);
- pl->hbtl_len = MAX(hbtl_len, pl->hbtl_len);
- pl->dev_len = MAX(dev_len, pl->dev_len);
- pl->dev_t_len = MAX(dev_t_len, pl->dev_t_len);
- pl->prio_len = MAX(prio_len, pl->prio_len);
+ for (j = 0; pd[j].header; j++) {
+ pd[j].width = strlen(pd[j].header);
+
+ vector_foreach_slot (pathvec, pp, i) {
+ pd[j].snprint(buff, MAX_FIELD_LEN, pp);
+ pd[j].width = MAX(pd[j].width, strlen(buff));
+ }
}
- return;
}
void
-get_map_layout (struct map_layout * ml, vector mpvec)
+get_multipath_layout (vector mpvec)
{
- int i;
+ int i, j;
char buff[MAX_FIELD_LEN];
struct multipath * mpp;
- int mapname_len;
- int mapdev_len;
- int failback_progress_len;
- int queueing_progress_len;
- int nr_active_len;
-
- /* reset max col lengths */
- ml->mapname_len = 0;
- ml->mapdev_len = 0;
- ml->failback_progress_len = 0;
- ml->queueing_progress_len = 0;
- ml->nr_active_len = 0;
-
- vector_foreach_slot (mpvec, mpp, i) {
- mapname_len = (mpp->alias) ?
- strlen(mpp->alias) : strlen(mpp->wwid);
- if (mpp->dmi) mapdev_len = snprintf(buff, MAX_FIELD_LEN,
- "dm-%i", mpp->dmi->minor);
- failback_progress_len = 4 + PROGRESS_LEN +
- (int)log10(mpp->failback_tick) +
- (int)log10(mpp->pgfailback);
- queueing_progress_len = 5 + (int)log10(mpp->retry_tick);
- nr_active_len = (int)log10(mpp->nr_active);
-
- ml->mapname_len = MAX(mapname_len, ml->mapname_len);
- ml->mapdev_len = MAX(mapdev_len, ml->mapdev_len);
- ml->failback_progress_len = MAX(failback_progress_len,
- ml->failback_progress_len);
- ml->queueing_progress_len = MAX(queueing_progress_len,
- ml->queueing_progress_len);
- ml->nr_active_len = MAX(nr_active_len, ml->nr_active_len);
+ for (j = 0; mpd[j].header; j++) {
+ mpd[j].width = strlen(mpd[j].header);
+
+ vector_foreach_slot (mpvec, mpp, i) {
+ mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
+ mpd[j].width = MAX(mpd[j].width, strlen(buff));
+ }
}
- return;
}
-#define TAIL (line + len - 1 - c)
-#define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
- *c++ = ' '; s = c
-#define NOPAD s = c
+static struct multipath_data *
+mpd_lookup(char wildcard)
+{
+ int i;
-#define PRINT(var, size, format, args...) \
- fwd = snprintf(var, size, format, ##args); \
- c += (fwd >= size) ? size : fwd;
+ for (i = 0; mpd[i].header; i++)
+ if (mpd[i].wildcard == wildcard)
+ return &mpd[i];
-#define PRINT_PROGRESS(cur, total) \
- int i = PROGRESS_LEN * cur / total; \
- int j = PROGRESS_LEN - i; \
- \
- while (i-- > 0) { \
- PRINT(c, TAIL, "X"); \
- } \
- while (j-- > 0) { \
- PRINT(c, TAIL, "."); \
- } \
- PRINT(c, TAIL, " %i/%i", cur, total)
+ return NULL;
+}
+
+static struct path_data *
+pd_lookup(char wildcard)
+{
+ int i;
+
+ for (i = 0; pd[i].header; i++)
+ if (pd[i].wildcard == wildcard)
+ return &pd[i];
+
+ return NULL;
+}
+
+static struct pathgroup_data *
+pgd_lookup(char wildcard)
+{
+ int i;
+
+ for (i = 0; pgd[i].header; i++)
+ if (pgd[i].wildcard == wildcard)
+ return &pgd[i];
+
+ return NULL;
+}
int
-snprint_map_header (char * line, int len, char * format,
- struct map_layout * ml)
+snprint_multipath_header (char * line, int len, char * format)
{
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
int fwd;
+ struct multipath_data * data;
do {
if (!TAIL)
@@ -136,41 +473,12 @@
continue;
}
f++;
- switch (*f) {
- case 'w':
- PRINT(c, TAIL, "name");
- ml->mapname_len = MAX(ml->mapname_len, 4);
- PAD(ml->mapname_len);
- break;
- case 'd':
- PRINT(c, TAIL, "sysfs");
- ml->mapdev_len = MAX(ml->mapdev_len, 5);
- PAD(ml->mapdev_len);
- break;
- case 'F':
- PRINT(c, TAIL, "failback");
- ml->failback_progress_len =
- MAX(ml->failback_progress_len, 8);
- PAD(ml->failback_progress_len);
- break;
- case 'Q':
- PRINT(c, TAIL, "queueing");
- ml->queueing_progress_len =
- MAX(ml->queueing_progress_len, 8);
- PAD(ml->queueing_progress_len);
- break;
- case 'n':
- PRINT(c, TAIL, "paths");
- ml->nr_active_len = MAX(ml->nr_active_len, 5);
- PAD(ml->nr_active_len);
- break;
- case 't':
- PRINT(c, TAIL, "dm-st");
- PAD(7);
- break;
- default:
- break;
- }
+
+ if (!(data = mpd_lookup(*f)))
+ break; /* unknown wildcard */
+
+ PRINT(c, TAIL, data->header);
+ PAD(data->width);
} while (*f++);
line[c - line - 1] = '\n';
@@ -180,13 +488,15 @@
}
int
-snprint_map (char * line, int len, char * format,
- struct multipath * mpp, struct map_layout * ml)
+snprint_multipath (char * line, int len, char * format,
+ struct multipath * mpp)
{
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
int fwd;
+ struct multipath_data * data;
+ char buff[MAX_FIELD_LEN];
do {
if (!TAIL)
@@ -198,63 +508,13 @@
continue;
}
f++;
- switch (*f) {
- case 'w':
- if (mpp->alias) {
- PRINT(c, TAIL, "%s", mpp->alias);
- } else {
- PRINT(c, TAIL, "%s", mpp->wwid);
- }
- PAD(ml->mapname_len);
- break;
- case 'd':
- if (mpp->dmi) {
- PRINT(c, TAIL, "dm-%i", mpp->dmi->minor);
- }
- PAD(ml->mapdev_len);
- break;
- case 'F':
- if (!mpp->failback_tick) {
- PRINT(c, TAIL, "-");
- } else {
- PRINT_PROGRESS(mpp->failback_tick,
- mpp->pgfailback);
- }
- PAD(ml->failback_progress_len);
- break;
- case 'Q':
- if (mpp->no_path_retry == NO_PATH_RETRY_FAIL) {
- PRINT(c, TAIL, "off");
- } else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE) {
- PRINT(c, TAIL, "on");
- } else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF) {
- PRINT(c, TAIL, "-");
- } else if (mpp->no_path_retry > 0) {
- if (mpp->retry_tick) {
- PRINT(c, TAIL, "%i sec",
- mpp->retry_tick);
- } else {
- PRINT(c, TAIL, "%i chk",
- mpp->no_path_retry);
- }
- }
- PAD(ml->queueing_progress_len);
- break;
- case 'n':
- PRINT(c, TAIL, "%i", mpp->nr_active);
- PAD(ml->nr_active_len);
- break;
- case 't':
- if (mpp->dmi && mpp->dmi->suspended) {
- PRINT(c, TAIL, "suspend");
- } else {
- PRINT(c, TAIL, "active");
- }
- PAD(7);
+
+ if (!(data = mpd_lookup(*f)))
break;
- default:
- break;
- }
+
+ data->snprint(buff, MAX_FIELD_LEN, mpp);
+ PRINT(c, TAIL, buff);
+ PAD(data->width);
} while (*f++);
line[c - line - 1] = '\n';
@@ -264,13 +524,13 @@
}
int
-snprint_path_header (char * line, int len, char * format,
- struct path_layout * pl)
+snprint_path_header (char * line, int len, char * format)
{
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
int fwd;
+ struct path_data * data;
do {
if (!TAIL)
@@ -282,49 +542,12 @@
continue;
}
f++;
- switch (*f) {
- case 'w':
- PRINT(c, TAIL, "uuid");
- PAD(pl->uuid_len);
- break;
- case 'i':
- PRINT(c, TAIL, "hcil");
- PAD(pl->hbtl_len);
- break;
- case 'd':
- PRINT(c, TAIL, "dev");
- pl->dev_len = MAX(pl->dev_len, 3);
- PAD(pl->dev_len);
- break;
- case 'D':
- PRINT(c, TAIL, "dev_t");
- pl->dev_t_len = MAX(pl->dev_t_len, 5);
- PAD(pl->dev_t_len);
- break;
- case 'T':
- PRINT(c, TAIL, "chk-st");
- PAD(8);
- break;
- case 't':
- PRINT(c, TAIL, "dm-st");
- PAD(8);
- break;
- case 's':
- PRINT(c, TAIL, "vendor/product/rev");
- NOPAD;
- break;
- case 'C':
- PRINT(c, TAIL, "next-check");
- NOPAD;
- break;
- case 'p':
- PRINT(c, TAIL, "pri");
- pl->prio_len = MAX(pl->prio_len, 3);
- PAD(pl->prio_len);
- break;
- default:
- break;
- }
+
+ if (!(data = pd_lookup(*f)))
+ break; /* unknown wildcard */
+
+ PRINT(c, TAIL, data->header);
+ PAD(data->width);
} while (*f++);
line[c - line - 1] = '\n';
@@ -334,13 +557,15 @@
}
int
-snprint_path (char * line, int len, char * format, struct path * pp,
- struct path_layout * pl)
+snprint_path (char * line, int len, char * format,
+ struct path * pp)
{
char * c = line; /* line cursor */
char * s = line; /* for padding */
char * f = format; /* format string cursor */
int fwd;
+ struct path_data * data;
+ char buff[MAX_FIELD_LEN];
do {
if (!TAIL)
@@ -352,93 +577,49 @@
continue;
}
f++;
- switch (*f) {
- case 'w':
- PRINT(c, TAIL, "%s", pp->wwid);
- PAD(pl->uuid_len);
- break;
- case 'i':
- if (pp->sg_id.host_no < 0) {
- PRINT(c, TAIL, "#:#:#:#");
- } else {
- PRINT(c, TAIL, "%i:%i:%i:%i",
- pp->sg_id.host_no,
- pp->sg_id.channel,
- pp->sg_id.scsi_id,
- pp->sg_id.lun);
- }
- PAD(pl->hbtl_len);
+
+ if (!(data = pd_lookup(*f)))
break;
- case 'd':
- if (!strlen(pp->dev)) {
- PRINT(c, TAIL, "-");
- } else {
- PRINT(c, TAIL, "%s", pp->dev);
- }
- PAD(pl->dev_len);
- break;
- case 'D':
- PRINT(c, TAIL, "%s", pp->dev_t);
- PAD(pl->dev_t_len);
- break;
- case 'T':
- switch (pp->state) {
- case PATH_UP:
- PRINT(c, TAIL, "[ready]");
- break;
- case PATH_DOWN:
- PRINT(c, TAIL, "[faulty]");
- break;
- case PATH_SHAKY:
- PRINT(c, TAIL, "[shaky]");
- break;
- case PATH_GHOST:
- PRINT(c, TAIL, "[ghost]");
- break;
- default:
- PRINT(c, TAIL, "[undef]");
- break;
- }
- PAD(8);
- break;
- case 't':
- switch (pp->dmstate) {
- case PSTATE_ACTIVE:
- PRINT(c, TAIL, "[active]");
- break;
- case PSTATE_FAILED:
- PRINT(c, TAIL, "[failed]");
- break;
- default:
- PRINT(c, TAIL, "[undef]");
- break;
- }
- PAD(8);
- break;
- case 's':
- PRINT(c, TAIL, "%s/%s/%s",
- pp->vendor_id, pp->product_id, pp->rev);
- NOPAD;
+
+ data->snprint(buff, MAX_FIELD_LEN, pp);
+ PRINT(c, TAIL, buff);
+ PAD(data->width);
+ } while (*f++);
+
+ line[c - line - 1] = '\n';
+ line[c - line] = '\0';
+
+ return (c - line);
+}
+
+int
+snprint_pathgroup (char * line, int len, char * format,
+ struct pathgroup * pgp)
+{
+ char * c = line; /* line cursor */
+ char * s = line; /* for padding */
+ char * f = format; /* format string cursor */
+ int fwd;
+ struct pathgroup_data * data;
+ char buff[MAX_FIELD_LEN];
+
+ do {
+ if (!TAIL)
break;
- case 'C':
- if (!pp->mpp) {
- PRINT(c, TAIL, "[orphan]");
- } else {
- PRINT_PROGRESS(pp->tick, pp->checkint);
- }
+
+ if (*f != '%') {
+ *c++ = *f;
NOPAD;
- break;
- case 'p':
- if (pp->priority) {
- PRINT(c, TAIL, "%i", pp->priority);
- } else {
- PRINT(c, TAIL, "#");
- }
- PAD(pl->prio_len);
- break;
- default:
- break;
+ continue;
}
+ f++;
+
+ if (!(data = pgd_lookup(*f)))
+ break;
+
+ data->snprint(buff, MAX_FIELD_LEN, pgp);
+ PRINT(c, TAIL, buff);
+ PAD(data->width);
} while (*f++);
line[c - line - 1] = '\n';
@@ -447,3 +628,347 @@
return (c - line);
}
+extern void
+print_multipath_topology (struct multipath * mpp, int verbosity)
+{
+ char buff[MAX_LINE_LEN * MAX_LINES];
+
+ snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
+ mpp, verbosity);
+ printf("%s", buff);
+}
+
+extern int
+snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
+ int verbosity)
+{
+ int j, i, fwd = 0;
+ struct path * pp = NULL;
+ struct pathgroup * pgp = NULL;
+ char style[64];
+ char * c = style;
+
+ if (verbosity <= 0)
+ return fwd;
+
+ if (verbosity == 1)
+ return snprint_multipath(buff, len, "%n", mpp);
+
+ if (verbosity > 1 &&
+ mpp->action != ACT_NOTHING &&
+ mpp->action != ACT_UNDEF)
+ c += sprintf(c, "%%A: ");
+
+ c += sprintf(c, "%%n");
+
+ if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
+ c += sprintf(c, " (%%w)");
+
+ fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
+ if (fwd > len)
+ return len;
+ fwd += snprint_multipath(buff + fwd, len - fwd,
+ "[size=%S][features=%f][hwhandler=%h]", mpp);
+ if (fwd > len)
+ return len;
+
+ if (!mpp->pg)
+ return fwd;
+
+ vector_foreach_slot (mpp->pg, pgp, j) {
+ pgp->selector = mpp->selector; /* hack */
+ fwd += snprint_pathgroup(buff + fwd, len - fwd,
+ PRINT_PG_INDENT, pgp);
+ if (fwd > len)
+ return len;
+
+ vector_foreach_slot (pgp->paths, pp, i) {
+ fwd += snprint_path(buff + fwd, len - fwd,
+ PRINT_PATH_INDENT, pp);
+ if (fwd > len)
+ return len;
+ }
+ }
+ return fwd;
+}
+
+static int
+snprint_hwentry (char * buff, int len, struct hwentry * hwe)
+{
+ int i;
+ int fwd = 0;
+ struct keyword * kw;
+ struct keyword * rootkw;
+
+ rootkw = find_keyword(NULL, "devices");
+
+ if (!rootkw || !rootkw->sub)
+ return 0;
+
+ rootkw = find_keyword(rootkw->sub, "device");
+
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
+ if (fwd > len)
+ return len;
+ iterate_sub_keywords(rootkw, kw, i) {
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, hwe);
+ if (fwd > len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+extern int
+snprint_hwtable (char * buff, int len, vector hwtable)
+{
+ int fwd = 0;
+ int i;
+ struct hwentry * hwe;
+ struct keyword * rootkw;
+
+ rootkw = find_keyword(NULL, "devices");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
+ if (fwd > len)
+ return len;
+ vector_foreach_slot (hwtable, hwe, i) {
+ fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
+ if (fwd > len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+static int
+snprint_mpentry (char * buff, int len, struct mpentry * mpe)
+{
+ int i;
+ int fwd = 0;
+ struct keyword * kw;
+ struct keyword * rootkw;
+
+ rootkw = find_keyword(NULL, "multipath");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
+ if (fwd > len)
+ return len;
+ iterate_sub_keywords(rootkw, kw, i) {
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, mpe);
+ if (fwd > len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+extern int
+snprint_mptable (char * buff, int len, vector mptable)
+{
+ int fwd = 0;
+ int i;
+ struct mpentry * mpe;
+ struct keyword * rootkw;
+
+ rootkw = find_keyword(NULL, "multipaths");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
+ if (fwd > len)
+ return len;
+ vector_foreach_slot (mptable, mpe, i) {
+ fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
+ if (fwd > len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+}
+
+extern int
+snprint_defaults (char * buff, int len)
+{
+ int fwd = 0;
+ int i;
+ struct keyword *rootkw;
+ struct keyword *kw;
+
+ rootkw = find_keyword(NULL, "defaults");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
+ if (fwd > len)
+ return len;
+
+ iterate_sub_keywords(rootkw, kw, i) {
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+ kw, NULL);
+ if (fwd > len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+
+}
+
+extern int
+snprint_blacklist (char * buff, int len)
+{
+ int i;
+ struct blentry * ble;
+ struct blentry_device * bled;
+ int fwd = 0;
+ struct keyword *rootkw;
+ struct keyword *kw;
+
+ rootkw = find_keyword(NULL, "blacklist");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
+ if (fwd > len)
+ return len;
+
+ vector_foreach_slot (conf->blist_devnode, ble, i) {
+ kw = find_keyword(rootkw->sub, "devnode");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+ kw, ble);
+ if (fwd > len)
+ return len;
+ }
+ vector_foreach_slot (conf->blist_wwid, ble, i) {
+ kw = find_keyword(rootkw->sub, "wwid");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+ kw, ble);
+ if (fwd > len)
+ return len;
+ }
+ rootkw = find_keyword(rootkw->sub, "device");
+ if (!rootkw)
+ return 0;
+
+ vector_foreach_slot (conf->blist_device, bled, i) {
+ fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
+ if (fwd > len)
+ return len;
+ kw = find_keyword(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");
+ if (!kw)
+ return 0;
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, bled);
+ if (fwd > len)
+ return len;
+ fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+ if (fwd > len)
+ return len;
+ }
+
+ fwd += snprintf(buff + fwd, len - fwd, "}\n");
+ if (fwd > len)
+ return len;
+ return fwd;
+
+}
+
+extern int
+snprint_config (char * buff, int len)
+{
+ return 0;
+}
+
+/*
+ * stdout printing helpers
+ */
+extern void
+print_path (struct path * pp, char * style)
+{
+ char line[MAX_LINE_LEN];
+
+ snprint_path(&line[0], MAX_LINE_LEN, style, pp);
+ printf("%s", line);
+}
+
+extern void
+print_multipath (struct multipath * mpp, char * style)
+{
+ char line[MAX_LINE_LEN];
+
+ snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
+ printf("%s", line);
+}
+
+extern void
+print_pathgroup (struct pathgroup * pgp, char * style)
+{
+ char line[MAX_LINE_LEN];
+
+ snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
+ printf("%s", line);
+}
+
+extern void
+print_map (struct multipath * mpp)
+{
+ if (mpp->size && mpp->params)
+ printf("0 %llu %s %s\n",
+ mpp->size, DEFAULT_TARGET, mpp->params);
+ return;
+}
+
+extern void
+print_all_paths (vector pathvec, int banner)
+{
+ int i;
+ struct path * pp;
+ char line[MAX_LINE_LEN];
+
+ if (!VECTOR_SIZE(pathvec)) {
+ if (banner)
+ fprintf(stdout, "===== no paths =====\n");
+ return;
+ }
+
+ if (banner)
+ fprintf(stdout, "===== paths list =====\n");
+
+ get_path_layout(pathvec);
+ snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
+ fprintf(stdout, "%s", line);
+
+ vector_foreach_slot (pathvec, pp, i)
+ print_path(pp, PRINT_PATH_LONG);
+}
+
Modified: multipath-tools/trunk/libmultipath/print.h
==============================================================================
--- multipath-tools/trunk/libmultipath/print.h (original)
+++ multipath-tools/trunk/libmultipath/print.h Mon Mar 13 15:16:41 2006
@@ -1,53 +1,55 @@
-/*
- * path format magics :
- *
- * %w : multipath uid
- * %i : scsi tuple
- * %d : device name
- * %D : device major:minor
- * %t : device mapper path status
- * %T : checker path status
- * %s : scsi strings
- * %p : priority
- *
- * map format magics :
- *
- * %w : multipath uid
- * %d : DM device name
- * %F : failback countdown
- * %C : checker countdown
- * %Q : queueing policy changer countdown (no_path_retry)
- * %n : number of active paths
- * %t : device mapper map status
- */
#define PRINT_PATH_LONG "%w %i %d %D %p %t%T %s"
#define PRINT_PATH_INDENT " \\_ %i %d %D %t%T"
#define PRINT_PATH_CHECKER "%i %d %D %p %t%T %C"
-#define PRINT_MAP_FAILBACK "%w %d %F %Q %n %t"
+#define PRINT_MAP_STATUS "%n %F %Q %N %t"
+#define PRINT_MAP_STATS "%n %0 %1 %2 %3 %4"
+#define PRINT_MAP_NAMES "%n %d %w"
+#define PRINT_PG_INDENT "\\_ %s [prio=%p]%t"
-#define MAX_LINE_LEN 80
-#define PROGRESS_LEN 10
+#define MAX_LINE_LEN 80
+#define MAX_LINES 64
+#define MAX_FIELD_LEN 64
+#define PROGRESS_LEN 10
-struct path_layout {
- int uuid_len;
- int hbtl_len;
- int dev_len;
- int dev_t_len;
- int prio_len;
+struct path_data {
+ char wildcard;
+ char * header;
+ int width;
+ int (*snprint)(char * buff, size_t len, struct path * pp);
};
-struct map_layout {
- int mapname_len;
- int mapdev_len;
- int failback_progress_len;
- int queueing_progress_len;
- int nr_active_len;
+struct multipath_data {
+ char wildcard;
+ char * header;
+ int width;
+ int (*snprint)(char * buff, size_t len, struct multipath * mpp);
};
+struct pathgroup_data {
+ char wildcard;
+ char * header;
+ int width;
+ int (*snprint)(char * buff, size_t len, struct pathgroup * pgp);
+};
+
+void get_path_layout (vector pathvec);
+void get_multipath_layout (vector mpvec);
+int snprint_path_header (char *, int, char *);
+int snprint_multipath_header (char *, int, char *);
+int snprint_path (char *, int, char *, struct path *);
+int snprint_multipath (char *, int, char *, struct multipath *);
+int snprint_multipath_topology (char *, int, struct multipath * mpp,
+ int verbosity);
+int snprint_defaults (char *, int);
+int snprint_blacklist (char *, int);
+int snprint_hwtable (char *, int, vector);
+int snprint_mptable (char *, int, vector);
+
+void print_multipath_topology (struct multipath * mpp, int verbosity);
+void print_path (struct path * pp, char * style);
+void print_multipath (struct multipath * mpp, char * style);
+void print_pathgroup (struct pathgroup * pgp, char * style);
+void print_map (struct multipath * mpp);
+void print_all_paths (vector pathvec, int banner);
+void print_hwtable (vector hwtable);
-void get_path_layout (struct path_layout * pl, vector pathvec);
-void get_map_layout (struct map_layout * pl, vector mpvec);
-int snprint_path_header (char *, int, char *, struct path_layout *);
-int snprint_map_header (char *, int, char *, struct map_layout *);
-int snprint_path (char *, int, char *, struct path *, struct path_layout *);
-int snprint_map (char *, int, char *,struct multipath *, struct map_layout *);
Modified: multipath-tools/trunk/libmultipath/propsel.c
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.c (original)
+++ multipath-tools/trunk/libmultipath/propsel.c Mon Mar 13 15:16:41 2006
@@ -1,13 +1,29 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ */
#include <stdio.h>
+#include <checkers.h>
+
+#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "config.h"
#include "debug.h"
#include "pgpolicies.h"
#include "alias.h"
+#include "defaults.h"
-#include "../libcheckers/checkers.h"
+pgpolicyfn *pgpolicies[] = {
+ NULL,
+ one_path_per_group,
+ one_group,
+ group_by_serial,
+ group_by_prio,
+ group_by_node_name
+};
/*
* selectors :
@@ -19,25 +35,25 @@
{
if (mp->mpe && mp->mpe->rr_weight) {
mp->rr_weight = mp->mpe->rr_weight;
- condlog(3, "rr_weight = %i (LUN setting)",
- mp->rr_weight);
+ condlog(3, "%s: rr_weight = %i (LUN setting)",
+ mp->alias, mp->rr_weight);
return 0;
}
if (mp->hwe && mp->hwe->rr_weight) {
mp->rr_weight = mp->hwe->rr_weight;
- condlog(3, "rr_weight = %i (controler setting)",
- mp->rr_weight);
+ condlog(3, "%s: rr_weight = %i (controler setting)",
+ mp->alias, mp->rr_weight);
return 0;
}
if (conf->rr_weight) {
mp->rr_weight = conf->rr_weight;
- condlog(3, "rr_weight = %i (config file default)",
- mp->rr_weight);
+ condlog(3, "%s: rr_weight = %i (config file default)",
+ mp->alias, mp->rr_weight);
return 0;
}
mp->rr_weight = RR_WEIGHT_NONE;
- condlog(3, "rr_weight = %i (internal default)",
- mp->rr_weight);
+ condlog(3, "%s: rr_weight = %i (internal default)",
+ mp->alias, mp->rr_weight);
return 0;
}
@@ -46,66 +62,74 @@
{
if (mp->mpe && mp->mpe->pgfailback != FAILBACK_UNDEF) {
mp->pgfailback = mp->mpe->pgfailback;
- condlog(3, "pgfailback = %i (LUN setting)", mp->pgfailback);
+ condlog(3, "%s: pgfailback = %i (LUN setting)",
+ mp->alias, mp->pgfailback);
return 0;
}
if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
mp->pgfailback = mp->hwe->pgfailback;
- condlog(3, "pgfailback = %i (controler setting)",
- mp->pgfailback);
+ condlog(3, "%s: pgfailback = %i (controler setting)",
+ mp->alias, mp->pgfailback);
return 0;
}
if (conf->pgfailback != FAILBACK_UNDEF) {
mp->pgfailback = conf->pgfailback;
- condlog(3, "pgfailback = %i (config file default)",
- mp->pgfailback);
+ condlog(3, "%s: pgfailback = %i (config file default)",
+ mp->alias, mp->pgfailback);
return 0;
}
- mp->pgfailback = -FAILBACK_MANUAL;
- condlog(3, "pgfailover = %i (internal default)", mp->pgfailback);
+ mp->pgfailback = DEFAULT_FAILBACK;
+ condlog(3, "%s: pgfailover = %i (internal default)",
+ mp->alias, mp->pgfailback);
return 0;
}
extern int
select_pgpolicy (struct multipath * mp)
{
- struct path * pp;
char pgpolicy_name[POLICY_NAME_SIZE];
- pp = VECTOR_SLOT(mp->paths, 0);
-
if (conf->pgpolicy_flag > 0) {
mp->pgpolicy = conf->pgpolicy_flag;
- if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
- return 1;
- condlog(3, "pgpolicy = %s (cmd line flag)", pgpolicy_name);
+ mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+ mp->pgpolicy);
+ condlog(3, "%s: pgpolicy = %s (cmd line flag)",
+ mp->alias, pgpolicy_name);
return 0;
}
if (mp->mpe && mp->mpe->pgpolicy > 0) {
mp->pgpolicy = mp->mpe->pgpolicy;
- if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
- return 1;
- condlog(3, "pgpolicy = %s (LUN setting)", pgpolicy_name);
+ mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+ mp->pgpolicy);
+ condlog(3, "%s: pgpolicy = %s (LUN setting)",
+ mp->alias, pgpolicy_name);
return 0;
}
if (mp->hwe && mp->hwe->pgpolicy > 0) {
mp->pgpolicy = mp->hwe->pgpolicy;
- if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
- return 1;
- condlog(3, "pgpolicy = %s (controler setting)", pgpolicy_name);
- return 0;
- }
- if (conf->default_pgpolicy > 0) {
- mp->pgpolicy = conf->default_pgpolicy;
- if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
- return 1;
- condlog(3, "pgpolicy = %s (config file default)", pgpolicy_name);
- return 0;
- }
- mp->pgpolicy = FAILOVER;
- if (get_pgpolicy_name(pgpolicy_name, mp->pgpolicy))
- return 1;
- condlog(3, "pgpolicy = %s (internal default)", pgpolicy_name);
+ mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+ mp->pgpolicy);
+ condlog(3, "%s: pgpolicy = %s (controler setting)",
+ mp->alias, pgpolicy_name);
+ return 0;
+ }
+ if (conf->pgpolicy > 0) {
+ mp->pgpolicy = conf->pgpolicy;
+ mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
+ mp->pgpolicy);
+ condlog(3, "%s: pgpolicy = %s (config file default)",
+ mp->alias, pgpolicy_name);
+ return 0;
+ }
+ mp->pgpolicy = DEFAULT_PGPOLICY;
+ mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
+ get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE, mp->pgpolicy);
+ condlog(3, "%s: pgpolicy = %s (internal default)",
+ mp->alias, pgpolicy_name);
return 0;
}
@@ -114,16 +138,19 @@
{
if (mp->mpe && mp->mpe->selector) {
mp->selector = mp->mpe->selector;
- condlog(3, "selector = %s (LUN setting)", mp->selector);
+ condlog(3, "%s: selector = %s (LUN setting)",
+ mp->alias, mp->selector);
return 0;
}
if (mp->hwe && mp->hwe->selector) {
mp->selector = mp->hwe->selector;
- condlog(3, "selector = %s (controler setting)", mp->selector);
+ condlog(3, "%s: selector = %s (controler setting)",
+ mp->alias, mp->selector);
return 0;
}
mp->selector = conf->selector;
- condlog(3, "selector = %s (internal default)", mp->selector);
+ condlog(3, "%s: selector = %s (internal default)",
+ mp->alias, mp->selector);
return 0;
}
@@ -149,11 +176,13 @@
{
if (mp->hwe && mp->hwe->features) {
mp->features = mp->hwe->features;
- condlog(3, "features = %s (controler setting)", mp->features);
+ condlog(3, "%s: features = %s (controler setting)",
+ mp->alias, mp->features);
return 0;
}
mp->features = conf->features;
- condlog(3, "features = %s (internal default)", mp->features);
+ condlog(3, "%s: features = %s (internal default)",
+ mp->alias, mp->features);
return 0;
}
@@ -162,28 +191,36 @@
{
if (mp->hwe && mp->hwe->hwhandler) {
mp->hwhandler = mp->hwe->hwhandler;
- condlog(3, "hwhandler = %s (controler setting)", mp->hwhandler);
+ condlog(3, "%s: hwhandler = %s (controler setting)",
+ mp->alias, mp->hwhandler);
return 0;
}
- mp->hwhandler = conf->default_hwhandler;
- condlog(3, "hwhandler = %s (internal default)", mp->hwhandler);
+ mp->hwhandler = conf->hwhandler;
+ condlog(3, "%s: hwhandler = %s (internal default)",
+ mp->alias, mp->hwhandler);
return 0;
}
extern int
-select_checkfn(struct path *pp)
+select_checker(struct path *pp)
{
- char checker_name[CHECKER_NAME_SIZE];
+ struct checker * c = &pp->checker;
- if (pp->hwe && pp->hwe->checker_index > 0) {
- get_checker_name(checker_name, pp->hwe->checker_index);
- condlog(3, "path checker = %s (controler setting)", checker_name);
- pp->checkfn = get_checker_addr(pp->hwe->checker_index);
+ if (pp->hwe && pp->hwe->checker) {
+ checker_get(c, pp->hwe->checker);
+ condlog(3, "%s: path checker = %s (controler setting)",
+ pp->dev, checker_name(c));
+ return 0;
+ }
+ if (conf->checker) {
+ checker_get(c, conf->checker);
+ condlog(3, "%s: path checker = %s (config file default)",
+ pp->dev, checker_name(c));
return 0;
}
- pp->checkfn = get_checker_addr(conf->default_checker_index);
- get_checker_name(checker_name, conf->default_checker_index);
- condlog(3, "path checker = %s (internal default)", checker_name);
+ checker_get(c, checker_default());
+ condlog(3, "%s: path checker = %s (internal default)",
+ pp->dev, checker_name(c));
return 0;
}
@@ -192,11 +229,19 @@
{
if (pp->hwe && pp->hwe->getuid) {
pp->getuid = pp->hwe->getuid;
- condlog(3, "getuid = %s (controler setting)", pp->getuid);
+ condlog(3, "%s: getuid = %s (controler setting)",
+ pp->dev, pp->getuid);
return 0;
}
- pp->getuid = conf->default_getuid;
- condlog(3, "getuid = %s (internal default)", pp->getuid);
+ if (conf->getuid) {
+ pp->getuid = conf->getuid;
+ condlog(3, "%s: getuid = %s (config file default)",
+ pp->dev, pp->getuid);
+ return 0;
+ }
+ pp->getuid = STRDUP(DEFAULT_GETUID);
+ condlog(3, "%s: getuid = %s (internal default)",
+ pp->dev, pp->getuid);
return 0;
}
@@ -205,11 +250,18 @@
{
if (pp->hwe && pp->hwe->getprio) {
pp->getprio = pp->hwe->getprio;
- condlog(3, "getprio = %s (controler setting)", pp->getprio);
+ condlog(3, "%s: getprio = %s (controler setting)",
+ pp->dev, pp->getprio);
return 0;
}
- pp->getprio = conf->default_getprio;
- condlog(3, "getprio = %s (internal default)", pp->getprio);
+ if (conf->getprio) {
+ pp->getprio = conf->getprio;
+ condlog(3, "%s: getprio = %s (config file default)",
+ pp->dev, pp->getprio);
+ return 0;
+ }
+ pp->getprio = DEFAULT_GETPRIO;
+ condlog(3, "%s: getprio = NULL (internal default)", pp->dev);
return 0;
}
@@ -218,23 +270,52 @@
{
if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
mp->no_path_retry = mp->mpe->no_path_retry;
- condlog(3, "no_path_retry = %i (multipath setting)",
- mp->no_path_retry);
+ condlog(3, "%s: no_path_retry = %i (multipath setting)",
+ mp->alias, mp->no_path_retry);
return 0;
}
if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
mp->no_path_retry = mp->hwe->no_path_retry;
- condlog(3, "no_path_retry = %i (controler setting)",
- mp->no_path_retry);
+ condlog(3, "%s: no_path_retry = %i (controler setting)",
+ mp->alias, mp->no_path_retry);
return 0;
}
if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
mp->no_path_retry = conf->no_path_retry;
- condlog(3, "no_path_retry = %i (config file default)",
- mp->no_path_retry);
+ condlog(3, "%s: no_path_retry = %i (config file default)",
+ mp->alias, mp->no_path_retry);
return 0;
}
mp->no_path_retry = NO_PATH_RETRY_UNDEF;
- condlog(3, "no_path_retry = NONE (internal default)");
+ condlog(3, "%s: no_path_retry = NONE (internal default)",
+ mp->alias);
+ return 0;
+}
+
+extern int
+select_minio (struct multipath * mp)
+{
+ if (mp->mpe && mp->mpe->minio) {
+ mp->minio = mp->mpe->minio;
+ condlog(3, "%s: minio = %i (LUN setting)",
+ mp->alias, mp->minio);
+ return 0;
+ }
+ if (mp->hwe && mp->hwe->minio) {
+ mp->minio = mp->hwe->minio;
+ condlog(3, "%s: minio = %i (controler setting)",
+ mp->alias, mp->minio);
+ return 0;
+ }
+ if (conf->minio) {
+ mp->minio = conf->minio;
+ condlog(3, "%s: minio = %i (config file default)",
+ mp->alias, mp->minio);
+ return 0;
+ }
+ mp->minio = DEFAULT_MINIO;
+ condlog(3, "%s: minio = %i (internal default)",
+ mp->alias, mp->minio);
return 0;
}
+
Modified: multipath-tools/trunk/libmultipath/propsel.h
==============================================================================
--- multipath-tools/trunk/libmultipath/propsel.h (original)
+++ multipath-tools/trunk/libmultipath/propsel.h Mon Mar 13 15:16:41 2006
@@ -5,7 +5,8 @@
int select_alias (struct multipath * mp);
int select_features (struct multipath * mp);
int select_hwhandler (struct multipath * mp);
-int select_checkfn(struct path *pp);
+int select_checker(struct path *pp);
int select_getuid (struct path * pp);
int select_getprio (struct path * pp);
int select_no_path_retry(struct multipath *mp);
+int select_minio(struct multipath *mp);
Modified: multipath-tools/trunk/libmultipath/structs.c
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.c (original)
+++ multipath-tools/trunk/libmultipath/structs.c Mon Mar 13 15:16:41 2006
@@ -1,13 +1,21 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2004 Stefan Bader, IBM
+ */
#include <stdio.h>
#include <unistd.h>
#include <libdevmapper.h>
+#include <checkers.h>
+
#include "memory.h"
#include "vector.h"
#include "util.h"
#include "structs.h"
#include "config.h"
#include "debug.h"
+#include "structs_vec.h"
+#include "blacklist.h"
struct path *
alloc_path (void)
@@ -32,8 +40,8 @@
if (!pp)
return;
- if (pp->checker_context)
- free(pp->checker_context);
+ if (checker_selected(&pp->checker))
+ checker_put(&pp->checker);
if (pp->fd >= 0)
close(pp->fd);
@@ -113,8 +121,8 @@
return mpp;
}
-void
-free_multipath (struct multipath * mpp, int free_paths)
+extern void
+free_multipath_attributes (struct multipath * mpp)
{
if (!mpp)
return;
@@ -122,27 +130,52 @@
if (mpp->selector &&
mpp->selector != conf->selector &&
(!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
- (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector)))
+ (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
FREE(mpp->selector);
-
- if (mpp->alias &&
- (!mpp->mpe || (mpp->mpe && mpp->alias != mpp->mpe->alias)) &&
- (mpp->wwid && mpp->alias != mpp->wwid))
- FREE(mpp->alias);
+ mpp->selector = NULL;
+ }
if (mpp->features &&
mpp->features != conf->features &&
- (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features)))
+ (!mpp->hwe || (mpp->hwe && mpp->features != mpp->hwe->features))) {
FREE(mpp->features);
+ mpp->features = NULL;
+ }
if (mpp->hwhandler &&
- mpp->hwhandler != conf->default_hwhandler &&
- (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler)))
+ mpp->hwhandler != conf->hwhandler &&
+ (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
FREE(mpp->hwhandler);
+ mpp->hwhandler = NULL;
+ }
+}
+
+void
+free_multipath (struct multipath * mpp, int free_paths)
+{
+ if (!mpp)
+ return;
+
+ free_multipath_attributes(mpp);
+
+ if (mpp->alias &&
+ (!mpp->mpe || (mpp->mpe && mpp->alias != mpp->mpe->alias)) &&
+ (mpp->wwid && mpp->alias != mpp->wwid)) {
+ FREE(mpp->alias);
+ mpp->alias = NULL;
+ }
if (mpp->dmi)
FREE(mpp->dmi);
+#if DAEMON
+ /*
+ * better own vecs->lock here
+ */
+ if (mpp->waiter)
+ ((struct event_thread *)mpp->waiter)->mpp = NULL;
+#endif
+
free_pathvec(mpp->paths, free_paths);
free_pgvec(mpp->pg, free_paths);
FREE(mpp);
@@ -204,28 +237,34 @@
}
struct multipath *
-find_mp_by_minor (vector mp, int minor)
+find_mp_by_minor (vector mpvec, int minor)
{
int i;
struct multipath * mpp;
- if (!mpp->dmi)
+ if (!mpvec)
return NULL;
- vector_foreach_slot (mp, mpp, i)
+ vector_foreach_slot (mpvec, mpp, i) {
+ if (!mpp->dmi)
+ continue;
+
if (mpp->dmi->minor == minor)
return mpp;
-
+ }
return NULL;
}
struct multipath *
-find_mp_by_wwid (vector mp, char * wwid)
+find_mp_by_wwid (vector mpvec, char * wwid)
{
int i;
struct multipath * mpp;
- vector_foreach_slot (mp, mpp, i)
+ if (!mpvec)
+ return NULL;
+
+ vector_foreach_slot (mpvec, mpp, i)
if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
return mpp;
@@ -233,18 +272,21 @@
}
struct multipath *
-find_mp_by_alias (vector mp, char * alias)
+find_mp_by_alias (vector mpvec, char * alias)
{
int i;
int len;
struct multipath * mpp;
+ if (!mpvec)
+ return NULL;
+
len = strlen(alias);
if (!len)
return NULL;
- vector_foreach_slot (mp, mpp, i) {
+ vector_foreach_slot (mpvec, mpp, i) {
if (strlen(mpp->alias) == len &&
!strncmp(mpp->alias, alias, len))
return mpp;
@@ -252,17 +294,31 @@
return NULL;
}
+struct multipath *
+find_mp_by_str (vector mpvec, char * str)
+{
+ int minor;
+
+ if (sscanf(str, "dm-%d", &minor) == 1)
+ return find_mp_by_minor(mpvec, minor);
+ else
+ return find_mp_by_alias(mpvec, str);
+}
+
struct path *
find_path_by_dev (vector pathvec, char * dev)
{
int i;
struct path * pp;
+
+ if (!pathvec)
+ return NULL;
vector_foreach_slot (pathvec, pp, i)
if (!strcmp_chomp(pp->dev, dev))
return pp;
- condlog(3, "path %s not found in pathvec\n", dev);
+ condlog(3, "%s: not found in pathvec", dev);
return NULL;
}
@@ -272,11 +328,40 @@
int i;
struct path * pp;
+ if (!pathvec)
+ return NULL;
+
vector_foreach_slot (pathvec, pp, i)
if (!strcmp_chomp(pp->dev_t, dev_t))
return pp;
- condlog(3, "path %s not found in pathvec\n", dev_t);
+ condlog(3, "%s: not found in pathvec", dev_t);
return NULL;
}
+extern int
+pathcountgr (struct pathgroup * pgp, int state)
+{
+ struct path *pp;
+ int count = 0;
+ int i;
+
+ vector_foreach_slot (pgp->paths, pp, i)
+ if ((pp->state == state) || (state < 0))
+ count++;
+
+ return count;
+}
+
+extern int
+pathcount (struct multipath * mpp, int state)
+{
+ struct pathgroup *pgp;
+ int count = 0;
+ int i;
+
+ vector_foreach_slot (mpp->pg, pgp, i)
+ count += pathcountgr(pgp, state);
+
+ return count;
+}
Modified: multipath-tools/trunk/libmultipath/structs.h
==============================================================================
--- multipath-tools/trunk/libmultipath/structs.h (original)
+++ multipath-tools/trunk/libmultipath/structs.h Mon Mar 13 15:16:41 2006
@@ -38,7 +38,8 @@
enum sysfs_buses {
SYSFS_BUS_UNDEF,
SYSFS_BUS_SCSI,
- SYSFS_BUS_IDE
+ SYSFS_BUS_IDE,
+ SYSFS_BUS_CCW,
};
enum pathstates {
@@ -99,8 +100,8 @@
int pgindex;
char * getuid;
char * getprio;
- int (*checkfn) (int, char *, void **);
- void * checker_context;
+ int getprio_selected;
+ struct checker checker;
struct multipath * mpp;
int fd;
@@ -108,9 +109,13 @@
struct hwentry * hwe;
};
+typedef int (pgpolicyfn) (struct multipath *);
+
struct multipath {
char wwid[WWID_SIZE];
+ char alias_old[WWID_SIZE];
int pgpolicy;
+ pgpolicyfn *pgpolicyfn;
int nextpg;
int bestpg;
int queuedio;
@@ -121,6 +126,7 @@
int nr_active; /* current available(= not known as failed) paths */
int no_path_retry; /* number of retries after all paths are down */
int retry_tick; /* remaining times for retries */
+ int minio;
unsigned long long size;
vector paths;
vector pg;
@@ -138,6 +144,13 @@
/* daemon store a data blob for DM event waiter threads */
void * waiter;
+
+ /* stats */
+ unsigned int stat_switchgroup;
+ unsigned int stat_path_failures;
+ unsigned int stat_map_loads;
+ unsigned int stat_total_queueing_time;
+ unsigned int stat_queueing_timeouts;
};
struct pathgroup {
@@ -145,6 +158,7 @@
int status;
int priority;
vector paths;
+ char * selector;
};
struct path * alloc_path (void);
@@ -155,6 +169,7 @@
void free_pathgroup (struct pathgroup * pgp, int free_paths);
void free_pgvec (vector pgvec, int free_paths);
void free_multipath (struct multipath *, int free_paths);
+void free_multipath_attributes (struct multipath *);
void drop_multipath (vector mpvec, char * wwid, int free_paths);
void free_multipathvec (vector mpvec, int free_paths);
@@ -163,11 +178,15 @@
struct multipath * find_mp_by_alias (vector mp, char * alias);
struct multipath * find_mp_by_wwid (vector mp, char * wwid);
+struct multipath * find_mp_by_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);
+int pathcountgr (struct pathgroup *, int);
+int pathcount (struct multipath *, int);
+
char sysfs_path[FILE_NAME_SIZE];
#endif
Added: multipath-tools/trunk/libmultipath/structs_vec.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/structs_vec.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,384 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <checkers.h>
+
+#include "vector.h"
+#include "defaults.h"
+#include "debug.h"
+#include "structs.h"
+#include "structs_vec.h"
+#include "devmapper.h"
+#include "dmparser.h"
+#include "config.h"
+#include "propsel.h"
+#include "discovery.h"
+
+
+/*
+ * creates or updates mpp->paths reading mpp->pg
+ */
+extern int
+update_mpp_paths(struct multipath * mpp, vector pathvec)
+{
+ struct pathgroup * pgp;
+ struct path * pp;
+ int i,j;
+
+ if (!mpp->pg)
+ return 0;
+
+ if (!mpp->paths &&
+ !(mpp->paths = vector_alloc()))
+ return 1;
+
+ vector_foreach_slot (mpp->pg, pgp, i) {
+ vector_foreach_slot (pgp->paths, pp, j) {
+ if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
+ (find_path_by_devt(pathvec, pp->dev_t)) &&
+ store_path(mpp->paths, pp))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+extern int
+adopt_paths (vector pathvec, struct multipath * mpp)
+{
+ int i;
+ struct path * pp;
+
+ if (!mpp)
+ return 0;
+
+ if (update_mpp_paths(mpp, pathvec))
+ return 1;
+
+ vector_foreach_slot (pathvec, pp, i) {
+ if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
+ condlog(3, "%s ownership set to %s",
+ pp->dev_t, mpp->alias);
+ pp->mpp = mpp;
+
+ if (!mpp->paths && !(mpp->paths = vector_alloc()))
+ return 1;
+
+ if (!find_path_by_dev(mpp->paths, pp->dev) &&
+ store_path(mpp->paths, pp))
+ return 1;
+ pathinfo(pp, conf->hwtable, DI_PRIO | DI_CHECKER);
+ }
+ }
+ return 0;
+}
+
+extern void
+orphan_path (struct path * pp)
+{
+ pp->mpp = NULL;
+ pp->dmstate = PSTATE_UNDEF;
+ pp->getuid = NULL;
+ pp->getprio = NULL;
+ pp->getprio_selected = 0;
+ checker_put(&pp->checker);
+ if (pp->fd >= 0)
+ close(pp->fd);
+ pp->fd = -1;
+}
+
+extern void
+orphan_paths (vector pathvec, struct multipath * mpp)
+{
+ int i;
+ struct path * pp;
+
+ vector_foreach_slot (pathvec, pp, i) {
+ if (pp->mpp == mpp) {
+ condlog(4, "%s is orphaned", pp->dev_t);
+ orphan_path(pp);
+ }
+ }
+}
+
+static void
+set_multipath_wwid (struct multipath * mpp)
+{
+ if (mpp->wwid)
+ return;
+
+ dm_get_uuid(mpp->alias, mpp->wwid);
+}
+
+extern void
+remove_map (struct multipath * mpp, struct vectors * vecs,
+ stop_waiter_thread_func *stop_waiter, int purge_vec)
+{
+ int i;
+
+ /*
+ * stop the DM event waiter thread
+ */
+ if (stop_waiter)
+ stop_waiter(mpp, vecs);
+
+ /*
+ * clear references to this map
+ */
+ orphan_paths(vecs->pathvec, mpp);
+
+ if (purge_vec &&
+ (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
+ vector_del_slot(vecs->mpvec, i);
+
+ /*
+ * final free
+ */
+ free_multipath(mpp, KEEP_PATHS);
+}
+
+extern void
+remove_maps (struct vectors * vecs,
+ stop_waiter_thread_func *stop_waiter)
+{
+ int i;
+ struct multipath * mpp;
+
+ vector_foreach_slot (vecs->mpvec, mpp, i) {
+ remove_map(mpp, vecs, stop_waiter, 1);
+ i--;
+ }
+
+ vector_free(vecs->mpvec);
+ vecs->mpvec = NULL;
+}
+
+static struct hwentry *
+extract_hwe_from_path(struct multipath * mpp)
+{
+ struct path * pp;
+ struct pathgroup * pgp;
+
+ pgp = VECTOR_SLOT(mpp->pg, 0);
+ pp = VECTOR_SLOT(pgp->paths, 0);
+
+ return pp->hwe;
+}
+
+static int
+update_multipath_table (struct multipath *mpp, vector pathvec)
+{
+ if (!mpp)
+ return 1;
+
+ if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
+ return 1;
+
+ if (disassemble_map(pathvec, mpp->params, mpp))
+ return 1;
+
+ return 0;
+}
+
+static int
+update_multipath_status (struct multipath *mpp)
+{
+ if (!mpp)
+ return 1;
+
+ if(dm_get_status(mpp->alias, mpp->status))
+ return 1;
+
+ if (disassemble_status(mpp->status, mpp))
+ return 1;
+
+ return 0;
+}
+
+extern int
+update_multipath_strings (struct multipath *mpp, vector pathvec)
+{
+ free_multipath_attributes(mpp);
+ free_pgvec(mpp->pg, KEEP_PATHS);
+ mpp->pg = NULL;
+
+ if (update_multipath_table(mpp, pathvec))
+ return 1;
+
+ if (update_multipath_status(mpp))
+ return 1;
+
+ return 0;
+}
+
+extern void
+set_no_path_retry(struct multipath *mpp)
+{
+ mpp->retry_tick = 0;
+ mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
+ select_no_path_retry(mpp);
+
+ switch (mpp->no_path_retry) {
+ case NO_PATH_RETRY_UNDEF:
+ break;
+ case NO_PATH_RETRY_FAIL:
+ dm_queue_if_no_path(mpp->alias, 0);
+ break;
+ case NO_PATH_RETRY_QUEUE:
+ dm_queue_if_no_path(mpp->alias, 1);
+ break;
+ default:
+ dm_queue_if_no_path(mpp->alias, 1);
+ if (mpp->nr_active == 0) {
+ /* Enter retry mode */
+ mpp->retry_tick = mpp->no_path_retry * conf->checkint;
+ condlog(1, "%s: Entering recovery mode: max_retries=%d",
+ mpp->alias, mpp->no_path_retry);
+ }
+ break;
+ }
+}
+
+extern int
+setup_multipath (struct vectors * vecs, struct multipath * mpp)
+{
+retry:
+ if (dm_get_info(mpp->alias, &mpp->dmi))
+ goto out;
+
+ set_multipath_wwid(mpp);
+ mpp->mpe = find_mpe(mpp->wwid);
+ condlog(3, "%s: discover", mpp->alias);
+
+ if (update_multipath_strings(mpp, vecs->pathvec)) {
+ char new_alias[WWID_SIZE];
+
+ /*
+ * detect an external rename of the multipath device
+ */
+ if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
+ condlog(3, "%s multipath mapped device name has "
+ "changed from %s to %s", mpp->wwid,
+ mpp->alias, new_alias);
+ strcpy(mpp->alias, new_alias);
+#if DAEMON
+ if (mpp->waiter)
+ strncpy(((struct event_thread *)mpp->waiter)->mapname,
+ new_alias, WWID_SIZE);
+#endif
+ goto retry;
+ }
+ goto out;
+ }
+
+ //adopt_paths(vecs->pathvec, mpp);
+ mpp->hwe = extract_hwe_from_path(mpp);
+ select_rr_weight(mpp);
+ select_pgfailback(mpp);
+ set_no_path_retry(mpp);
+
+ return 0;
+out:
+ condlog(0, "%s: failed to setup multipath", mpp->alias);
+ remove_map(mpp, vecs, NULL, 1);
+ return 1;
+}
+
+extern struct multipath *
+add_map_without_path (struct vectors * vecs,
+ int minor, char * alias,
+ start_waiter_thread_func *start_waiter)
+{
+ struct multipath * mpp = alloc_multipath();
+
+ if (!mpp)
+ return NULL;
+
+ mpp->alias = alias;
+
+ if (setup_multipath(vecs, mpp))
+ return NULL; /* mpp freed in setup_multipath */
+
+ if (adopt_paths(vecs->pathvec, mpp))
+ goto out;
+
+ if (!vector_alloc_slot(vecs->mpvec))
+ goto out;
+
+ vector_set_slot(vecs->mpvec, mpp);
+
+ if (start_waiter(mpp, vecs))
+ goto out;
+
+ return mpp;
+out:
+ remove_map(mpp, vecs, NULL, 1);
+ return NULL;
+}
+
+extern struct multipath *
+add_map_with_path (struct vectors * vecs,
+ struct path * pp, int add_vec)
+{
+ struct multipath * mpp;
+
+ if (!(mpp = alloc_multipath()))
+ return NULL;
+
+ mpp->mpe = find_mpe(pp->wwid);
+ mpp->hwe = pp->hwe;
+
+ strcpy(mpp->wwid, pp->wwid);
+ select_alias(mpp);
+ mpp->size = pp->size;
+
+ if (adopt_paths(vecs->pathvec, mpp))
+ goto out;
+
+ if (add_vec) {
+ if (!vector_alloc_slot(vecs->mpvec))
+ goto out;
+
+ vector_set_slot(vecs->mpvec, mpp);
+ }
+
+ return mpp;
+
+out:
+ remove_map(mpp, vecs, NULL, add_vec);
+ return NULL;
+}
+
+extern int
+verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
+{
+ struct path * pp;
+ int count = 0;
+ int i, j;
+
+ vector_foreach_slot (mpp->paths, pp, i) {
+ /*
+ * see if path is in sysfs
+ */
+ if (!pp->dev || sysfs_get_dev(sysfs_path,
+ pp->dev, pp->dev_t, BLK_DEV_SIZE)) {
+ condlog(0, "%s: failed to access path %s", mpp->alias,
+ pp->dev ? pp->dev : pp->dev_t);
+ count++;
+ vector_del_slot(mpp->paths, i);
+ i--;
+
+ if (rpvec)
+ store_path(rpvec, pp);
+ else {
+ if ((j = find_slot(vecs->pathvec,
+ (void *)pp)) != -1)
+ vector_del_slot(vecs->pathvec, j);
+ free_path(pp);
+ }
+ }
+ }
+ return count;
+}
+
Added: multipath-tools/trunk/libmultipath/structs_vec.h
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/libmultipath/structs_vec.h Mon Mar 13 15:16:41 2006
@@ -0,0 +1,48 @@
+#ifndef _STRUCTS_VEC_H
+#define _STRUCTS_VEC_H
+
+struct vectors {
+#if DAEMON
+ pthread_mutex_t *lock;
+#endif
+ vector pathvec;
+ vector mpvec;
+};
+
+#if DAEMON
+struct event_thread {
+ struct dm_task *dmt;
+ pthread_t thread;
+ int event_nr;
+ char mapname[WWID_SIZE];
+ struct vectors *vecs;
+ struct multipath *mpp;
+};
+#endif
+
+typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
+typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
+
+void set_no_path_retry(struct multipath *mpp);
+
+int adopt_paths (vector pathvec, struct multipath * mpp);
+void orphan_paths (vector pathvec, struct multipath * mpp);
+void orphan_path (struct path * pp);
+
+int verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec);
+int update_mpp_paths(struct multipath * mpp, vector pathvec);
+int setup_multipath (struct vectors * vecs, struct multipath * mpp);
+int update_multipath_strings (struct multipath *mpp, vector pathvec);
+
+void remove_map (struct multipath * mpp, struct vectors * vecs,
+ stop_waiter_thread_func *stop_waiter, int purge_vec);
+void remove_maps (struct vectors * vecs,
+ stop_waiter_thread_func *stop_waiter);
+
+struct multipath * add_map_without_path (struct vectors * vecs,
+ int minor, char * alias,
+ start_waiter_thread_func *start_waiter);
+struct multipath * add_map_with_path (struct vectors * vecs,
+ struct path * pp, int add_vec);
+
+#endif /* _STRUCTS_VEC_H */
Modified: multipath-tools/trunk/libmultipath/switchgroup.c
==============================================================================
--- multipath-tools/trunk/libmultipath/switchgroup.c (original)
+++ multipath-tools/trunk/libmultipath/switchgroup.c Mon Mar 13 15:16:41 2006
@@ -1,7 +1,12 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
+#include <checkers.h>
+
#include "vector.h"
#include "structs.h"
#include "switchgroup.h"
-#include "../libcheckers/path_state.h"
extern int
select_path_group (struct multipath * mpp)
@@ -11,6 +16,7 @@
int bestpg = 1;
struct pathgroup * pgp;
struct path * pp;
+ int priority;
if (!mpp->pg)
return 1;
@@ -18,11 +24,14 @@
vector_foreach_slot (mpp->pg, pgp, i) {
if (!pgp->paths)
continue;
-
+
+ priority = 0;
+
vector_foreach_slot (pgp->paths, pp, j) {
if (pp->state != PATH_DOWN)
- pgp->priority += pp->priority;
+ priority += pp->priority;
}
+ pgp->priority = priority;
if (pgp->priority > highest) {
highest = pgp->priority;
Modified: multipath-tools/trunk/libmultipath/uevent.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uevent.c (original)
+++ multipath-tools/trunk/libmultipath/uevent.c Mon Mar 13 15:16:41 2006
@@ -33,22 +33,103 @@
#include <sys/user.h>
#include <asm/types.h>
#include <linux/netlink.h>
+#include <pthread.h>
+#include <sys/mman.h>
#include "memory.h"
#include "debug.h"
#include "uevent.h"
+typedef int (uev_trigger)(struct uevent *, void * trigger_data);
+
+pthread_t uevq_thr;
+struct uevent *uevqhp, *uevqtp;
+pthread_mutex_t uevq_lock, *uevq_lockp = &uevq_lock;
+pthread_mutex_t uevc_lock, *uevc_lockp = &uevc_lock;
+pthread_cond_t uev_cond, *uev_condp = &uev_cond;
+uev_trigger *my_uev_trigger;
+void * my_trigger_data;
+
struct uevent * alloc_uevent (void)
{
return (struct uevent *)MALLOC(sizeof(struct uevent));
}
+void
+service_uevq(void)
+{
+ int empty;
+ struct uevent *uev;
+
+ do {
+ pthread_mutex_lock(uevq_lockp);
+ empty = (uevqhp == NULL);
+ if (!empty) {
+ uev = uevqhp;
+ uevqhp = uev->next;
+ if (uevqtp == uev)
+ uevqtp = uev->next;
+ pthread_mutex_unlock(uevq_lockp);
+
+ if (my_uev_trigger && my_uev_trigger(uev,
+ my_trigger_data))
+ condlog(0, "uevent trigger error");
+
+ FREE(uev);
+ }
+ else {
+ pthread_mutex_unlock(uevq_lockp);
+ }
+ } while (empty == 0);
+}
+
+/*
+ * Service the uevent queue.
+ */
+static void *
+uevq_thread(void * et)
+{
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+
+ while (1) {
+ pthread_mutex_lock(uevc_lockp);
+ pthread_cond_wait(uev_condp, uevc_lockp);
+ pthread_mutex_unlock(uevc_lockp);
+
+ service_uevq();
+ }
+}
+
int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data),
void * trigger_data)
{
int sock;
struct sockaddr_nl snl;
int retval;
+ int rcvbufsz = 128*1024;
+ int rcvsz = 0;
+ int rcvszsz = sizeof(rcvsz);
+ unsigned int *prcvszsz = (unsigned int *)&rcvszsz;
+ pthread_attr_t attr;
+
+ my_uev_trigger = uev_trigger;
+ my_trigger_data = trigger_data;
+
+ /*
+ * Queue uevents for service by dedicated thread so that the uevent
+ * listening thread does not block on multipathd locks (vecs->lock)
+ * thereby not getting to empty the socket's receive buffer queue
+ * often enough.
+ */
+ uevqhp = uevqtp = NULL;
+
+ pthread_mutex_init(uevq_lockp, NULL);
+ pthread_mutex_init(uevc_lockp, NULL);
+ pthread_cond_init(uev_condp, NULL);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 64 * 1024);
+ pthread_create(&uevq_thr, &attr, uevq_thread, NULL);
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
@@ -57,35 +138,56 @@
sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (sock == -1) {
- condlog(0, "error getting socket, exit\n");
+ condlog(0, "error getting socket, exit");
return 1;
}
+ /*
+ * try to avoid dropping uevents, even so, this is not a guarantee,
+ * but it does help to change the netlink uevent socket's
+ * receive buffer threshold from the default value of 106,496 to
+ * the maximum value of 262,142.
+ */
+ retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
+ sizeof(rcvbufsz));
+
+ if (retval < 0) {
+ condlog(0, "error setting receive buffer size for socket, exit");
+ exit(1);
+ }
+ retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
+
+ if (retval < 0) {
+ condlog(0, "error setting receive buffer size for socket, exit");
+ exit(1);
+ }
+ condlog(3, "receive buffer size for socket is %u.", rcvsz);
+
retval = bind(sock, (struct sockaddr *) &snl,
sizeof(struct sockaddr_nl));
if (retval < 0) {
- condlog(0, "bind failed, exit\n");
+ condlog(0, "bind failed, exit");
goto exit;
}
while (1) {
- static char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
+ static char buff[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
int i;
char *pos;
size_t bufpos;
ssize_t buflen;
struct uevent *uev;
+ char *buffer;
- buflen = recv(sock, &buffer, sizeof(buffer), 0);
+ buflen = recv(sock, &buff, sizeof(buff), 0);
if (buflen < 0) {
- condlog(0, "error receiving message\n");
+ condlog(0, "error receiving message");
continue;
}
- if ((size_t)buflen > sizeof(buffer)-1)
- buflen = sizeof(buffer)-1;
+ if ((size_t)buflen > sizeof(buff)-1)
+ buflen = sizeof(buff)-1;
- buffer[buflen] = '\0';
uev = alloc_uevent();
if (!uev) {
@@ -93,6 +195,14 @@
continue;
}
+ /*
+ * Copy the shared receive buffer contents to buffer private
+ * to this uevent so we can immediately reuse the shared buffer.
+ */
+ memcpy(uev->buffer, buff, HOTPLUG_BUFFER_SIZE + OBJECT_SIZE);
+ buffer = uev->buffer;
+ buffer[buflen] = '\0';
+
/* save start of payload */
bufpos = strlen(buffer) + 1;
@@ -118,19 +228,39 @@
}
uev->envp[i] = NULL;
- condlog(3, "uevent '%s' from '%s'\n", uev->action, uev->devpath);
+ condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath);
/* print payload environment */
for (i = 0; uev->envp[i] != NULL; i++)
- condlog(3, "%s\n", uev->envp[i]);
+ condlog(3, "%s", uev->envp[i]);
- if (uev_trigger && uev_trigger(uev, trigger_data))
- condlog(0, "uevent trigger error");
-
- FREE(uev);
+ /*
+ * Queue uevent and poke service pthread.
+ */
+ pthread_mutex_lock(uevq_lockp);
+ if (uevqtp)
+ uevqtp->next = uev;
+ else
+ uevqhp = uev;
+ uevqtp = uev;
+ uev->next = NULL;
+ pthread_mutex_unlock(uevq_lockp);
+
+ pthread_mutex_lock(uevc_lockp);
+ pthread_cond_signal(uev_condp);
+ pthread_mutex_unlock(uevc_lockp);
}
exit:
close(sock);
+
+ pthread_mutex_lock(uevq_lockp);
+ pthread_cancel(uevq_thr);
+ pthread_mutex_unlock(uevq_lockp);
+
+ pthread_mutex_destroy(uevq_lockp);
+ pthread_mutex_destroy(uevc_lockp);
+ pthread_cond_destroy(uev_condp);
+
return 1;
}
Modified: multipath-tools/trunk/libmultipath/uevent.h
==============================================================================
--- multipath-tools/trunk/libmultipath/uevent.h (original)
+++ multipath-tools/trunk/libmultipath/uevent.h Mon Mar 13 15:16:41 2006
@@ -8,6 +8,8 @@
#endif
struct uevent {
+ void *next;
+ char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE];
char *devpath;
char *action;
char *envp[HOTPLUG_NUM_ENVP];
Modified: multipath-tools/trunk/libmultipath/uxsock.c
==============================================================================
--- multipath-tools/trunk/libmultipath/uxsock.c (original)
+++ multipath-tools/trunk/libmultipath/uxsock.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Original author : tridge at samba.org, January 2002
+ *
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Alasdair Kergon, Redhat
+ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Modified: multipath-tools/trunk/libmultipath/vector.c
==============================================================================
--- multipath-tools/trunk/libmultipath/vector.c (original)
+++ multipath-tools/trunk/libmultipath/vector.c Mon Mar 13 15:16:41 2006
@@ -14,6 +14,9 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 2002, 2003, 2004 Alexandre Cassen
+ * Copyright (c) 2005 Christophe Varoqui
*/
#include "memory.h"
Modified: multipath-tools/trunk/multipath-tools.spec.in
==============================================================================
--- multipath-tools/trunk/multipath-tools.spec.in (original)
+++ multipath-tools/trunk/multipath-tools.spec.in Mon Mar 13 15:16:41 2006
@@ -44,11 +44,19 @@
%{prefix}/sbin/devmap_name
%{prefix}/sbin/multipath
%{prefix}/sbin/kpartx
+%{prefix}/sbin/mpath_prio_alua
+%{prefix}/sbin/mpath_prio_emc
+%{prefix}/sbin/mpath_prio_random
+%{prefix}/sbin/mpath_prio_balance_units
+%{prefix}/sbin/mpath_prio_netapp
+%{prefix}/sbin/mpath_prio_tpc
%{prefix}/usr/share/man/man8/devmap_name.8.gz
%{prefix}/usr/share/man/man8/multipath.8.gz
-%{prefix}/usr/bin/multipathd
-%{prefix}/etc/hotplug.d/scsi/multipath.hotplug
-%{prefix}/etc/init.d/multipathd
+%{prefix}/usr/share/man/man8/kpartx.8.gz
+%{prefix}/usr/share/man/man8/mpath_prio_alua.8.gz
+%{prefix}/usr/share/man/man8/multipathd.8.gz
+%{prefix}/sbin/multipathd
+%{prefix}/etc/udev/rules.d/multipath.rules
%changelog
Modified: multipath-tools/trunk/multipath.conf.annotated
==============================================================================
--- multipath-tools/trunk/multipath.conf.annotated (original)
+++ multipath-tools/trunk/multipath.conf.annotated Mon Mar 13 15:16:41 2006
@@ -137,6 +137,10 @@
# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
# devnode "^hd[a-z][[0-9]*]"
# devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
+# device {
+# vendor DEC.*
+# product MSA[15]00
+# }
#}
#
##
@@ -213,6 +217,15 @@
# # default : (null)
# #
# #no_path_retry queue
+#
+# #
+# # name : rr_min_io
+# # scope : multipath
+# # desc : the number of IO to route to a path before switching
+# # to the next in the same path group
+# # default : 1000
+# #
+# rr_min_io 100
# }
# multipath {
# wwid 1DEC_____321816758474
@@ -305,6 +318,23 @@
# # default : immediate
# #
# failback 30
+#
+# #
+# # name : rr_min_io
+# # scope : multipath
+# # desc : the number of IO to route to a path before switching
+# # to the next in the same path group
+# # default : 1000
+# #
+# rr_min_io 100
+#
+# #
+# # name : product_blacklist
+# # scope : multipath & multipathd
+# # desc : product strings to blacklist for this vendor
+# # default : none
+# #
+# product_blacklist LUN_Z
# }
# device {
# vendor "COMPAQ "
Modified: multipath-tools/trunk/multipath.conf.synthetic
==============================================================================
--- multipath-tools/trunk/multipath.conf.synthetic (original)
+++ multipath-tools/trunk/multipath.conf.synthetic Mon Mar 13 15:16:41 2006
@@ -14,13 +14,17 @@
# rr_weight priorities
# failback immediate
# no_path_retry fail
-# user_friendly_name no
+# user_friendly_names no
#}
#devnode_blacklist {
# wwid 26353900f02796769
# devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
# devnode "^hd[a-z][[0-9]*]"
# devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
+# device {
+# vendor DEC.*
+# product MSA[15]00
+# }
#}
#multipaths {
# multipath {
@@ -32,6 +36,7 @@
# failback manual
# rr_weight priorities
# no_path_retry 5
+# rr_min_io 100
# }
# multipath {
# wwid 1DEC_____321816758474
@@ -50,6 +55,8 @@
# failback 15
# rr_weight priorities
# no_path_retry queue
+# rr_min_io 100
+# product_blacklist LUN_Z
# }
# device {
# vendor "COMPAQ "
Modified: multipath-tools/trunk/multipath/Makefile
==============================================================================
--- multipath-tools/trunk/multipath/Makefile (original)
+++ multipath-tools/trunk/multipath/Makefile Mon Mar 13 15:16:41 2006
@@ -7,13 +7,12 @@
OBJS = main.o $(MULTIPATHLIB)-$(BUILD).a $(CHECKERSLIB)-$(BUILD).a
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
- -I$(multipathdir) -I$(checkersdir)
+CFLAGS += -I$(multipathdir) -I$(checkersdir)
ifeq ($(strip $(BUILD)),klibc)
OBJS += $(libdm) $(libsysfs)
else
- LDFLAGS += -ldevmapper -lsysfs -lm
+ LDFLAGS += -ldevmapper -lsysfs
endif
EXEC = multipath
@@ -27,7 +26,7 @@
glibc: prepare $(OBJS)
$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
+
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
Modified: multipath-tools/trunk/multipath/main.c
==============================================================================
--- multipath-tools/trunk/multipath/main.c (original)
+++ multipath-tools/trunk/multipath/main.c Mon Mar 13 15:16:41 2006
@@ -3,7 +3,7 @@
*
* Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
*
- * Author: Copyright (C) 2003 Christophe Varoqui
+ * Author: Christophe Varoqui
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,270 +14,40 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Patrick Caulfield, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
*/
#include <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
-#include <sys/file.h>
-#include <errno.h>
+#include <ctype.h>
+#include <sysfs/libsysfs.h>
-#include <parser.h>
+#include <checkers.h>
#include <vector.h>
#include <memory.h>
#include <libdevmapper.h>
#include <devmapper.h>
-#include <checkers.h>
-#include <path_state.h>
-#include <blacklist.h>
-#include <hwtable.h>
#include <util.h>
#include <defaults.h>
#include <structs.h>
+#include <structs_vec.h>
#include <dmparser.h>
-#include <cache.h>
#include <config.h>
-#include <propsel.h>
+#include <blacklist.h>
#include <discovery.h>
#include <debug.h>
#include <switchgroup.h>
-#include <sysfs/libsysfs.h>
#include <print.h>
#include <alias.h>
+#include <configure.h>
+#include <pgpolicies.h>
#include "main.h"
-#include "pgpolicies.h"
-#include "dict.h"
-
-/* for column aligned output */
-struct path_layout pl;
-
-static char *
-get_refwwid (vector pathvec)
-{
- struct path * pp;
- char buff[FILE_NAME_SIZE];
- char * refwwid;
-
- if (conf->dev_type == DEV_NONE)
- return NULL;
-
- if (conf->dev_type == DEV_DEVNODE) {
- basename(conf->dev, buff);
- pp = find_path_by_dev(pathvec, buff);
-
- if (!pp) {
- pp = alloc_path();
-
- if (!pp)
- return NULL;
-
- strncpy(pp->dev, buff, FILE_NAME_SIZE);
-
- if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
- return NULL;
-
- if (store_path(pathvec, pp)) {
- free_path(pp);
- return NULL;
- }
- }
- refwwid = pp->wwid;
- goto out;
- }
-
- if (conf->dev_type == DEV_DEVT) {
- pp = find_path_by_devt(pathvec, conf->dev);
-
- if (!pp) {
- if (devt2devname(buff, conf->dev))
- return NULL;
-
- pp = alloc_path();
-
- if (!pp)
- return NULL;
-
- strncpy(pp->dev, buff, FILE_NAME_SIZE);
-
- if (pathinfo(pp, conf->hwtable, DI_SYSFS | DI_WWID))
- return NULL;
-
- if (store_path(pathvec, pp)) {
- free_path(pp);
- return NULL;
- }
- }
- refwwid = pp->wwid;
- goto out;
- }
- if (conf->dev_type == DEV_DEVMAP) {
- /*
- * may be a binding
- */
- refwwid = get_user_friendly_wwid(conf->dev,
- conf->bindings_file);
-
- if (refwwid)
- return refwwid;
-
- /*
- * or may be an alias
- */
- refwwid = get_mpe_wwid(conf->dev);
-
- /*
- * or directly a wwid
- */
- if (!refwwid)
- refwwid = conf->dev;
- }
-out:
- if (refwwid && strlen(refwwid))
- return STRDUP(refwwid);
-
- return NULL;
-}
-
-static void
-print_path (struct path * pp, char * style)
-{
- char line[MAX_LINE_LEN];
-
- snprint_path(&line[0], MAX_LINE_LEN, style, pp, &pl);
- printf("%s", line);
-}
-
-static void
-print_map (struct multipath * mpp)
-{
- if (mpp->size && mpp->params)
- printf("0 %llu %s %s\n",
- mpp->size, DEFAULT_TARGET, mpp->params);
- return;
-}
-
-static void
-print_all_paths (vector pathvec, int banner)
-{
- int i;
- struct path * pp;
- char line[MAX_LINE_LEN];
-
- if (!VECTOR_SIZE(pathvec)) {
- if (banner)
- fprintf(stdout, "===== no paths =====\n");
- return;
- }
-
- if (banner)
- fprintf(stdout, "===== paths list =====\n");
-
- get_path_layout(&pl, pathvec);
- snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG, &pl);
- fprintf(stdout, "%s", line);
-
- vector_foreach_slot (pathvec, pp, i)
- print_path(pp, PRINT_PATH_LONG);
-}
-
-static void
-print_mp (struct multipath * mpp)
-{
- int j, i;
- struct path * pp = NULL;
- struct pathgroup * pgp = NULL;
-
- if (mpp->action == ACT_NOTHING || !conf->verbosity || !mpp->size)
- return;
-
- if (conf->verbosity > 1) {
- switch (mpp->action) {
- case ACT_RELOAD:
- printf("%s: ", ACT_RELOAD_STR);
- break;
-
- case ACT_CREATE:
- printf("%s: ", ACT_CREATE_STR);
- break;
-
- case ACT_SWITCHPG:
- printf("%s: ", ACT_SWITCHPG_STR);
- break;
-
- default:
- break;
- }
- }
-
- if (mpp->alias)
- printf("%s", mpp->alias);
-
- if (conf->verbosity == 1) {
- printf("\n");
- return;
- }
- if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
- printf(" (%s)", mpp->wwid);
-
- printf("\n");
-
- if (mpp->size < (1 << 11))
- printf("[size=%llu kB]", mpp->size >> 1);
- else if (mpp->size < (1 << 21))
- printf("[size=%llu MB]", mpp->size >> 11);
- else if (mpp->size < (1 << 31))
- printf("[size=%llu GB]", mpp->size >> 21);
- else
- printf("[size=%llu TB]", mpp->size >> 31);
-
- if (mpp->features)
- printf("[features=\"%s\"]", mpp->features);
-
- if (mpp->hwhandler)
- printf("[hwhandler=\"%s\"]", mpp->hwhandler);
-
- fprintf(stdout, "\n");
-
- if (!mpp->pg)
- return;
-
- vector_foreach_slot (mpp->pg, pgp, j) {
- printf("\\_ ");
-
- if (mpp->selector) {
- printf("%s ", mpp->selector);
-#if 0
- /* align to path status info */
- for (i = pl.hbtl_len + pl.dev_len + pl.dev_t_len + 4;
- i > strlen(mpp->selector); i--)
- printf(" ");
-#endif
- }
- if (pgp->priority)
- printf("[prio=%i]", pgp->priority);
-
- switch (pgp->status) {
- case PGSTATE_ENABLED:
- printf("[enabled]");
- break;
- case PGSTATE_DISABLED:
- printf("[disabled]");
- break;
- case PGSTATE_ACTIVE:
- printf("[active]");
- break;
- default:
- break;
- }
- printf("\n");
-
- vector_foreach_slot (pgp->paths, pp, i)
- print_path(pp, PRINT_PATH_INDENT);
- }
- printf("\n");
-}
static int
filter_pathvec (vector pathvec, char * refwwid)
@@ -299,535 +69,6 @@
return 0;
}
-/*
- * Transforms the path group vector into a proper device map string
- */
-int
-assemble_map (struct multipath * mp)
-{
- int i, j;
- int shift, freechar;
- int minio;
- char * p;
- struct pathgroup * pgp;
- struct path * pp;
-
- p = mp->params;
- freechar = sizeof(mp->params);
-
- shift = snprintf(p, freechar, "%s %s %i %i",
- mp->features, mp->hwhandler,
- VECTOR_SIZE(mp->pg), mp->bestpg);
-
- if (shift >= freechar) {
- fprintf(stderr, "mp->params too small\n");
- return 1;
- }
- p += shift;
- freechar -= shift;
-
- vector_foreach_slot (mp->pg, pgp, i) {
- pgp = VECTOR_SLOT(mp->pg, i);
- shift = snprintf(p, freechar, " %s %i 1", mp->selector,
- VECTOR_SIZE(pgp->paths));
- if (shift >= freechar) {
- fprintf(stderr, "mp->params too small\n");
- return 1;
- }
- p += shift;
- freechar -= shift;
-
- vector_foreach_slot (pgp->paths, pp, j) {
- minio = conf->minio;
-
- if (mp->rr_weight == RR_WEIGHT_PRIO && pp->priority)
- minio *= pp->priority;
-
- shift = snprintf(p, freechar, " %s %d",
- pp->dev_t, minio);
- if (shift >= freechar) {
- fprintf(stderr, "mp->params too small\n");
- return 1;
- }
- p += shift;
- freechar -= shift;
- }
- }
- if (freechar < 1) {
- fprintf(stderr, "mp->params too small\n");
- return 1;
- }
- snprintf(p, 1, "\n");
-
- if (conf->verbosity > 2)
- print_map(mp);
-
- return 0;
-}
-
-static int
-setup_map (struct multipath * mpp)
-{
- /*
- * don't bother if devmap size is unknown
- */
- if (mpp->size <= 0) {
- condlog(3, "%s devmap size is unknown", mpp->alias);
- return 1;
- }
-
- /*
- * properties selectors
- */
- select_pgpolicy(mpp);
- select_selector(mpp);
- select_features(mpp);
- select_hwhandler(mpp);
- select_rr_weight(mpp);
- select_no_path_retry(mpp);
-
- /*
- * apply selected grouping policy to valid paths
- */
- switch (mpp->pgpolicy) {
- case MULTIBUS:
- one_group(mpp);
- break;
- case FAILOVER:
- one_path_per_group(mpp);
- break;
- case GROUP_BY_SERIAL:
- group_by_serial(mpp);
- break;
- case GROUP_BY_PRIO:
- group_by_prio(mpp);
- break;
- case GROUP_BY_NODE_NAME:
- group_by_node_name(mpp);
- break;
- default:
- break;
- }
-
- if (mpp->pg == NULL) {
- condlog(3, "pgpolicy failed to produce a pg vector");
- return 1;
- }
-
- /*
- * ponders each path group and determine highest prio pg
- * to switch over (default to first)
- */
- mpp->bestpg = select_path_group(mpp);
-
- /*
- * transform the mp->pg vector of vectors of paths
- * into a mp->params strings to feed the device-mapper
- */
- if (assemble_map(mpp)) {
- condlog(3, "problem assembing map");
- return 1;
- }
- return 0;
-}
-
-static int
-pathcount (struct multipath * mpp, int state)
-{
- struct pathgroup *pgp;
- struct path *pp;
- int i, j;
- int count = 0;
-
- vector_foreach_slot (mpp->pg, pgp, i)
- vector_foreach_slot (pgp->paths, pp, j)
- if (pp->state == state)
- count++;
- return count;
-}
-
-static void
-compute_pgid(struct pathgroup * pgp)
-{
- struct path * pp;
- int i;
-
- vector_foreach_slot (pgp->paths, pp, i)
- pgp->id ^= (long)pp;
-}
-
-static int
-pgcmp (struct multipath * mpp, struct multipath * cmpp)
-{
- int i, j;
- struct pathgroup * pgp;
- struct pathgroup * cpgp;
- int r = 0;
-
- vector_foreach_slot (mpp->pg, pgp, i) {
- compute_pgid(pgp);
-
- vector_foreach_slot (cmpp->pg, cpgp, j) {
- if (pgp->id == cpgp->id) {
- r = 0;
- break;
- }
- r++;
- }
- if (r)
- return r;
- }
- return r;
-}
-
-static void
-select_action (struct multipath * mpp, vector curmp)
-{
- struct multipath * cmpp;
-
- cmpp = find_mp_by_alias(curmp, mpp->alias);
-
- if (!cmpp) {
- cmpp = find_mp_by_wwid(curmp, mpp->wwid);
-
- if (cmpp && !conf->dry_run) {
- condlog(2, "remove: %s (dup of %s)",
- cmpp->alias, mpp->alias);
- dm_flush_map(cmpp->alias, DEFAULT_TARGET);
- }
- mpp->action = ACT_CREATE;
- condlog(3, "set ACT_CREATE: map does not exists");
- return;
- }
-
- if (!find_mp_by_wwid(curmp, mpp->wwid)) {
- condlog(2, "remove: %s (wwid changed)", cmpp->alias);
- dm_flush_map(mpp->alias, NULL);
- strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
- drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
- mpp->action = ACT_CREATE;
- condlog(3, "set ACT_CREATE: map wwid change");
- return;
- }
-
- if (pathcount(mpp, PATH_UP) == 0) {
- mpp->action = ACT_NOTHING;
- condlog(3, "set ACT_NOTHING: no usable path");
- return;
- }
- if (cmpp->size != mpp->size) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: size change");
- return;
- }
- if (!mpp->no_path_retry && /* let features be handled by the daemon */
- strncmp(cmpp->features, mpp->features, strlen(mpp->features))) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: features change");
- return;
- }
- if (strncmp(cmpp->hwhandler, mpp->hwhandler,
- strlen(mpp->hwhandler))) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: hwhandler change");
- return;
- }
- if (strncmp(cmpp->selector, mpp->selector,
- strlen(mpp->selector))) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: selector change");
- return;
- }
- if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: number of path group change");
- return;
- }
- if (pgcmp(mpp, cmpp)) {
- mpp->action = ACT_RELOAD;
- condlog(3, "set ACT_RELOAD: path group topology change");
- return;
- }
- if (cmpp->nextpg != mpp->bestpg) {
- mpp->action = ACT_SWITCHPG;
- condlog(3, "set ACT_SWITCHPG: next path group change");
- return;
- }
- mpp->action = ACT_NOTHING;
- condlog(3, "set ACT_NOTHING: map unchanged");
- return;
-}
-
-static int
-reinstate_paths (struct multipath * mpp)
-{
- int i, j;
- struct pathgroup * pgp;
- struct path * pp;
-
- if (!mpp->pg)
- return 0;
-
- vector_foreach_slot (mpp->pg, pgp, i) {
- if (!pgp->paths)
- continue;
-
- vector_foreach_slot (pgp->paths, pp, j) {
- if (pp->state != PATH_UP &&
- (pgp->status == PGSTATE_DISABLED ||
- pgp->status == PGSTATE_ACTIVE))
- continue;
-
- if (pp->dmstate == PSTATE_FAILED) {
- if (dm_reinstate_path(mpp->alias, pp->dev_t))
- condlog(0, "error reinstating %s",
- pp->dev);
- }
- }
- }
- return 0;
-}
-
-int lock_multipath (struct multipath * mpp, int lock)
-{
- struct pathgroup * pgp;
- struct path * pp;
- int i, j;
-
- if (!mpp || !mpp->pg)
- return 0;
-
- vector_foreach_slot (mpp->pg, pgp, i) {
- if (!pgp->paths)
- continue;
- vector_foreach_slot(pgp->paths, pp, j) {
- if (lock && flock(pp->fd, LOCK_EX | LOCK_NB) &&
- errno == EWOULDBLOCK)
- return 1;
- else if (!lock)
- flock(pp->fd, LOCK_UN);
- }
- }
- return 0;
-}
-
-/*
- * Return value:
- * -1: Retry
- * 0: DM_DEVICE_CREATE or DM_DEVICE_RELOAD failed, or dry_run mode.
- * 1: DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded.
- * 2: Map is already existing.
- */
-static int
-domap (struct multipath * mpp)
-{
- int r = 0;
-
- /*
- * last chance to quit before touching the devmaps
- */
- if (conf->dry_run) {
- print_mp(mpp);
- return 0;
- }
-
- switch (mpp->action) {
- case ACT_NOTHING:
- return 2;
-
- case ACT_SWITCHPG:
- dm_switchgroup(mpp->alias, mpp->bestpg);
- /*
- * we may have avoided reinstating paths because there where in
- * active or disabled PG. Now that the topology has changed,
- * retry.
- */
- reinstate_paths(mpp);
- return 2;
-
- case ACT_CREATE:
- if (lock_multipath(mpp, 1)) {
- condlog(3, "%s: in use", mpp->alias);
- return -1;
- }
- dm_shut_log();
-
- if (dm_map_present(mpp->alias))
- break;
-
- r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
- mpp->params, mpp->size, mpp->wwid);
-
- /*
- * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
- * DM_TABLE_LOAD. Failing the second part leaves an
- * empty map. Clean it up.
- */
- if (!r && dm_map_present(mpp->alias)) {
- condlog(3, "%s: failed to load map "
- "(a path might be in use)",
- mpp->alias);
- dm_flush_map(mpp->alias, NULL);
- }
-
- lock_multipath(mpp, 0);
- dm_restore_log();
- break;
-
- case ACT_RELOAD:
- r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
- mpp->params, mpp->size, NULL) &&
- dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
- break;
-
- default:
- break;
- }
-
- if (r) {
- /*
- * DM_DEVICE_CREATE or DM_DEVICE_RELOAD succeeded
- */
- dm_switchgroup(mpp->alias, mpp->bestpg);
- print_mp(mpp);
- }
-
- return r;
-}
-
-static int
-deadmap (struct multipath * mpp)
-{
- int i, j;
- struct pathgroup * pgp;
- struct path * pp;
-
- if (!mpp->pg)
- return 1;
-
- vector_foreach_slot (mpp->pg, pgp, i) {
- if (!pgp->paths)
- continue;
-
- vector_foreach_slot (pgp->paths, pp, j)
- if (strlen(pp->dev))
- return 0; /* alive */
- }
-
- return 1; /* dead */
-}
-
-static int
-coalesce_paths (vector curmp, vector pathvec)
-{
- int r = 1;
- int k, i;
- char empty_buff[WWID_SIZE];
- struct multipath * mpp;
- struct path * pp1;
- struct path * pp2;
-
- memset(empty_buff, 0, WWID_SIZE);
-
- vector_foreach_slot (pathvec, pp1, k) {
- /* skip this path for some reason */
-
- /* 1. if path has no unique id or wwid blacklisted */
- if (memcmp(empty_buff, pp1->wwid, WWID_SIZE) == 0 ||
- blacklist(conf->blist, pp1->wwid))
- continue;
-
- /* 2. if path already coalesced */
- if (pp1->mpp)
- continue;
-
- /*
- * at this point, we know we really got a new mp
- */
- mpp = alloc_multipath();
-
- if (!mpp)
- return 1;
-
- mpp->mpe = find_mpe(pp1->wwid);
- mpp->hwe = pp1->hwe;
- strcpy(mpp->wwid, pp1->wwid);
- select_alias(mpp);
-
- pp1->mpp = mpp;
- mpp->size = pp1->size;
- mpp->paths = vector_alloc();
-
- if (pp1->priority < 0)
- mpp->action = ACT_NOTHING;
-
- if (!mpp->paths)
- return 1;
-
- if (store_path(mpp->paths, pp1))
- return 1;
-
- for (i = k + 1; i < VECTOR_SIZE(pathvec); i++) {
- pp2 = VECTOR_SLOT(pathvec, i);
-
- if (strcmp(pp1->wwid, pp2->wwid))
- continue;
-
- pp2->mpp = mpp;
-
- if (pp2->size != mpp->size) {
- /*
- * ouch, avoid feeding that to the DM
- */
- condlog(3, "path size mismatch : discard %s",
- mpp->wwid);
- mpp->action = ACT_NOTHING;
- }
- if (pp2->priority < 0)
- mpp->action = ACT_NOTHING;
-
- if (store_path(mpp->paths, pp2))
- return 1;
- }
- if (setup_map(mpp))
- goto next;
-
- if (mpp->action == ACT_UNDEF)
- select_action(mpp, curmp);
-
- r = domap(mpp);
-
- if (r < 0)
- return r;
-
- if (r && mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
- if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
- dm_queue_if_no_path(mpp->alias, 0);
- else
- dm_queue_if_no_path(mpp->alias, 1);
- }
-
-next:
- drop_multipath(curmp, mpp->wwid, KEEP_PATHS);
- free_multipath(mpp, KEEP_PATHS);
- }
- /*
- * Flush maps with only dead paths (ie not in sysfs)
- * Keep maps with only failed paths
- */
- vector_foreach_slot (curmp, mpp, i) {
- if (!deadmap(mpp))
- continue;
-
- if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
- condlog(2, "remove: %s (dead) failed!",
- mpp->alias);
- else
- condlog(2, "remove: %s (dead)", mpp->alias);
- }
- return 0;
-}
-
static void
usage (char * progname)
{
@@ -887,9 +128,7 @@
pp->state = PATH_DOWN;
continue;
}
- pathinfo(pp, conf->hwtable,
- DI_SYSFS | DI_CHECKER | \
- DI_SERIAL | DI_PRIO);
+ pathinfo(pp, conf->hwtable, DI_ALL);
continue;
}
if (pp->state == PATH_UNCHECKED)
@@ -943,7 +182,7 @@
disassemble_status(mpp->status, mpp);
if (conf->list)
- print_mp(mpp);
+ print_multipath_topology(mpp, conf->verbosity);
if (!conf->dry_run)
reinstate_paths(mpp);
@@ -963,6 +202,7 @@
{
vector curmp = NULL;
vector pathvec = NULL;
+ struct vectors vecs;
int r = 1;
int di_flag = 0;
char * refwwid = NULL;
@@ -978,6 +218,8 @@
condlog(0, "can not allocate memory");
goto out;
}
+ vecs.pathvec = pathvec;
+ vecs.mpvec = curmp;
/*
* if we have a blacklisted device parameter, exit early
@@ -990,27 +232,24 @@
dev = conf->dev;
}
- if (dev && blacklist(conf->blist, dev))
+ if (dev && blacklist(conf->blist_devnode, dev))
goto out;
- condlog(3, "load path identifiers cache");
- cache_load(pathvec);
-
- if (conf->verbosity > 2)
- print_all_paths(pathvec, 1);
-
/*
* scope limiting must be translated into a wwid
* failing the translation is fatal (by policy)
*/
if (conf->dev) {
- refwwid = get_refwwid(pathvec);
+ refwwid = get_refwwid(conf->dev, conf->dev_type, pathvec);
if (!refwwid) {
condlog(3, "scope is nul");
goto out;
}
condlog(3, "scope limited to %s", refwwid);
+
+ if (blacklist(conf->blist_wwid, refwwid))
+ goto out;
}
/*
@@ -1035,7 +274,7 @@
if (conf->verbosity > 2)
print_all_paths(pathvec, 1);
- get_path_layout(&pl, pathvec);
+ get_path_layout(pathvec);
if (get_dm_mpvec(curmp, pathvec, refwwid))
goto out;
@@ -1048,7 +287,7 @@
/*
* core logic entry point
*/
- r = coalesce_paths(curmp, pathvec);
+ r = coalesce_paths(&vecs, NULL, NULL);
out:
if (refwwid)
Modified: multipath-tools/trunk/multipath/main.h
==============================================================================
--- multipath-tools/trunk/multipath/main.h (original)
+++ multipath-tools/trunk/multipath/main.h Mon Mar 13 15:16:41 2006
@@ -20,31 +20,12 @@
#define _MAIN_H
/*
- * configurator actions
- */
-#define ACT_NOTHING_STR "unchanged"
-#define ACT_RELOAD_STR "reload"
-#define ACT_SWITCHPG_STR "switchpg"
-#define ACT_CREATE_STR "create"
-
-enum actions {
- ACT_UNDEF,
- ACT_NOTHING,
- ACT_RELOAD,
- ACT_SWITCHPG,
- ACT_CREATE
-};
-
-#define FLUSH_ONE 1
-#define FLUSH_ALL 2
-
-/*
* Build version
*/
#define PROG "multipath"
-#define VERSION_CODE 0x000406
-#define DATE_CODE 0x0b0a05
+#define VERSION_CODE 0x000407
+#define DATE_CODE 0x030c06
#define MULTIPATH_VERSION(version) \
(version >> 16) & 0xFF, \
Modified: multipath-tools/trunk/multipath/multipath.rules
==============================================================================
--- multipath-tools/trunk/multipath/multipath.rules (original)
+++ multipath-tools/trunk/multipath/multipath.rules Mon Mar 13 15:16:41 2006
@@ -8,7 +8,3 @@
PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info", \
RUN+="/sbin/kpartx -a /dev/mapper/%c"
-# insert new paths in multipath topology
-ACTION=="add", SUBSYSTEM=="block", KERNEL!="dm-*", \
- RUN+="/sbin/multipath -v0 %r/%k"
-
Modified: multipath-tools/trunk/multipathd/Makefile
==============================================================================
--- multipath-tools/trunk/multipathd/Makefile (original)
+++ multipath-tools/trunk/multipathd/Makefile Mon Mar 13 15:16:41 2006
@@ -4,18 +4,10 @@
include ../Makefile.inc
#
-# directories where to put stuff
-#
-bindir = /usr/bin
-mandir = /usr/share/man/man8
-rcdir = /etc/init.d
-
-#
# basic flags setting
#
-CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
- -DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses -lm
+CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
+LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses
#
# debuging stuff
Modified: multipath-tools/trunk/multipathd/cli.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli.c (original)
+++ multipath-tools/trunk/multipathd/cli.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,6 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
#include <memory.h>
#include <vector.h>
#include <util.h>
@@ -127,12 +130,16 @@
r += add_key(keys, "fail", FAIL, 0);
r += add_key(keys, "paths", PATHS, 0);
r += add_key(keys, "maps", MAPS, 0);
+ r += add_key(keys, "multipaths", MAPS, 0);
r += add_key(keys, "path", PATH, 1);
r += add_key(keys, "map", MAP, 1);
+ r += add_key(keys, "multipath", MAP, 1);
r += add_key(keys, "group", GROUP, 1);
- r += add_key(keys, "dump", DUMP, 0);
- r += add_key(keys, "pathvec", PATHVEC, 0);
r += add_key(keys, "reconfigure", RECONFIGURE, 0);
+ r += add_key(keys, "status", STATUS, 0);
+ r += add_key(keys, "stats", STATS, 0);
+ r += add_key(keys, "topology", TOPOLOGY, 0);
+ r += add_key(keys, "config", CONFIG, 0);
if (r) {
free_keys(keys);
@@ -147,14 +154,26 @@
find_key (char * str)
{
int i;
+ int len, klen;
struct key * kw = NULL;
+ struct key * foundkw = NULL;
- vector_foreach_slot (keys, kw, i)
- if (strlen(str) == strlen(kw->str) &&
- !strcmp(kw->str, str))
- return kw;
-
- return NULL;
+ vector_foreach_slot (keys, kw, i) {
+ len = strlen(str);
+ klen = strlen(kw->str);
+
+ if (strncmp(kw->str, str, len))
+ continue;
+ else if (len == klen)
+ return kw; /* exact match */
+ else if (len < klen) {
+ if (!foundkw)
+ foundkw = kw; /* shortcut match */
+ else
+ return NULL; /* ambiguous word */
+ }
+ }
+ return foundkw;
}
static struct handler *
@@ -280,7 +299,7 @@
char * reply;
char * p;
- reply = MALLOC(MAX_REPLY_LEN);
+ reply = MALLOC(INITIAL_REPLY_LEN);
if (!reply)
return NULL;
Modified: multipath-tools/trunk/multipathd/cli.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli.h (original)
+++ multipath-tools/trunk/multipathd/cli.h Mon Mar 13 15:16:41 2006
@@ -12,9 +12,11 @@
__PATH,
__MAP,
__GROUP,
- __DUMP,
- __PATHVEC,
- __RECONFIGURE
+ __RECONFIGURE,
+ __STATUS,
+ __STATS,
+ __TOPOLOGY,
+ __CONFIG,
};
#define LIST (1 << __LIST)
@@ -30,11 +32,13 @@
#define PATH (1 << __PATH)
#define MAP (1 << __MAP)
#define GROUP (1 << __GROUP)
-#define DUMP (1 << __DUMP)
-#define PATHVEC (1 << __PATHVEC)
#define RECONFIGURE (1 << __RECONFIGURE)
+#define STATUS (1 << __STATUS)
+#define STATS (1 << __STATS)
+#define TOPOLOGY (1 << __TOPOLOGY)
+#define CONFIG (1 << __CONFIG)
-#define MAX_REPLY_LEN 1000
+#define INITIAL_REPLY_LEN 1000
struct key {
char * str;
Modified: multipath-tools/trunk/multipathd/cli_handlers.c
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.c (original)
+++ multipath-tools/trunk/multipathd/cli_handlers.c Mon Mar 13 15:16:41 2006
@@ -1,20 +1,242 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <checkers.h>
#include <memory.h>
#include <vector.h>
#include <structs.h>
+#include <structs_vec.h>
#include <libdevmapper.h>
#include <devmapper.h>
#include <config.h>
+#include <configure.h>
#include <blacklist.h>
+#include <debug.h>
+#include <print.h>
#include "main.h"
#include "cli.h"
int
+show_paths (char ** r, int * len, struct vectors * vecs, char * style)
+{
+ int i;
+ struct path * pp;
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ get_path_layout(vecs->pathvec);
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+
+ if (VECTOR_SIZE(vecs->pathvec) > 0)
+ c += snprint_path_header(c, reply + maxlen - c,
+ style);
+
+ vector_foreach_slot(vecs->pathvec, pp, i)
+ c += snprint_path(c, reply + maxlen - c,
+ style, pp);
+
+ again = ((c - reply) == (maxlen - 1));
+
+ if (again)
+ reply = REALLOC(reply, maxlen *= 2);
+
+ }
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+show_map_topology (char ** r, int * len, struct multipath * mpp)
+{
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+
+ c += snprint_multipath_topology( c, reply + maxlen - c, mpp, 2);
+ again = ((c - reply) == (maxlen - 1));
+
+ if (again)
+ reply = REALLOC(reply, maxlen *= 2);
+
+ }
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+show_maps_topology (char ** r, int * len, struct vectors * vecs)
+{
+ int i;
+ struct multipath * mpp;
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+
+ vector_foreach_slot(vecs->mpvec, mpp, i)
+ c += snprint_multipath_topology(c, reply + maxlen - c,
+ mpp, 2);
+
+ again = ((c - reply) == (maxlen - 1));
+
+ if (again)
+ reply = REALLOC(reply, maxlen *= 2);
+
+ }
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+show_config (char ** r, int * len)
+{
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+ c = reply;
+ c += snprint_defaults(c, reply + maxlen - c);
+ again = ((c - reply) == maxlen);
+ if (again) {
+ reply = REALLOC(reply, maxlen *= 2);
+ continue;
+ }
+ c += snprint_blacklist(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);
+ again = ((c - reply) == maxlen);
+ if (again) {
+ reply = REALLOC(reply, maxlen *= 2);
+ continue;
+ }
+ c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
+ again = ((c - reply) == maxlen);
+ if (again)
+ reply = REALLOC(reply, maxlen *= 2);
+ }
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
+}
+
+int
+cli_list_config (void * v, char ** reply, int * len, void * data)
+{
+ condlog(3, "list config (operator)");
+
+ return show_config(reply, len);
+}
+
+int
cli_list_paths (void * v, char ** reply, int * len, void * data)
{
struct vectors * vecs = (struct vectors *)data;
- return show_paths(reply, len, vecs);
+ condlog(3, "list paths (operator)");
+
+ return show_paths(reply, len, vecs, PRINT_PATH_CHECKER);
+}
+
+int
+cli_list_map_topology (void * v, char ** reply, int * len, void * data)
+{
+ struct multipath * mpp;
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ condlog(3, "list multipath %s (operator)", param);
+
+ return show_map_topology(reply, len, mpp);
+}
+
+int
+cli_list_maps_topology (void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+
+ condlog(3, "list multipaths (operator)");
+
+ return show_maps_topology(reply, len, vecs);
+}
+
+int
+show_maps (char ** r, int *len, struct vectors * vecs, char * style)
+{
+ int i;
+ struct multipath * mpp;
+ char * c;
+ char * reply;
+ unsigned int maxlen = INITIAL_REPLY_LEN;
+ int again = 1;
+
+ get_multipath_layout(vecs->mpvec);
+ reply = MALLOC(maxlen);
+
+ while (again) {
+ if (!reply)
+ return 1;
+
+ c = reply;
+ if (VECTOR_SIZE(vecs->mpvec) > 0)
+ c += snprint_multipath_header(c, reply + maxlen - c,
+ style);
+
+ vector_foreach_slot(vecs->mpvec, mpp, i)
+ c += snprint_multipath(c, reply + maxlen - c,
+ style, mpp);
+
+ again = ((c - reply) == (maxlen - 1));
+
+ if (again)
+ reply = REALLOC(reply, maxlen *= 2);
+ }
+ *r = reply;
+ *len = (int)(c - reply + 1);
+ return 0;
}
int
@@ -22,7 +244,29 @@
{
struct vectors * vecs = (struct vectors *)data;
- return show_maps(reply, len, vecs);
+ condlog(3, "list maps (operator)");
+
+ return show_maps(reply, len, vecs, PRINT_MAP_NAMES);
+}
+
+int
+cli_list_maps_status (void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+
+ condlog(3, "list maps status (operator)");
+
+ return show_maps(reply, len, vecs, PRINT_MAP_STATUS);
+}
+
+int
+cli_list_maps_stats (void * v, char ** reply, int * len, void * data)
+{
+ struct vectors * vecs = (struct vectors *)data;
+
+ condlog(3, "list maps stats (operator)");
+
+ return show_maps(reply, len, vecs, PRINT_MAP_STATS);
}
int
@@ -30,13 +274,18 @@
{
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
+ int r;
+
+ condlog(2, "%s: add path (operator)", param);
- if (blacklist(conf->blist, param)) {
+ if (blacklist(conf->blist_devnode, param) ||
+ (r = ev_add_path(param, vecs)) == 2) {
*reply = strdup("blacklisted");
*len = strlen(*reply) + 1;
+ condlog(2, "%s: path blacklisted", param);
return 0;
}
- return uev_add_path(param, vecs);
+ return r;
}
int
@@ -45,7 +294,9 @@
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
- return uev_remove_path(param, vecs);
+ condlog(2, "%s: remove path (operator)", param);
+
+ return ev_remove_path(param, vecs);
}
int
@@ -54,7 +305,15 @@
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
- return uev_add_map(param, vecs);
+ condlog(2, "%s: add map (operator)", param);
+
+ if (blacklist(conf->blist_wwid, param)) {
+ *reply = strdup("blacklisted");
+ *len = strlen(*reply) + 1;
+ condlog(2, "%s: map blacklisted", param);
+ return 0;
+ }
+ return ev_add_map(param, vecs);
}
int
@@ -63,7 +322,9 @@
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, MAP);
- return uev_remove_map(param, vecs);
+ condlog(2, "%s: remove map (operator)", param);
+
+ return ev_remove_map(param, vecs);
}
int
@@ -72,15 +333,9 @@
char * mapname = get_keyparam(v, MAP);
int groupnum = atoi(get_keyparam(v, GROUP));
- return dm_switchgroup(mapname, groupnum);
-}
+ condlog(2, "%s: switch to path group #%i (operator)", mapname, groupnum);
-int
-cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
-{
- struct vectors * vecs = (struct vectors *)data;
-
- return dump_pathvec(reply, len, vecs);
+ return dm_switchgroup(mapname, groupnum);
}
int
@@ -88,6 +343,8 @@
{
struct vectors * vecs = (struct vectors *)data;
+ condlog(2, "reconfigure (operator)");
+
return reconfigure(vecs);
}
@@ -98,6 +355,8 @@
char * param = get_keyparam(v, MAP);
int r = dm_simplecmd(DM_DEVICE_SUSPEND, param);
+ condlog(2, "%s: suspend (operator)", param);
+
if (!r) /* error */
return 1;
@@ -117,6 +376,8 @@
char * param = get_keyparam(v, MAP);
int r = dm_simplecmd(DM_DEVICE_RESUME, param);
+ condlog(2, "%s: resume (operator)", param);
+
if (!r) /* error */
return 1;
@@ -144,6 +405,9 @@
if (!pp || !pp->mpp || !pp->mpp->alias)
return 1;
+ condlog(2, "%s: reinstate path %s (operator)",
+ pp->mpp->alias, pp->dev_t);
+
return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
}
@@ -162,5 +426,8 @@
if (!pp || !pp->mpp || !pp->mpp->alias)
return 1;
+ condlog(2, "%s: fail path %s (operator)",
+ pp->mpp->alias, pp->dev_t);
+
return dm_fail_path(pp->mpp->alias, pp->dev_t);
}
Modified: multipath-tools/trunk/multipathd/cli_handlers.h
==============================================================================
--- multipath-tools/trunk/multipathd/cli_handlers.h (original)
+++ multipath-tools/trunk/multipathd/cli_handlers.h Mon Mar 13 15:16:41 2006
@@ -1,11 +1,15 @@
int cli_list_paths (void * v, char ** reply, int * len, void * data);
int cli_list_maps (void * v, char ** reply, int * len, void * data);
+int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
+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_config (void * v, char ** reply, int * len, void * data);
int cli_add_path (void * v, char ** reply, int * len, void * data);
int cli_del_path (void * v, char ** reply, int * len, void * data);
int cli_add_map (void * v, char ** reply, int * len, void * data);
int cli_del_map (void * v, char ** reply, int * len, void * data);
int cli_switch_group(void * v, char ** reply, int * len, void * data);
-int cli_dump_pathvec(void * v, char ** reply, int * len, void * data);
int cli_reconfigure(void * v, char ** reply, int * len, void * data);
int cli_suspend(void * v, char ** reply, int * len, void * data);
int cli_resume(void * v, char ** reply, int * len, void * data);
Modified: multipath-tools/trunk/multipathd/main.c
==============================================================================
--- multipath-tools/trunk/multipathd/main.c (original)
+++ multipath-tools/trunk/multipathd/main.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ * Copyright (c) 2005 Kiyoshi Ueda, NEC
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ * Copyright (c) 2005 Edward Goggin, EMC
+ */
#include <unistd.h>
#include <sys/stat.h>
#include <libdevmapper.h>
@@ -17,7 +23,6 @@
* libcheckers
*/
#include <checkers.h>
-#include <path_state.h>
/*
* libmultipath
@@ -26,12 +31,13 @@
#include <vector.h>
#include <memory.h>
#include <config.h>
-#include <callout.h>
#include <util.h>
-#include <blacklist.h>
#include <hwtable.h>
#include <defaults.h>
#include <structs.h>
+#include <callout.h>
+#include <blacklist.h>
+#include <structs_vec.h>
#include <dmparser.h>
#include <devmapper.h>
#include <dict.h>
@@ -40,8 +46,8 @@
#include <propsel.h>
#include <uevent.h>
#include <switchgroup.h>
-#include <path_state.h>
#include <print.h>
+#include <configure.h>
#include "main.h"
#include "pidfile.h"
@@ -54,10 +60,7 @@
#define CMDSIZE 160
#define LOG_MSG(a,b) \
- if (strlen(b)) { \
- condlog(a, "%s: %s", pp->dev_t, b); \
- memset(b, 0, MAX_CHECKER_MSG_SIZE); \
- }
+ if (strlen(b)) condlog(a, "%s: %s", pp->dev_t, b);
#ifdef LCKDBG
#define lock(a) \
@@ -81,13 +84,7 @@
/*
* structs
*/
-struct event_thread {
- struct dm_task *dmt;
- pthread_t thread;
- int event_nr;
- char mapname[WWID_SIZE];
- struct vectors *vecs;
-};
+struct vectors * gvecs; /* global copy of vecs for use in sig handlers */
static struct event_thread *
alloc_waiter (void)
@@ -105,8 +102,24 @@
{
struct event_thread * wp = (struct event_thread *)data;
+ /*
+ * indicate in mpp that the wp is already freed storage
+ */
+ lock(wp->vecs->lock);
+
+ if (wp->mpp)
+ /*
+ * be careful, mpp may already be freed -- null if so
+ */
+ wp->mpp->waiter = NULL;
+ else
+ condlog(3, "free_waiter, mpp freed before wp=%p,", wp);
+
+ unlock(wp->vecs->lock);
+
if (wp->dmt)
dm_task_destroy(wp->dmt);
+
FREE(wp);
}
@@ -114,157 +127,19 @@
stop_waiter_thread (struct multipath * mpp, struct vectors * vecs)
{
struct event_thread * wp = (struct event_thread *)mpp->waiter;
- pthread_t thread;
if (!wp) {
condlog(3, "%s: no waiter thread", mpp->alias);
return;
}
- thread = wp->thread;
-
- if (!wp) {
- condlog(3, "%s: thread not started", mpp->alias);
- return;
- }
condlog(2, "%s: stop event checker thread", wp->mapname);
- pthread_kill(thread, SIGHUP);
+ pthread_kill((pthread_t)wp->thread, SIGUSR1);
}
static void
cleanup_lock (void * data)
{
- pthread_mutex_unlock((pthread_mutex_t *)data);
-}
-
-static void
-adopt_paths (struct vectors * vecs, struct multipath * mpp)
-{
- int i;
- struct path * pp;
-
- if (!mpp)
- return;
-
- vector_foreach_slot (vecs->pathvec, pp, i) {
- if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
- condlog(4, "%s ownership set", pp->dev_t);
- pp->mpp = mpp;
- }
- }
-}
-
-static void
-orphan_path (struct path * pp)
-{
- pp->mpp = NULL;
- pp->checkfn = NULL;
- pp->dmstate = PSTATE_UNDEF;
- pp->checker_context = NULL;
- pp->getuid = NULL;
- pp->getprio = NULL;
-
- if (pp->fd >= 0)
- close(pp->fd);
-
- pp->fd = -1;
-}
-
-static void
-orphan_paths (struct vectors * vecs, struct multipath * mpp)
-{
- int i;
- struct path * pp;
-
- vector_foreach_slot (vecs->pathvec, pp, i) {
- if (pp->mpp == mpp) {
- condlog(4, "%s is orphaned", pp->dev_t);
- orphan_path(pp);
- }
- }
-}
-
-static int
-update_multipath_table (struct multipath *mpp, vector pathvec)
-{
- if (!mpp)
- return 1;
-
- if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
- return 1;
-
- if (disassemble_map(pathvec, mpp->params, mpp))
- return 1;
-
- return 0;
-}
-
-static int
-update_multipath_status (struct multipath *mpp)
-{
- if (!mpp)
- return 1;
-
- if(dm_get_status(mpp->alias, mpp->status))
- return 1;
-
- if (disassemble_status(mpp->status, mpp))
- return 1;
-
- return 0;
-}
-
-static int
-update_multipath_strings (struct multipath *mpp, vector pathvec)
-{
- if (mpp->selector) {
- FREE(mpp->selector);
- mpp->selector = NULL;
- }
-
- if (mpp->features) {
- FREE(mpp->features);
- mpp->features = NULL;
- }
-
- if (mpp->hwhandler) {
- FREE(mpp->hwhandler);
- mpp->hwhandler = NULL;
- }
-
- free_pgvec(mpp->pg, KEEP_PATHS);
- mpp->pg = NULL;
-
- if (update_multipath_table(mpp, pathvec))
- return 1;
-
- if (update_multipath_status(mpp))
- return 1;
-
- return 0;
-}
-
-static void
-set_multipath_wwid (struct multipath * mpp)
-{
- if (mpp->wwid)
- return;
-
- dm_get_uuid(mpp->alias, mpp->wwid);
-}
-
-static int
-pathcount (struct multipath *mpp, int state)
-{
- struct pathgroup *pgp;
- struct path *pp;
- int i, j;
- int count = 0;
-
- vector_foreach_slot (mpp->pg, pgp, i)
- vector_foreach_slot (pgp->paths, pp, j)
- if (pp->state == state)
- count++;
- return count;
+ unlock((pthread_mutex_t *)data);
}
/*
@@ -283,6 +158,7 @@
* meaning of +1: retry_tick may be decremented in
* checkerloop before starting retry.
*/
+ mpp->stat_queueing_timeouts++;
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);
@@ -303,111 +179,6 @@
condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
}
-static void
-set_no_path_retry(struct multipath *mpp)
-{
- mpp->retry_tick = 0;
- mpp->nr_active = pathcount(mpp, PATH_UP);
- select_no_path_retry(mpp);
-
- switch (mpp->no_path_retry) {
- case NO_PATH_RETRY_UNDEF:
- break;
- case NO_PATH_RETRY_FAIL:
- dm_queue_if_no_path(mpp->alias, 0);
- break;
- case NO_PATH_RETRY_QUEUE:
- dm_queue_if_no_path(mpp->alias, 1);
- break;
- default:
- dm_queue_if_no_path(mpp->alias, 1);
- if (mpp->nr_active == 0) {
- /* Enter retry mode */
- mpp->retry_tick = mpp->no_path_retry * conf->checkint;
- condlog(1, "%s: Entering recovery mode: max_retries=%d",
- mpp->alias, mpp->no_path_retry);
- }
- break;
- }
-}
-
-static struct hwentry *
-extract_hwe_from_path(struct multipath * mpp)
-{
- struct path * pp;
- struct pathgroup * pgp;
-
- pgp = VECTOR_SLOT(mpp->pg, 0);
- pp = VECTOR_SLOT(pgp->paths, 0);
-
- return pp->hwe;
-}
-
-static void
-remove_map (struct multipath * mpp, struct vectors * vecs)
-{
- int i;
-
- stop_waiter_thread(mpp, vecs);
-
- /*
- * clear references to this map
- */
- orphan_paths(vecs, mpp);
-
- /*
- * purge the multipath vector
- */
- i = find_slot(vecs->mpvec, (void *)mpp);
- vector_del_slot(vecs->mpvec, i);
-
- /*
- * final free
- */
- free_multipath(mpp, KEEP_PATHS);
- mpp = NULL;
-}
-
-static void
-remove_maps (struct vectors * vecs)
-{
- int i;
- struct multipath * mpp;
-
- vector_foreach_slot (vecs->mpvec, mpp, i) {
- remove_map(mpp, vecs);
- i--;
- }
-
- vector_free(vecs->mpvec);
- vecs->mpvec = NULL;
-}
-
-static int
-setup_multipath (struct vectors * vecs, struct multipath * mpp)
-{
- if (dm_get_info(mpp->alias, &mpp->dmi))
- goto out;
-
- set_multipath_wwid(mpp);
- mpp->mpe = find_mpe(mpp->wwid);
- condlog(4, "discovered map %s", mpp->alias);
-
- if (update_multipath_strings(mpp, vecs->pathvec))
- goto out;
-
- adopt_paths(vecs, mpp);
- mpp->hwe = extract_hwe_from_path(mpp);
- select_pgfailback(mpp);
- set_no_path_retry(mpp);
-
- return 0;
-out:
- condlog(0, "%s: failed to setup multipath", mpp->alias);
- remove_map(mpp, vecs);
- return 1;
-}
-
static int
need_switch_pathgroup (struct multipath * mpp, int refresh)
{
@@ -437,12 +208,52 @@
static void
switch_pathgroup (struct multipath * mpp)
{
+ mpp->stat_switchgroup++;
dm_switchgroup(mpp->alias, mpp->bestpg);
condlog(2, "%s: switch to path group #%i",
mpp->alias, mpp->bestpg);
}
static int
+coalesce_maps(struct vectors *vecs, vector nmpv)
+{
+ struct multipath * ompp;
+ vector ompv = vecs->mpvec;
+ int i, j;
+
+ vector_foreach_slot (ompv, ompp, i) {
+ if (!find_mp_by_wwid(nmpv, ompp->wwid)) {
+ /*
+ * remove all current maps not allowed by the
+ * current configuration
+ */
+ if (dm_flush_map(ompp->alias, DEFAULT_TARGET)) {
+ condlog(0, "%s: unable to flush devmap",
+ ompp->alias);
+ /*
+ * may be just because the device is open
+ */
+ if (!vector_alloc_slot(nmpv))
+ return 1;
+
+ vector_set_slot(nmpv, ompp);
+ setup_multipath(vecs, ompp);
+
+ if ((j = find_slot(ompv, (void *)ompp)) != -1)
+ vector_del_slot(ompv, j);
+
+ continue;
+ }
+ else {
+ dm_lib_release();
+ condlog(3, "%s devmap removed", ompp->alias);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
update_multipath (struct vectors *vecs, char *mapname)
{
struct multipath *mpp;
@@ -471,9 +282,13 @@
continue;
if (pp->state != PATH_DOWN) {
+ int oldstate = pp->state;
condlog(2, "%s: mark as failed", pp->dev_t);
+ mpp->stat_path_failures++;
pp->state = PATH_DOWN;
- update_queue_mode_del_path(mpp);
+ if (oldstate == PATH_UP ||
+ oldstate == PATH_GHOST)
+ update_queue_mode_del_path(mpp);
/*
* if opportune,
@@ -492,12 +307,13 @@
return r;
}
-static sigset_t unblock_sighup(void)
+static sigset_t unblock_signals(void)
{
sigset_t set, old;
sigemptyset(&set);
sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &set, &old);
return old;
}
@@ -516,16 +332,23 @@
if (!waiter->event_nr)
waiter->event_nr = dm_geteventnr(waiter->mapname);
- if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
+ if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+ condlog(0, "%s: devmap event #%i dm_task_create error",
+ waiter->mapname, waiter->event_nr);
return 1;
+ }
if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+ condlog(0, "%s: devmap event #%i dm_task_set_name error",
+ waiter->mapname, waiter->event_nr);
dm_task_destroy(waiter->dmt);
return 1;
}
if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
waiter->event_nr)) {
+ condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+ waiter->mapname, waiter->event_nr);
dm_task_destroy(waiter->dmt);
return 1;
}
@@ -533,7 +356,7 @@
dm_task_no_open_count(waiter->dmt);
/* accept wait interruption */
- set = unblock_sighup();
+ set = unblock_signals();
/* interruption spits messages */
dm_shut_log();
@@ -635,6 +458,7 @@
mpp->waiter = (void *)wp;
strncpy(wp->mapname, mpp->alias, WWID_SIZE);
wp->vecs = vecs;
+ wp->mpp = mpp;
if (pthread_create(&wp->thread, &attr, waitevent, wp)) {
condlog(0, "%s: cannot create event checker", wp->mapname);
@@ -651,13 +475,83 @@
return 1;
}
-int
+static void
+sync_map_state(struct multipath *mpp)
+{
+ int i, j;
+ struct pathgroup *pgp;
+ struct path *pp;
+
+ vector_foreach_slot (mpp->pg, pgp, i){
+ vector_foreach_slot (pgp->paths, pp, j){
+ if (pp->state <= PATH_UNCHECKED)
+ continue;
+ if ((pp->dmstate == PSTATE_FAILED ||
+ pp->dmstate == PSTATE_UNDEF) &&
+ (pp->state == PATH_UP || pp->state == PATH_GHOST))
+ dm_reinstate_path(mpp->alias, pp->dev_t);
+ else if ((pp->dmstate == PSTATE_ACTIVE ||
+ pp->dmstate == PSTATE_UNDEF) &&
+ (pp->state == PATH_DOWN ||
+ pp->state == PATH_SHAKY))
+ dm_fail_path(mpp->alias, pp->dev_t);
+ }
+ }
+}
+
+static void
+sync_maps_state(vector mpvec)
+{
+ int i;
+ struct multipath *mpp;
+
+ vector_foreach_slot (mpvec, mpp, i)
+ sync_map_state(mpp);
+}
+
+static int
+flush_map(struct multipath * mpp, struct vectors * vecs)
+{
+ /*
+ * clear references to this map before flushing so we can ignore
+ * the spurious uevent we may generate with the dm_flush_map call below
+ */
+ if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) {
+ /*
+ * May not really be an error -- if the map was already flushed
+ * from the device mapper by dmsetup(8) for instance.
+ */
+ condlog(0, "%s: can't flush", mpp->alias);
+ return 1;
+ }
+ else {
+ dm_lib_release();
+ condlog(3, "%s: devmap removed", mpp->alias);
+ }
+
+ orphan_paths(vecs->pathvec, mpp);
+ remove_map(mpp, vecs, stop_waiter_thread, 1);
+
+ return 0;
+}
+
+static int
uev_add_map (char * devname, struct vectors * vecs)
{
+ condlog(2, "%s: add map (uevent)", devname);
+ return ev_add_map(devname, vecs);
+}
+
+int
+ev_add_map (char * devname, struct vectors * vecs)
+{
int major, minor;
char dev_t[BLK_DEV_SIZE];
char * alias;
+ char * refwwid;
struct multipath * mpp;
+ int map_present;
+ int r = 1;
if (sscanf(devname, "dm-%d", &minor) == 1 &&
!sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
@@ -669,7 +563,9 @@
if (!alias)
return 1;
- if (!dm_type(alias, DEFAULT_TARGET)) {
+ map_present = dm_map_present(alias);
+
+ if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
condlog(4, "%s: not a multipath map", alias);
FREE(alias);
return 0;
@@ -678,206 +574,325 @@
mpp = find_mp_by_alias(vecs->mpvec, alias);
if (mpp) {
- /*
- * this should not happen,
- * we missed a remove map event (not sent ?)
+ /*
+ * Not really an error -- we generate our own uevent
+ * if we create a multipath mapped device as a result
+ * of uev_add_path
*/
- condlog(2, "%s: already registered", alias);
- remove_map(mpp, vecs);
+ condlog(0, "%s: devmap already registered",
+ devname);
+ FREE(alias);
+ return 0;
}
/*
- * now we can allocate
+ * now we can register the map
*/
- mpp = alloc_multipath();
-
- if (!mpp)
- return 1;
-
- mpp->alias = alias;
-
- if (setup_multipath(vecs, mpp))
- return 1; /* mpp freed in setup_multipath */
-
- if (!vector_alloc_slot(vecs->mpvec))
- goto out;
+ if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
+ start_waiter_thread))) {
+ sync_map_state(mpp);
+ condlog(3, "%s: devmap %s added", alias, devname);
+ return 0;
+ }
+ refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec);
- vector_set_slot(vecs->mpvec, mpp);
- adopt_paths(vecs, mpp);
+ if (refwwid) {
+ r = coalesce_paths(vecs, NULL, refwwid);
+ dm_lib_release();
+ }
+
+ if (!r)
+ condlog(3, "%s: devmap %s added", alias, devname);
+ else
+ condlog(0, "%s: uev_add_map %s failed", alias, devname);
- if (start_waiter_thread(mpp, vecs))
- goto out;
+ FREE(refwwid);
+ FREE(alias);
+ return r;
+}
- return 0;
-out:
- condlog(2, "%s: add devmap failed", mpp->alias);
- remove_map(mpp, vecs);
- return 1;
+static int
+uev_remove_map (char * devname, struct vectors * vecs)
+{
+ condlog(2, "%s: remove map (uevent)", devname);
+ return ev_remove_map(devname, vecs);
}
int
-uev_remove_map (char * devname, struct vectors * vecs)
+ev_remove_map (char * devname, struct vectors * vecs)
{
- int minor;
struct multipath * mpp;
- if (sscanf(devname, "dm-%d", &minor) == 1)
- mpp = find_mp_by_minor(vecs->mpvec, minor);
- else
- mpp = find_mp_by_alias(vecs->mpvec, devname);
+ mpp = find_mp_by_str(vecs->mpvec, devname);
if (!mpp) {
condlog(3, "%s: devmap not registered, can't remove",
devname);
return 0;
}
-
- condlog(2, "remove %s devmap", mpp->alias);
- remove_map(mpp, vecs);
+ flush_map(mpp, vecs);
return 0;
}
-int
-uev_add_path (char * devname, struct vectors * vecs)
+static int
+uev_umount_map (char * devname, struct vectors * vecs)
{
- struct path * pp;
+ struct multipath * mpp;
- pp = find_path_by_dev(vecs->pathvec, devname);
+ condlog(2, "%s: umount map (uevent)", devname);
- if (pp) {
- condlog(3, "%s: already in pathvec");
- return 1;
- }
- pp = store_pathinfo(vecs->pathvec, conf->hwtable,
- devname, DI_SYSFS | DI_WWID);
+ mpp = find_mp_by_str(vecs->mpvec, devname);
- if (!pp) {
- condlog(0, "%s: failed to store path info", devname);
- return 1;
- }
+ if (!mpp)
+ return 0;
- condlog(2, "%s: path checker registered", devname);
- pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+ update_mpp_paths(mpp, vecs->pathvec);
+ verify_paths(mpp, vecs, NULL);
- if (pp->mpp) {
- condlog(4, "%s: ownership set to %s",
- pp->dev_t, pp->mpp->alias);
- } else {
- condlog(4, "%s: orphaned", pp->dev_t);
- orphan_path(pp);
- }
+ if (!VECTOR_SIZE(mpp->paths))
+ flush_map(mpp, vecs);
return 0;
}
+
+static int
+uev_add_path (char * devname, struct vectors * vecs)
+{
+ condlog(2, "%s: add path (uevent)", devname);
+ return (ev_add_path(devname, vecs) != 1)? 0 : 1;
+}
+
+/*
+ * returns:
+ * 0: added
+ * 1: error
+ * 2: blacklisted
+ */
int
-uev_remove_path (char * devname, struct vectors * vecs)
+ev_add_path (char * devname, struct vectors * vecs)
{
- int i;
+ struct multipath * mpp;
struct path * pp;
+ char empty_buff[WWID_SIZE] = {0};
pp = find_path_by_dev(vecs->pathvec, devname);
- if (!pp) {
- condlog(3, "%s: not in pathvec");
- return 1;
+ if (pp) {
+ condlog(0, "%s: spurious uevent, path already in pathvec",
+ devname);
+ if (pp->mpp)
+ return 0;
+ }
+ else {
+ /*
+ * get path vital state
+ */
+ if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable,
+ devname, DI_ALL))) {
+ condlog(0, "%s: failed to store path info", devname);
+ return 1;
+ }
+ pp->checkint = conf->checkint;
}
- if (pp->mpp && pp->state == PATH_UP)
- update_queue_mode_del_path(pp->mpp);
+ /*
+ * need path UID to go any further
+ */
+ if (memcmp(empty_buff, pp->wwid, WWID_SIZE) == 0) {
+ condlog(0, "%s: failed to get path uid", devname);
+ return 1; /* leave path added to pathvec */
+ }
+ if (blacklist_path(conf, pp)){
+ int i = find_slot(vecs->pathvec, (void *)pp);
+ if (i != -1)
+ vector_del_slot(vecs->pathvec, i);
+ free_path(pp);
+ return 2;
+ }
+ mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
+rescan:
+ if (mpp) {
+ if (adopt_paths(vecs->pathvec, mpp))
+ return 1; /* leave path added to pathvec */
- condlog(2, "remove %s path checker", devname);
- i = find_slot(vecs->pathvec, (void *)pp);
- vector_del_slot(vecs->pathvec, i);
- free_path(pp);
+ verify_paths(mpp, vecs, NULL);
+ mpp->action = ACT_RELOAD;
+ }
+ else {
+ if ((mpp = add_map_with_path(vecs, pp, 1)))
+ mpp->action = ACT_CREATE;
+ else
+ return 1; /* leave path added to pathvec */
+ }
- return 0;
-}
+ /*
+ * push the map to the device-mapper
+ */
+ if (setup_map(mpp)) {
+ condlog(0, "%s: failed to setup map for addition of new "
+ "path %s", mpp->alias, devname);
+ goto out;
+ }
+ /*
+ * reload the map for the multipath mapped device
+ */
+ if (domap(mpp) <= 0) {
+ condlog(0, "%s: failed in domap for addition of new "
+ "path %s", mpp->alias, devname);
+ /*
+ * deal with asynchronous uevents :((
+ */
+ if (mpp->action == ACT_RELOAD) {
+ condlog(0, "%s: uev_add_path sleep", mpp->alias);
+ sleep(1);
+ update_mpp_paths(mpp, vecs->pathvec);
+ goto rescan;
+ }
+ else
+ goto out;
+ }
+ dm_lib_release();
-int
-show_paths (char ** r, int * len, struct vectors * vecs)
-{
- int i;
- struct path * pp;
- char * c;
- char * reply;
- struct path_layout pl;
+ /*
+ * update our state from kernel regardless of create or reload
+ */
+ if (setup_multipath(vecs, mpp))
+ goto out;
- get_path_layout(&pl, vecs->pathvec);
- reply = MALLOC(MAX_REPLY_LEN);
+ sync_map_state(mpp);
- if (!reply)
- return 1;
+ if (mpp->action == ACT_CREATE &&
+ start_waiter_thread(mpp, vecs))
+ goto out;
- c = reply;
+ condlog(3, "%s path added to devmap %s", devname, mpp->alias);
+ return 0;
- if (VECTOR_SIZE(vecs->pathvec) > 0)
- c += snprint_path_header(c, reply + MAX_REPLY_LEN - c,
- PRINT_PATH_CHECKER, &pl);
-
- vector_foreach_slot(vecs->pathvec, pp, i)
- c += snprint_path(c, reply + MAX_REPLY_LEN - c,
- PRINT_PATH_CHECKER, pp, &pl);
+out:
+ remove_map(mpp, vecs, NULL, 1);
+ return 1;
+}
- *r = reply;
- *len = (int)(c - reply + 1);
- return 0;
+static int
+uev_remove_path (char * devname, struct vectors * vecs)
+{
+ condlog(2, "%s: remove path (uevent)", devname);
+ return ev_remove_path(devname, vecs);
}
int
-show_maps (char ** r, int *len, struct vectors * vecs)
+ev_remove_path (char * devname, struct vectors * vecs)
{
- int i;
struct multipath * mpp;
- char * c;
- char * reply;
- struct map_layout ml;
+ struct path * pp;
+ int i;
+ int rm_path = 1;
- get_map_layout(&ml, vecs->mpvec);
- reply = MALLOC(MAX_REPLY_LEN);
+ pp = find_path_by_dev(vecs->pathvec, devname);
- if (!reply)
+ if (!pp) {
+ condlog(0, "%s: spurious uevent, path not in pathvec", devname);
return 1;
+ }
- c = reply;
- if (VECTOR_SIZE(vecs->mpvec) > 0)
- c += snprint_map_header(c, reply + MAX_REPLY_LEN - c,
- PRINT_MAP_FAILBACK, &ml);
-
- vector_foreach_slot(vecs->mpvec, mpp, i)
- c += snprint_map(c, reply + MAX_REPLY_LEN - c,
- PRINT_MAP_FAILBACK, mpp, &ml);
+ /*
+ * avoid referring to the map of an orphanned path
+ */
+ if ((mpp = pp->mpp)) {
- *r = reply;
- *len = (int)(c - reply + 1);
- return 0;
-}
+ /*
+ * remove the map IFF removing the last path
+ */
+ if (pathcount(mpp, PATH_WILD) > 1) {
+ vector rpvec = vector_alloc();
-int
-dump_pathvec (char ** r, int * len, struct vectors * vecs)
-{
- int i;
- struct path * pp;
- char * reply;
- char * p;
+ /*
+ * transform the mp->pg vector of vectors of paths
+ * into a mp->params string to feed the device-mapper
+ */
+ update_mpp_paths(mpp, vecs->pathvec);
+ if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
+ vector_del_slot(mpp->paths, i);
- *len = VECTOR_SIZE(vecs->pathvec) * sizeof(struct path);
- reply = (char *)MALLOC(*len);
- *r = reply;
+ if (VECTOR_SIZE(mpp->paths) == 0) {
+ char alias[WWID_SIZE];
- if (!reply)
- return 1;
+ /*
+ * flush_map will fail if the device is open
+ */
+ strncpy(alias, mpp->alias, WWID_SIZE);
+ if (flush_map(mpp, vecs))
+ rm_path = 0;
+ else
+ condlog(3, "%s: removed map after removing"
+ " multiple paths", alias);
+ }
+ else {
+ if (setup_map(mpp)) {
+ condlog(0, "%s: failed to setup map for"
+ " removal of path %s", mpp->alias, devname);
+ free_pathvec(rpvec, KEEP_PATHS);
+ goto out;
+ }
+ /*
+ * reload the map
+ */
+ mpp->action = ACT_RELOAD;
+ if (domap(mpp) <= 0) {
+ condlog(0, "%s: failed in domap for "
+ "removal of path %s",
+ mpp->alias, devname);
+ /*
+ * Delete path from pathvec so that
+ * update_mpp_paths wont find it later
+ * when/if another path is removed.
+ */
+ if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+ vector_del_slot(vecs->pathvec, i);
+ free_path(pp);
+ return 1;
+ }
+ /*
+ * update our state from kernel
+ */
+ if (setup_multipath(vecs, mpp)) {
+ free_pathvec(rpvec, KEEP_PATHS);
+ goto out;
+ }
+ sync_map_state(mpp);
- p = reply;
+ condlog(3, "%s path removed from devmap %s",
+ devname, mpp->alias);
+ }
+ free_pathvec(rpvec, KEEP_PATHS);
+ }
+ else {
+ char alias[WWID_SIZE];
- vector_foreach_slot (vecs->pathvec, pp, i) {
- memcpy((void *)p, pp, sizeof(struct path));
- p += sizeof(struct path);
+ /*
+ * flush_map will fail if the device is open
+ */
+ strncpy(alias, mpp->alias, WWID_SIZE);
+ if (flush_map(mpp, vecs))
+ rm_path = 0;
+ else
+ condlog(3, "%s: removed map", alias);
+ }
+ }
+
+ if (rm_path) {
+ if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+ vector_del_slot(vecs->pathvec, i);
+ free_path(pp);
}
- /* return negative to hint caller not to add "ok" to the dump */
- return -1;
+ return 0;
+
+out:
+ remove_map(mpp, vecs, stop_waiter_thread, 1);
+ return 1;
}
static int
@@ -889,49 +904,14 @@
if (dm_get_maps(vecs->mpvec, "multipath"))
return 1;
- vector_foreach_slot (vecs->mpvec, mpp, i) {
+ vector_foreach_slot (vecs->mpvec, mpp, i)
if (setup_multipath(vecs, mpp))
return 1;
- start_waiter_thread(mpp, vecs);
- }
return 0;
}
int
-reconfigure (struct vectors * vecs)
-{
- struct config * old = conf;
- struct multipath * mpp;
- struct path * pp;
- int i;
-
- conf = NULL;
-
- if (load_config(DEFAULT_CONFIGFILE)) {
- conf = old;
- condlog(2, "reconfigure failed, continue with old config");
- return 1;
- }
- conf->verbosity = old->verbosity;
- free_config(old);
-
- vector_foreach_slot (vecs->mpvec, mpp, i) {
- mpp->mpe = find_mpe(mpp->wwid);
- mpp->hwe = extract_hwe_from_path(mpp);
- adopt_paths(vecs, mpp);
- set_no_path_retry(mpp);
- }
- vector_foreach_slot (vecs->pathvec, pp, i) {
- select_checkfn(pp);
- select_getuid(pp);
- select_getprio(pp);
- }
- condlog(2, "reconfigured");
- return 0;
-}
-
-int
uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
{
struct vectors * vecs;
@@ -988,7 +968,7 @@
vecs = (struct vectors *)trigger_data;
if (uev_discard(uev->devpath))
- goto out;
+ return 0;
basename(uev->devpath, devname);
lock(vecs->lock);
@@ -1001,19 +981,21 @@
r = uev_add_map(devname, vecs);
goto out;
}
-#if 0
if (!strncmp(uev->action, "remove", 6)) {
r = uev_remove_map(devname, vecs);
goto out;
}
-#endif
+ if (!strncmp(uev->action, "umount", 6)) {
+ r = uev_umount_map(devname, vecs);
+ goto out;
+ }
goto out;
}
/*
* path add/remove event
*/
- if (blacklist(conf->blist, devname))
+ if (blacklist(conf->blist_devnode, devname))
goto out;
if (!strncmp(uev->action, "add", 3)) {
@@ -1050,12 +1032,17 @@
add_handler(LIST+PATHS, cli_list_paths);
add_handler(LIST+MAPS, cli_list_maps);
+ add_handler(LIST+MAPS+STATUS, cli_list_maps_status);
+ add_handler(LIST+MAPS+STATS, cli_list_maps_stats);
+ add_handler(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);
+ add_handler(LIST+TOPOLOGY, cli_list_maps_topology);
+ add_handler(LIST+MAP+TOPOLOGY, cli_list_map_topology);
+ add_handler(LIST+CONFIG, cli_list_config);
add_handler(ADD+PATH, cli_add_path);
add_handler(DEL+PATH, cli_del_path);
add_handler(ADD+MAP, cli_add_map);
add_handler(DEL+MAP, cli_del_map);
add_handler(SWITCH+MAP+GROUP, cli_switch_group);
- add_handler(DUMP+PATHVEC, cli_dump_pathvec);
add_handler(RECONFIGURE, cli_reconfigure);
add_handler(SUSPEND+MAP, cli_suspend);
add_handler(RESUME+MAP, cli_resume);
@@ -1084,7 +1071,7 @@
}
static void
-fail_path (struct path * pp)
+fail_path (struct path * pp, int del_active)
{
if (!pp->mpp)
return;
@@ -1093,14 +1080,15 @@
pp->dev_t, pp->mpp->alias);
dm_fail_path(pp->mpp->alias, pp->dev_t);
- update_queue_mode_del_path(pp->mpp);
+ if (del_active)
+ update_queue_mode_del_path(pp->mpp);
}
/*
* caller must have locked the path list before calling that function
*/
static void
-reinstate_path (struct path * pp)
+reinstate_path (struct path * pp, int add_active)
{
if (!pp->mpp)
return;
@@ -1109,7 +1097,8 @@
condlog(0, "%s: reinstate failed", pp->dev_t);
else {
condlog(2, "%s: reinstated", pp->dev_t);
- update_queue_mode_add_path(pp->mpp);
+ if (add_active)
+ update_queue_mode_add_path(pp->mpp);
}
}
@@ -1125,7 +1114,7 @@
* we can safely return here, because upon map reload, all
* PG will be enabled.
*/
- if (!pp->pgindex)
+ if (!pp->mpp->pg || !pp->pgindex)
return;
pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1);
@@ -1145,7 +1134,7 @@
vector_foreach_slot (vecs->mpvec, mpp, i) {
if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
condlog(2, "%s: remove dead map", mpp->alias);
- remove_map(mpp, vecs);
+ remove_map(mpp, vecs, stop_waiter_thread, 1);
i--;
}
}
@@ -1178,6 +1167,7 @@
vector_foreach_slot (mpvec, mpp, i) {
if (mpp->retry_tick) {
+ mpp->stat_total_queueing_time++;
condlog(4, "%s: Retrying.. No active path", mpp->alias);
if(--mpp->retry_tick == 0) {
dm_queue_if_no_path(mpp->alias, 0);
@@ -1194,13 +1184,9 @@
struct path *pp;
int i, count = 0;
int newstate;
- char checker_msg[MAX_CHECKER_MSG_SIZE];
mlockall(MCL_CURRENT | MCL_FUTURE);
-
- memset(checker_msg, 0, MAX_CHECKER_MSG_SIZE);
vecs = (struct vectors *)ap;
-
condlog(2, "path checkers start up");
/*
@@ -1228,21 +1214,27 @@
*/
pp->tick = conf->checkint;
- if (!pp->checkfn) {
+ if (!checker_selected(&pp->checker)) {
pathinfo(pp, conf->hwtable, DI_SYSFS);
- select_checkfn(pp);
+ select_checker(pp);
}
- if (!pp->checkfn) {
- condlog(0, "%s: checkfn is void", pp->dev);
+ if (!checker_selected(&pp->checker)) {
+ condlog(0, "%s: checker is not set", pp->dev);
continue;
}
- newstate = pp->checkfn(pp->fd, checker_msg,
- &pp->checker_context);
+ newstate = checker_check(&pp->checker);
+ if (newstate < 0) {
+ condlog(2, "%s: unusable path", pp->dev);
+ pathinfo(pp, conf->hwtable, 0);
+ continue;
+ }
+
if (newstate != pp->state) {
+ int oldstate = pp->state;
pp->state = newstate;
- LOG_MSG(1, checker_msg);
+ LOG_MSG(1, checker_message(&pp->checker));
/*
* upon state change, reset the checkint
@@ -1251,33 +1243,38 @@
pp->checkint = conf->checkint;
if (newstate == PATH_DOWN ||
- newstate == PATH_SHAKY) {
+ newstate == PATH_SHAKY ||
+ update_multipath_strings(pp->mpp,
+ vecs->pathvec)) {
/*
* proactively fail path in the DM
*/
- fail_path(pp);
+ if (oldstate == PATH_UP ||
+ oldstate == PATH_GHOST)
+ fail_path(pp, 1);
+ else
+ fail_path(pp, 0);
/*
* cancel scheduled failback
*/
pp->mpp->failback_tick = 0;
+ pp->mpp->stat_path_failures++;
continue;
}
/*
* reinstate this path
*/
- reinstate_path(pp);
-
- /*
- * need to switch group ?
- */
- update_multipath_strings(pp->mpp,
- vecs->pathvec);
+ if (oldstate != PATH_UP &&
+ oldstate != PATH_GHOST)
+ reinstate_path(pp, 1);
+ else
+ reinstate_path(pp, 0);
/*
- * schedule defered failback
+ * schedule [defered] failback
*/
if (pp->mpp->pgfailback > 0)
pp->mpp->failback_tick =
@@ -1294,7 +1291,7 @@
enable_group(pp);
}
else if (newstate == PATH_UP || newstate == PATH_GHOST) {
- LOG_MSG(4, checker_msg);
+ LOG_MSG(4, checker_message(&pp->checker));
/*
* double the next check delay.
* max at conf->max_checkint
@@ -1307,8 +1304,10 @@
pp->tick = pp->checkint;
condlog(4, "%s: delay next check %is",
pp->dev_t, pp->tick);
-
}
+ else if (newstate == PATH_DOWN)
+ LOG_MSG(2, checker_message(&pp->checker));
+
pp->state = newstate;
/*
@@ -1318,7 +1317,8 @@
pathinfo(pp, conf->hwtable, DI_PRIO);
if (need_switch_pathgroup(pp->mpp, 0)) {
- if (pp->mpp->pgfailback > 0)
+ if (pp->mpp->pgfailback > 0 &&
+ pp->mpp->failback_tick <= 0)
pp->mpp->failback_tick =
pp->mpp->pgfailback + 1;
else if (pp->mpp->pgfailback ==
@@ -1343,8 +1343,116 @@
return NULL;
}
+int
+configure (struct vectors * vecs, int start_waiters)
+{
+ struct multipath * mpp;
+ struct path * pp;
+ vector mpvec;
+ int i;
+
+ if (!(vecs->pathvec = vector_alloc()))
+ return 1;
+
+ if (!(vecs->mpvec = vector_alloc()))
+ return 1;
+
+ if (!(mpvec = vector_alloc()))
+ return 1;
+
+ /*
+ * probe for current path (from sysfs) and map (from dm) sets
+ */
+ path_discovery(vecs->pathvec, conf, DI_ALL);
+
+ vector_foreach_slot (vecs->pathvec, pp, i){
+ if (blacklist_path(conf, pp)){
+ vector_del_slot(vecs->pathvec, i);
+ free_path(pp);
+ i--;
+ }
+ else
+ pp->checkint = conf->checkint;
+ }
+ if (map_discovery(vecs))
+ return 1;
+
+ /*
+ * create new set of maps & push changed ones into dm
+ */
+ if (coalesce_paths(vecs, mpvec, NULL))
+ return 1;
+
+ /*
+ * may need to remove some maps which are no longer relevant
+ * e.g., due to blacklist changes in conf file
+ */
+ if (coalesce_maps(vecs, mpvec))
+ return 1;
+
+ dm_lib_release();
+
+ sync_maps_state(mpvec);
+
+ if (conf->verbosity > 2)
+ vector_foreach_slot(mpvec, mpp, i)
+ print_map(mpp);
+
+ /*
+ * purge dm of old maps
+ */
+ remove_maps(vecs, NULL);
+
+ /*
+ * save new set of maps formed by considering current path state
+ */
+ vecs->mpvec = mpvec;
+
+ /*
+ * start dm event waiter threads for these new maps
+ */
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (setup_multipath(vecs, mpp))
+ return 1;
+ if (start_waiters)
+ if (start_waiter_thread(mpp, vecs))
+ return 1;
+ }
+ return 0;
+}
+
+int
+reconfigure (struct vectors * vecs)
+{
+ struct config * old = conf;
+
+ /*
+ * free old map and path vectors ... they use old conf state
+ */
+ if (VECTOR_SIZE(vecs->mpvec))
+ remove_maps(vecs, stop_waiter_thread);
+
+ if (VECTOR_SIZE(vecs->pathvec))
+ free_pathvec(vecs->pathvec, FREE_PATHS);
+
+ conf = NULL;
+
+ if (load_config(DEFAULT_CONFIGFILE))
+ return 1;
+
+ conf->verbosity = old->verbosity;
+
+ if (!conf->checkint) {
+ conf->checkint = DEFAULT_CHECKINT;
+ conf->max_checkint = MAX_CHECKINT(conf->checkint);
+ }
+ configure(vecs, 1);
+ free_config(old);
+ return 0;
+}
+
static struct vectors *
-init_paths (void)
+init_vecs (void)
{
struct vectors * vecs;
@@ -1405,7 +1513,11 @@
static void
sighup (int sig)
{
- condlog(3, "SIGHUP received");
+ condlog(2, "reconfigure (SIGHUP)");
+
+ lock(gvecs->lock);
+ reconfigure(gvecs);
+ unlock(gvecs->lock);
#ifdef _DEBUG_
dbg_free_final(NULL);
@@ -1419,9 +1531,16 @@
}
static void
+sigusr1 (int sig)
+{
+ condlog(3, "SIGUSR1 received");
+}
+
+static void
signal_init(void)
{
signal_set(SIGHUP, sighup);
+ signal_set(SIGUSR1, sigusr1);
signal_set(SIGINT, sigend);
signal_set(SIGTERM, sigend);
signal_set(SIGKILL, sigend);
@@ -1480,8 +1599,8 @@
* fill the voids left in the config file
*/
if (!conf->checkint) {
- conf->checkint = CHECKINT;
- conf->max_checkint = MAX_CHECKINT;
+ conf->checkint = DEFAULT_CHECKINT;
+ conf->max_checkint = MAX_CHECKINT(conf->checkint);
}
if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
@@ -1492,8 +1611,8 @@
}
signal_init();
setscheduler();
- set_oom_adj(-17);
- vecs = init_paths();
+ set_oom_adj(-16);
+ vecs = gvecs = init_vecs();
if (!vecs)
exit(1);
@@ -1504,12 +1623,12 @@
}
/*
- * fetch paths and multipaths lists
- * no paths and/or no multipaths are valid scenarii
- * vectors maintenance will be driven by events
+ * fetch and configure both paths and multipaths
*/
- path_discovery(vecs->pathvec, conf, DI_SYSFS | DI_WWID | DI_CHECKER);
- map_discovery(vecs);
+ if (configure(vecs, 1)) {
+ condlog(0, "failure during configuration");
+ exit(1);
+ }
/*
* start threads
@@ -1528,7 +1647,7 @@
* exit path
*/
lock(vecs->lock);
- remove_maps(vecs);
+ remove_maps(vecs, stop_waiter_thread);
free_pathvec(vecs->pathvec, FREE_PATHS);
pthread_cancel(check_thr);
@@ -1555,6 +1674,9 @@
if (logsink)
log_thread_stop();
+ dm_lib_release();
+ dm_lib_exit();
+
#ifdef _DEBUG_
dbg_free_final(NULL);
#endif
@@ -1669,3 +1791,4 @@
/* child lives */
return (child(NULL));
}
+
Modified: multipath-tools/trunk/multipathd/main.h
==============================================================================
--- multipath-tools/trunk/multipathd/main.h (original)
+++ multipath-tools/trunk/multipathd/main.h Mon Mar 13 15:16:41 2006
@@ -2,23 +2,12 @@
#define MAIN_H
#define DAEMON 1
-#define CHECKINT 5
#define MAPGCINT 5
-#define MAX_CHECKINT CHECKINT << 2
-
-struct vectors {
- pthread_mutex_t *lock;
- vector pathvec;
- vector mpvec;
-};
int reconfigure (struct vectors *);
-int show_paths (char **, int *, struct vectors *);
-int show_maps (char **, int *, struct vectors *);
-int dump_pathvec (char **, int *, struct vectors *);
-int uev_add_path (char *, struct vectors *);
-int uev_remove_path (char *, struct vectors *);
-int uev_add_map (char *, struct vectors *);
-int uev_remove_map (char *, struct vectors *);
+int ev_add_path (char *, struct vectors *);
+int ev_remove_path (char *, struct vectors *);
+int ev_add_map (char *, struct vectors *);
+int ev_remove_map (char *, struct vectors *);
#endif /* MAIN_H */
Modified: multipath-tools/trunk/multipathd/uxclnt.c
==============================================================================
--- multipath-tools/trunk/multipathd/uxclnt.c (original)
+++ multipath-tools/trunk/multipathd/uxclnt.c Mon Mar 13 15:16:41 2006
@@ -1,3 +1,9 @@
+/*
+ * Original author : tridge at samba.org, January 2002
+ *
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Modified: multipath-tools/trunk/multipathd/uxlsnr.c
==============================================================================
--- multipath-tools/trunk/multipathd/uxlsnr.c (original)
+++ multipath-tools/trunk/multipathd/uxlsnr.c Mon Mar 13 15:16:41 2006
@@ -1,6 +1,12 @@
/*
- * A simple domain socket listener
* Original author : tridge at samba.org, January 2002
+ *
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
+
+/*
+ * A simple domain socket listener
*/
#include <stdio.h>
#include <stdlib.h>
@@ -14,6 +20,8 @@
#include <sys/un.h>
#include <sys/poll.h>
+#include <checkers.h>
+
#include <memory.h>
#include <debug.h>
#include <vector.h>
Modified: multipath-tools/trunk/path_priority/pp_alua/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_alua/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_alua/Makefile Mon Mar 13 15:16:41 2006
@@ -17,6 +17,7 @@
DEBUG = 0
DEBUG_DUMPHEX = 0
OBJS = main.o rtpg.o
+INSTALL = install -D
TOPDIR = ../..
@@ -24,7 +25,7 @@
include $(TOPDIR)/Makefile.inc
endif
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -DDEBUG=$(DEBUG)
+CFLAGS += -DDEBUG=$(DEBUG)
all: $(BUILD)
@@ -35,10 +36,8 @@
$(CC) -static -o $(EXEC) $(OBJS)
install: $(BUILD) $(EXEC).8.gz
- install -d $(DESTDIR)$(bindir)
- install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
- install -d $(DESTDIR)$(mandir)
- install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+ $(INSTALL) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+ $(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz
uninstall:
rm $(DESTDIR)$(bindir)/$(EXEC)
@@ -47,9 +46,6 @@
clean:
rm -f *.o *.gz $(EXEC)
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
$(EXEC).8.gz: $(EXEC).8
$(GZIP) $< >$@
Modified: multipath-tools/trunk/path_priority/pp_balance_units/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_balance_units/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_balance_units/Makefile Mon Mar 13 15:16:41 2006
@@ -9,16 +9,15 @@
include $(TOPDIR)/Makefile.inc
ifeq ($(strip $(BUILD)),klibc)
- CFLAGS = -I/usr/include -DDEBUG=$(DEBUG)
+ CFLAGS += -I/usr/include -DDEBUG=$(DEBUG)
OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
else
- CFLAGS = -pipe -g -Wall -Wunused -Wstrict-prototypes \
- -I$(multipathdir) -DDEBUG=$(DEBUG)
+ CFLAGS += -I$(multipathdir) -DDEBUG=$(DEBUG)
LDFLAGS = -ldevmapper
OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
endif
-EXEC = pp_balance_units
+EXEC = mpath_prio_balance_units
all: $(BUILD)
@@ -27,7 +26,7 @@
glibc: prepare $(OBJS)
$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
+
klibc: prepare $(OBJS)
$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
Modified: multipath-tools/trunk/path_priority/pp_emc/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_emc/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_emc/Makefile Mon Mar 13 15:16:41 2006
@@ -5,8 +5,6 @@
TOPDIR = ../..
include $(TOPDIR)/Makefile.inc
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
-
all: $(BUILD)
glibc: $(OBJS)
Added: multipath-tools/trunk/path_priority/pp_netapp/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_netapp/Makefile Mon Mar 13 15:16:41 2006
@@ -0,0 +1,22 @@
+EXEC = mpath_prio_netapp
+BUILD = glibc
+OBJS = pp_netapp.o
+
+TOPDIR = ../..
+include $(TOPDIR)/Makefile.inc
+
+all: $(BUILD)
+
+glibc: $(OBJS)
+ $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
+
+klibc: $(OBJS)
+ $(CC) -static -o $(EXEC) $(OBJS)
+
+install: $(EXEC)
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+
+uninstall:
+ rm $(DESTDIR)$(bindir)/$(EXEC)
+clean:
+ rm -f *.o $(EXEC)
Added: multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_netapp/pp_netapp.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2005 Network Appliance, Inc., All Rights Reserved
+ * Author: David Wysochanski available at davidw at netapp.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License v2 for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "../../libmultipath/sg_include.h"
+
+#define INQUIRY_CMD 0x12
+#define INQUIRY_CMDLEN 6
+#define DEFAULT_PRIO 10
+#define RESULTS_MAX 256
+#define SG_TIMEOUT 30000
+
+
+static void dump_cdb(unsigned char *cdb, int size)
+{
+ int i;
+
+ fprintf(stderr, "- SCSI CDB: ");
+ for (i=0; i<size; i++) {
+ fprintf(stderr, "0x%02x ", cdb[i]);
+ }
+ fprintf(stderr, "\n");
+}
+
+static void process_sg_error(struct sg_io_hdr *io_hdr)
+{
+ int i;
+
+ fprintf(stderr, "- masked_status=0x%02x, host_status=0x%02x, "
+ "driver_status=0x%02x\n", io_hdr->masked_status,
+ io_hdr->host_status, io_hdr->driver_status);
+ if (io_hdr->sb_len_wr > 0) {
+ fprintf(stderr, "- SCSI sense data: ");
+ for (i=0; i<io_hdr->sb_len_wr; i++) {
+ fprintf(stderr, "0x%02x ", io_hdr->sbp[i]);
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+/*
+ * Returns:
+ * -1: error, errno set
+ * 0: success
+ */
+static int send_gva(const char *dev, unsigned char pg,
+ unsigned char *results, int *results_size)
+{
+ unsigned char sb[128];
+ unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
+ pg, sizeof(sb), 0, 0};
+ struct sg_io_hdr io_hdr;
+ int ret = -1;
+ int fd;
+
+ fd = open(dev, O_RDWR|O_NONBLOCK);
+
+ if (fd <= 0) {
+ fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
+ goto out_no_close;
+ }
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (cdb);
+ io_hdr.mx_sb_len = sizeof (sb);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = *results_size;
+ io_hdr.dxferp = results;
+ io_hdr.cmdp = cdb;
+ io_hdr.sbp = sb;
+ io_hdr.timeout = SG_TIMEOUT;
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ fprintf(stderr, "SG_IO ioctl failed, errno=%d\n", errno);
+ dump_cdb(cdb, sizeof(cdb));
+ goto out;
+ }
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+ fprintf(stderr, "SCSI error\n");
+ dump_cdb(cdb, sizeof(cdb));
+ process_sg_error(&io_hdr);
+ goto out;
+ }
+
+ if (results[4] != 0x0a || results[5] != 0x98 ||
+ results[6] != 0x0a ||results[7] != 0x01) {
+ dump_cdb(cdb, sizeof(cdb));
+ fprintf(stderr, "GVA return wrong format ");
+ fprintf(stderr, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ results[4], results[5], results[6], results[7]);
+ goto out;
+ }
+ ret = 0;
+ out:
+ close(fd);
+ out_no_close:
+ return(ret);
+}
+
+/*
+ * Retuns:
+ * -1: Unable to obtain proxy info
+ * 0: Device _not_ proxy path
+ * 1: Device _is_ proxy path
+ */
+static int get_proxy(const char *dev)
+{
+ unsigned char results[256];
+ unsigned char sb[128];
+ unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
+ sizeof(sb), 0};
+ struct sg_io_hdr io_hdr;
+ int ret = -1;
+ int fd;
+
+ fd = open(dev, O_RDWR|O_NONBLOCK);
+
+ if (fd <= 0) {
+ fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
+ goto out_no_close;
+ }
+
+ memset(&results, 0, sizeof (results));
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (cdb);
+ io_hdr.mx_sb_len = sizeof (sb);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = sizeof (results);
+ io_hdr.dxferp = results;
+ io_hdr.cmdp = cdb;
+ io_hdr.sbp = sb;
+ io_hdr.timeout = SG_TIMEOUT;
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ fprintf(stderr, "ioctl sending inquiry command failed, "
+ "errno=%d\n", errno);
+ dump_cdb(cdb, sizeof(cdb));
+ goto out;
+ }
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+ fprintf(stderr, "SCSI error\n");
+ dump_cdb(cdb, sizeof(cdb));
+ process_sg_error(&io_hdr);
+ goto out;
+ }
+
+ if (results[1] != 0xc1 || results[8] != 0x0a ||
+ results[9] != 0x98 || results[10] != 0x0a ||
+ results[11] != 0x0 || results[12] != 0xc1 ||
+ results[13] != 0x0) {
+ fprintf(stderr,"Proxy info page in unknown format - ");
+ fprintf(stderr,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n",
+ results[8], results[9], results[10],
+ results[11], results[12], results[13]);
+ dump_cdb(cdb, sizeof(cdb));
+ goto out;
+ }
+ ret = (results[19] & 0x02) >> 1;
+
+ out:
+ close(fd);
+ out_no_close:
+ return(ret);
+}
+
+/*
+ * Returns priority of device based on device info.
+ *
+ * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
+ * 3: iSCSI HBA
+ * 2: iSCSI software
+ * 1: FCP proxy
+ */
+static int netapp_prio(const char *dev)
+{
+ unsigned char results[RESULTS_MAX];
+ int results_size=RESULTS_MAX;
+ int rc;
+ int is_proxy;
+ int is_iscsi_software;
+ int is_iscsi_hardware;
+ int tot_len;
+
+ is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
+
+ memset(&results, 0, sizeof (results));
+ rc = send_gva(dev, 0x41, results, &results_size);
+ if (rc == 0) {
+ tot_len = results[0] << 24 | results[1] << 16 |
+ results[2] << 8 | results[3];
+ if (tot_len <= 8) {
+ goto try_fcp_proxy;
+ }
+ if (results[8] != 0x41) {
+ fprintf(stderr, "GVA page 0x41 error - "
+ "results[8] = 0x%x\n", results[8]);
+ goto try_fcp_proxy;
+ }
+ if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
+ (strncmp((char *)&results[12], "iswt", 4) == 0)) {
+ is_iscsi_software = 1;
+ goto prio_select;
+ }
+ else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
+ is_iscsi_hardware = 1;
+ goto prio_select;
+ }
+ }
+
+ try_fcp_proxy:
+ rc = get_proxy(dev);
+ if (rc >= 0) {
+ is_proxy = rc;
+ }
+
+ prio_select:
+ if (is_iscsi_hardware) {
+ return 3;
+ } else if (is_iscsi_software) {
+ return 2;
+ } else {
+ if (is_proxy) {
+ return 1;
+ } else {
+ /* Either non-proxy, or couldn't get proxy info */
+ return 4;
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ int prio;
+ if (argc != 2) {
+ fprintf(stderr, "Arguments wrong!\n");
+ prio = 0;
+ } else
+ prio = netapp_prio(argv[1]);
+
+ printf("%d\n", prio);
+ exit(0);
+}
+
Modified: multipath-tools/trunk/path_priority/pp_random/Makefile
==============================================================================
--- multipath-tools/trunk/path_priority/pp_random/Makefile (original)
+++ multipath-tools/trunk/path_priority/pp_random/Makefile Mon Mar 13 15:16:41 2006
@@ -5,8 +5,6 @@
TOPDIR = ../..
include $(TOPDIR)/Makefile.inc
-CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes
-
all: $(BUILD)
glibc: $(OBJS)
@@ -23,6 +21,3 @@
rm $(DESTDIR)$(bindir)/$(EXEC)
clean:
rm -f *.o $(EXEC)
-
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
Added: multipath-tools/trunk/path_priority/pp_tpc/Makefile
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_tpc/Makefile Mon Mar 13 15:16:41 2006
@@ -0,0 +1,22 @@
+EXEC = mpath_prio_tpc
+BUILD = glibc
+OBJS = pp_tpc.o
+
+TOPDIR = ../..
+include $(TOPDIR)/Makefile.inc
+
+all: $(BUILD)
+
+glibc: $(OBJS)
+ $(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
+
+klibc: $(OBJS)
+ $(CC) -static -o $(EXEC) $(OBJS)
+
+install: $(EXEC)
+ install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+
+uninstall:
+ rm $(DESTDIR)$(bindir)/$(EXEC)
+clean:
+ rm -f *.o $(EXEC)
Added: multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c
==============================================================================
--- (empty file)
+++ multipath-tools/trunk/path_priority/pp_tpc/pp_tpc.c Mon Mar 13 15:16:41 2006
@@ -0,0 +1,118 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../../libmultipath/sg_include.h"
+
+#define INQUIRY_CMD 0x12
+#define INQUIRY_CMDLEN 6
+
+int sgi_tpc_prio(const char *dev)
+{
+ unsigned char sense_buffer[256];
+ unsigned char sb[128];
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
+ sizeof(sb), 0};
+ struct sg_io_hdr io_hdr;
+ int ret = 0;
+ int fd;
+
+ fd = open(dev, O_RDWR|O_NONBLOCK);
+
+ if (fd <= 0) {
+ fprintf(stderr, "opening of the device failed.\n");
+ goto out;
+ }
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sb);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = sizeof (sense_buffer);
+ io_hdr.dxferp = sense_buffer;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sb;
+ io_hdr.timeout = 60000;
+ io_hdr.pack_id = 0;
+ if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+ fprintf(stderr, "sending inquiry command failed\n");
+ goto out;
+ }
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+ fprintf(stderr, "inquiry command indicates error");
+ goto out;
+ }
+
+ close(fd);
+
+ if (/* Verify the code page - right page & page identifier */
+ sense_buffer[1] != 0xc9 ||
+ sense_buffer[3] != 0x2c ||
+ sense_buffer[4] != 'v' ||
+ sense_buffer[5] != 'a' ||
+ sense_buffer[6] != 'c' ) {
+ fprintf(stderr, "Volume access control page in unknown format");
+ goto out;
+ }
+
+ if ( /* Auto-volume Transfer Enabled */
+ (sense_buffer[8] & 0x80) != 0x80 ) {
+ fprintf(stderr, "Auto-volume Transfer not enabled");
+ }
+
+ if ( /* Current Volume Path Bit */
+ ( sense_buffer[8] & 0x01) == 0x01 ) {
+ /*
+ * This volume was owned by the controller receiving
+ * the inquiry command.
+ */
+ ret |= 0x02;
+ }
+
+ /* Volume Preferred Path Priority */
+ switch ( sense_buffer[9] & 0x0F ) {
+ case 0x01:
+ /*
+ * Access to this volume is most preferred through
+ * this path and other paths with this value.
+ */
+ ret |= 0x04;
+ break;
+ case 0x02:
+ /*
+ * Access to this volume through this path is to be used
+ * as a secondary path. Typically this path would be used
+ * for fail-over situations.
+ */
+ ret |= 0x01;
+ break;
+ default:
+ /* Reserved values */
+ break;
+ }
+
+out:
+ return(ret);
+}
+
+int
+main (int argc, char **argv)
+{
+ int prio;
+ if (argc != 2) {
+ fprintf(stderr, "Wrong number of arguments.\n");
+ fprintf(stderr, "Usage: %s device\n", argv[0]);
+ prio = 0;
+ } else
+ prio = sgi_tpc_prio(argv[1]);
+
+ printf("%d\n", prio);
+ exit(0);
+}
More information about the pkg-lvm-commits
mailing list